UNPKG

libmodulor

Version:

A TypeScript library to create platform-agnostic applications

256 lines (255 loc) 9.61 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; import { inject, injectable } from 'inversify'; import knex, {} from 'knex'; import { NotAvailableError, NotCallableError } from '../../error/index.js'; const FILTERS_MAPPING = new Map([ ['aggregateId', 'aggregate_id'], ['appName', 'app_name'], ['name', 'name'], ['organizationId', 'organization_id'], ['userId', 'user_id'], ]); let KnexUCDataStore = class KnexUCDataStore { settingsManager; config; client; constructor(settingsManager) { this.settingsManager = settingsManager; this.config = {}; this.fillConfig(); this.client = knex(this.config); } s() { return { knex_uc_data_store_conn_string: this.settingsManager.get()('knex_uc_data_store_conn_string'), knex_uc_data_store_file_path: this.settingsManager.get()('knex_uc_data_store_file_path'), knex_uc_data_store_pool_max: this.settingsManager.get()('knex_uc_data_store_pool_max'), knex_uc_data_store_pool_min: this.settingsManager.get()('knex_uc_data_store_pool_min'), knex_uc_data_store_type: this.settingsManager.get()('knex_uc_data_store_type'), uc_data_store_ucs_dataset_name: this.settingsManager.get()('uc_data_store_ucs_dataset_name'), }; } async clear() { await this.client .table(this.s().uc_data_store_ucs_dataset_name) .truncate(); } async destroy() { await this.client.schema.dropTableIfExists(this.s().uc_data_store_ucs_dataset_name); } async exists() { return this.client.schema.hasTable(this.s().uc_data_store_ucs_dataset_name); } async init() { await this.migration001CreateMainTable(); } initSync() { throw new NotCallableError('initSync', 'init', 'async-only'); } async read(opts) { const query = this.client(this.s().uc_data_store_ucs_dataset_name); // Filter if (opts?.filters) { const { aggregateId, appName, idWithinInput, name, organizationId, userId, } = opts.filters; this.filter(query, aggregateId, 'aggregateId'); this.filter(query, appName, 'appName'); this.filter(query, name, 'name'); this.filter(query, organizationId, 'organizationId'); this.filter(query, userId, 'userId'); if (idWithinInput !== undefined) { for (const [k, v] of Object.entries(idWithinInput)) { // Not comfortable with the key here but it seems to escape correctly : // select * from "d2efe54a-ce85-437c-958e-440f54c0743d" // where jsonb_path_query_first("input", ?) #>> '{}' = ? // and "name" = ? // and "organization_id" = ? // order by "created_at" asc query.whereJsonPath('input', `$.${k}`, '=', v); } } } // Sort query.orderBy('created_at', 'asc'); const records = (await query).map((r) => this.mapRowToRecord(r)); return { records, }; } async readProjection(name, opts) { const query = this.client(name); // Sort if (opts?.orderBy) { for (const [k, v] of Object.entries(opts.orderBy)) { query.orderBy(k, v); } } // Paginate if (opts?.limit) { query.limit(opts.limit); } const records = await query; return records; } async startTx() { return this.client.transaction(); } supportedSpecificBindings() { const type = this.s().knex_uc_data_store_type; switch (type) { case 'pg': return ['to_tsvector(?)']; case 'sqlite3': return []; default: ((_) => { })(type); return []; } } async testKey(_encryptionKey) { throw new NotAvailableError('testKey'); } async write(record, opts) { await this.writeBulk([record], opts); } async writeBulk(records, opts) { const query = this.client(this.s().uc_data_store_ucs_dataset_name).insert(records.map((r) => this.mapRecordToRow(r))); if (opts?.tx) { query.transacting(opts.tx.ref); } await query; } async writeProjection(name, data, opts) { const dataToInsert = {}; for (const [k, v] of Object.entries(data)) { const specificBinding = opts?.specificBindings?.[k]; dataToInsert[k] = specificBinding && this.supportedSpecificBindings().includes(specificBinding) ? this.client.raw(specificBinding, [v]) : v; } const query = this.client(name).insert(dataToInsert); if (opts?.tx) { query.transacting(opts.tx.ref); } await query; } fillConfig() { const type = this.s().knex_uc_data_store_type; this.config.client = type; switch (type) { case 'pg': this.fillConfigForPG(); break; case 'sqlite3': this.fillConfigForSQLite3(); break; default: ((_) => { })(type); } } fillConfigForPG() { this.config.connection = { connectionString: this.s().knex_uc_data_store_conn_string, }; this.config.pool = { max: this.s().knex_uc_data_store_pool_max, min: this.s().knex_uc_data_store_pool_min, }; } fillConfigForSQLite3() { this.config.useNullAsDefault = true; this.config.connection = { filename: this.s().knex_uc_data_store_file_path, }; } filter(query, value, field) { if (value === undefined) { return; } const col = FILTERS_MAPPING.get(field); if (!col) { return; } Array.isArray(value) ? query.whereIn(col, value) : query.where(col, value); } mapRecordToRow(record) { return { aggregate_id: record.aggregateId, app_name: record.appName, created_at: record.createdAt, data: record.data, execution_mode: record.executionMode, id: record.id, input: record.input, name: record.name, organization_id: record.organizationId, user_id: record.userId, }; } mapRowToRecord(row) { return { aggregateId: row.aggregate_id, appName: row.app_name, createdAt: row.created_at, data: this.parseJSONColIfNecessary(row.data), executionMode: row.execution_mode, id: row.id, input: this.parseJSONColIfNecessary(row.input), name: row.name, organizationId: row.organization_id, userId: row.user_id, }; } parseJSONColIfNecessary(value) { // In some DBs, the json type is returned as string (e.g. sqlite3) return typeof value === 'string' ? JSON.parse(value) : value; } //#region migrations async migration001CreateMainTable() { // Using hasTable and then createTable because createTableIfNotExists has been deprecated // See https://github.com/knex/knex/issues/1303#issuecomment-594489136 const exists = await this.client.schema.hasTable(this.s().uc_data_store_ucs_dataset_name); if (exists) { return; } await this.client.schema.createTable(this.s().uc_data_store_ucs_dataset_name, (table) => { table.uuid('aggregate_id').notNullable(); table.string('app_name').notNullable(); table .dateTime('created_at') .notNullable() .defaultTo(this.client.fn.now()); table.jsonb('data'); table.string('execution_mode').notNullable(); table.uuid('id').notNullable().primary(); table.jsonb('input'); table.string('name').notNullable(); table.uuid('organization_id'); table.uuid('user_id'); table.index('aggregate_id'); table.index('name'); table.index('organization_id'); table.index('user_id'); }); } }; KnexUCDataStore = __decorate([ injectable(), __param(0, inject('SettingsManager')), __metadata("design:paramtypes", [Object]) ], KnexUCDataStore); export { KnexUCDataStore };