UNPKG

ts-sql

Version:

An SQL builder in Typescript. This project is heavily inspired by [XQL](/extjs/xql). A big shout out to @exjs and @kobalicek for this amazing project.

242 lines 9.02 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const ast = require("./astsql"); class QueryableImpl { constructor(queryBuilder) { this.queryBuilder = queryBuilder; this.select = (element, ...moreElements) => { const all = "*"; let query = this.statement.query.query; if (element === all) { query.selectAll = all; query.elements = moreElements; } else { query.elements = [typeof element === "string" ? this.queryBuilder.column(element) : element].concat(moreElements); } return this; }; this.from = (table, alias) => { let query = this.statement.query.query; let tableSourceItems = []; if (typeof table === "string") { let tableSpec = new ast.TableSpec(table); tableSourceItems.push(alias ? new ast.AliasedTerm(tableSpec, alias) : tableSpec); } else { if (!alias) { throw Error("Alias required for nested select statements"); } else { tableSourceItems.push(new ast.AliasedTerm(table, alias)); } } query.from = new ast.FromClause(tableSourceItems.map(item => new ast.TableSource(item))); return this; }; this.join = (table, alias, on) => { return this.buildJoinClause(table, alias, on, "INNER"); }; this.lefJoin = (table, alias, on) => { return this.buildJoinClause(table, alias, on, "LEFT OUTER"); }; this.rightJoin = (table, alias, on) => { return this.buildJoinClause(table, alias, on, "RIGHT OUTER"); }; this.where = (expression) => { let query = this.statement.query.query; if (query.from) { query.from.where = new ast.WhereClause(expression); } return this; }; this.groupBy = (...fields) => { let groupByClause = new ast.GroupByClause(fields.map(f => typeof f === "string" ? new ast.GroupByItem(new ast.ColumnName(f)) : f)); if (this.statement.query.query.from) { this.statement.query.query.from.groupBy = groupByClause; } else { throw Error("Can't group anything"); } return this; }; this.having = (condition) => { if (this.statement.query.query.from) { this.statement.query.query.from.having = condition; } else { throw Error("Invalid use of 'having'"); } return this; }; this.orderBy = (...expressions) => { this.statement.query.query.orderBy = new ast.OrderByClause(expressions); return this; }; this.limit = (limit, offset) => { this.statement.query.query.limit = new ast.LimitClause(limit, offset); return this; }; this.into = (...fields) => { throw Error("Into is not yet implemented"); }; this.toSelect = () => { return this.statement; }; this.build = () => { return new ast.SqlRoot(this.queryBuilder.dialect, [this.toSelect()]); }; this.statement = new ast.SelectStatement(new ast.QueryIntoExpression(new ast.QueryExpression())); } buildJoinClause(table, alias, on, joinType) { let tableSpec = new ast.AliasedTerm(typeof table === "string" ? new ast.TableSpec(table) : table, alias); let joinPart = new ast.JoinClause(tableSpec); joinPart.joinType = joinType; joinPart.on = on; if (this.statement.query.query.from !== undefined) { let tables = this.statement.query.query.from.tables; let lastTable = tables[tables.length - 1]; lastTable.joins = lastTable.joins ? lastTable.joins.concat(joinPart) : [joinPart]; } else { throw Error("Can't join with anything meaningful"); } return this; } } class QueryBuilderBase { constructor(dialect) { this.dialect = dialect; this.equals = (left, right) => { return this.buildBinaryPredicate(left, "=", right); }; this.greater = (left, right) => { return this.buildBinaryPredicate(left, ">", right); }; this.less = (left, right) => { return this.buildBinaryPredicate(left, "<", right); }; this.greaterOrEquals = (left, right) => { return this.buildBinaryPredicate(left, ">=", right); }; this.lessOrEquals = (left, right) => { return this.buildBinaryPredicate(left, "<=", right); }; this.notEquals = (left, right) => { return this.buildBinaryPredicate(left, "!=", right); }; this.nullSafeEquals = (left, right) => { return this.buildBinaryPredicate(left, "<=>", right); }; } alias(node, aliasName) { return new ast.AliasedTerm(node, aliasName); } func(name, ...funcArgs) { return new ast.SimpleFunctionCall(name, funcArgs.map(f => typeof f === "string" ? this.column(f) : f)); } column(name, table) { let lastDot = name.lastIndexOf("."); if (lastDot !== -1) { if (table) { throw Error("Invalid syntax for column name"); } else { table = name.substr(0, lastDot); name = name.substr(lastDot + 1); if (!name || name === "") { throw Error("Invalid syntax for column name"); } } } return new ast.ColumnName(name, table); } literal(value, alias) { let constant = new ast.Constant(value); return alias ? new ast.AliasedTerm(constant, alias) : constant; } variable(name) { return new ast.Variable(name); } exists(statement) { return new ast.ExistsSelectStatement(statement); } nested(statement) { return new ast.NestedSelectStatement(statement); } not(expression) { return new ast.NotExpression(expression); } and(left, right, ...more) { let result = new ast.BinaryExpression(left, "AND", right); for (let expr of more) { result = new ast.BinaryExpression(result, "AND", expr); } return result; } or(left, right, ...more) { let result = new ast.BinaryExpression(left, "OR", right); for (let expr of more) { result = new ast.BinaryExpression(result, "OR", expr); } return result; } xor(left, right) { return new ast.BinaryExpression(left, "XOR", right); } isTrue(predicate) { return new ast.TruthyPredicate(predicate, false, true); } isFalse(predicate) { return new ast.TruthyPredicate(predicate, false, false); } isUnknown(predicate) { throw new Error("Method not implemented."); } in(predicate, target) { return new ast.InPredicate(predicate, target); } notIn(predicate, target) { return new ast.InPredicate(predicate, target, true); } isNull(predicate) { return new ast.IsNullNotNullPredicate(predicate, "NULL"); } isNotNull(predicate) { return new ast.IsNullNotNullPredicate(predicate, "NOT NULL"); } binaryPredicate(left, operator, right) { return new ast.BinaryExpression(left, operator, right); } between(operand, start, end) { return new ast.BetweenPredicate(operand, start, end); } notBetween(operand, left, right) { return new ast.BetweenPredicate(operand, left, right, true); } soundsLike(left, right) { return new ast.SoundsLikePredicate(left, right); } like(left, right) { return new ast.LikePredicate(left, right); } notLike(left, right) { return new ast.LikePredicate(left, right, true); } query() { return new QueryableImpl(this); } buildBinaryPredicate(left, operator, right) { let lp = typeof left === "string" ? this.column(left) : left; let rp = typeof right === "string" ? this.column(right) : right; return new ast.BinaryPredicate(lp, operator, rp); } } exports.QueryBuilderBase = QueryBuilderBase; class MySQLQueryBuilder extends QueryBuilderBase { constructor() { super("MySQL"); } } exports.MySQLQueryBuilder = MySQLQueryBuilder; //# sourceMappingURL=queryBuilder.js.map