silvie
Version:
Typescript Back-end Framework
730 lines (728 loc) • 28 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.ReverseMySQLTypes = exports.MySQLTypes = void 0;
var _mysql = _interopRequireDefault(require("mysql2"));
var _table = _interopRequireDefault(require("../../../migration/table"));
var _column = _interopRequireDefault(require("../../../migration/column"));
var _query = _interopRequireDefault(require("../../../builders/query"));
var _spatial = _interopRequireDefault(require("./datatypes/spatial"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
const MySQLTypes = exports.MySQLTypes = {
TinyInteger: 'TINYINT',
SmallInteger: 'SMALLINT',
MediumInteger: 'MEDIUMINT',
Integer: 'INT',
BigInteger: 'BIGINT',
Bit: 'BIT',
Boolean: 'TINYINT(1)',
Decimal: 'DECIMAL',
Float: 'FLOAT',
Double: 'DOUBLE',
Year: 'YEAR',
Date: 'DATE',
Time: 'TIME',
DateTime: 'DATETIME',
Timestamp: 'TIMESTAMP',
Character: 'CHAR',
String: 'VARCHAR',
Binary: 'BINARY',
TinyBlob: 'TINYBLOB',
Blob: 'BLOB',
MediumBlob: 'MEDIUMBLOB',
LongBlob: 'LONGBLOB',
TinyText: 'TINYTEXT',
Text: 'TEXT',
MediumText: 'MEDIUMTEXT',
LongText: 'LONGTEXT',
Enum: 'ENUM',
Set: 'SET',
Geometry: 'GEOMETRY',
Point: 'POINT',
LineString: 'LINESTRING',
Polygon: 'POLYGON',
GeometryCollection: 'GEOMETRYCOLLECTION',
MultiPoint: 'MULTIPOINT',
MultiLineString: 'MULTILINESTRING',
MultiPolygon: 'MULTIPOLYGON',
JSON: 'JSON'
};
const ReverseMySQLTypes = exports.ReverseMySQLTypes = {
tinyint: 'TinyInteger',
smallint: 'SmallInteger',
mediumint: 'MediumInteger',
int: 'Integer',
bigint: 'BigInteger',
bit: 'Bit',
boolean: 'Boolean',
decimal: 'Decimal',
float: 'Float',
double: 'Double',
year: 'Year',
date: 'Date',
time: 'Time',
datetime: 'DateTime',
timestamp: 'Timestamp',
char: 'Character',
varchar: 'String',
binary: 'Binary',
tinyblob: 'TinyBlob',
blob: 'Blob',
mediumblob: 'MediumBlob',
longblob: 'LongBlob',
tinytext: 'TinyText',
text: 'Text',
mediumtext: 'MediumText',
longtext: 'LongText',
enum: 'Enum',
set: 'Set',
geometry: 'Geometry',
point: 'Point',
linestring: 'LineString',
polygon: 'Polygon',
geometrycollection: 'GeometryCollection',
multipoint: 'MultiPoint',
multilinestring: 'MultiLineString',
multipolygon: 'MultiPolygon',
json: 'JSON'
};
class MySQLDriver {
constructor(config, instanceCallback) {
_defineProperty(this, "pool", void 0);
let pool = _mysql.default.createPool({
host: config.host,
port: config.port,
database: config.database,
user: config.username,
password: config.password,
connectionLimit: config.connectionLimit || 10,
dateStrings: config.dateStrings || true,
multipleStatements: config.multipleStatements || false,
charset: config.charset || 'utf8'
});
if (instanceCallback instanceof Function) {
pool = instanceCallback("mysql", pool);
}
this.pool = pool;
}
static resolveType(typeName) {
return MySQLTypes[typeName];
}
static tbl(tableName) {
return `\`${tableName.replace(/['"`]/, '')}\``;
}
static col(columnName, tableName) {
const cleanColumnName = columnName.replace(/['"`]/, '');
const columnParts = cleanColumnName.split('.');
if (tableName && columnParts.length === 1) {
const cleanTableName = tableName.replace(/['"`]/, '');
columnParts.splice(0, -1, cleanTableName);
}
return columnParts.map(part => part !== '*' ? `\`${part}\`` : '*').join('.');
}
static compileColumn(column) {
const queryParts = [];
const params = [];
queryParts.push(this.col(column.name));
const type = this.resolveType(column.type);
if (column.size) {
queryParts.push(`${type}(${column.size})`);
} else if (column.type === 'Enum' || column.type === 'Set') {
queryParts.push(`${type}(${column.options.meta.values.map(val => `"${val}"`).join(', ')})`);
} else if (column.type === 'Decimal') {
queryParts.push(`${type}(${column.options.meta.percision},${column.options.meta.scale})`);
} else {
queryParts.push(type);
}
if (type.endsWith('INT') && column.options.unsigned) queryParts.push('UNSIGNED');
if (column.options.defaultValue !== undefined) {
if (column.options.defaultValue === null) {
queryParts.push(`DEFAULT NULL`);
} else {
queryParts.push(`DEFAULT ?`);
params.push(column.options.defaultValue);
}
} else if (column.options.useCurrent) {
if (column.type === 'Date') {
queryParts.push(`DEFAULT CURRENT_DATE`);
} else if (column.type === 'Time') {
queryParts.push(`DEFAULT CURRENT_TIME`);
} else if (column.type === 'Timestamp' || column.type === 'DateTime') {
queryParts.push(`DEFAULT CURRENT_TIMESTAMP`);
}
}
if (column.options.nullable) queryParts.push('NULL');else queryParts.push('NOT NULL');
if (column.options.autoIncrement) queryParts.push('AUTO_INCREMENT');
if (column.options.charset) queryParts.push(`CHARACTER SET ${column.options.charset}`);
if (column.options.collation) queryParts.push(`COLLATE ${column.options.collation}`);
return [queryParts.join(' '), params];
}
static compileCreateTable(table) {
const {
indices,
fullTextIndices,
spatialIndices,
primaries,
uniques
} = table.getConstraints();
const params = [];
let query = `CREATE TABLE ${table.name} (`;
query += table.columns.map(column => {
const [q, p] = this.compileColumn(column);
params.push(...p);
return q;
}).join(', ');
if (primaries.length > 0) {
query += `, PRIMARY KEY (${primaries.map(column => this.col(column.name)).join(', ')})`;
}
if (uniques.length > 0) {
query += `, UNIQUE (${uniques.map(column => this.col(column.name)).join(', ')})`;
}
if (indices.length > 0) {
query += `, ${indices.map(column => `INDEX (${this.col(column.name)})`).join(', ')}`;
}
if (fullTextIndices.length > 0) {
query += `, ${fullTextIndices.map(column => `FULLTEXT (${this.col(column.name)})`).join(', ')}`;
}
if (spatialIndices.length > 0) {
query += `, ${spatialIndices.map(column => `SPATIAL (${this.col(column.name)})`).join(', ')}`;
}
if (table.relations.length > 0) {
query += `, ${table.relations.map(relation => `FOREIGN KEY (${this.col(relation.foreignKey)}) REFERENCES ${this.col(relation.table)}(${this.col(relation.primaryKey)})`).join(', ')}`;
}
query += ');';
return [query, params];
}
createTable(table) {
return this.execute(...MySQLDriver.compileCreateTable(table));
}
async fetchTable(tableName) {
const table = new _table.default(tableName);
const [{
'Create Table': sql
}] = await this.execute(`SHOW CREATE TABLE ${MySQLDriver.tbl(tableName)};`);
const lines = sql.split('\n').slice(1, -1).map(line => line.trim().replace(/,$/, ''));
lines.forEach(line => {
if (line.startsWith('`')) {
const query = line.replace('tinyint(1)', 'boolean');
const col = _column.default.fromQuery(query, ReverseMySQLTypes);
table.columns.push(col);
} else {
// TODO: CONSTRAINT
}
});
return table;
}
async updateTable(table) {
const t = await this.fetchTable(table.name);
console.log(t);
return null;
}
truncateTable(tableName) {
return this.execute(`TRUNCATE TABLE ${MySQLDriver.tbl(tableName)};`);
}
dropTableIfExists(tableName) {
return this.execute(`DROP TABLE IF EXISTS ${MySQLDriver.tbl(tableName)};`);
}
dropTable(tableName) {
return this.execute(`DROP TABLE ${MySQLDriver.tbl(tableName)};`);
}
static compileConditions(conditions, tableName) {
const params = [];
const query = conditions.map((condition, index) => {
const relation = index === 0 ? '' : {
and: 'AND',
or: 'OR'
}[condition.relation];
let clause = index === 0 ? '' : `${relation} `;
if (condition.type === 'raw') {
params.push(...condition.params);
clause += condition.query;
return clause;
}
if (condition.type === 'group') {
const [q, p] = this.compileConditions(condition.conditions, tableName);
params.push(...p);
clause += `(${q})`;
return clause;
}
if (condition.type === 'column') {
clause += `${this.col(condition.leftHandSide, tableName)} ${condition.operator} ${this.col(condition.rightHandSide, tableName)}`;
return clause;
}
let lhs;
if (condition.leftHandSide instanceof _query.default) {
const [q, p] = this.compileSelect(condition.leftHandSide);
params.push(...p);
lhs = `(${q})`;
} else {
lhs = this.col(condition.leftHandSide, tableName);
}
let rhs;
if (condition.rightHandSide instanceof _query.default) {
const [q, p] = this.compileSelect(condition.rightHandSide);
params.push(...p);
rhs = `(${q})`;
} else {
rhs = condition.rightHandSide;
}
if (condition.type === 'value') {
params.push(rhs);
clause += `${lhs} ${condition.operator} ?`;
}
if (condition.type === 'null' || condition.type === 'not null') {
clause += `${lhs} ${condition.type.startsWith('not') ? 'IS NOT' : 'IS'} NULL`;
}
if (condition.type === 'between' || condition.type === 'not between') {
params.push(...rhs);
clause += `${lhs} ${condition.type.startsWith('not') ? 'NOT BETWEEN' : 'BETWEEN'} ? AND ?`;
}
if (condition.type === 'like' || condition.type === 'not like') {
params.push(rhs);
clause += `${lhs} ${condition.type.startsWith('not') ? 'NOT LIKE' : 'LIKE'} ?`;
}
if (condition.type === 'in' || condition.type === 'not in') {
if (condition.rightHandSide instanceof _query.default) {
clause += `${lhs} ${condition.type.startsWith('not') ? 'NOT IN' : 'IN'} ${rhs}`;
} else {
params.push(...rhs);
clause += `${lhs} ${condition.type.startsWith('not') ? 'NOT IN' : 'IN'} (${new Array(rhs.length).fill('?').join(', ')})`;
}
}
if (condition.type === 'date' || condition.type === 'year' || condition.type === 'month' || condition.type === 'day' || condition.type === 'time') {
params.push(condition.rightHandSide);
clause += `${condition.type.toUpperCase()}(${lhs}) ${condition.operator} ?`;
}
return clause;
}).join(' ');
return [query, params];
}
static compileSelectFields(qb) {
const fields = qb.options.select;
if (fields.length === 0) {
return ['*', []];
}
const params = [];
const query = fields.map(field => {
if (field.type === 'column') {
return this.col(field.column, qb.options.table);
}
if (field.type === 'query') {
const [q, p] = this.compileSelect(field.queryBuilder);
params.push(...p);
return `(${q})${field.alias ? ` AS ${this.tbl(field.alias)}` : ''}`;
}
if (field.type === 'raw') {
params.push(...field.params);
return field.query;
}
if (field.type === 'aggregate') {
if (field.aggregation === 'count') {
return `COUNT(*)${field.alias ? ` AS ${this.col(field.alias)}` : ''}`;
}
if (field.aggregation === 'average') {
return `AVG(${this.col(field.column)})${field.alias ? ` AS ${this.col(field.alias)}` : ''}`;
}
if (field.aggregation === 'summation') {
return `SUM(${this.col(field.column)})${field.alias ? ` AS ${this.col(field.alias)}` : ''}`;
}
if (field.aggregation === 'minimum') {
return `MIN(${this.col(field.column)})${field.alias ? ` AS ${this.col(field.alias)}` : ''}`;
}
if (field.aggregation === 'maximum') {
return `MAX(${this.col(field.column)})${field.alias ? ` AS ${this.col(field.alias)}` : ''}`;
}
}
throw new Error(`Invalid select field`);
}).join(', ');
return [query, params];
}
static compileJoin(qb) {
const joins = qb.options.join;
if (joins.length === 0) {
return ['', []];
}
const params = [];
const query = joins.map(join => {
const type = {
inner: 'INNER JOIN',
left: 'LEFT JOIN',
right: 'RIGHT JOIN',
outer: 'OUTER JOIN',
cross: 'CROSS JOIN'
}[join.type];
let table;
if (join.queryBuilder) {
const [q, p] = this.compileSelect(join.queryBuilder);
params.push(...p);
table = `(${q}) ${this.tbl(join.alias)}`;
} else {
table = `${this.tbl(join.table)}${join.alias ? ` ${this.tbl(join.alias)}` : ''}`;
}
let conditions;
if (join.conditions) {
const [q, p] = this.compileConditions(join.conditions, qb.options.table);
params.push(...p);
conditions = q;
} else {
conditions = `${this.col(join.column1, qb.options.table)} ${join.operator} ${this.col(join.column2, qb.options.table)}`;
}
return `${type} ${table} ON ${conditions}`;
}).join(' ');
return [query, params];
}
static compileUnion(qb) {
const unions = qb.options.union;
if (unions.length === 0) {
return ['', []];
}
const params = [];
const query = unions.map(union => {
if (union.type === 'raw') {
params.push(...union.params);
return `UNION${union.all ? ' ALL' : ''} ${union.query}`;
}
if (union.type === 'query') {
const [q, p] = this.compileSelect(union.queryBuilder);
params.push(...p);
return `UNION${union.all ? ' ALL' : ''} ${q}`;
}
throw new Error(`Invalid select field`);
}).join(' ');
return [query, params];
}
static compileOrder(qb) {
const orders = qb.options.order;
if (qb.options.randomOrder) {
return ['ORDER BY RAND(?)', [qb.options.randomSeed || Math.floor(Math.random() * 100000)]];
}
if (orders.length === 0) {
return ['', []];
}
const params = [];
const query = `ORDER BY ${orders.map(order => {
if (order.type === 'column') {
return `${this.col(order.column, qb.options.table)} ${order.direction || 'ASC'}`;
}
if (order.type === 'query') {
const [q, p] = this.compileSelect(order.queryBuilder);
params.push(...p);
return `(${q})`;
}
if (order.type === 'raw') {
params.push(...order.params);
return order.query;
}
return '';
}).join(', ')}`;
return [query, params];
}
static compileGroup(qb) {
const groups = qb.options.group;
const havingConditions = qb.options.having;
const params = [];
let query = '';
if (groups.length > 0) {
query = `GROUP BY ${groups.map(group => {
if (group.type === 'column') {
return this.col(group.column, qb.options.table);
}
if (group.type === 'raw') {
params.push(...group.params);
return group.query;
}
return '';
}).join(', ')}`;
}
if (groups.length > 0 && havingConditions.length > 0) {
query += ' ';
}
if (havingConditions.length > 0) {
const [q, p] = this.compileConditions(havingConditions, qb.options.table);
params.push(...p);
query += `HAVING ${q}`;
}
return [query, params];
}
static compileWhere(qb) {
const whereConditions = qb.options.where;
if (whereConditions.length === 0) {
return ['', []];
}
const [q, p] = this.compileConditions(whereConditions, qb.options.table);
return [`WHERE ${q}`, p];
}
static compileLimit(qb) {
const {
limit,
offset
} = qb.options;
if (!limit) {
if (!offset) {
return ['', []];
}
// eslint-disable-next-line no-loss-of-precision, @typescript-eslint/no-loss-of-precision
return [`Limit ?,?`, [offset, 18446744073709551615]];
}
if (offset) {
return [`Limit ?,?`, [offset, limit]];
}
return [`Limit ?`, [limit]];
}
static compileSelect(queryBuilder) {
const qb = queryBuilder.clone();
if (qb.options.useSoftDeletes && qb.options.softDeleteTimestamp) {
if (qb.options.onlyTrashed) {
qb.groupWhereConditions().whereNotNull(qb.options.softDeleteTimestamp);
} else if (!qb.options.withTrashed) {
qb.groupWhereConditions().whereNull(qb.options.softDeleteTimestamp);
}
}
if (qb.options.processFinalQuery instanceof Function) {
qb.options.processFinalQuery(qb);
}
const [fieldsQuery, fieldsParams] = this.compileSelectFields(qb);
const [whereQuery, whereParams] = this.compileWhere(qb);
const [groupQuery, groupParams] = this.compileGroup(qb);
const [orderQuery, orderParams] = this.compileOrder(qb);
const [limitQuery, limitParams] = this.compileLimit(qb);
const [unionQuery, unionParams] = this.compileUnion(qb);
const [joinQuery, joinParams] = this.compileJoin(qb);
const params = fieldsParams;
let query = `SELECT ${fieldsQuery} `;
if (qb.options.selectInto) {
query += `INTO ${qb.options.selectInto} `;
}
if (qb.options.aliasTable) {
const [q, p] = this.compileSelect(qb.options.aliasTable.queryBuilder);
params.push(...p);
query += `FROM (${q}) ${qb.options.aliasTable.alias ? `${this.tbl(qb.options.aliasTable.alias)} ` : ''}`;
} else {
query += `FROM ${this.tbl(qb.options.table)} `;
}
params.push(...joinParams, ...whereParams, ...groupParams, ...orderParams, ...limitParams, ...unionParams);
query += `${[joinQuery, whereQuery, groupQuery, orderQuery, limitQuery, unionQuery].filter(q => q !== '').join(' ')}`;
qb.options.alongQueries.forEach(aqb => {
const [q, p] = this.compileSelect(aqb);
params.push(...p);
query += `;${q}`;
});
return [query, params];
}
select(queryBuilder) {
return this.execute(...MySQLDriver.compileSelect(queryBuilder));
}
async count(queryBuilder) {
const qb = queryBuilder.clone().selectRaw(`COUNT(*) AS ${MySQLDriver.col('mysql_driver_count')}`);
if (qb.options.group.length > 0) {
return qb.pluck('mysql_driver_count');
}
return (await qb.first()).mysql_driver_count;
}
async average(queryBuilder, column) {
const qb = queryBuilder.clone().selectRaw(`AVG(${MySQLDriver.col(column, queryBuilder.options.table)}) AS ${MySQLDriver.col('mysql_driver_average')}`);
if (qb.options.group.length > 0) {
return qb.pluck('mysql_driver_average');
}
return (await qb.first()).mysql_driver_average;
}
async sum(queryBuilder, column) {
const qb = queryBuilder.clone().selectRaw(`SUM(${MySQLDriver.col(column, queryBuilder.options.table)}) AS ${MySQLDriver.col('mysql_driver_summation')}`);
if (qb.options.group.length > 0) {
return qb.pluck('mysql_driver_summation');
}
return (await qb.first()).mysql_driver_summation;
}
async min(queryBuilder, column) {
const qb = queryBuilder.clone().selectRaw(`MIN(${MySQLDriver.col(column, queryBuilder.options.table)}) AS ${MySQLDriver.col('mysql_driver_minimum')}`);
if (qb.options.group.length > 0) {
return qb.pluck('mysql_driver_minimum');
}
return (await qb.first()).mysql_driver_minimum;
}
async max(queryBuilder, column) {
const qb = queryBuilder.clone().selectRaw(`MAX(${MySQLDriver.col(column, queryBuilder.options.table)}) AS ${MySQLDriver.col('mysql_driver_maximum')}`);
if (qb.options.group.length > 0) {
return qb.pluck('mysql_driver_maximum');
}
return (await qb.first()).mysql_driver_maximum;
}
async exists(queryBuilder) {
const [query, params] = MySQLDriver.compileSelect(queryBuilder);
const [result] = await this.execute(`SELECT EXISTS(${query}) AS ${MySQLDriver.col('exists')}`, params);
return !!result.exists;
}
static compileInsert(qb) {
const params = [];
let query = `INSERT${qb.options.ignoreDuplicates ? ' IGNORE' : ''} INTO ${this.tbl(qb.options.table)}`;
const fieldNames = Object.keys(qb.options.insert[0]);
query += `(${fieldNames.map(fieldName => this.col(fieldName)).join(', ')}) VALUES `;
const values = qb.options.insert.map(dataset => {
const placeHolders = [];
fieldNames.forEach(fieldName => {
if (dataset[fieldName] instanceof _spatial.default) {
params.push(dataset[fieldName].sql);
placeHolders.push('ST_GeomFromText(?)');
} else {
params.push(dataset[fieldName]);
placeHolders.push('?');
}
});
return `(${placeHolders.join(', ')})`;
});
query += `${values.join(', ')}`;
return [query, params];
}
async insert(queryBuilder) {
const result = await this.execute(...MySQLDriver.compileInsert(queryBuilder));
return [result.insertId, result.affectedRows];
}
static compileUpdateFields(qb) {
const updateData = qb.options.update;
const params = [];
let query = Object.keys(updateData).map(key => {
const column = this.col(key);
const value = updateData[key];
if (value === null) {
return `${column} = NULL`;
}
if (value instanceof _spatial.default) {
params.push(value.sql);
return `${column} = ST_GeomFromText(?)`;
}
params.push(value);
return `${column} = ?`;
}).join(', ');
if (qb.options.useTimestamps && qb.options.updateTimestamp && !qb.options.silentUpdate) {
query += `, ${this.col(qb.options.updateTimestamp)} = NOW()`;
}
return [query, params];
}
static compileUpdate(qb) {
const [fieldsQuery, fieldsParams] = this.compileUpdateFields(qb);
const [whereQuery, whereParams] = this.compileWhere(qb);
const [orderQuery, orderParams] = this.compileOrder(qb);
const [offsetQuery, offsetParams] = this.compileLimit(qb);
const params = [...fieldsParams, ...whereParams, ...orderParams, ...offsetParams];
let query = `UPDATE ${qb.options.table} SET `;
query += [fieldsQuery, whereQuery, orderQuery, offsetQuery].join(' ');
return [query, params];
}
async update(queryBuilder) {
const result = await this.execute(...MySQLDriver.compileUpdate(queryBuilder));
return [result.affectedRows, result.changedRows];
}
static compileBulkUpdate(qb) {
const data = qb.options.bulkUpdateData || [];
const keys = qb.options.bulkUpdateKeys || [];
if (data.length === 0) {
return ['', []];
}
const dataKeys = Object.keys(data[0]);
const updateKeys = dataKeys.filter(key => !keys.includes(key));
if (dataKeys.length === 0) {
throw new Error('There are no fields to update');
}
if (updateKeys.length === 0 && qb.options.silentUpdate) {
throw new Error('Bulk update dataset is empty');
}
if (keys.filter(key => dataKeys.includes(key)).length !== keys.length) throw new Error('Bulk update keys are not present in the dataset');
const params = [];
const selects = data.map((row, index) => {
const values = dataKeys.map(key => row[key]);
params.push(...values);
if (index === 0) {
return `SELECT ${dataKeys.map(key => `? AS ${updateKeys.includes(key) ? 'new_' : ''}${key}`).join(', ')}`;
}
return `SELECT ${new Array(values.length).fill('?').join(', ')}`;
});
let query = `UPDATE ${this.tbl(qb.options.table)} ${this.tbl('bt')} `;
query += `JOIN (${selects.join(' UNION ALL ')}) ${this.tbl('vt')} `;
query += `ON ${keys.map(key => `${this.col(key, 'bt')} = ${this.col(key, 'vt')}`).join(' AND ')} `;
query += `SET ${updateKeys.map(key => `${this.col(key)} = ${this.col(`new_${key}`)}`).join(', ')}`;
if (qb.options.useTimestamps && !qb.options.silentUpdate) {
query += `${updateKeys.length > 0 ? ', ' : ''}${this.col(qb.options.updateTimestamp)} = NOW()`;
}
return [query, params];
}
async bulkUpdate(queryBuilder) {
const result = await this.execute(...MySQLDriver.compileBulkUpdate(queryBuilder));
return [result.affectedRows, result.changedRows];
}
static compileDelete(qb) {
const [whereQuery, whereParams] = this.compileWhere(qb);
const [orderQuery, orderParams] = this.compileOrder(qb);
const [limitQuery, limitParams] = this.compileLimit(qb);
const params = [...whereParams, ...orderParams, ...limitParams];
let query = `DELETE FROM ${this.tbl(qb.options.table)} `;
query += [whereQuery, orderQuery, limitQuery].filter(q => q !== '').join(' ');
return [query, params];
}
async delete(queryBuilder) {
const result = await this.execute(...MySQLDriver.compileDelete(queryBuilder));
return [result.affectedRows, result.changedRows];
}
static compileSoftDelete(qb) {
if (!qb.options.useSoftDeletes || !qb.options.softDeleteTimestamp) {
return ['', []];
}
const [whereQuery, whereParams] = this.compileWhere(qb);
const [orderQuery, orderParams] = this.compileOrder(qb);
const [limitQuery, limitParams] = this.compileLimit(qb);
const params = [...whereParams, ...orderParams, ...limitParams];
let query = `UPDATE ${this.tbl(qb.options.table)} SET ${this.col(qb.options.softDeleteTimestamp)} = NOW() `;
query += [whereQuery, orderQuery, limitQuery].filter(q => q !== '').join(' ');
return [query, params];
}
async softDelete(queryBuilder) {
if (!queryBuilder.options.useSoftDeletes) {
throw new Error('Soft deletes are not enabled for this query builder');
}
if (!queryBuilder.options.softDeleteTimestamp) {
throw new Error('Soft delete timestamp is not specified in this query builder');
}
const result = await this.execute(...MySQLDriver.compileSoftDelete(queryBuilder));
return [result.affectedRows, result.changedRows];
}
static compileUndelete(qb) {
if (!qb.options.useSoftDeletes || !qb.options.softDeleteTimestamp) {
return ['', []];
}
const [whereQuery, whereParams] = this.compileWhere(qb);
const [orderQuery, orderParams] = this.compileOrder(qb);
const [limitQuery, limitParams] = this.compileLimit(qb);
const params = [...whereParams, ...orderParams, ...limitParams];
let query = `UPDATE ${this.tbl(qb.options.table)} SET ${this.col(qb.options.softDeleteTimestamp)} = NULL `;
query += [whereQuery, orderQuery, limitQuery].filter(q => q !== '').join(' ');
return [query, params];
}
async restore(queryBuilder) {
if (!queryBuilder.options.useSoftDeletes) {
throw new Error('Soft deletes are not enabled for this query builder');
}
if (!queryBuilder.options.softDeleteTimestamp) {
throw new Error('Soft delete timestamp is not specified in this query builder');
}
const result = await this.execute(...MySQLDriver.compileUndelete(queryBuilder));
return [result.affectedRows, result.changedRows];
}
async setForeignKeyChecks(state) {
await this.execute(`SET FOREIGN_KEY_CHECKS = ${state ? 1 : 0};`);
}
execute(query, params = []) {
return new Promise((resolve, reject) => {
this.pool.query(query, params, (error, result) => {
if (error) return reject(error);
return resolve(result);
});
});
}
closeConnection() {
this.pool.end();
}
}
exports.default = MySQLDriver;