123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307 |
- const QueryBuilderContextBase = require('./QueryBuilderContextBase');
- const QueryBuilderUserContext = require('./QueryBuilderUserContext');
- class QueryBuilderOperationSupport {
- constructor(knex) {
- this._knex = knex;
- this._operations = [];
- this._context = new this.constructor.QueryBuilderContext(this);
- this._parentQuery = null;
- }
- static get QueryBuilderContext() {
- return QueryBuilderContextBase;
- }
- static get QueryBuilderUserContext() {
- return QueryBuilderUserContext;
- }
- context(obj) {
- const ctx = this._context;
- if (arguments.length === 0) {
- return ctx.userContext;
- } else {
- ctx.userContext = ctx.userContext.newFromObject(this, obj);
- return this;
- }
- }
- mergeContext(obj) {
- const ctx = this._context;
- ctx.userContext = ctx.userContext.newMerge(this, obj);
- return this;
- }
- internalContext(ctx) {
- if (arguments.length === 0) {
- return this._context;
- } else {
- this._context = ctx;
- return this;
- }
- }
- internalOptions(opt) {
- if (arguments.length === 0) {
- return this._context.options;
- } else {
- const oldOpt = this._context.options;
- this._context.options = Object.assign(oldOpt, opt);
- return this;
- }
- }
- childQueryOf(query, fork) {
- if (query) {
- let ctx = query.internalContext();
- if (fork) {
- ctx = ctx.clone();
- }
- this._parentQuery = query;
- this.internalContext(ctx);
- if (this.unsafeKnex() === null) {
- this.knex(query.unsafeKnex());
- }
- }
- return this;
- }
- subqueryOf(query) {
- if (query) {
- this._parentQuery = query;
- this.knex(query.knex());
- }
- return this;
- }
- parentQuery() {
- return this._parentQuery;
- }
- knex() {
- if (arguments.length === 0) {
- const knex = this.unsafeKnex();
- if (!knex) {
- throw new Error(
- `no database connection available for a query. You need to bind the model class or the query to a knex instance.`
- );
- }
- return knex;
- } else {
- this._knex = arguments[0];
- return this;
- }
- }
- unsafeKnex() {
- return this._context.knex || this._knex || null;
- }
- clear(operationSelector) {
- const operations = [];
- this.forEachOperation(
- operationSelector,
- op => {
- operations.push(op);
- },
- false
- );
- this._operations = operations;
- return this;
- }
- copyFrom(queryBuilder, operationSelector) {
- const operations = this._operations;
- queryBuilder.forEachOperation(operationSelector, op => {
- operations.push(op);
- });
- return this;
- }
- has(operationSelector) {
- return this.indexOfOperation(operationSelector) !== -1;
- }
- indexOfOperation(operationSelector) {
- let idx = -1;
- this.forEachOperation(operationSelector, (op, i) => {
- idx = i;
- return false;
- });
- return idx;
- }
- indexOfLastOperation(operationSelector) {
- let idx = -1;
- this.forEachOperation(operationSelector, (op, i) => {
- idx = i;
- });
- return idx;
- }
- findLastOperation(operationSelector) {
- const idx = this.indexOfLastOperation(operationSelector);
- if (idx !== -1) {
- return this._operations[idx];
- } else {
- return null;
- }
- }
- forEachOperation(operationSelector, callback, match) {
- match = match == null ? true : match;
- let check;
- if (operationSelector instanceof RegExp) {
- check = op => operationSelector.test(op.name);
- } else if (typeof operationSelector === 'string') {
- check = op => op.name === operationSelector;
- } else {
- check = op => op.is(operationSelector);
- }
- for (let i = 0, l = this._operations.length; i < l; ++i) {
- const op = this._operations[i];
- if (check(op) === match) {
- if (callback(op, i) === false) {
- break;
- }
- }
- }
- return this;
- }
- addOperation(operation, args) {
- const shouldAdd = operation.onAdd(this, args);
- if (shouldAdd) {
- this._operations.push(operation);
- }
- return this;
- }
- addOperationToFront(operation, args) {
- const shouldAdd = operation.onAdd(this, args);
- if (shouldAdd) {
- this._operations.unshift(operation);
- }
- return this;
- }
- clone() {
- return this.baseCloneInto(new this.constructor(this.unsafeKnex()));
- }
- baseCloneInto(builder) {
- builder._knex = this._knex;
- builder._operations = this._operations.slice();
- builder._context = this._context.clone();
- builder._parentQuery = this._parentQuery;
- return builder;
- }
- build() {
- return this.buildInto(this.knex().queryBuilder());
- }
- buildInto(knexBuilder) {
- this.executeOnBuild();
- // onBuildKnex operations should never add new operations. They should only call
- // methods on the knex query builder.
- for (let i = 0, l = this._operations.length; i < l; ++i) {
- this._operations[i].onBuildKnex(knexBuilder, this);
- if (this._operations.length !== l) {
- throw new Error('onBuildKnex should only call query building methods on the knex builder');
- }
- }
- return knexBuilder;
- }
- executeOnBuild() {
- const operationSet = new Set();
- for (let i = 0; i < this._operations.length; ++i) {
- operationSet.add(this._operations[i]);
- }
- let i = 0;
- while (i < this._operations.length) {
- const iOp = this._operations[i];
- const newOps = [];
- iOp.onBuild(this);
- for (let j = 0; j < this._operations.length; ++j) {
- const jOp = this._operations[j];
- // onBuild may have removed operations before `op`.
- // We need to update the index.
- if (iOp === jOp) {
- i = j;
- }
- if (!operationSet.has(jOp)) {
- // New operation was added.
- newOps.push(jOp);
- operationSet.add(jOp);
- }
- }
- if (newOps.length !== 0) {
- // Make room for the new operations after the current operation.
- for (let j = this._operations.length - 1; j > i + newOps.length; --j) {
- this._operations[j] = this._operations[j - newOps.length];
- }
- // Move the new operations after the current operation.
- for (let j = 0; j < newOps.length; ++j) {
- this._operations[i + j + 1] = newOps[j];
- }
- }
- ++i;
- }
- }
- toString() {
- return this.build().toString();
- }
- toSql() {
- return this.toString();
- }
- skipUndefined() {
- this._context.options.skipUndefined = true;
- return this;
- }
- }
- module.exports = QueryBuilderOperationSupport;
|