@js-ak/db-manager
Version:
844 lines (843 loc) • 39.8 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseTable = void 0;
const Helpers = __importStar(require("../helpers/index.js"));
const SharedHelpers = __importStar(require("../../../shared-helpers/index.js"));
const connection = __importStar(require("../connection.js"));
const index_js_1 = require("../query-builder/index.js");
const queries_js_1 = __importDefault(require("./queries.js"));
/**
* Represents a base table with common database operations.
*/
class BaseTable {
#insertOptions;
#sortingOrders = new Set(["ASC", "DESC"]);
#tableFieldsSet;
#isLoggerEnabled;
#logger;
#executeSql;
#executeSqlStream;
#initialArgs;
/**
* The PostgreSQL executor.
* - pg.Pool
* - pg.PoolClient
* - pg.Client
*/
#executor;
createField;
primaryKey;
tableName;
tableFields;
updateField;
/**
* Creates an instance of BaseTable.
*
* Initializes a new instance of the `BaseTable` class with the provided table configuration and database credentials.
* Optionally, additional database options can be specified.
*
* @param data - The configuration object for the table, which includes:
* - `additionalSortingFields`: An optional array of fields to use for additional sorting.
* - `createField`: An optional object specifying a field to set with a timestamp when a record is created.
* - `title`: The field name.
* - `type`: The type of timestamp (`"unix_timestamp"` or `"timestamp"`).
* - `primaryKey`: The primary key field or fields for the table. This can be a single field or an array of fields.
* - `tableFields`: The fields in the table.
* - `tableName`: The name of the table.
* - `updateField`: An optional object specifying a field to update with a timestamp when a record is updated.
* - `title`: The field name.
* - `type`: The type of timestamp (`"unix_timestamp"` or `"timestamp"`).
* @param [dbCreds] - The credentials for connecting to the database, including:
* - `database`: The name of the database.
* - `host`: The database host.
* - `password`: The password for connecting to the database.
* - `port`: The port number for connecting to the database.
* - `user`: The username for connecting to the database.
* @param [options] - Optional configuration options for the database connection, which can include:
* - `insertOptions`: Configuration for insert operations.
* - `onConflict`: Specifies the action to take when there is a conflict on insert.
* - `poolClient`: An optional `pg.PoolClient` for managing database connections.
*/
constructor(data, dbCreds, options) {
const { client, insertOptions, isLoggerEnabled, logger } = options || {};
if (client) {
this.#executor = client;
}
else if (dbCreds) {
this.#executor = connection.getStandardPool(dbCreds);
}
else {
throw new Error("No client or dbCreds provided");
}
this.createField = data.createField;
this.primaryKey = data.primaryKey;
this.tableName = data.tableName;
this.tableFields = [...data.tableFields];
this.updateField = data.updateField;
this.#tableFieldsSet = new Set([
...this.tableFields,
...(data.additionalSortingFields || []),
]);
this.#initialArgs = { data, dbCreds, options };
const preparedOptions = Helpers.setLoggerAndExecutor(this.#executor, { isLoggerEnabled, logger });
const { executeSqlStream } = Helpers.setStreamExecutor(this.#executor, { isLoggerEnabled, logger });
this.#insertOptions = insertOptions;
this.#executeSql = preparedOptions.executeSql;
this.#executeSqlStream = executeSqlStream;
this.#isLoggerEnabled = preparedOptions.isLoggerEnabled;
this.#logger = preparedOptions.logger;
}
/**
* Gets the database client for the table.
*
* @returns The database client for the table.
*/
get pool() {
return this.#executor;
}
/**
* Gets the PostgreSQL executor for the table.
*
* @returns The PostgreSQL executor for the table.
*/
get executor() {
return this.#executor;
}
/**
* Sets the logger for the table.
*
* @param logger - The logger to use for the table.
*/
setLogger(logger) {
const preparedOptions = Helpers.setLoggerAndExecutor(this.#executor, { isLoggerEnabled: true, logger });
const { executeSqlStream } = Helpers.setStreamExecutor(this.#executor, { isLoggerEnabled: true, logger });
this.#executeSql = preparedOptions.executeSql;
this.#executeSqlStream = executeSqlStream;
this.#isLoggerEnabled = preparedOptions.isLoggerEnabled;
this.#logger = preparedOptions.logger;
}
/**
* Sets the executor for the table.
*
* @param executor - The executor to use for the table.
*/
setExecutor(executor) {
const preparedOptions = Helpers.setLoggerAndExecutor(executor, { isLoggerEnabled: this.#isLoggerEnabled, logger: this.#logger });
const { executeSqlStream } = Helpers.setStreamExecutor(executor, { isLoggerEnabled: this.#isLoggerEnabled, logger: this.#logger });
this.#executeSql = preparedOptions.executeSql;
this.#executeSqlStream = executeSqlStream;
this.#isLoggerEnabled = preparedOptions.isLoggerEnabled;
this.#logger = preparedOptions.logger;
this.#executor = executor;
}
get isLoggerEnabled() {
return this.#isLoggerEnabled;
}
get executeSql() {
return this.#executeSql;
}
get executeSqlStream() {
return this.#executeSqlStream;
}
/**
* Sets the client in the current class.
*
* @experimental
*
* @param client - The client connection to set.
*
* @returns The current instance with the new connection client.
*/
setClientInCurrentClass(client) {
return new this.constructor({ ...this.#initialArgs.data }, this.#initialArgs.dbCreds ? { ...this.#initialArgs.dbCreds } : undefined, { ...this.#initialArgs.options, client });
}
/**
* Sets the client in the base class.
*
* @experimental
*
* @param client - The client connection to set.
*
* @returns A new instance of the base class with the new connection client.
*/
setClientInBaseClass(client) {
return new BaseTable({ ...this.#initialArgs.data }, this.#initialArgs.dbCreds ? { ...this.#initialArgs.dbCreds } : undefined, { ...this.#initialArgs.options, client });
}
compareFields = Helpers.compareFields;
getFieldsToSearch = Helpers.getFieldsToSearch;
compareQuery = {
createMany: (recordParams, saveOptions) => {
const v = [];
const k = [];
const headers = new Set();
const example = recordParams[0];
if (!example)
throw new Error("Invalid recordParams");
const params = SharedHelpers.clearUndefinedFields(example);
Object.keys(params).forEach((e) => headers.add(e));
if (this.createField) {
headers.add(this.createField.title);
}
for (const pR of recordParams) {
const params = SharedHelpers.clearUndefinedFields(pR);
const keys = new Set(Object.keys(params));
const paramsPrepared = [...Object.values(params)];
if (this.createField) {
if (!keys.has(this.createField.title)) {
keys.add(this.createField.title);
switch (this.createField.type) {
case "timestamp":
paramsPrepared.push(new Date().toISOString());
break;
case "unix_timestamp":
paramsPrepared.push(Date.now());
break;
default:
throw new Error("Invalid type: " + this.createField.type);
}
}
}
k.push([...keys]);
v.push(...paramsPrepared);
if (!k.length) {
throw new Error(`Invalid params, all fields are undefined - ${Object.keys(recordParams).join(", ")}`);
}
for (const key of keys) {
if (!headers.has(key)) {
throw new Error(`Invalid params, all fields are undefined - ${Object.keys(pR).join(", ")}`);
}
}
}
const onConflict = this.#insertOptions?.onConflict || "";
return {
query: queries_js_1.default.createMany({
fields: k,
headers: [...headers],
onConflict,
returning: saveOptions?.returningFields,
tableName: this.tableName,
}),
values: v,
};
},
createOne: (recordParams = {}, saveOptions) => {
const clearedParams = SharedHelpers.clearUndefinedFields(recordParams);
const fields = Object.keys(clearedParams);
const onConflict = this.#insertOptions?.onConflict || "";
if (!fields.length) {
throw new Error("No one save field arrived");
}
return {
query: queries_js_1.default.createOne(this.tableName, fields, this.createField, onConflict, saveOptions?.returningFields),
values: Object.values(clearedParams),
};
},
deleteAll: () => {
return { query: queries_js_1.default.deleteAll(this.tableName) };
},
deleteByParams: ({ $and = {}, $or }) => {
const { queryArray, queryOrArray, values } = this.compareFields($and, $or);
const { searchFields } = this.getFieldsToSearch({ queryArray, queryOrArray });
return {
query: queries_js_1.default.deleteByParams(this.tableName, searchFields),
values,
};
},
deleteOneByPk: (primaryKey) => {
if (!this.primaryKey) {
throw new Error("Primary key not specified");
}
return {
query: queries_js_1.default.deleteByPk(this.tableName, this.primaryKey),
values: Array.isArray(primaryKey) ? primaryKey : [primaryKey],
};
},
getArrByParams: ({ $and = {}, $or }, selected = ["*"], pagination, order) => {
if (order?.length) {
for (const o of order) {
if (!this.#tableFieldsSet.has(o.orderBy)) {
const allowedFields = Array.from(this.#tableFieldsSet).join(", ");
throw new Error(`Invalid orderBy: ${o.orderBy}. Allowed fields are: ${allowedFields}`);
}
if (!this.#sortingOrders.has(o.ordering)) {
throw new Error("Invalid ordering");
}
}
}
if (!selected.length)
selected.push("*");
const { queryArray, queryOrArray, values } = this.compareFields($and, $or);
const { orderByFields, paginationFields, searchFields, selectedFields } = this.getFieldsToSearch({ queryArray, queryOrArray }, selected, pagination, order);
return {
query: queries_js_1.default.getByParams(this.tableName, selectedFields, searchFields, orderByFields, paginationFields),
values,
};
},
getCountByParams: ({ $and = {}, $or }) => {
const { queryArray, queryOrArray, values } = this.compareFields($and, $or);
const { searchFields } = this.getFieldsToSearch({ queryArray, queryOrArray });
return {
query: queries_js_1.default.getCountByParams(this.tableName, searchFields),
values,
};
},
getCountByPks: (pks) => {
if (!this.primaryKey) {
throw new Error("Primary key not specified");
}
if (Array.isArray(pks[0])) {
if (!Array.isArray(this.primaryKey)) {
throw new Error("invalid primary key type");
}
return {
query: queries_js_1.default.getCountByCompositePks(this.primaryKey, this.tableName, pks.length),
values: pks.flat(),
};
}
if (Array.isArray(this.primaryKey)) {
throw new Error("invalid primary key type");
}
return {
query: queries_js_1.default.getCountByPks(this.primaryKey, this.tableName),
values: [pks],
};
},
getCountByPksAndParams: (pks, { $and = {}, $or }) => {
if (!this.primaryKey) {
throw new Error("Primary key not specified");
}
const { queryArray, queryOrArray, values } = this.compareFields($and, $or);
const { orderNumber, searchFields } = this.getFieldsToSearch({ queryArray, queryOrArray });
if (Array.isArray(pks[0])) {
if (!Array.isArray(this.primaryKey)) {
throw new Error("invalid primary key type");
}
return {
query: queries_js_1.default.getCountByCompositePksAndParams(this.primaryKey, this.tableName, searchFields, orderNumber, pks.length),
values: [...values, ...pks.flat()],
};
}
if (Array.isArray(this.primaryKey)) {
throw new Error("invalid primary key type");
}
return {
query: queries_js_1.default.getCountByPksAndParams(this.primaryKey, this.tableName, searchFields, orderNumber),
values: [...values, pks],
};
},
getOneByParams: ({ $and = {}, $or }, selected = ["*"]) => {
if (!selected.length)
selected.push("*");
const { queryArray, queryOrArray, values } = this.compareFields($and, $or);
const { orderByFields, paginationFields, searchFields, selectedFields } = this.getFieldsToSearch({ queryArray, queryOrArray }, selected, { limit: 1, offset: 0 });
return {
query: queries_js_1.default.getByParams(this.tableName, selectedFields, searchFields, orderByFields, paginationFields),
values,
};
},
getOneByPk: (primaryKey) => {
if (!this.primaryKey) {
throw new Error("Primary key not specified");
}
return {
query: queries_js_1.default.getOneByPk(this.tableName, this.primaryKey),
values: Array.isArray(primaryKey) ? [...primaryKey] : [primaryKey],
};
},
streamArrByParams: ({ $and = {}, $or }, selected = ["*"], pagination, order) => {
if (order?.length) {
for (const o of order) {
if (!this.#tableFieldsSet.has(o.orderBy)) {
const allowedFields = Array.from(this.#tableFieldsSet).join(", ");
throw new Error(`Invalid orderBy: ${o.orderBy}. Allowed fields are: ${allowedFields}`);
}
if (!this.#sortingOrders.has(o.ordering)) {
throw new Error("Invalid ordering");
}
}
}
if (!selected.length)
selected.push("*");
const { queryArray, queryOrArray, values } = this.compareFields($and, $or);
const { orderByFields, paginationFields, searchFields, selectedFields } = this.getFieldsToSearch({ queryArray, queryOrArray }, selected, pagination, order);
return {
query: queries_js_1.default.getByParams(this.tableName, selectedFields, searchFields, orderByFields, paginationFields),
values,
};
},
updateByParams: (queryConditions, updateFields = {}) => {
const { queryArray, queryOrArray, values } = this.compareFields(queryConditions.$and, queryConditions.$or);
const { orderNumber, searchFields } = this.getFieldsToSearch({ queryArray, queryOrArray });
const clearedUpdate = SharedHelpers.clearUndefinedFields(updateFields);
const fieldsToUpdate = Object.keys(clearedUpdate);
if (!queryArray.length)
throw new Error("No one update field arrived");
return {
query: queries_js_1.default.updateByParams(this.tableName, fieldsToUpdate, searchFields, this.updateField, orderNumber + 1, queryConditions?.returningFields),
values: [...values, ...Object.values(clearedUpdate)],
};
},
updateOneByPk: (primaryKeyValue, updateFields = {}, updateOptions) => {
if (!this.primaryKey) {
throw new Error("Primary key not specified");
}
const clearedParams = SharedHelpers.clearUndefinedFields(updateFields);
const fields = Object.keys(clearedParams);
if (!fields.length)
throw new Error("No one update field arrived");
return {
query: queries_js_1.default.updateByPk(this.tableName, fields, this.primaryKey, this.updateField, updateOptions?.returningFields),
values: [...Object.values(clearedParams), ...Array.isArray(primaryKeyValue) ? [...primaryKeyValue] : [primaryKeyValue]],
};
},
};
/**
* Deletes all records from the table.
*
* This method executes a `DELETE` SQL statement to remove all records from the table, leaving it empty.
* It does not return any data or status, only ensures that the operation has been completed.
*
* @returns A promise that resolves when the delete operation has been successfully completed.
*/
async deleteAll() {
const sql = this.compareQuery.deleteAll();
await this.#executeSql(sql);
return;
}
/**
* Deletes a single record from the database based on the provided primary key.
*
* @param primaryKey - The value of the primary key of the record to be deleted. The type of the primary key depends on the table schema and could be a string, number, or any other type.
*
* @returns A promise that resolves to the primary key of the deleted record if found, or `null` if no record with the given primary key was found.
*/
async deleteOneByPk(primaryKey) {
const sql = this.compareQuery.deleteOneByPk(primaryKey);
const { rows } = await this.#executeSql(sql);
const entity = rows[0];
if (!entity)
return null;
if (Array.isArray(this.primaryKey)) {
return this.primaryKey.map((e) => entity[e]);
}
else {
return entity[this.primaryKey];
}
}
/**
* Deletes records from the database based on the specified search parameters.
*
* @param params - The search parameters to identify which records to delete.
* @param params.$and - The conditions that must be met for a record to be deleted. This is an array of conditions that are combined with logical AND.
* @param [params.$or] - Optional. An array of additional conditions combined with logical OR. If provided, records that match any of these conditions will also be deleted.
*
* @returns A promise that resolves to `null` once the delete operation is complete.
*/
async deleteByParams(params) {
const sql = this.compareQuery.deleteByParams(params);
await this.#executeSql(sql);
return null;
}
/**
* Drops the table from the database, with optional additional behaviors.
*
* @param [options={}] - Options to customize the drop operation.
* @param [options.cascade=false] - If true, drops tables that have foreign key references to this table.
* @param [options.ifExists=false] - If true, does not raise an error if the table does not exist.
* @param [options.restrict=false] - If true, prevents dropping the table if there are any foreign key references.
*
* @returns A promise that resolves when the drop operation is complete.
*/
async dropTable(options = {}) {
const { cascade = false, ifExists = false, restrict = false, } = options;
const behaviorOption = cascade ? "CASCADE" : restrict ? "RESTRICT" : "";
const query = `DROP TABLE ${ifExists ? "IF EXISTS " : ""}${this.tableName} ${behaviorOption};`;
await this.#executeSql({ query });
}
/**
* Truncates the table, removing all records and optionally applying additional options.
*
* @param [options={}] - Options to customize the truncate operation.
* @param [options.cascade=false] - If true, truncates tables that have foreign key references to this table.
* @param [options.continueIdentity=false] - If true, does not reset the sequence for identity columns.
* @param [options.only=false] - If true, only truncates the specified table and not its partitions.
* @param [options.restrict=false] - If true, prevents truncating if there are any foreign key references.
* @param [options.restartIdentity=false] - If true, resets the sequence for identity columns.
*
* @returns A promise that resolves when the truncate operation is complete.
*/
async truncateTable(options = {}) {
const { cascade = false, continueIdentity = false, only = false, restartIdentity = false, restrict = false, } = options;
const identityOption = restartIdentity ? "RESTART IDENTITY" : continueIdentity ? "CONTINUE IDENTITY" : "";
const behaviorOption = cascade ? "CASCADE" : restrict ? "RESTRICT" : "";
const truncateOptions = [identityOption, behaviorOption].filter(Boolean).join(" ");
const query = `TRUNCATE ${only ? "ONLY " : ""}${this.tableName} ${truncateOptions};`;
await this.#executeSql({ query });
}
/**
* Retrieves an array of records from the database based on the provided search parameters.
*
* @param params - The search parameters used to filter records.
* @param params.$and - The conditions that must be met for a record to be included in the results.
* @param [params.$or] - Optional array of conditions where at least one must be met for a record to be included in the results.
* @param [selected=["*"]] - Optional array of fields to select from the records. If not specified, all fields are selected.
* @param [pagination] - Optional pagination options to limit and offset the results.
* @param [order] - Optional array of order options for sorting the results.
* @param order[].orderBy - The field by which to sort the results.
* @param order[].ordering - The sorting direction ("ASC" for ascending or "DESC" for descending).
*
* @returns A promise that resolves to an array of records matching the search parameters.
*/
async getArrByParams(params, selected = ["*"], pagination, order) {
const sql = this.compareQuery.getArrByParams(params, selected, pagination, order);
const { rows } = await this.#executeSql(sql);
return rows;
}
/**
* Retrieves the count of records from the database based on the provided primary key values.
*
* @param pks - An array of primary key values for which to count the records.
*
* @returns A promise that resolves to the count of records with the specified primary keys.
*/
async getCountByPks(pks) {
const sql = this.compareQuery.getCountByPks(pks);
const { rows } = await this.#executeSql(sql);
return Number(rows[0]?.count) || 0;
}
/**
* Retrieves the count of records from the database based on the provided primary key values and search parameters.
*
* @param pks - An array of primary key values to filter the records.
* @param params - The search parameters to further filter the records.
* @param params.$and - The conditions that must be met for a record to be counted.
* @param [params.$or] - Optional array of conditions where at least one must be met for a record to be counted.
*
* @returns A promise that resolves to the count of records matching the primary keys and search parameters.
*/
async getCountByPksAndParams(pks, params) {
const sql = this.compareQuery.getCountByPksAndParams(pks, params);
const { rows } = await this.#executeSql(sql);
return Number(rows[0]?.count) || 0;
}
/**
* Retrieves the count of records from the database based on the provided search parameters.
*
* @param params - The search parameters to filter the records.
* @param params.$and - The conditions that must be met for a record to be counted.
* @param [params.$or] - Optional array of conditions where at least one must be met for a record to be counted.
*
* @returns A promise that resolves to the count of records matching the search parameters.
*/
async getCountByParams(params) {
const sql = this.compareQuery.getCountByParams(params);
const { rows } = await this.#executeSql(sql);
return Number(rows[0]?.count) || 0;
}
/**
* Retrieves a single record from the database based on search parameters.
*
* @param params - The search parameters to filter the records.
* @param params.$and - The search conditions that must be met.
* @param [params.$or] - Optional array of search conditions where at least one must be met.
* @param[selected=["*"]] - The fields to select in the result. Defaults to selecting all fields.
*
* @returns A promise that resolves to the retrieved record or undefined if no record is found.
*/
async getOneByParams(params, selected = ["*"]) {
const sql = this.compareQuery.getOneByParams(params, selected);
const { rows } = await this.#executeSql(sql);
return rows[0];
}
/**
* Retrieves a single record from the database based on the primary key.
*
* @param primaryKey - The value of the primary key to identify the record.
*
* @returns A promise that resolves to the retrieved record or undefined if no record is found.
*/
async getOneByPk(primaryKey) {
const sql = this.compareQuery.getOneByPk(primaryKey);
const { rows } = await this.#executeSql(sql);
return rows[0];
}
/**
* Creates a single record in the database.
*
* @param [recordParams={}] - The parameters for the record to be created.
* @param [saveOptions] - The options for saving the record.
* @param [saveOptions.returningFields] - An array of field names to return after the record is created.
*
* @returns A promise that resolves to the created record or undefined if no record was created.
*/
async createOne(recordParams = {}, saveOptions) {
const sql = this.compareQuery.createOne(recordParams, saveOptions);
const { rows } = await this.#executeSql(sql);
return rows[0];
}
/**
* Creates multiple records in the database.
*
* @param recordParams - An array of record parameters to insert.
* @param [saveOptions] - The options for saving records.
* @param [saveOptions.returningFields] - An array of field names to return after the records are created.
*
* @returns A promise that resolves to an array of created records.
*/
async createMany(recordParams, saveOptions) {
const sql = this.compareQuery.createMany(recordParams, saveOptions);
const { rows } = await this.#executeSql(sql);
return rows;
}
/**
* Returns a stream of records from the database based on the provided search parameters.
* Useful for handling large result sets efficiently without loading all data into memory.
*
* @param params - The filter conditions for the query.
* @param params.$and - Required set of conditions combined with AND.
* @param [params.$or] - Optional set of conditions combined with OR.
*
* @param [selected=["*"]] - List of field names to select from each record.
*
* @param [pagination] - Controls the offset and limit of the query.
*
* @param [order] - Specifies sorting rules for the result set.
* @param order[].orderBy - Field to sort the results by.
* @param order[].ordering - Sorting direction: `"ASC"` or `"DESC"`.
*
* @param [streamOptions] - Optional configuration for stream behavior:
* - `batchSize`: Number of rows fetched from the database per batch.
* - `highWaterMark`: Maximum number of rows buffered internally before pausing reads.
* - `rowMode`: If set to `"array"`, rows are returned as arrays instead of objects.
* - `types`: Custom type parser map for PostgreSQL data types.
*
* @returns A readable stream that emits rows of type `T` on the `"data"` event.
*/
async streamArrByParams(params, selected = ["*"], pagination, order, streamOptions) {
const sql = this.compareQuery.streamArrByParams(params, selected, pagination, order);
return this.#executeSqlStream(sql, streamOptions);
}
/**
* Updates records based on search parameters.
*
* @param queryConditions - The query conditions for identifying records to update.
* @param queryConditions.$and - The mandatory conditions for the update.
* @param [queryConditions.$or] - The optional conditions for the update.
* @param [queryConditions.returningFields] - The fields to return after the update.
* @param [updateFields={}] - An object containing the fields to update.
*
* @returns A promise that resolves to the rows affected by the update.
*/
async updateByParams(queryConditions, updateFields = {}) {
const sql = this.compareQuery.updateByParams(queryConditions, updateFields);
const { rows } = await this.#executeSql(sql);
return rows;
}
/**
* Updates one record by primary key.
*
* @param primaryKeyValue - The value of the primary key to identify the record to be updated.
* @param [updateFields={}] - An object containing the fields to update.
* @param [updateOptions] - Options for the update operation.
* @param [updateOptions.returningFields] - An array of fields to return after the update.
*
* @returns A promise that resolves to the query result.
*/
async updateOneByPk(primaryKeyValue, updateFields = {}, updateOptions) {
const sql = this.compareQuery.updateOneByPk(primaryKeyValue, updateFields, updateOptions);
const { rows } = await this.#executeSql(sql);
return rows[0];
}
/**
* Returns a new QueryBuilder instance for building SQL queries.
*
* @param [options] - Optional settings for the query builder.
* @param [options.client] - Optional database client or pool to use for query execution.
* @param [options.isLoggerEnabled] - Whether to enable logging for this query builder.
* @param [options.logger] - Optional custom logger instance.
* @param [options.tableName] - Optional table name to use (defaults to this.tableName).
*
* @returns A configured QueryBuilder instance.
*/
queryBuilder(options) {
const { client, isLoggerEnabled, logger, tableName } = options || {};
return new index_js_1.QueryBuilder(tableName ?? this.tableName, client ?? this.#executor, {
isLoggerEnabled: isLoggerEnabled ?? this.#isLoggerEnabled,
logger: logger ?? this.#logger,
});
}
// STATIC METHODS
/**
* Gets a standard pool for database connections.
*
* @param creds - The database credentials.
* @param [poolName] - The name of the pool.
*
* @returns The database connection pool.
*/
static getStandardPool(creds, poolName) {
return connection.getStandardPool(creds, poolName);
}
/**
* Removes a standard pool for database connections.
*
* @param creds - The database credentials.
* @param [poolName] - The name of the pool.
*
* @returns
*/
static async removeStandardPool(creds, poolName) {
return connection.removeStandardPool(creds, poolName);
}
/**
* Gets a transaction pool for database connections.
*
* @param creds - The database credentials.
* @param [poolName] - The name of the pool.
*
* @returns The transaction connection pool.
*/
static getTransactionPool(creds, poolName) {
return connection.getTransactionPool(creds, poolName);
}
/**
* Removes a transaction pool for database connections.
*
* @param creds - The database credentials.
* @param [poolName] - The name of the pool.
*
* @returns
*/
static async removeTransactionPool(creds, poolName) {
return connection.removeTransactionPool(creds, poolName);
}
/**
* Generates an SQL insert query and its corresponding values array based on the provided data.
*
* @param data - The data for generating the insert query.
* @param data.params - The parameters for the insert query. Can be a single object or an array of objects.
* @param [data.returning] - The fields to return after the insert operation.
* @param data.tableName - The name of the table to insert into.
*
* @returns An object containing the SQL insert query and its values.
*/
static getInsertFields(data) {
const { params: paramsRaw, returning, tableName, } = data;
if (Array.isArray(paramsRaw)) {
const v = [];
const k = [];
const headers = new Set();
const example = paramsRaw[0];
if (!example)
throw new Error("Invalid parameters");
const params = SharedHelpers.clearUndefinedFields(example);
Object.keys(params).forEach((e) => headers.add(e));
for (const pR of paramsRaw) {
const params = SharedHelpers.clearUndefinedFields(pR);
const keys = Object.keys(params);
k.push(keys);
v.push(...Object.values(params));
if (!k.length) {
throw new Error(`Invalid params, all fields are undefined - ${Object.keys(paramsRaw).join(", ")}`);
}
for (const key of keys) {
if (!headers.has(key)) {
throw new Error(`Invalid params, all fields are undefined - ${Object.keys(pR).join(", ")}`);
}
}
}
const returningSQL = returning?.length
? `RETURNING ${returning.join(",")}`
: "";
let idx = 0;
const query = `
INSERT INTO ${tableName}(${Array.from(headers).join(",")})
VALUES(${k.map((e) => e.map(() => "$" + ++idx)).join("),(")})
${returningSQL}
`;
return { query, values: v };
}
const params = SharedHelpers.clearUndefinedFields(paramsRaw);
const k = Object.keys(params);
const v = Object.values(params);
if (!k.length)
throw new Error(`Invalid params, all fields are undefined - ${Object.keys(paramsRaw).join(", ")}`);
const returningSQL = returning?.length
? `RETURNING ${returning.join(",")}`
: "";
const query = `INSERT INTO ${tableName}(${k.join(",")}) VALUES(${k.map((_, idx) => "$" + ++idx).join(",")}) ${returningSQL};`;
return { query, values: v };
}
/**
* Generates an SQL update query and its corresponding values array based on the provided data.
*
* @param data - The data for generating the update query.
* @param data.params - The parameters for the update query.
* @param data.primaryKey - The primary key field and its value.
* @param data.primaryKey.field - The primary key field name.
* @param data.primaryKey.value - The primary key value.
* @param [data.returning] - The fields to return after the update.
* @param data.tableName - The name of the table to update.
* @param [data.updateField] - The field to update with a timestamp.
* @param data.updateField.title - The field name to update.
* @param data.updateField.type - The type of the timestamp.
*
* @returns An object containing the SQL update query and its values.
*/
static getUpdateFields(data) {
const { params: paramsRaw, primaryKey, returning, tableName, updateField, } = data;
const params = SharedHelpers.clearUndefinedFields(paramsRaw);
const k = Object.keys(params);
const v = Object.values(params);
if (!k.length)
throw new Error(`Invalid params, all fields are undefined - ${Object.keys(paramsRaw).join(", ")}`);
let updateFields = k.map((e, idx) => `${e} = $${idx + 2}`).join(",");
if (updateField) {
switch (updateField.type) {
case "timestamp": {
updateFields += `, ${updateField.title} = NOW()`;
break;
}
case "unix_timestamp": {
updateFields += `, ${updateField.title} = ROUND((EXTRACT(EPOCH FROM NOW()) * (1000)::NUMERIC))`;
break;
}
default: {
throw new Error("Invalid type: " + updateField.type);
}
}
}
const returningSQL = returning?.length
? `RETURNING ${returning.join(",")}`
: "";
const query = `UPDATE ${tableName} SET ${updateFields} WHERE ${primaryKey.field} = $1 ${returningSQL};`;
return { query, values: [primaryKey.value, ...v] };
}
}
exports.BaseTable = BaseTable;