UNPKG

@vulcan-sql/core

Version:
635 lines 22.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DataQueryBuilder = exports.Direction = exports.WherePredicate = exports.JoinCommandType = exports.AggregateFuncType = exports.SelectCommandType = void 0; const tslib_1 = require("tslib"); const models_1 = require("../../../models/index"); const uuid = require("uuid"); const lodash_1 = require("lodash"); const commonTypes_1 = require("./commonTypes"); const joinOnClause_1 = require("./joinOnClause"); const errors_1 = require("../../utils/errors"); var SelectCommandType; (function (SelectCommandType) { SelectCommandType["SELECT"] = "SELECT"; SelectCommandType["SELECT_DISTINCT"] = "SELECT_DISTINCT"; })(SelectCommandType = exports.SelectCommandType || (exports.SelectCommandType = {})); var AggregateFuncType; (function (AggregateFuncType) { AggregateFuncType["COUNT"] = "COUNT"; AggregateFuncType["SUM"] = "SUM"; AggregateFuncType["AVG"] = "AVG"; AggregateFuncType["MIN"] = "MIN"; AggregateFuncType["MAX"] = "MAX"; })(AggregateFuncType = exports.AggregateFuncType || (exports.AggregateFuncType = {})); var JoinCommandType; (function (JoinCommandType) { JoinCommandType["INNER_JOIN"] = "INNER_JOIN"; JoinCommandType["LEFT_JOIN"] = "LEFT_JOIN"; JoinCommandType["RIGHT_JOIN"] = "RIGHT_JOIN"; JoinCommandType["FULL_JOIN"] = "FULL_JOIN"; })(JoinCommandType = exports.JoinCommandType || (exports.JoinCommandType = {})); var WherePredicate; (function (WherePredicate) { WherePredicate["WRAPPED"] = "WRAPPED"; WherePredicate["LIKE"] = "LIKE"; })(WherePredicate = exports.WherePredicate || (exports.WherePredicate = {})); // Order by clause operation var Direction; (function (Direction) { Direction["ASC"] = "ASCENDING"; Direction["DESC"] = "DESCENDING"; })(Direction = exports.Direction || (exports.Direction = {})); class DataQueryBuilder { constructor({ statement, operations, parameterizer, dataSource, profileName, headers, }) { this.identifier = uuid.v4(); this.statement = statement; this.dataSource = dataSource; this.parameterizer = parameterizer; this.operations = operations || { select: null, where: [], join: [], groupBy: [], having: [], orderBy: [], limit: null, offset: null, }; this.headers = headers; this.profileName = profileName; } // Select clause methods select(...columns) { // if columns is empty, set to select all if ((0, lodash_1.isEmpty)(columns)) columns = ['*']; // skip current select if select only '*' value and has existed select '*' in record. const isSelectAllExist = (column) => column.name === '*'; const isAllColumns = (column) => ['*', ''].includes(column) || [{ name: '*' }, { name: '' }].includes(column); if (columns.length === 1 && isAllColumns(columns[0]) && this.operations.select && (0, lodash_1.find)(this.operations.select.columns, isSelectAllExist)) { return this; } this.recordSelect({ command: SelectCommandType.SELECT, columns }); return this; } distinct(...columns) { this.recordSelect({ command: SelectCommandType.SELECT_DISTINCT, columns }); return this; } // alias name method for select column(...columns) { return this.select(...columns); } // select and limit 1 first(...columns) { this.select(...columns); this.limit(1); return this; } count(column = '*') { const normalized = typeof column === 'string' ? { name: '*', aggregateType: AggregateFuncType.COUNT, } : Object.assign(Object.assign({}, column), { aggregateType: AggregateFuncType.COUNT }); this.select(normalized); return this; } min(column) { const normalized = typeof column === 'string' ? { name: column, aggregateType: AggregateFuncType.MIN, } : Object.assign(Object.assign({}, column), { aggregateType: AggregateFuncType.MIN }); this.select(normalized); return this; } max(column) { const normalized = typeof column === 'string' ? { name: column, aggregateType: AggregateFuncType.MAX, } : Object.assign(Object.assign({}, column), { aggregateType: AggregateFuncType.MAX }); this.select(normalized); return this; } avg(column) { const normalized = typeof column === 'string' ? { name: column, aggregateType: AggregateFuncType.AVG, } : Object.assign(Object.assign({}, column), { aggregateType: AggregateFuncType.AVG }); this.select(normalized); return this; } sum(column) { const normalized = typeof column === 'string' ? { name: column, aggregateType: AggregateFuncType.SUM, } : Object.assign(Object.assign({}, column), { aggregateType: AggregateFuncType.SUM }); this.select(normalized); return this; } // Join clause methods innerJoin(builder, joinCallback) { this.recordJoin({ command: JoinCommandType.INNER_JOIN, builder, joinCallback, }); return this; } leftJoin(builder, joinCallback) { this.recordJoin({ command: JoinCommandType.LEFT_JOIN, builder, joinCallback, }); return this; } rightJoin(builder, joinCallback) { this.recordJoin({ command: JoinCommandType.RIGHT_JOIN, builder, joinCallback, }); return this; } fullJoin(builder, joinCallback) { this.recordJoin({ command: JoinCommandType.FULL_JOIN, builder, joinCallback, }); return this; } // Where clause methods where(column, operator, value) { if (!(0, commonTypes_1.isOfComparisonOperator)(operator)) throw new errors_1.TemplateError(`'There is no ${operator} operator.`); this.recordWhere({ command: null, data: { column, operator, value, }, }); return this; } whereNot(column, operator, value) { this.recordWhere({ command: commonTypes_1.LogicalOperator.NOT }); return this.where(column, operator, value); } whereWrapped(builderCallback) { const wrappedBuilder = new DataQueryBuilder({ statement: '', dataSource: this.dataSource, parameterizer: this.parameterizer, profileName: this.profileName, headers: this.headers, }); builderCallback(wrappedBuilder); this.recordWhere({ command: WherePredicate.WRAPPED, data: wrappedBuilder.operations.where, }); return this; } whereNotWrapped(builderCallback) { this.recordWhere({ command: commonTypes_1.LogicalOperator.NOT }); return this.whereWrapped(builderCallback); } whereBetween(column, min, max) { this.recordWhere({ command: commonTypes_1.ComparisonPredicate.BETWEEN, data: { column, min, max }, }); return this; } whereNotBetween(column, min, max) { this.recordWhere({ command: commonTypes_1.LogicalOperator.NOT }); return this.whereBetween(column, min, max); } whereIn(column, values) { this.recordWhere({ command: commonTypes_1.ComparisonPredicate.IN, data: { column, values: values }, }); return this; } whereNotIn(column, values) { this.recordWhere({ command: commonTypes_1.LogicalOperator.NOT }); return this.whereIn(column, values); } whereNull(column) { this.recordWhere({ command: commonTypes_1.ComparisonPredicate.IS_NULL, data: { column }, }); return this; } whereNotNull(column) { this.recordWhere({ command: commonTypes_1.LogicalOperator.NOT }); return this.whereNull(column); } whereLike(column, searchValue) { this.recordWhere({ command: WherePredicate.LIKE, data: { column, searchValue }, }); return this; } whereExists(subQueryBuilder) { this.recordWhere({ command: commonTypes_1.ComparisonPredicate.EXISTS, data: subQueryBuilder, }); return this; } whereNotExists(subQueryBuilder) { this.recordWhere({ command: commonTypes_1.LogicalOperator.NOT }); return this.whereExists(subQueryBuilder); } // and andWhere(column, operator, value) { this.recordWhere({ command: commonTypes_1.LogicalOperator.AND }); return this.where(column, operator, value); } andWhereNot(column, operator, value) { this.recordWhere({ command: commonTypes_1.LogicalOperator.AND }); return this.whereNot(column, operator, value); } andWhereWrapped(builderCallback) { this.recordWhere({ command: commonTypes_1.LogicalOperator.AND }); return this.whereWrapped(builderCallback); } andWhereNotWrapped(builderCallback) { this.recordWhere({ command: commonTypes_1.LogicalOperator.AND }); return this.whereNotWrapped(builderCallback); } andWhereBetween(column, min, max) { this.recordWhere({ command: commonTypes_1.LogicalOperator.AND }); return this.whereBetween(column, min, max); } andWhereNotBetween(column, min, max) { this.recordWhere({ command: commonTypes_1.LogicalOperator.AND }); return this.whereNotBetween(column, min, max); } andWhereIn(column, values) { this.recordWhere({ command: commonTypes_1.LogicalOperator.AND }); return this.whereIn(column, values); } andWhereNotIn(column, values) { this.recordWhere({ command: commonTypes_1.LogicalOperator.AND }); return this.whereNotIn(column, values); } andWhereNull(column) { this.recordWhere({ command: commonTypes_1.LogicalOperator.AND }); return this.whereNull(column); } andWhereNotNull(column) { this.recordWhere({ command: commonTypes_1.LogicalOperator.AND }); return this.whereNotNull(column); } andWhereLike(column, searchValue) { this.recordWhere({ command: commonTypes_1.LogicalOperator.AND }); return this.whereLike(column, searchValue); } andWhereExists(subQueryBuilder) { this.recordWhere({ command: commonTypes_1.LogicalOperator.AND }); return this.whereExists(subQueryBuilder); } andWhereNotExists(subQueryBuilder) { this.recordWhere({ command: commonTypes_1.LogicalOperator.AND }); return this.whereNotExists(subQueryBuilder); } // or orWhere(column, operator, value) { this.recordWhere({ command: commonTypes_1.LogicalOperator.OR }); return this.where(column, operator, value); } orWhereNot(column, operator, value) { this.recordWhere({ command: commonTypes_1.LogicalOperator.OR }); return this.whereNot(column, operator, value); } orWhereWrapped(builderCallback) { this.recordWhere({ command: commonTypes_1.LogicalOperator.OR }); return this.whereWrapped(builderCallback); } orWhereNotWrapped(builderCallback) { this.recordWhere({ command: commonTypes_1.LogicalOperator.OR }); return this.whereNotWrapped(builderCallback); } orWhereBetween(column, min, max) { this.recordWhere({ command: commonTypes_1.LogicalOperator.OR }); return this.whereBetween(column, min, max); } orWhereNotBetween(column, min, max) { this.recordWhere({ command: commonTypes_1.LogicalOperator.OR }); return this.whereNotBetween(column, min, max); } orWhereIn(column, values) { this.recordWhere({ command: commonTypes_1.LogicalOperator.OR }); return this.whereIn(column, values); } orWhereNotIn(column, values) { this.recordWhere({ command: commonTypes_1.LogicalOperator.OR }); return this.whereNotIn(column, values); } orWhereNull(column) { this.recordWhere({ command: commonTypes_1.LogicalOperator.OR }); return this.whereNull(column); } orWhereNotNull(column) { this.recordWhere({ command: commonTypes_1.LogicalOperator.OR }); return this.whereNotNull(column); } orWhereLike(column, searchValue) { this.recordWhere({ command: commonTypes_1.LogicalOperator.OR }); return this.whereLike(column, searchValue); } orWhereExists(subQueryBuilder) { this.recordWhere({ command: commonTypes_1.LogicalOperator.OR }); return this.whereExists(subQueryBuilder); } orWhereNotExists(subQueryBuilder) { this.recordWhere({ command: commonTypes_1.LogicalOperator.OR }); return this.whereNotExists(subQueryBuilder); } // Group by clause method groupBy(...columns) { this.operations.groupBy = this.operations.groupBy.concat(columns); return this; } having(column, operator, value) { const normalized = typeof column === 'string' ? { name: column } : column; if (!(0, commonTypes_1.isOfComparisonOperator)(operator)) throw new errors_1.TemplateError(`'There is no ${operator} operator.`); this.recordHaving({ command: null, data: { column: normalized, operator, value, }, }); return this; } havingIn(column, values) { const normalized = typeof column === 'string' ? { name: column } : column; this.recordHaving({ command: commonTypes_1.ComparisonPredicate.IN, data: { column: normalized, values, }, }); return this; } havingNotIn(column, values) { this.recordHaving({ command: commonTypes_1.LogicalOperator.NOT }); return this.havingIn(column, values); } havingBetween(column, min, max) { const normalized = typeof column === 'string' ? { name: column } : column; this.recordHaving({ command: commonTypes_1.ComparisonPredicate.BETWEEN, data: { column: normalized, min, max, }, }); return this; } havingNotBetween(column, min, max) { this.recordHaving({ command: commonTypes_1.LogicalOperator.NOT }); return this.havingBetween(column, min, max); } havingNull(column) { this.recordHaving({ command: commonTypes_1.ComparisonPredicate.IS_NULL, data: { column }, }); return this; } havingNotNull(column) { this.recordHaving({ command: commonTypes_1.LogicalOperator.NOT }); return this.havingNull(column); } havingExists(subQueryBuilder) { this.recordHaving({ command: commonTypes_1.ComparisonPredicate.EXISTS, data: subQueryBuilder, }); return this; } havingNotExists(subQueryBuilder) { this.recordHaving({ command: commonTypes_1.LogicalOperator.NOT }); return this.havingExists(subQueryBuilder); } // And Having clause andHaving(column, operator, value) { this.recordHaving({ command: commonTypes_1.LogicalOperator.AND }); return this.having(column, operator, value); } andHavingIn(column, values) { this.recordHaving({ command: commonTypes_1.LogicalOperator.AND }); return this.havingIn(column, values); } andHavingNotIn(column, values) { this.recordHaving({ command: commonTypes_1.LogicalOperator.AND }); return this.havingNotIn(column, values); } andHavingBetween(column, min, max) { this.recordHaving({ command: commonTypes_1.LogicalOperator.AND }); return this.havingBetween(column, min, max); } andHavingNotBetween(column, min, max) { this.recordHaving({ command: commonTypes_1.LogicalOperator.AND }); return this.havingNotBetween(column, min, max); } andHavingNull(column) { this.recordHaving({ command: commonTypes_1.LogicalOperator.AND }); return this.havingNull(column); } andHavingNotNull(column) { this.recordHaving({ command: commonTypes_1.LogicalOperator.AND }); return this.havingNotNull(column); } andHavingExists(subQueryBuilder) { this.recordHaving({ command: commonTypes_1.LogicalOperator.AND }); return this.havingExists(subQueryBuilder); } andHavingNotExists(subQueryBuilder) { this.recordHaving({ command: commonTypes_1.LogicalOperator.AND }); return this.havingNotExists(subQueryBuilder); } // Or Having clause orHaving(column, operator, value) { this.recordHaving({ command: commonTypes_1.LogicalOperator.OR }); return this.having(column, operator, value); } orHavingIn(column, values) { this.recordHaving({ command: commonTypes_1.LogicalOperator.OR }); return this.havingIn(column, values); } orHavingNotIn(column, values) { this.recordHaving({ command: commonTypes_1.LogicalOperator.OR }); return this.havingNotIn(column, values); } orHavingBetween(column, min, max) { this.recordHaving({ command: commonTypes_1.LogicalOperator.OR }); return this.havingBetween(column, min, max); } orHavingNotBetween(column, min, max) { this.recordHaving({ command: commonTypes_1.LogicalOperator.OR }); return this.havingNotBetween(column, min, max); } orHavingNull(column) { this.recordHaving({ command: commonTypes_1.LogicalOperator.OR }); return this.havingNull(column); } orHavingNotNull(column) { this.recordHaving({ command: commonTypes_1.LogicalOperator.OR }); return this.havingNotNull(column); } orHavingExists(subQueryBuilder) { this.recordHaving({ command: commonTypes_1.LogicalOperator.OR }); return this.havingExists(subQueryBuilder); } orHavingNotExists(subQueryBuilder) { this.recordHaving({ command: commonTypes_1.LogicalOperator.OR }); return this.havingNotExists(subQueryBuilder); } // Order by clause method orderBy(column, direction = Direction.ASC) { this.operations.orderBy.push({ column, direction, }); return this; } // Limit and Offset clause limit(size) { this.operations.limit = size; return this; } offset(move) { this.operations.offset = move; return this; } take(size, move) { this.operations.limit = size; this.operations.offset = move; return this; } clone() { return new DataQueryBuilder({ statement: this.statement, dataSource: this.dataSource, operations: this.operations, parameterizer: this.parameterizer.clone(), profileName: this.profileName, headers: this.headers, }); } // setup pagination if would like to do paginate paginate(pagination) { if (!(0, models_1.isOffsetPagination)(pagination)) { throw new errors_1.InternalError(`Only offset pagination is supported`); } this.take(pagination.limit, pagination.offset); } setHeaders(headers) { if (!headers) return; this.headers = headers; } parameterizeOperations() { return tslib_1.__awaiter(this, void 0, void 0, function* () { // We only support offset and limit now. const parameterizedOperations = { offset: yield this.parameterizeValue(this.operations.offset), limit: yield this.parameterizeValue(this.operations.limit), }; this.parameterizer.reset(); return parameterizedOperations; }); } value() { return tslib_1.__awaiter(this, void 0, void 0, function* () { // call data source const result = yield this.dataSource.execute({ statement: this.statement, operations: yield this.parameterizeOperations(), bindParams: this.parameterizer.getBinding(), profileName: this.profileName, headers: this.headers, }); return result; }); } // record Select-On related operations recordSelect({ command, columns, }) { const normalized = columns.map((column) => { if (typeof column === 'string') return { name: column }; return column; }); if (this.operations.select === null) { this.operations.select = { command, columns: normalized, }; return; } // distinct will replace previous select command, // even builder call select method in later of the distinct method, it not influence distinct. if (command === SelectCommandType.SELECT_DISTINCT) this.operations.select.command = command; this.operations.select.columns = this.operations.select.columns.concat(normalized); } recordJoin({ command, builder, joinCallback, }) { const joinOnClause = new joinOnClause_1.JoinOnClause(); joinCallback(joinOnClause); this.operations.join.push({ command, onClauses: joinOnClause.operations, joinBuilder: builder, }); } recordWhere({ command, data, }) { this.operations.where.push({ command, data, }); } recordHaving({ command, data, }) { this.operations.having.push({ command, data, }); } parameterizeValue(value) { return tslib_1.__awaiter(this, void 0, void 0, function* () { if ((0, lodash_1.isUndefined)(value) || (0, lodash_1.isNull)(value)) return null; return yield this.parameterizer.generateIdentifier(value); }); } } exports.DataQueryBuilder = DataQueryBuilder; //# sourceMappingURL=dataQueryBuilder.js.map