UNPKG

@smallprod/models

Version:
300 lines (299 loc) 14 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (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 }); const pg_1 = __importStar(require("pg")); const global_sql_1 = __importDefault(require("./global.sql")); const getPool = async (config, quitOnFail = false) => { pg_1.default.types.setTypeParser(20, Number); return new Promise(async (resolve, reject) => { const pool = new pg_1.Pool(config); pool.on('error', (err) => { if (GlobalPostgreModel.debug) { console.error('Unexpected error on postgres database'); console.error(err); } if (quitOnFail) { process.exit(-1); } else { reject(err); } }); resolve(pool); }); }; class GlobalPostgreModel extends global_sql_1.default { constructor() { super(...arguments); this.pool = null; this.transactionConnection = null; this.transactionDone = null; this.disconnect = async () => { var _a; await ((_a = this.pool) === null || _a === void 0 ? void 0 : _a.end()); }; this.query = async (query, params, throwErrors = false) => { if (!this.pool) { if (throwErrors) { throw Error('No pool'); } return null; } try { if (!this.transactionConnection) { return await this.pool.query(query, params); } return await this.transactionConnection.query(query, params); } catch (err) { if (GlobalPostgreModel.debug) { console.error(`An error occured while executing ${query} with parameters:`, params); console.error(err); } if (throwErrors) { throw err; } return null; } }; this.insert = async (tableName, attributes) => { const columns = attributes.map((a) => `"${a.column}"`).join(', '); const params = attributes.map((a, index) => `$${index + 1}`).join(', '); const query = `INSERT INTO "${tableName}" (${columns}) VALUES (${params}) RETURNING *`; const res = await this.query(query, attributes.map((a) => a.value)); return res === null || res === void 0 ? void 0 : res.rows[0].id; }; this.select = async (tableName, distinct = false, attributes = [], wheres = [], sorts = [], tableAlias = '', limit = -1, offset = 0, joins = [], groups = [], havings = []) => { var _a; const query = `SELECT${distinct ? ' DISTINCT' : ''}${this.computeAttributes(attributes, '"')} FROM "${tableName}" ${tableAlias ? `${tableAlias}` : ''} ${this.computeJoins(joins, '"', '')}${this.computeWhere(wheres, '$', true, '"')}${this.computeGroupBy(groups)}${this.computeWhere(havings, '$', true, '"', 'HAVING', wheres.filter((w) => !w.keyword).length)}${this.computeSort(sorts, '"')}${limit !== -1 ? ` LIMIT ${limit} OFFSET ${offset}` : ''}`; const havingAttr = this.getWhereAttributes(havings); return (_a = (await this.query(query, havingAttr.concat(this.getWhereAttributes(wheres))))) === null || _a === void 0 ? void 0 : _a.rows; }; this.update = async (tableName, attributes, wheres) => { var _a; const columns = attributes .map((a, index) => `"${a.column}" = $${index + 1}`) .join(', '); const query = `UPDATE "${tableName}" SET ${columns} ${this.computeWhere(wheres, '$', true, '"', 'WHERE', attributes.length)}`; return (_a = (await this.query(query, attributes.map((a) => a.value).concat(this.getWhereAttributes(wheres))))) === null || _a === void 0 ? void 0 : _a.rowCount; }; this.delete = async (tableName, wheres) => { var _a; const query = `DELETE FROM "${tableName}" ${this.computeWhere(wheres, '$', true, '"')}`; return (_a = (await this.query(query, this.getWhereAttributes(wheres)))) === null || _a === void 0 ? void 0 : _a.rowCount; }; this.createTable = async (tableName, fields) => { const query = `CREATE TABLE ${tableName} (${fields .map((f) => this.formatFieldForTableManagement(f)) .join(', ')})`; await this.query(query); await fields.reduce(async (prevField, curField) => { await prevField; const constraints = this.getFieldConstraintsForTableManagement(curField, tableName); await constraints.reduce(async (prevConst, curConst) => { await prevConst; await this.query(curConst); }, Promise.resolve()); }, Promise.resolve()); }; this.removeTable = async (tableName) => { const query = `DROP TABLE ${tableName}`; return await this.query(query); }; this.alterTable = async (tableName, fieldsToAdd, fieldsToRemove) => { await fieldsToRemove.reduce(async (prev, cur) => { await prev; const query = `ALTER TABLE ${tableName} DROP COLUMN ${cur}`; await this.query(query); }, Promise.resolve()); await fieldsToAdd.reduce(async (prev, cur) => { await prev; const query = `ALTER TABLE ${tableName} ADD ${this.formatFieldForTableManagement(cur)}`; await this.query(query); const constraints = this.getFieldConstraintsForTableManagement(cur, tableName); await constraints.reduce(async (prevConst, curConst) => { await prevConst; await this.query(curConst); }, Promise.resolve()); }, Promise.resolve()); }; this.startTransaction = async () => { return new Promise((resolve, reject) => { if (this.transactionConnection) { if (GlobalPostgreModel.debug) console.error('Already in a transaction'); return resolve(false); } if (!this.pool) { if (GlobalPostgreModel.debug) console.error('No pool'); return resolve(false); } this.pool.connect((err, client, done) => { if (err) { if (GlobalPostgreModel.debug) console.error(err); return resolve(false); } client.query('BEGIN', (error) => { if (error) { done(); return resolve(false); } this.transactionDone = done; this.transactionConnection = client; resolve(true); }); }); }); }; this.commit = async () => { return new Promise((resolve, reject) => { if (!this.transactionConnection) { if (GlobalPostgreModel.debug) console.error('Not in a transaction'); return resolve(); } this.transactionConnection.query('COMMIT', (err) => { var _a; if (err) { if (GlobalPostgreModel.debug) console.error(err); (_a = this.transactionConnection) === null || _a === void 0 ? void 0 : _a.query('ROLLBACK', (e) => { this.transactionConnection = null; if (e) { if (GlobalPostgreModel.debug) console.error(e); } resolve(); }); } if (this.transactionDone) { this.transactionDone(); this.transactionDone = null; } this.transactionConnection = null; resolve(); }); }); }; this.rollback = async () => { return new Promise((resolve) => { if (!this.transactionConnection) { if (GlobalPostgreModel.debug) console.error('Not in a transaction'); return resolve(); } this.transactionConnection.query('ROLLBACK', (err) => { this.transactionConnection = null; if (err) { if (GlobalPostgreModel.debug) console.error(err); } if (this.transactionDone) { this.transactionDone(); this.transactionDone = null; } resolve(); }); }); }; this.checkMigrationTable = async () => { const res = await this.query('SELECT table_name FROM information_schema.tables WHERE table_name = $1', ['migrations']); return res && res.rowCount ? true : false; }; this.setPool = async (config) => { const p = await getPool(config); if (p) { this.pool = p; } }; this.formatFieldForTableManagement = (field) => { const fInfos = field.getAll(); if (fInfos.ai) { return `${fInfos.name} ${fInfos.type === 'bigint' ? 'BIGSERIAL' : fInfos.type === 'smallint' ? 'SMALLSERIAL' : 'SERIAL'}${fInfos.len !== 0 ? `(${fInfos.len})` : ''}${fInfos.null ? '' : ' NOT NULL'}`; } return `${fInfos.name} ${this.getCorrespondingType(fInfos.type)}${fInfos.len !== 0 ? `(${fInfos.len})` : ''}${fInfos.null ? '' : ' NOT NULL'}`; }; this.getFieldConstraintsForTableManagement = (field, tableName) => { const fieldInfos = field.getAll(); const constraints = []; if (fieldInfos.mustBeUnique || fieldInfos.primaryKey) { constraints.push(`ALTER TABLE ${tableName} ADD CONSTRAINT unique_${tableName.toLowerCase()}_${fieldInfos.name.toLowerCase()} UNIQUE (${fieldInfos.name})`); } if (fieldInfos.checkValue) { constraints.push(`ALTER TABLE ${tableName} ADD CONSTRAINT check_${tableName.toLowerCase()}_${fieldInfos.name.toLowerCase()} CHECK(${fieldInfos.name}${fieldInfos.checkValue})`); } if (fieldInfos.defaultValue) { constraints.push(`ALTER TABLE ${tableName} ALTER ${fieldInfos.name} SET DEFAULT ${fieldInfos.defaultValue.isSystem ? `${fieldInfos.defaultValue.value}` : `'${fieldInfos.defaultValue.value}'`};`); } if (fieldInfos.primaryKey) { constraints.push(`ALTER TABLE ${tableName} ADD CONSTRAINT pk_${tableName.toLowerCase()}_${fieldInfos.name.toLowerCase()} PRIMARY KEY (${fieldInfos.name})`); } if (fieldInfos.foreignKey) { constraints.push(`ALTER TABLE ${tableName} ADD CONSTRAINT fk_${tableName.toLowerCase()}_${fieldInfos.name.toLowerCase()} FOREIGN KEY (${fieldInfos.name}) REFERENCES ${fieldInfos.foreignKey.table}(${fieldInfos.foreignKey.column})`); } return constraints; }; this.getCorrespondingType = (type) => { switch (type) { case 'binary': return 'bytea'; case 'blob': return 'bytea'; case 'datetime': return 'timestamp'; case 'float': return 'double'; case 'longblob': return 'bytea'; case 'longtext': return 'text'; case 'mediumblob': return 'bytea'; case 'mediumint': return 'int'; case 'tinyint': return 'smallint'; case 'mediumtext': return 'text'; case 'tinyblob': return 'bytea'; case 'tinytext': return 'text'; case 'varbinary': return 'bytea'; default: return type; } }; } } exports.default = GlobalPostgreModel;