UNPKG

@getanthill/datastore

Version:

Event-Sourced Datastore

130 lines 5.42 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const pg_1 = require("pg"); const lodash_1 = require("lodash"); class PostgreSQLClient { constructor(config) { this._config = config; this._client = new pg_1.Client(config.client); } static async init(config) { const url = new URL(config.client.connectionString); const dbName = url.pathname.slice(1); const client = new pg_1.Client({ ...config.client, connectionString: config.client.connectionString.replace(`/${dbName}`, ''), }); try { await client.connect(); await client.query(`CREATE DATABASE ${dbName}`); } catch (err) { // ... } finally { await client.end(); } } connect() { return this._client.connect(); } disconnect() { return this._client.end(); } static getTableBaseName(modelConfig, namespace) { const modelName = modelConfig.name; return `${namespace ? namespace + '_' : ''}${modelName}`; } static getSqlSchemaForModelDeletion(modelConfig, namespace) { const tableBaseName = PostgreSQLClient.getTableBaseName(modelConfig, namespace); return [ `DROP TABLE IF EXISTS "${tableBaseName}";`, `DROP TABLE IF EXISTS "${tableBaseName}_events";`, `DROP TABLE IF EXISTS "${tableBaseName}_snapshots";`, ]; } static getSqlSchemaForModel(modelConfig, namespace) { const sql = []; const correlationField = modelConfig.correlation_field; const tableBaseName = PostgreSQLClient.getTableBaseName(modelConfig, namespace); const modelDescription = modelConfig.description ?? ''; sql.push(`CREATE TABLE IF NOT EXISTS "${tableBaseName}" ( "${correlationField}" TEXT, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL, "version" BIGINT, "entity" JSON, PRIMARY KEY ("${correlationField}") );`); sql.push(`CREATE TABLE IF NOT EXISTS "${tableBaseName}_events" ( "${correlationField}" TEXT, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, "version" BIGINT, "type" VARCHAR(256), "event" JSON, PRIMARY KEY ("${correlationField}", "version") );`); sql.push(`CREATE TABLE IF NOT EXISTS "${tableBaseName}_snapshots" ( "${correlationField}" TEXT, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL, "version" BIGINT, "entity" JSON, PRIMARY KEY ("${correlationField}") );`); sql.push(`COMMENT ON TABLE "${tableBaseName}" IS ${modelDescription ? "'[entities] " + modelDescription + "'" : 'NULL'}`); sql.push(`COMMENT ON TABLE "${tableBaseName}_events" IS ${modelDescription ? "'[events] " + modelDescription + "'" : 'NULL'}`); sql.push(`COMMENT ON TABLE "${tableBaseName}_snapshots" IS ${modelDescription ? "'[snapshots] " + modelDescription + "'" : 'NULL'}`); return sql; } static getSqlSchemaForModels(modelConfigs, mustClean = false, namespace) { const sql = []; for (const modelConfig of modelConfigs) { sql.push(...(mustClean === true ? PostgreSQLClient.getSqlSchemaForModelDeletion(modelConfig, namespace) : []), ...PostgreSQLClient.getSqlSchemaForModel(modelConfig, namespace)); } return sql; } query(q) { return this._client.query(q); } async queryAll(queries) { const results = []; for (const q of queries) { const result = await this.query(q); results.push(result); } return results; } insert(modelConfig, source, data, options) { let safeData = data; if (options?.with_encrypted_data !== true) { safeData = (0, lodash_1.cloneDeep)(data); (modelConfig.encrypted_fields ?? []).forEach((path) => (0, lodash_1.unset)(safeData, `${path}.encrypted`)); } const json = JSON.stringify(safeData).replace(/'/g, "''"); const tableBaseName = PostgreSQLClient.getTableBaseName(modelConfig, this._config.namespace); const tableName = `${tableBaseName}${source === 'events' ? '_events' : ''}`; const sql = `INSERT INTO "${tableName}" ( ${modelConfig.correlation_field}, created_at,${source === 'entities' ? ' updated_at,' : ''} version, ${source === 'events' ? ' type,' : ''} ${source === 'events' ? 'event' : 'entity'} ) VALUES ( '${safeData[modelConfig.correlation_field]}', '${safeData.created_at}',${source === 'entities' ? "'" + safeData.updated_at + "'," : ''} ${safeData.version},${source === 'events' ? "'" + safeData.type + "'," : ''} '${json}' ) ON CONFLICT ON CONSTRAINT ${tableName}_pkey DO UPDATE SET "version" = ${safeData.version}, ${source === 'entities' ? '"updated_at" = \'' + safeData.updated_at + "'," : '"created_at" = \'' + safeData.created_at + "',"} "${source === 'events' ? 'event' : 'entity'}" = '${json}'`; return this.query(sql); } } PostgreSQLClient.ERRORS = {}; exports.default = PostgreSQLClient; //# sourceMappingURL=pg.js.map