Unverified Commit f847937a authored by Hong Minhee's avatar Hong Minhee
Browse files

Fix escaping for binding parameters

parent 9b20ddcb
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -68,8 +68,8 @@ Changelog

To be released.

 -  Use the explicitly typed binding instead of an implicit one to work
    around the stringification issue.
 -  Fixed a bug where binding parameters have not been properly escaped with
    some settings of Postgres.js.

### Version 0.2.1

+10 −2
Original line number Diff line number Diff line
import type { KvKey, KvStore, KvStoreSetOptions } from "@fedify/fedify";
import type { JSONValue, Sql } from "postgres";
import type { JSONValue, Parameter, Sql } from "postgres";
import { driverSerializesJson } from "./utils.ts";

/**
 * Options for the PostgreSQL key-value store.
@@ -39,6 +40,7 @@ export class PostgresKvStore implements KvStore {
  readonly #sql: Sql<{}>;
  readonly #tableName: string;
  #initialized: boolean;
  #driverSerializesJson = false;

  /**
   * Creates a new PostgreSQL key-value store.
@@ -84,7 +86,7 @@ export class PostgresKvStore implements KvStore {
      INSERT INTO ${this.#sql(this.#tableName)} (key, value, ttl)
      VALUES (
        ${key},
        ${this.#sql.json(value as JSONValue)},
        ${this.#json(value)},
        ${ttl}
      )
      ON CONFLICT (key)
@@ -116,6 +118,7 @@ export class PostgresKvStore implements KvStore {
        ttl interval
      );
    `;
    this.#driverSerializesJson = await driverSerializesJson(this.#sql);
    this.#initialized = true;
  }

@@ -126,4 +129,9 @@ export class PostgresKvStore implements KvStore {
  async drop(): Promise<void> {
    await this.#sql`DROP TABLE IF EXISTS ${this.#sql(this.#tableName)};`;
  }

  #json(value: unknown): Parameter {
    if (this.#driverSerializesJson) return this.#sql.json(value as JSONValue);
    return this.#sql.json(JSON.stringify(value));
  }
}
+10 −2
Original line number Diff line number Diff line
@@ -3,8 +3,9 @@ import type {
  MessageQueueEnqueueOptions,
  MessageQueueListenOptions,
} from "@fedify/fedify";
import type { Sql } from "postgres";
import type { JSONValue, Parameter, Sql } from "postgres";
import postgres from "postgres";
import { driverSerializesJson } from "./utils.ts";

/**
 * Options for the PostgreSQL message queue.
@@ -61,6 +62,7 @@ export class PostgresMessageQueue implements MessageQueue {
  readonly #channelName: string;
  readonly #pollIntervalMs: number;
  #initialized: boolean;
  #driverSerializesJson = false;

  constructor(
    // deno-lint-ignore ban-types
@@ -86,7 +88,7 @@ export class PostgresMessageQueue implements MessageQueue {
    await this.#sql`
      INSERT INTO ${this.#sql(this.#tableName)} (message, delay)
      VALUES (
        ${this.#sql.json(message)},
        ${this.#json(message)},
        ${delay.toString()}
      );
    `;
@@ -181,6 +183,7 @@ export class PostgresMessageQueue implements MessageQueue {
        throw e;
      }
    }
    this.#driverSerializesJson = await driverSerializesJson(this.#sql);
    this.#initialized = true;
  }

@@ -190,6 +193,11 @@ export class PostgresMessageQueue implements MessageQueue {
  async drop(): Promise<void> {
    await this.#sql`DROP TABLE IF EXISTS ${this.#sql(this.#tableName)};`;
  }

  #json(value: unknown): Parameter {
    if (this.#driverSerializesJson) return this.#sql.json(value as JSONValue);
    return this.#sql.json(JSON.stringify(value));
  }
}

// cSpell: ignore typname

src/utils.ts

0 → 100644
+7 −0
Original line number Diff line number Diff line
import type { Sql } from "postgres";

// deno-lint-ignore ban-types
export async function driverSerializesJson(sql: Sql<{}>): Promise<boolean> {
  const result = await sql`SELECT ${sql.json('{"foo":1}')}::jsonb AS test;`;
  return result[0].test === '{"foo":1}';
}