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
JavaScript
"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 });
}
}