QueryBuilder.js 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423
  1. const Promise = require('bluebird');
  2. const { raw } = require('./RawBuilder');
  3. const { Type: ValidationErrorType } = require('../model/ValidationError');
  4. const { isObject, isString, isFunction, last, upperFirst } = require('../utils/objectUtils');
  5. const QueryBuilderContext = require('./QueryBuilderContext');
  6. const RelationExpression = require('./RelationExpression');
  7. const QueryBuilderBase = require('./QueryBuilderBase');
  8. const FindOperation = require('./operations/FindOperation');
  9. const DeleteOperation = require('./operations/DeleteOperation');
  10. const UpdateOperation = require('./operations/UpdateOperation');
  11. const InsertOperation = require('./operations/InsertOperation');
  12. const RelateOperation = require('./operations/RelateOperation');
  13. const UnrelateOperation = require('./operations/UnrelateOperation');
  14. const InsertGraphAndFetchOperation = require('./operations/InsertGraphAndFetchOperation');
  15. const UpsertGraphAndFetchOperation = require('./operations/UpsertGraphAndFetchOperation');
  16. const InsertAndFetchOperation = require('./operations/InsertAndFetchOperation');
  17. const UpdateAndFetchOperation = require('./operations/UpdateAndFetchOperation');
  18. const QueryBuilderOperation = require('./operations/QueryBuilderOperation');
  19. const JoinRelationOperation = require('./operations/JoinRelationOperation');
  20. const OnBuildKnexOperation = require('./operations/OnBuildKnexOperation');
  21. const InsertGraphOperation = require('./operations/InsertGraphOperation');
  22. const UpsertGraphOperation = require('./operations/UpsertGraphOperation');
  23. const DeleteByIdOperation = require('./operations/DeleteByIdOperation');
  24. const RunBeforeOperation = require('./operations/RunBeforeOperation');
  25. const RunAfterOperation = require('./operations/RunAfterOperation');
  26. const FindByIdOperation = require('./operations/FindByIdOperation');
  27. const FindByIdsOperation = require('./operations/FindByIdsOperation');
  28. const OnBuildOperation = require('./operations/OnBuildOperation');
  29. const OnErrorOperation = require('./operations/OnErrorOperation');
  30. const SelectOperation = require('./operations/select/SelectOperation');
  31. const EagerOperation = require('./operations/eager/EagerOperation');
  32. const RangeOperation = require('./operations/RangeOperation');
  33. const FirstOperation = require('./operations/FirstOperation');
  34. const FromOperation = require('./operations/FromOperation');
  35. const KnexOperation = require('./operations/KnexOperation');
  36. class QueryBuilder extends QueryBuilderBase {
  37. constructor(modelClass) {
  38. super(modelClass.knex());
  39. this._modelClass = modelClass;
  40. this._resultModelClass = null;
  41. this._explicitRejectValue = null;
  42. this._explicitResolveValue = null;
  43. this._eagerExpression = null;
  44. this._eagerFilters = null;
  45. this._eagerFiltersAtPath = [];
  46. this._allowedEagerExpression = null;
  47. this._allowedUpsertExpression = null;
  48. this._findOperationOptions = modelClass.defaultFindOptions;
  49. this._eagerOperationOptions = modelClass.defaultEagerOptions;
  50. this._findOperationFactory = findOperationFactory;
  51. this._insertOperationFactory = insertOperationFactory;
  52. this._updateOperationFactory = updateOperationFactory;
  53. this._patchOperationFactory = patchOperationFactory;
  54. this._relateOperationFactory = relateOperationFactory;
  55. this._unrelateOperationFactory = unrelateOperationFactory;
  56. this._deleteOperationFactory = deleteOperationFactory;
  57. this._eagerOperationFactory = modelClass.defaultEagerAlgorithm;
  58. }
  59. static forClass(modelClass) {
  60. return new this(modelClass);
  61. }
  62. static get QueryBuilderContext() {
  63. return QueryBuilderContext;
  64. }
  65. tableNameFor(modelClass, tableName) {
  66. const ctx = this.internalContext();
  67. const tableMap = ctx.tableMap;
  68. if (isString(tableName)) {
  69. ctx.tableMap = tableMap || new Map();
  70. ctx.tableMap.set(modelClass.getTableName(), tableName);
  71. return this;
  72. } else {
  73. return (tableMap && tableMap.get(modelClass.getTableName())) || modelClass.getTableName();
  74. }
  75. }
  76. aliasFor(modelClass, alias) {
  77. const ctx = this.internalContext();
  78. const aliasMap = ctx.aliasMap;
  79. if (isString(alias)) {
  80. ctx.aliasMap = aliasMap || new Map();
  81. ctx.aliasMap.set(modelClass.getTableName(), alias);
  82. return this;
  83. } else {
  84. return (aliasMap && aliasMap.get(modelClass.getTableName())) || null;
  85. }
  86. }
  87. alias(alias) {
  88. return this.aliasFor(this._modelClass, alias);
  89. }
  90. tableRefFor(modelClass) {
  91. return this.aliasFor(modelClass) || this.tableNameFor(modelClass);
  92. }
  93. subqueryOf(query) {
  94. const ctx = this.internalContext();
  95. // Merge alias and table name maps for subqueries.
  96. ctx.aliasMap = mergeMaps(query.internalContext().aliasMap, ctx.aliasMap);
  97. ctx.tableMap = mergeMaps(query.internalContext().tableMap, ctx.tableMap);
  98. return super.subqueryOf(query);
  99. }
  100. fullIdColumnFor(modelClass) {
  101. const tableName = this.tableRefFor(modelClass);
  102. const idColumn = modelClass.getIdColumn();
  103. if (Array.isArray(idColumn)) {
  104. const id = new Array(idColumn.length);
  105. for (let i = 0, l = idColumn.length; i < l; ++i) {
  106. id[i] = `${tableName}.${idColumn[i]}`;
  107. }
  108. return id;
  109. } else {
  110. return `${tableName}.${idColumn}`;
  111. }
  112. }
  113. applyFilter() {
  114. const namedFilters = this._modelClass.namedFilters;
  115. for (let i = 0, l = arguments.length; i < l; ++i) {
  116. const name = arguments[i];
  117. const filter = namedFilters[name];
  118. if (typeof filter !== 'function') {
  119. throw new Error(`Could not find filter "${name}".`);
  120. }
  121. filter(this);
  122. }
  123. return this;
  124. }
  125. modify() {
  126. return isString(arguments[0])
  127. ? this.applyFilter.apply(this, arguments)
  128. : super.modify.apply(this, arguments);
  129. }
  130. reject(error) {
  131. this._explicitRejectValue = error;
  132. return this;
  133. }
  134. resolve(value) {
  135. this._explicitResolveValue = value;
  136. return this;
  137. }
  138. isExecutable() {
  139. const hasExecutor = !!findQueryExecutorOperation(this);
  140. return !this._explicitRejectValue && !this._explicitResolveValue && !hasExecutor;
  141. }
  142. findOperationFactory(factory) {
  143. this._findOperationFactory = factory;
  144. return this;
  145. }
  146. insertOperationFactory(factory) {
  147. this._insertOperationFactory = factory;
  148. return this;
  149. }
  150. updateOperationFactory(factory) {
  151. this._updateOperationFactory = factory;
  152. return this;
  153. }
  154. patchOperationFactory(factory) {
  155. this._patchOperationFactory = factory;
  156. return this;
  157. }
  158. deleteOperationFactory(factory) {
  159. this._deleteOperationFactory = factory;
  160. return this;
  161. }
  162. relateOperationFactory(factory) {
  163. this._relateOperationFactory = factory;
  164. return this;
  165. }
  166. unrelateOperationFactory(factory) {
  167. this._unrelateOperationFactory = factory;
  168. return this;
  169. }
  170. eagerOperationFactory(factory) {
  171. if (arguments.length) {
  172. this._eagerOperationFactory = factory;
  173. return this;
  174. } else {
  175. return this._eagerOperationFactory;
  176. }
  177. }
  178. eagerAlgorithm(algorithm, eagerOptions) {
  179. this.eagerOperationFactory(algorithm);
  180. if (eagerOptions) {
  181. this.eagerOptions(eagerOptions);
  182. }
  183. return this;
  184. }
  185. eager(exp, filters) {
  186. this._eagerExpression = parseRelationExpression(this._modelClass, exp);
  187. this._eagerFilters = filters;
  188. checkEager(this);
  189. return this;
  190. }
  191. joinEager(exp, filters) {
  192. return this.eagerAlgorithm(this._modelClass.JoinEagerAlgorithm).eager(exp, filters);
  193. }
  194. naiveEager(exp, filters) {
  195. return this.eagerAlgorithm(this._modelClass.NaiveEagerAlgorithm).eager(exp, filters);
  196. }
  197. mergeEager(exp, filters) {
  198. if (!this._eagerExpression) {
  199. return this.eager(exp, filters);
  200. }
  201. this._eagerExpression = this._eagerExpression.merge(
  202. parseRelationExpression(this._modelClass, exp)
  203. );
  204. this._eagerFilters = Object.assign({}, this._eagerFilters, filters);
  205. checkEager(this);
  206. return this;
  207. }
  208. mergeJoinEager(exp, filters) {
  209. return this.eagerAlgorithm(this._modelClass.JoinEagerAlgorithm).mergeEager(exp, filters);
  210. }
  211. mergeNaiveEager(exp, filters) {
  212. return this.eagerAlgorithm(this._modelClass.NaiveEagerAlgorithm).mergeEager(exp, filters);
  213. }
  214. allowEager(exp) {
  215. this._allowedEagerExpression = parseRelationExpression(this._modelClass, exp);
  216. checkEager(this);
  217. return this;
  218. }
  219. allowedEagerExpression() {
  220. return this._allowedEagerExpression;
  221. }
  222. mergeAllowEager(exp) {
  223. if (!this._allowedEagerExpression) {
  224. return this.allowEager(exp);
  225. }
  226. this._allowedEagerExpression = this._allowedEagerExpression.merge(
  227. parseRelationExpression(this._modelClass, exp)
  228. );
  229. checkEager(this);
  230. return this;
  231. }
  232. modifyEager(path, filter) {
  233. this._eagerFiltersAtPath.push({ path, filter });
  234. return this;
  235. }
  236. filterEager() {
  237. return this.modifyEager.apply(this, arguments);
  238. }
  239. allowUpsert(exp) {
  240. this._allowedUpsertExpression = exp || null;
  241. if (isString(this._allowedUpsertExpression)) {
  242. this._allowedUpsertExpression = parseRelationExpression(
  243. this._modelClass,
  244. this._allowedUpsertExpression
  245. );
  246. }
  247. return this;
  248. }
  249. allowedUpsertExpression() {
  250. return this._allowedUpsertExpression;
  251. }
  252. allowInsert(exp) {
  253. return this.allowUpsert(exp);
  254. }
  255. eagerOptions(opt) {
  256. if (arguments.length !== 0) {
  257. this._eagerOperationOptions = Object.assign({}, this._eagerOperationOptions, opt);
  258. return this;
  259. } else {
  260. return this._eagerOperationOptions;
  261. }
  262. }
  263. findOptions(opt) {
  264. if (arguments.length !== 0) {
  265. this._findOperationOptions = Object.assign({}, this._findOperationOptions, opt);
  266. return this;
  267. } else {
  268. return this._findOperationOptions;
  269. }
  270. }
  271. modelClass() {
  272. return this._modelClass;
  273. }
  274. resultModelClass() {
  275. return this._resultModelClass || this.modelClass();
  276. }
  277. isFind() {
  278. return !(
  279. this.isInsert() ||
  280. this.isUpdate() ||
  281. this.isDelete() ||
  282. this.isRelate() ||
  283. this.isUnrelate()
  284. );
  285. }
  286. isInsert() {
  287. return this.has(InsertOperation);
  288. }
  289. isUpdate() {
  290. return this.has(UpdateOperation);
  291. }
  292. isDelete() {
  293. return this.has(DeleteOperation);
  294. }
  295. isRelate() {
  296. return this.has(RelateOperation);
  297. }
  298. isUnrelate() {
  299. return this.has(UnrelateOperation);
  300. }
  301. hasWheres() {
  302. return this.has(QueryBuilderBase.WhereSelector);
  303. }
  304. hasSelects() {
  305. return this.has(QueryBuilderBase.SelectSelector);
  306. }
  307. hasEager() {
  308. return !!this._eagerExpression;
  309. }
  310. isSelectAll() {
  311. if (this._operations.length === 0) {
  312. return true;
  313. }
  314. const tableRef = this.tableRefFor(this.modelClass());
  315. const tableName = this.tableNameFor(this.modelClass());
  316. return this._operations.every(op => {
  317. if (op.constructor === SelectOperation) {
  318. // SelectOperations with zero selections are the ones that only have
  319. // raw items or other non-trivial selections.
  320. return (
  321. op.selections.length > 0 &&
  322. op.selections.every(select => {
  323. return (!select.table || select.table === tableRef) && select.column === '*';
  324. })
  325. );
  326. } else if (op.constructor === FromOperation) {
  327. return op.table === tableName;
  328. } else if (op.name === 'as') {
  329. return true;
  330. } else {
  331. return false;
  332. }
  333. });
  334. }
  335. isFindQuery() {
  336. console.warn(
  337. `isFindQuery is deprecated. Use isFind instead. This method will be removed in version 2.0`
  338. );
  339. return this.isFind();
  340. }
  341. isEagerQuery() {
  342. console.warn(
  343. `isEagerQuery is deprecated. Use hasEager instead. This method will be removed in version 2.0`
  344. );
  345. return this.hasEager();
  346. }
  347. toString() {
  348. try {
  349. return this.build().toString();
  350. } catch (err) {
  351. return `This query cannot be built synchronously. Consider using debug() method instead.`;
  352. }
  353. }
  354. toSql() {
  355. return this.toString();
  356. }
  357. clone() {
  358. const builder = new this.constructor(this._modelClass);
  359. // Call the super class's clone implementation.
  360. this.baseCloneInto(builder);
  361. builder._resultModelClass = this._resultModelClass;
  362. builder._explicitRejectValue = this._explicitRejectValue;
  363. builder._explicitResolveValue = this._explicitResolveValue;
  364. builder._eagerExpression = this._eagerExpression;
  365. builder._eagerFilters = this._eagerFilters;
  366. builder._eagerFiltersAtPath = this._eagerFiltersAtPath.slice();
  367. builder._allowedEagerExpression = this._allowedEagerExpression;
  368. builder._allowedUpsertExpression = this._allowedUpsertExpression;
  369. builder._findOperationOptions = this._findOperationOptions;
  370. builder._eagerOperationOptions = this._eagerOperationOptions;
  371. builder._findOperationFactory = this._findOperationFactory;
  372. builder._insertOperationFactory = this._insertOperationFactory;
  373. builder._updateOperationFactory = this._updateOperationFactory;
  374. builder._patchOperationFactory = this._patchOperationFactory;
  375. builder._relateOperationFactory = this._relateOperationFactory;
  376. builder._unrelateOperationFactory = this._unrelateOperationFactory;
  377. builder._deleteOperationFactory = this._deleteOperationFactory;
  378. builder._eagerOperationFactory = this._eagerOperationFactory;
  379. return builder;
  380. }
  381. clearEager() {
  382. this._eagerExpression = null;
  383. this._eagerFilters = null;
  384. this._eagerFiltersAtPath = [];
  385. return this;
  386. }
  387. clearReject() {
  388. this._explicitRejectValue = null;
  389. return this;
  390. }
  391. clearResolve() {
  392. this._explicitResolveValue = null;
  393. return this;
  394. }
  395. castTo(modelClass) {
  396. this._resultModelClass = modelClass;
  397. return this;
  398. }
  399. then(successHandler, errorHandler) {
  400. const promise = this.execute();
  401. return promise.then.apply(promise, arguments);
  402. }
  403. map(mapper) {
  404. const promise = this.execute();
  405. return promise.map.apply(promise, arguments);
  406. }
  407. reduce(reducer, initialValue) {
  408. const promise = this.execute();
  409. return promise.reduce.apply(promise, arguments);
  410. }
  411. catch(errorHandler) {
  412. const promise = this.execute();
  413. return promise.catch.apply(promise, arguments);
  414. }
  415. return(returnValue) {
  416. const promise = this.execute();
  417. return promise.return.apply(promise, arguments);
  418. }
  419. reflect() {
  420. const promise = this.execute();
  421. return promise.reflect();
  422. }
  423. bind(context) {
  424. const promise = this.execute();
  425. return promise.bind.apply(promise, arguments);
  426. }
  427. asCallback(callback) {
  428. const promise = this.execute();
  429. return promise.asCallback.apply(promise, arguments);
  430. }
  431. nodeify(callback) {
  432. const promise = this.execute();
  433. return promise.nodeify.apply(promise, arguments);
  434. }
  435. resultSize() {
  436. const knex = this.knex();
  437. const builder = this.clone().clear(/orderBy|offset|limit/);
  438. const countQuery = knex.count('* as count').from(knexBuilder => {
  439. builder.build(knexBuilder).as('temp');
  440. });
  441. if (this.internalOptions().debug) {
  442. countQuery.debug();
  443. }
  444. return countQuery.then(result => (result[0] ? result[0].count : 0));
  445. }
  446. build(knexBuilder) {
  447. // Take a clone so that we don't modify this instance during build.
  448. const builder = this.clone();
  449. if (builder.isFind()) {
  450. // If no write operations have been called at this point this query is a
  451. // find query and we need to call the custom find implementation.
  452. addFindOperation(builder);
  453. }
  454. if (builder.hasEager()) {
  455. // If the query is an eager query, add the eager operation only at
  456. // this point of the query execution.
  457. addEagerFetchOperation(builder);
  458. }
  459. // We need to build the builder even if a query executor operation
  460. // has been called so that the onBuild hooks get called.
  461. knexBuilder = buildInto(builder, knexBuilder || builder.knex().queryBuilder());
  462. const queryExecutorOperation = findQueryExecutorOperation(builder);
  463. if (queryExecutorOperation) {
  464. // If the query executor is set, we build the builder that it returns.
  465. return queryExecutorOperation.queryExecutor(builder).build();
  466. } else {
  467. return knexBuilder;
  468. }
  469. }
  470. execute() {
  471. // Take a clone so that we don't modify this instance during execution.
  472. const builder = this.clone();
  473. return Promise.try(() => beforeExecute(builder))
  474. .then(() => doExecute(builder))
  475. .then(result => afterExecute(builder, result))
  476. .catch(error => handleExecuteError(builder, error));
  477. }
  478. pluck(propertyName) {
  479. return this.runAfter(result => {
  480. if (Array.isArray(result)) {
  481. return result.map(it => it && it[propertyName]);
  482. } else {
  483. return result;
  484. }
  485. });
  486. }
  487. throwIfNotFound() {
  488. return this.runAfter((result, builder) => {
  489. if (
  490. (Array.isArray(result) && result.length === 0) ||
  491. result === null ||
  492. result === undefined ||
  493. result === 0
  494. ) {
  495. throw this._modelClass.createNotFoundError(builder.context());
  496. } else {
  497. return result;
  498. }
  499. });
  500. }
  501. findSelection(selection, explicit) {
  502. explicit = explicit == null ? false : explicit;
  503. const table = this.tableRefFor(this._modelClass);
  504. let noSelectStatements = true;
  505. for (let i = 0, l = this._operations.length; i < l; ++i) {
  506. const op = this._operations[i];
  507. if (op.constructor === SelectOperation) {
  508. const selectionObj = op.findSelection(selection, table);
  509. noSelectStatements = false;
  510. if (selectionObj) {
  511. return selectionObj;
  512. }
  513. }
  514. }
  515. if (noSelectStatements && !explicit) {
  516. return SelectOperation.Selection.SelectAll;
  517. } else {
  518. return null;
  519. }
  520. }
  521. findAllSelections() {
  522. return this._operations
  523. .filter(op => op.is(SelectOperation))
  524. .reduce((selects, op) => selects.concat(op.selections), []);
  525. }
  526. hasSelection(selection, explicit) {
  527. return this.findSelection(selection, explicit) !== null;
  528. }
  529. hasSelectionAs(selection, alias, explicit) {
  530. const select = this.findSelection(selection, explicit);
  531. return select !== null && (select.column === '*' || select.name === alias);
  532. }
  533. traverse(modelClass, traverser) {
  534. if (typeof traverser === 'undefined') {
  535. traverser = modelClass;
  536. modelClass = null;
  537. }
  538. return this.runAfter(result => {
  539. this.resultModelClass().traverse(modelClass, result, traverser);
  540. return result;
  541. });
  542. }
  543. pick(modelClass, properties) {
  544. if (typeof properties === 'undefined') {
  545. properties = modelClass;
  546. modelClass = null;
  547. }
  548. // Turn the properties into a hash for performance.
  549. properties = properties.reduce((obj, prop) => {
  550. obj[prop] = true;
  551. return obj;
  552. }, {});
  553. return this.traverse(modelClass, model => {
  554. model.$pick(properties);
  555. });
  556. }
  557. omit(modelClass, properties) {
  558. if (typeof properties === 'undefined') {
  559. properties = modelClass;
  560. modelClass = null;
  561. }
  562. // Turn the properties into a hash for performance.
  563. properties = properties.reduce((obj, prop) => {
  564. obj[prop] = true;
  565. return obj;
  566. }, {});
  567. return this.traverse(modelClass, model => {
  568. model.$omit(properties);
  569. });
  570. }
  571. page(page, pageSize) {
  572. return this.range(page * pageSize, (page + 1) * pageSize - 1);
  573. }
  574. columnInfo({ table = null } = {}) {
  575. table = table || this.tableNameFor(this.modelClass());
  576. const knex = this.knex();
  577. const tableParts = table.split('.');
  578. const columnInfoQuery = knex(last(tableParts)).columnInfo();
  579. if (tableParts.length > 1) {
  580. columnInfoQuery.withSchema(tableParts[0]);
  581. }
  582. if (this.internalOptions().debug) {
  583. columnInfoQuery.debug();
  584. }
  585. return columnInfoQuery;
  586. }
  587. withSchema(schema) {
  588. this.internalContext().onBuild.push(builder => {
  589. if (!builder.has(/withSchema/)) {
  590. // Need to push this operation to the front because knex doesn't use the
  591. // schema for operations called before `withSchema`.
  592. builder.addOperationToFront(new KnexOperation('withSchema'), [schema]);
  593. }
  594. });
  595. return this;
  596. }
  597. debug /* istanbul ignore next */() {
  598. this.internalOptions().debug = true;
  599. this.internalContext().onBuild.push(builder => {
  600. builder.addOperation(new KnexOperation('debug'), []);
  601. });
  602. return this;
  603. }
  604. insert(modelsOrObjects) {
  605. return writeOperation(this, () => {
  606. const insertOperation = this._insertOperationFactory(this);
  607. this.addOperation(insertOperation, [modelsOrObjects]);
  608. });
  609. }
  610. insertAndFetch(modelsOrObjects) {
  611. return writeOperation(this, () => {
  612. const insertOperation = this._insertOperationFactory(this);
  613. const insertAndFetchOperation = new InsertAndFetchOperation('insertAndFetch', {
  614. delegate: insertOperation
  615. });
  616. this.addOperation(insertAndFetchOperation, [modelsOrObjects]);
  617. });
  618. }
  619. insertGraph(modelsOrObjects, opt) {
  620. return writeOperation(this, () => {
  621. const insertOperation = this._insertOperationFactory(this);
  622. const insertGraphOperation = new InsertGraphOperation('insertGraph', {
  623. delegate: insertOperation,
  624. opt
  625. });
  626. this.addOperation(insertGraphOperation, [modelsOrObjects]);
  627. });
  628. }
  629. insertWithRelated() {
  630. return this.insertGraph.apply(this, arguments);
  631. }
  632. insertGraphAndFetch(modelsOrObjects, opt) {
  633. return writeOperation(this, () => {
  634. const insertOperation = this._insertOperationFactory(this);
  635. const insertGraphOperation = new InsertGraphOperation('insertGraph', {
  636. delegate: insertOperation,
  637. opt
  638. });
  639. const insertGraphAndFetchOperation = new InsertGraphAndFetchOperation('insertGraphAndFetch', {
  640. delegate: insertGraphOperation
  641. });
  642. return this.addOperation(insertGraphAndFetchOperation, [modelsOrObjects]);
  643. });
  644. }
  645. insertWithRelatedAndFetch() {
  646. return this.insertGraphAndFetch.apply(this, arguments);
  647. }
  648. update(modelOrObject) {
  649. return writeOperation(this, () => {
  650. const updateOperation = this._updateOperationFactory(this);
  651. this.addOperation(updateOperation, [modelOrObject]);
  652. });
  653. }
  654. updateAndFetch(modelOrObject) {
  655. return writeOperation(this, () => {
  656. const updateOperation = this._updateOperationFactory(this);
  657. if (!(updateOperation.instance instanceof this._modelClass)) {
  658. throw new Error('updateAndFetch can only be called for instance operations');
  659. }
  660. const updateAndFetch = new UpdateAndFetchOperation('updateAndFetch', {
  661. delegate: updateOperation
  662. });
  663. // patchOperation is an instance update operation that already adds the
  664. // required "where id = $" clause.
  665. updateAndFetch.skipIdWhere = true;
  666. this.addOperation(updateAndFetch, [updateOperation.instance.$id(), modelOrObject]);
  667. });
  668. }
  669. updateAndFetchById(id, modelOrObject) {
  670. return writeOperation(this, () => {
  671. const updateOperation = this._updateOperationFactory(this);
  672. const updateAndFetch = new UpdateAndFetchOperation('updateAndFetch', {
  673. delegate: updateOperation
  674. });
  675. this.addOperation(updateAndFetch, [id, modelOrObject]);
  676. });
  677. }
  678. upsertGraph(modelsOrObjects, opt) {
  679. return writeOperation(this, () => {
  680. const insertOperation = this._insertOperationFactory(this);
  681. const upsertGraphOperation = new UpsertGraphOperation('upsertGraph', {
  682. delegate: insertOperation,
  683. opt
  684. });
  685. this.addOperation(upsertGraphOperation, [modelsOrObjects]);
  686. });
  687. }
  688. upsertGraphAndFetch(modelsOrObjects, opt) {
  689. return writeOperation(this, () => {
  690. const insertOperation = this._insertOperationFactory(this);
  691. const upsertGraphOperation = new UpsertGraphOperation('upsertGraph', {
  692. delegate: insertOperation,
  693. opt
  694. });
  695. const upsertGraphAndFetchOperation = new UpsertGraphAndFetchOperation('upsertGraphAndFetch', {
  696. delegate: upsertGraphOperation
  697. });
  698. return this.addOperation(upsertGraphAndFetchOperation, [modelsOrObjects]);
  699. });
  700. }
  701. patch(modelOrObject) {
  702. return writeOperation(this, () => {
  703. const patchOperation = this._patchOperationFactory(this);
  704. this.addOperation(patchOperation, [modelOrObject]);
  705. });
  706. }
  707. patchAndFetch(modelOrObject) {
  708. return writeOperation(this, () => {
  709. const patchOperation = this._patchOperationFactory(this);
  710. if (!(patchOperation.instance instanceof this._modelClass)) {
  711. throw new Error('patchAndFetch can only be called for instance operations');
  712. }
  713. const patchAndFetch = new UpdateAndFetchOperation('patchAndFetch', {
  714. delegate: patchOperation
  715. });
  716. // patchOperation is an instance update operation that already adds the
  717. // required "where id = $" clause.
  718. patchAndFetch.skipIdWhere = true;
  719. this.addOperation(patchAndFetch, [patchOperation.instance.$id(), modelOrObject]);
  720. });
  721. }
  722. patchAndFetchById(id, modelOrObject) {
  723. return writeOperation(this, () => {
  724. const patchOperation = this._patchOperationFactory(this);
  725. const patchAndFetch = new UpdateAndFetchOperation('patchAndFetch', {
  726. delegate: patchOperation
  727. });
  728. this.addOperation(patchAndFetch, [id, modelOrObject]);
  729. });
  730. }
  731. delete() {
  732. return writeOperation(this, () => {
  733. if (arguments.length) {
  734. throw new Error(
  735. `Don't pass arguments to delete(). You should use it like this: delete().where('foo', 'bar').andWhere(...)`
  736. );
  737. }
  738. const deleteOperation = this._deleteOperationFactory(this);
  739. this.addOperation(deleteOperation, arguments);
  740. });
  741. }
  742. del() {
  743. return this.delete.apply(this, arguments);
  744. }
  745. relate() {
  746. return writeOperation(this, () => {
  747. const relateOperation = this._relateOperationFactory(this);
  748. this.addOperation(relateOperation, arguments);
  749. });
  750. }
  751. unrelate() {
  752. return writeOperation(this, () => {
  753. if (arguments.length) {
  754. throw new Error(
  755. `Don't pass arguments to unrelate(). You should use it like this: unrelate().where('foo', 'bar').andWhere(...)`
  756. );
  757. }
  758. const unrelateOperation = this._unrelateOperationFactory(this);
  759. this.addOperation(unrelateOperation, arguments);
  760. });
  761. }
  762. increment(propertyName, howMuch) {
  763. const columnName = this.modelClass().propertyNameToColumnName(propertyName);
  764. return this.patch({
  765. [columnName]: raw('?? + ?', [columnName, howMuch])
  766. });
  767. }
  768. decrement(propertyName, howMuch) {
  769. const columnName = this.modelClass().propertyNameToColumnName(propertyName);
  770. return this.patch({
  771. [columnName]: raw('?? - ?', [columnName, howMuch])
  772. });
  773. }
  774. findOne() {
  775. return this.where.apply(this, arguments).first();
  776. }
  777. range() {
  778. return this.addOperation(new RangeOperation('range'), arguments);
  779. }
  780. first() {
  781. return this.addOperation(new FirstOperation('first'), arguments);
  782. }
  783. joinRelation() {
  784. return this.addOperation(
  785. new JoinRelationOperation('joinRelation', { joinOperation: 'join' }),
  786. arguments
  787. );
  788. }
  789. innerJoinRelation() {
  790. return this.addOperation(
  791. new JoinRelationOperation('innerJoinRelation', { joinOperation: 'innerJoin' }),
  792. arguments
  793. );
  794. }
  795. outerJoinRelation() {
  796. return this.addOperation(
  797. new JoinRelationOperation('outerJoinRelation', { joinOperation: 'outerJoin' }),
  798. arguments
  799. );
  800. }
  801. leftJoinRelation() {
  802. return this.addOperation(
  803. new JoinRelationOperation('leftJoinRelation', { joinOperation: 'leftJoin' }),
  804. arguments
  805. );
  806. }
  807. leftOuterJoinRelation() {
  808. return this.addOperation(
  809. new JoinRelationOperation('leftOuterJoinRelation', { joinOperation: 'leftOuterJoin' }),
  810. arguments
  811. );
  812. }
  813. rightJoinRelation() {
  814. return this.addOperation(
  815. new JoinRelationOperation('rightJoinRelation', { joinOperation: 'rightJoin' }),
  816. arguments
  817. );
  818. }
  819. rightOuterJoinRelation() {
  820. return this.addOperation(
  821. new JoinRelationOperation('rightOuterJoinRelation', { joinOperation: 'rightOuterJoin' }),
  822. arguments
  823. );
  824. }
  825. fullOuterJoinRelation() {
  826. return this.addOperation(
  827. new JoinRelationOperation('fullOuterJoinRelation', { joinOperation: 'fullOuterJoin' }),
  828. arguments
  829. );
  830. }
  831. deleteById() {
  832. return this.addOperation(new DeleteByIdOperation('deleteById'), arguments);
  833. }
  834. findById() {
  835. return this.addOperation(new FindByIdOperation('findById'), arguments);
  836. }
  837. findByIds() {
  838. return this.addOperation(new FindByIdsOperation('findByIds'), arguments);
  839. }
  840. runBefore() {
  841. return this.addOperation(new RunBeforeOperation('runBefore'), arguments);
  842. }
  843. onBuild() {
  844. return this.addOperation(new OnBuildOperation('onBuild'), arguments);
  845. }
  846. onBuildKnex() {
  847. return this.addOperation(new OnBuildKnexOperation('onBuildKnex'), arguments);
  848. }
  849. runAfter() {
  850. return this.addOperation(new RunAfterOperation('runAfter'), arguments);
  851. }
  852. onError() {
  853. return this.addOperation(new OnErrorOperation('onError'), arguments);
  854. }
  855. from() {
  856. return this.addOperation(new FromOperation('from'), arguments);
  857. }
  858. table() {
  859. return this.addOperation(new FromOperation('table'), arguments);
  860. }
  861. }
  862. Object.defineProperties(QueryBuilder.prototype, {
  863. isObjectionQueryBuilder: {
  864. enumerable: false,
  865. writable: false,
  866. value: true
  867. }
  868. });
  869. function parseRelationExpression(modelClass, exp) {
  870. try {
  871. return RelationExpression.create(exp);
  872. } catch (err) {
  873. throw modelClass.createValidationError({
  874. type: ValidationErrorType.RelationExpression,
  875. message: `Invalid relation expression "${exp}"`
  876. });
  877. }
  878. }
  879. function checkEager(builder) {
  880. const expr = builder._eagerExpression;
  881. const allowedExpr = builder._allowedEagerExpression;
  882. if (expr && allowedExpr && !allowedExpr.isSubExpression(expr)) {
  883. const modelClass = builder.modelClass();
  884. builder.reject(
  885. modelClass.createValidationError({
  886. type: ValidationErrorType.UnallowedRelation,
  887. message: 'eager expression not allowed'
  888. })
  889. );
  890. }
  891. }
  892. function findQueryExecutorOperation(builder) {
  893. for (let i = 0, l = builder._operations.length; i < l; ++i) {
  894. const op = builder._operations[i];
  895. if (op.hasQueryExecutor()) {
  896. return op;
  897. }
  898. }
  899. return null;
  900. }
  901. function beforeExecute(builder) {
  902. let promise = Promise.resolve();
  903. if (builder.isFind()) {
  904. // If no write operations have been called at this point this query is a
  905. // find query and we need to call the custom find implementation.
  906. addFindOperation(builder);
  907. }
  908. if (builder.hasEager()) {
  909. // If the query is an eager query, add the eager operation only at
  910. // this point of the query execution.
  911. addEagerFetchOperation(builder);
  912. }
  913. // Resolve all before hooks before building and executing the query
  914. // and the rest of the hooks.
  915. builder._operations.forEach(op => {
  916. if (op.hasOnBefore1()) {
  917. promise = promise.then(result => op.onBefore1(builder, result));
  918. }
  919. });
  920. promise = chainHooks(promise, builder, builder.context().runBefore);
  921. promise = chainHooks(promise, builder, builder.internalContext().runBefore);
  922. builder._operations.forEach(op => {
  923. if (op.hasOnBefore2()) {
  924. promise = promise.then(result => op.onBefore2(builder, result));
  925. }
  926. });
  927. builder._operations.forEach(op => {
  928. if (op.hasOnBefore3()) {
  929. promise = promise.then(result => op.onBefore3(builder, result));
  930. }
  931. });
  932. return promise;
  933. }
  934. function doExecute(builder) {
  935. let promise = Promise.resolve();
  936. const knexBuilder = buildInto(builder, builder.knex().queryBuilder());
  937. const queryExecutorOperation = findQueryExecutorOperation(builder);
  938. const explicitRejectValue = builder._explicitRejectValue;
  939. const explicitResolveValue = builder._explicitResolveValue;
  940. if (explicitRejectValue !== null) {
  941. promise = Promise.reject(explicitRejectValue);
  942. } else if (explicitResolveValue !== null) {
  943. promise = Promise.resolve(explicitResolveValue);
  944. } else if (queryExecutorOperation !== null) {
  945. promise = Promise.resolve(queryExecutorOperation.queryExecutor(builder));
  946. } else {
  947. promise = Promise.resolve(knexBuilder);
  948. builder._operations.forEach(op => {
  949. if (op.hasOnRawResult()) {
  950. promise = promise.then(result => op.onRawResult(builder, result));
  951. }
  952. });
  953. promise = promise.then(result => createModels(result, builder));
  954. }
  955. return promise;
  956. }
  957. function afterExecute(builder, result) {
  958. let promise = Promise.resolve(result);
  959. builder._operations.forEach(op => {
  960. if (op.hasOnAfter1()) {
  961. promise = promise.then(result => op.onAfter1(builder, result));
  962. }
  963. });
  964. builder._operations.forEach(op => {
  965. if (op.hasOnAfter2()) {
  966. promise = promise.then(result => op.onAfter2(builder, result));
  967. }
  968. });
  969. promise = chainHooks(promise, builder, builder.context().runAfter);
  970. promise = chainHooks(promise, builder, builder.internalContext().runAfter);
  971. builder._operations.forEach(op => {
  972. if (op.hasOnAfter3()) {
  973. promise = promise.then(result => op.onAfter3(builder, result));
  974. }
  975. });
  976. return promise;
  977. }
  978. function handleExecuteError(builder, err) {
  979. let promise = Promise.reject(err);
  980. builder._operations.forEach(op => {
  981. if (op.hasOnError()) {
  982. promise = promise.catch(err => op.onError(builder, err));
  983. }
  984. });
  985. return promise;
  986. }
  987. function addFindOperation(builder) {
  988. if (!builder.has(FindOperation)) {
  989. const operation = builder._findOperationFactory(builder);
  990. builder.addOperationToFront(operation, []);
  991. }
  992. }
  993. function addEagerFetchOperation(builder) {
  994. if (!builder.has(EagerOperation) && builder._eagerExpression) {
  995. const operation = builder._eagerOperationFactory(builder);
  996. const expression = builder._eagerExpression.clone();
  997. const filters = Object.assign({}, builder._eagerFilters);
  998. builder._eagerFiltersAtPath.forEach((filter, i) => {
  999. const filterName = `_f${i}_`;
  1000. expression.expressionsAtPath(filter.path).forEach(expr => {
  1001. expr.rawNode.$modify.push(filterName);
  1002. });
  1003. filters[filterName] = filter.filter;
  1004. });
  1005. builder.addOperation(operation, [expression, filters]);
  1006. }
  1007. }
  1008. function buildInto(builder, knexBuilder) {
  1009. callOnBuildHooks(builder, builder.context().onBuild);
  1010. callOnBuildHooks(builder, builder.internalContext().onBuild);
  1011. // Call super class build.
  1012. knexBuilder = builder.buildInto(knexBuilder);
  1013. const fromOperation = builder.findLastOperation(QueryBuilderBase.FromSelector);
  1014. const hasSelects = builder.has(QueryBuilderBase.SelectSelector);
  1015. // Set the table only if it hasn't been explicitly set yet.
  1016. if (!fromOperation) {
  1017. setDefaultTable(builder, knexBuilder);
  1018. }
  1019. // Only add `table.*` select if there are no explicit selects
  1020. // and `from` is a table name and not a subquery.
  1021. if (!hasSelects && (!fromOperation || fromOperation.table)) {
  1022. setDefaultSelect(builder, knexBuilder);
  1023. }
  1024. return knexBuilder;
  1025. }
  1026. function callOnBuildHooks(builder, func) {
  1027. if (isFunction(func)) {
  1028. func.call(builder, builder);
  1029. } else if (Array.isArray(func)) {
  1030. func.forEach(func => callOnBuildHooks(builder, func));
  1031. }
  1032. }
  1033. function setDefaultTable(builder, knexBuilder) {
  1034. const table = builder.tableNameFor(builder.modelClass());
  1035. const tableRef = builder.tableRefFor(builder.modelClass());
  1036. if (table === tableRef) {
  1037. knexBuilder.table(table);
  1038. } else {
  1039. knexBuilder.table(`${table} as ${tableRef}`);
  1040. }
  1041. }
  1042. function setDefaultSelect(builder, knexBuilder) {
  1043. const tableRef = builder.tableRefFor(builder.modelClass());
  1044. knexBuilder.select(`${tableRef}.*`);
  1045. }
  1046. function chainHooks(promise, builder, func) {
  1047. if (isFunction(func)) {
  1048. promise = promise.then(result => func.call(builder, result, builder));
  1049. } else if (Array.isArray(func)) {
  1050. func.forEach(func => {
  1051. promise = chainHooks(promise, builder, func);
  1052. });
  1053. }
  1054. return promise;
  1055. }
  1056. function createModels(result, builder) {
  1057. const modelClass = builder.resultModelClass();
  1058. if (result === null || result === undefined) {
  1059. return null;
  1060. }
  1061. if (Array.isArray(result)) {
  1062. if (result.length && shouldBeConvertedToModel(result[0], modelClass)) {
  1063. for (let i = 0, l = result.length; i < l; ++i) {
  1064. result[i] = modelClass.fromDatabaseJson(result[i]);
  1065. }
  1066. }
  1067. } else if (shouldBeConvertedToModel(result, modelClass)) {
  1068. result = modelClass.fromDatabaseJson(result);
  1069. }
  1070. return result;
  1071. }
  1072. function shouldBeConvertedToModel(obj, modelClass) {
  1073. return isObject(obj) && !(obj instanceof modelClass);
  1074. }
  1075. function writeOperation(builder, cb) {
  1076. if (!builder.isFind()) {
  1077. return builder.reject(
  1078. new Error(
  1079. 'Double call to a write method. ' +
  1080. 'You can only call one of the write methods ' +
  1081. '(insert, update, patch, delete, relate, unrelate, increment, decrement) ' +
  1082. 'and only once per query builder.'
  1083. )
  1084. );
  1085. }
  1086. try {
  1087. cb();
  1088. return builder;
  1089. } catch (err) {
  1090. return builder.reject(err);
  1091. }
  1092. }
  1093. function mergeMaps(map1, map2) {
  1094. const map = new Map();
  1095. if (map1) {
  1096. for (let key of map1.keys()) {
  1097. map.set(key, map1.get(key));
  1098. }
  1099. }
  1100. if (map2) {
  1101. for (let key of map2.keys()) {
  1102. map.set(key, map2.get(key));
  1103. }
  1104. }
  1105. return map;
  1106. }
  1107. function findOperationFactory() {
  1108. return new FindOperation('find');
  1109. }
  1110. function insertOperationFactory() {
  1111. return new InsertOperation('insert');
  1112. }
  1113. function updateOperationFactory() {
  1114. return new UpdateOperation('update');
  1115. }
  1116. function patchOperationFactory() {
  1117. return new UpdateOperation('patch', {
  1118. modelOptions: { patch: true }
  1119. });
  1120. }
  1121. function relateOperationFactory() {
  1122. return new RelateOperation('relate', {});
  1123. }
  1124. function unrelateOperationFactory() {
  1125. return new UnrelateOperation('unrelate', {});
  1126. }
  1127. function deleteOperationFactory() {
  1128. return new DeleteOperation('delete');
  1129. }
  1130. module.exports = QueryBuilder;