@fedify/postgres
Version:
PostgreSQL drivers for Fedify
116 lines (112 loc) • 3.41 kB
JavaScript
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;