UNPKG

@fedify/postgres

Version:

PostgreSQL drivers for Fedify

116 lines (112 loc) 3.41 kB
const { Temporal } = require("@js-temporal/polyfill"); const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs'); const require_utils = require('./utils.cjs'); const __logtape_logtape = require_rolldown_runtime.__toESM(require("@logtape/logtape")); //#region src/kv.ts const logger = (0, __logtape_logtape.getLogger)([ "fedify", "postgres", "kv" ]); /** * A key–value store that uses PostgreSQL as the underlying storage. * * @example * ```ts * import { createFederation } from "@fedify/fedify"; * import { PostgresKvStore } from "@fedify/postgres"; * import postgres from "postgres"; * * const federation = createFederation({ * // ... * kv: new PostgresKvStore(postgres("postgres://user:pass@localhost/db")), * }); * ``` */ var PostgresKvStore = class { #sql; #tableName; #initialized; #driverSerializesJson = false; /** * Creates a new PostgreSQL key–value store. * @param sql The PostgreSQL client to use. * @param options The options for the key–value store. */ constructor(sql, options = {}) { this.#sql = sql; this.#tableName = options.tableName ?? "fedify_kv_v2"; this.#initialized = options.initialized ?? false; } async #expire() { await this.#sql` DELETE FROM ${this.#sql(this.#tableName)} WHERE ttl IS NOT NULL AND created + ttl < CURRENT_TIMESTAMP; `; } async get(key) { await this.initialize(); const result = await this.#sql` SELECT value FROM ${this.#sql(this.#tableName)} WHERE key = ${key} AND (ttl IS NULL OR created + ttl > CURRENT_TIMESTAMP); `; if (result.length < 1) return void 0; return result[0].value; } async set(key, value, options) { await this.initialize(); const ttl = options?.ttl == null ? null : options.ttl.toString(); await this.#sql` INSERT INTO ${this.#sql(this.#tableName)} (key, value, ttl) VALUES ( ${key}, ${this.#json(value)}, ${ttl} ) ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, ttl = EXCLUDED.ttl; `; await this.#expire(); } async delete(key) { await this.initialize(); await this.#sql` DELETE FROM ${this.#sql(this.#tableName)} WHERE key = ${key}; `; await this.#expire(); } /** * Creates the table used by the key–value store if it does not already exist. * Does nothing if the table already exists. */ async initialize() { if (this.#initialized) return; logger.debug("Initializing the key–value store table {tableName}...", { tableName: this.#tableName }); await this.#sql` CREATE UNLOGGED TABLE IF NOT EXISTS ${this.#sql(this.#tableName)} ( key text[] PRIMARY KEY, value jsonb NOT NULL, created timestamp with time zone DEFAULT CURRENT_TIMESTAMP, ttl interval ); `; this.#driverSerializesJson = await require_utils.driverSerializesJson(this.#sql); this.#initialized = true; logger.debug("Initialized the key–value store table {tableName}.", { tableName: this.#tableName }); } /** * Drops the table used by the key–value store. Does nothing if the table * does not exist. */ async drop() { await this.#sql`DROP TABLE IF EXISTS ${this.#sql(this.#tableName)};`; } #json(value) { if (this.#driverSerializesJson) return this.#sql.json(value); return this.#sql.json(JSON.stringify(value)); } }; //#endregion exports.PostgresKvStore = PostgresKvStore;