UNPKG

ts-sql-query

Version:

Type-safe SQL query builder like QueryDSL or JOOQ in Java or Linq in .Net for TypeScript with MariaDB, MySql, Oracle, PostgreSql, Sqlite and SqlServer support.

361 lines (360 loc) 14.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.LoopBackSqlServerQueryRunner = exports.LoopBackPostgreSqlQueryRunner = exports.LoopBackOracleQueryRunner = exports.LoopBackMySqlQueryRunner = exports.LoopBackAbstractQueryRunner = exports.createLoopBackQueryRunner = void 0; const PromiseBasedQueryRunner_1 = require("./PromiseBasedQueryRunner"); const OracleUtils_1 = require("./OracleUtils"); /** * @deprecated */ function createLoopBackQueryRunner(datasource, transaction) { const connector = datasource.connector; if (!connector) { throw new Error('The provided datasource have no connector loaded'); } switch (connector.name) { case 'mysql': return new LoopBackMySqlQueryRunner(datasource, transaction); case 'oracle': return new LoopBackOracleQueryRunner(datasource, transaction); case 'postgresql': return new LoopBackPostgreSqlQueryRunner(datasource, transaction); case 'mssql': return new LoopBackSqlServerQueryRunner(datasource, transaction); case 'sqlite3': return new LoopBackSqliteQueryRunner(datasource, transaction); default: throw new Error('Unsupported Loopback connector of name ' + connector.name); } } exports.createLoopBackQueryRunner = createLoopBackQueryRunner; /** * @deprecated */ class LoopBackAbstractQueryRunner extends PromiseBasedQueryRunner_1.PromiseBasedQueryRunner { constructor(database, datasource, transaction) { super(); this.database = database; this.datasource = datasource; this.transaction = transaction; const connector = datasource.connector; if (!connector) { throw new Error('The provided datasource have no connector loaded'); } this.connectorName = connector.name; } useDatabase(database) { if (database !== this.database) { throw new Error('Unsupported database: ' + database + '. The current datasource used in LoopbackQueryRunner only supports ' + this.database + ' databases'); } } getNativeRunner() { return this.datasource; } getCurrentNativeTransaction() { return this.transaction; } execute(fn) { return fn(this.datasource, this.transaction); } executeBeginTransaction() { return this.datasource.beginTransaction({}).then((transaction) => { this.transaction = transaction; }); } executeCommit() { if (!this.transaction) { return Promise.reject(new Error('Not in an transaction, you cannot commit the transaction')); } return this.transaction.commit().then(() => { // Transaction count only modified when commit successful, in case of error there is still an open transaction this.transaction = undefined; }); } executeRollback() { if (!this.transaction) { return Promise.reject(new Error('Not in an transaction, you cannot rollback the transaction')); } return this.transaction.rollback().finally(() => { this.transaction = undefined; }); } isTransactionActive() { return !!this.transaction; } executeQueryReturning(query, params) { return this.query(query, params); } query(query, params) { return this.datasource.execute(query, params, { transaction: this.transaction }); } } exports.LoopBackAbstractQueryRunner = LoopBackAbstractQueryRunner; /** * @deprecated */ class LoopBackMySqlQueryRunner extends LoopBackAbstractQueryRunner { constructor(datasource, transaction) { super('mySql', datasource, transaction); if (this.connectorName !== 'mysql') { throw new Error('Unsupported connector type: ' + this.connectorName + '. LoopBackMySqlQueryRunner only supports mysql connectors'); } } useDatabase(database) { if (database !== this.database) { if (this.database === 'mySql' && database === 'mariaDB') { //@ts-ignore this.database = database; } else if (this.database === 'mariaDB' && database === 'mySql') { //@ts-ignore this.database = database; } else { throw new Error('Unsupported database: ' + database + '. The current datasource used in LoopbackQueryRunner only supports mySql or mariaDB databases'); } } } executeMutation(query, params) { return this.query(query, params).then(result => result.affectedRows); } executeInsertReturningLastInsertedId(query, params = []) { if (this.containsInsertReturningClause(query, params)) { return super.executeInsertReturningLastInsertedId(query, params); } return this.query(query, params).then(result => result.insertId); } addParam(params, value) { params.push(value); return '?'; } } exports.LoopBackMySqlQueryRunner = LoopBackMySqlQueryRunner; /** * @deprecated */ class LoopBackOracleQueryRunner extends LoopBackAbstractQueryRunner { constructor(datasource, transaction) { super('oracle', datasource, transaction); if (this.connectorName !== 'oracle') { throw new Error('Unsupported connector type: ' + this.connectorName + '. LoopBackMySqlQueryRunner only supports oracle connectors'); } } executeMutation(query, params) { return this.query(query, params).then(result => result.rowsAffected); } executeMutationReturning(query, params = []) { return this.query(query, params).then((result) => { return (0, OracleUtils_1.processOutBinds)(params, result.outBinds); }); } addParam(params, value) { const index = params.length; params.push(value); return ':' + index; } addOutParam(params, name) { const index = params.length; if (name) { params.push({ dir: 3003 /*oracledb.BIND_OUT*/, as: name }); // See https://github.com/oracle/node-oracledb/blob/master/lib/oracledb.js } else { params.push({ dir: 3003 /*oracledb.BIND_OUT*/ }); // See https://github.com/oracle/node-oracledb/blob/master/lib/oracledb.js } return ':' + index; } } exports.LoopBackOracleQueryRunner = LoopBackOracleQueryRunner; /** * @deprecated */ class LoopBackPostgreSqlQueryRunner extends LoopBackAbstractQueryRunner { constructor(datasource, transaction) { super('postgreSql', datasource, transaction); if (this.connectorName !== 'postgresql') { throw new Error('Unsupported connector type: ' + this.connectorName + '. LoopBackMySqlQueryRunner only supports postgresql connectors'); } } executeMutation(query, params) { return this.query(query, params).then(result => result?.affectedRows || 0); } executeMutationReturning(query, params) { return this.query(query, params).then(result => { if (!result) { return result; } if (Array.isArray(result)) { return result; } return result.rows || []; }); } executeInsert(query, params = []) { const rowsToInsert = this.guessInsertRowCount(query); if (!isNaN(rowsToInsert)) { return this.query(query, params).then(() => { return rowsToInsert; }); } else { query = 'with rows as (' + query + ' returning true) select count(*) from rows'; return this.query(query, params).then((result) => { if (result.length > 1) { throw new Error('Too many rows, expected only zero or one row'); } const row = result[0]; if (row) { const columns = Object.getOwnPropertyNames(row); if (columns.length > 1) { throw new Error('Too many columns, expected only one column'); } return +row[columns[0]]; // Value in the row of the first column without care about the name } throw new Error('Unable to find the the affected row count'); }); } } addParam(params, value) { params.push(value); return '$' + params.length; } guessInsertRowCount(query) { const insert = query.toLowerCase(); if (/\)\s*values\s*\(/g.test(insert)) { const matches = /\)\s*,\s*\(/g.exec(insert); if (matches) { return matches.length + 1; } else { return 1; } } else if (/default\s*values/.test(insert)) { return 1; } return NaN; } } exports.LoopBackPostgreSqlQueryRunner = LoopBackPostgreSqlQueryRunner; /** * @deprecated */ class LoopBackSqlServerQueryRunner extends LoopBackAbstractQueryRunner { constructor(datasource, transaction) { super('sqlServer', datasource, transaction); if (this.connectorName !== 'mssql') { throw new Error('Unsupported connector type: ' + this.connectorName + '. LoopBackMySqlQueryRunner only supports mssql connectors'); } } executeMutation(query, params) { return this.query(query + '; select @@ROWCOUNT as count', params).then((result) => { if (result.length > 1) { throw new Error('Too many rows, expected only zero or one row'); } const row = result[0]; if (row) { const columns = Object.getOwnPropertyNames(row); if (columns.length > 1) { throw new Error('Too many columns, expected only one column'); } return row[columns[0]]; // Value in the row of the first column without care about the name } throw new Error('Unable to find the affected row count'); }); } executeProcedure(query, params = []) { return this.query(query, params).then(() => undefined); } executeDatabaseSchemaModification(query, params = []) { return this.query(query, params).then(() => undefined); } addParam(params, value) { params.push(value); return '@param' + params.length; } } exports.LoopBackSqlServerQueryRunner = LoopBackSqlServerQueryRunner; /** * @deprecated */ class LoopBackSqliteQueryRunner extends LoopBackAbstractQueryRunner { constructor(datasource, transaction) { super('sqlite', datasource, transaction); if (this.connectorName !== 'sqlite3') { throw new Error('Unsupported connector type: ' + this.connectorName + '. LoopBackMySqlQueryRunner only supports sqlite3 connectors'); } // Fix invalid transaction type const connector = datasource.connector; if (!connector.__tssqlquery_fixed) { const beginTransaction = connector.beginTransaction; connector.beginTransaction = function (isolationLevel, cb) { if (isolationLevel === 'READ COMMITTED' || isolationLevel === 'READ UNCOMMITTED' || isolationLevel === 'SERIALIZABLE' || isolationLevel === 'REPEATABLE READ') { isolationLevel = ''; } beginTransaction.call(this, isolationLevel, cb); }; // Implements forceReturning option const executeSQL = connector.executeSQL; connector.executeSQL = function (sql, params, options, callback) { const connection = options?.transaction?.connection; if (connection && !connection.__tssqlquery_fixed) { const all = connection.all; connection.all = function (sql, ...args) { if (sql instanceof String) { sql = sql.valueOf(); } return all.apply(this, [sql, ...args]); }; connection.__tssqlquery_fixed = true; } if (options?.forceReturning) { const q = new String(sql); q.trim = () => { return 'select: ' + sql; }; executeSQL.call(this, q, params, options, callback); } else { executeSQL.call(this, sql, params, options, callback); } }; connector.connect((_err, connection) => { if (connection && !connection.__tssqlquery_fixed) { const all = connection.all; connection.all = function (sql, ...args) { if (sql instanceof String) { sql = sql.valueOf(); } return all.apply(this, [sql, ...args]); }; connection.__tssqlquery_fixed = true; } }); connector.__tssqlquery_fixed = true; } } executeMutation(query, params) { return this.queryNoSelect(query, params).then(result => result.count); } executeInsertReturningLastInsertedId(query, params = []) { if (this.containsInsertReturningClause(query, params)) { super.executeInsertReturningLastInsertedId(query, params); } return this.queryNoSelect(query, params).then(result => result.lastID); } executeMutationReturning(query, params) { return this.datasource.execute(query, params, { transaction: this.transaction, forceReturning: true }); } addParam(params, value) { params.push(value); return '?'; } query(query, params) { return this.datasource.execute(query, params, { transaction: this.transaction, forceReturning: query.startsWith('with ') }); } queryNoSelect(query, params) { return this.datasource.execute(query, params, { transaction: this.transaction }); } }