@abedmurrar/objection 0.0.0-stage → 4.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +69 -2
  3. package/lib/.eslintrc.json +8 -0
  4. package/lib/initialize.js +14 -0
  5. package/lib/model/AjvValidator.js +325 -0
  6. package/lib/model/Model.js +942 -0
  7. package/lib/model/ModifierNotFoundError.js +12 -0
  8. package/lib/model/NotFoundError.js +23 -0
  9. package/lib/model/RelationDoesNotExistError.js +14 -0
  10. package/lib/model/ValidationError.js +54 -0
  11. package/lib/model/Validator.js +26 -0
  12. package/lib/model/getModel.js +9 -0
  13. package/lib/model/graph/ModelGraph.js +80 -0
  14. package/lib/model/graph/ModelGraphBuilder.js +241 -0
  15. package/lib/model/graph/ModelGraphEdge.js +52 -0
  16. package/lib/model/graph/ModelGraphNode.js +240 -0
  17. package/lib/model/inheritModel.js +28 -0
  18. package/lib/model/modelBindKnex.js +83 -0
  19. package/lib/model/modelClone.js +121 -0
  20. package/lib/model/modelColPropMap.js +34 -0
  21. package/lib/model/modelId.js +62 -0
  22. package/lib/model/modelJsonAttributes.js +92 -0
  23. package/lib/model/modelParseRelations.js +82 -0
  24. package/lib/model/modelQueryProps.js +147 -0
  25. package/lib/model/modelSet.js +136 -0
  26. package/lib/model/modelTableMetadata.js +83 -0
  27. package/lib/model/modelToJson.js +187 -0
  28. package/lib/model/modelUtils.js +47 -0
  29. package/lib/model/modelValidate.js +48 -0
  30. package/lib/model/modelValues.js +126 -0
  31. package/lib/model/modelVisitor.js +41 -0
  32. package/lib/objection.js +114 -0
  33. package/lib/queryBuilder/FunctionBuilder.js +339 -0
  34. package/lib/queryBuilder/InternalOptions.js +29 -0
  35. package/lib/queryBuilder/JoinBuilder.js +157 -0
  36. package/lib/queryBuilder/QueryBuilder.js +1398 -0
  37. package/lib/queryBuilder/QueryBuilderBase.js +884 -0
  38. package/lib/queryBuilder/QueryBuilderContext.js +27 -0
  39. package/lib/queryBuilder/QueryBuilderContextBase.js +35 -0
  40. package/lib/queryBuilder/QueryBuilderOperationSupport.js +558 -0
  41. package/lib/queryBuilder/QueryBuilderUserContext.js +31 -0
  42. package/lib/queryBuilder/RawBuilder.js +93 -0
  43. package/lib/queryBuilder/ReferenceBuilder.js +284 -0
  44. package/lib/queryBuilder/RelationExpression.js +431 -0
  45. package/lib/queryBuilder/StaticHookArguments.js +134 -0
  46. package/lib/queryBuilder/ValueBuilder.js +127 -0
  47. package/lib/queryBuilder/expressions.js +151 -0
  48. package/lib/queryBuilder/functions/mysql.js +817 -0
  49. package/lib/queryBuilder/graph/GraphAction.js +69 -0
  50. package/lib/queryBuilder/graph/GraphData.js +14 -0
  51. package/lib/queryBuilder/graph/GraphFetcher.js +191 -0
  52. package/lib/queryBuilder/graph/GraphNodeDbExistence.js +184 -0
  53. package/lib/queryBuilder/graph/GraphOperation.js +27 -0
  54. package/lib/queryBuilder/graph/GraphOptions.js +207 -0
  55. package/lib/queryBuilder/graph/GraphUpsert.js +305 -0
  56. package/lib/queryBuilder/graph/delete/GraphDelete.js +20 -0
  57. package/lib/queryBuilder/graph/delete/GraphDeleteAction.js +74 -0
  58. package/lib/queryBuilder/graph/insert/GraphInsert.js +145 -0
  59. package/lib/queryBuilder/graph/insert/GraphInsertAction.js +225 -0
  60. package/lib/queryBuilder/graph/insert/JoinRowGraphInsertAction.js +92 -0
  61. package/lib/queryBuilder/graph/patch/GraphPatch.js +20 -0
  62. package/lib/queryBuilder/graph/patch/GraphPatchAction.js +258 -0
  63. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsert.js +31 -0
  64. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsertAction.js +126 -0
  65. package/lib/queryBuilder/join/JoinResultColumn.js +23 -0
  66. package/lib/queryBuilder/join/JoinResultParser.js +119 -0
  67. package/lib/queryBuilder/join/RelationJoiner.js +341 -0
  68. package/lib/queryBuilder/join/TableNode.js +163 -0
  69. package/lib/queryBuilder/join/TableTree.js +85 -0
  70. package/lib/queryBuilder/join/utils.js +25 -0
  71. package/lib/queryBuilder/operations/DelegateOperation.js +141 -0
  72. package/lib/queryBuilder/operations/DeleteOperation.js +51 -0
  73. package/lib/queryBuilder/operations/FindByIdOperation.js +37 -0
  74. package/lib/queryBuilder/operations/FindByIdsOperation.js +29 -0
  75. package/lib/queryBuilder/operations/FindOperation.js +164 -0
  76. package/lib/queryBuilder/operations/FirstOperation.js +27 -0
  77. package/lib/queryBuilder/operations/FromOperation.js +110 -0
  78. package/lib/queryBuilder/operations/InsertAndFetchOperation.js +49 -0
  79. package/lib/queryBuilder/operations/InsertGraphAndFetchOperation.js +45 -0
  80. package/lib/queryBuilder/operations/InsertGraphOperation.js +108 -0
  81. package/lib/queryBuilder/operations/InsertOperation.js +206 -0
  82. package/lib/queryBuilder/operations/InstanceDeleteOperation.js +46 -0
  83. package/lib/queryBuilder/operations/InstanceFindOperation.js +21 -0
  84. package/lib/queryBuilder/operations/InstanceInsertOperation.js +24 -0
  85. package/lib/queryBuilder/operations/InstanceUpdateOperation.js +59 -0
  86. package/lib/queryBuilder/operations/JoinRelatedOperation.js +103 -0
  87. package/lib/queryBuilder/operations/KnexOperation.js +14 -0
  88. package/lib/queryBuilder/operations/MergeOperation.js +56 -0
  89. package/lib/queryBuilder/operations/ObjectionToKnexConvertingOperation.js +192 -0
  90. package/lib/queryBuilder/operations/OnBuildKnexOperation.js +29 -0
  91. package/lib/queryBuilder/operations/OnBuildOperation.js +29 -0
  92. package/lib/queryBuilder/operations/OnErrorOperation.js +29 -0
  93. package/lib/queryBuilder/operations/QueryBuilderOperation.js +297 -0
  94. package/lib/queryBuilder/operations/RangeOperation.js +47 -0
  95. package/lib/queryBuilder/operations/RelateOperation.js +27 -0
  96. package/lib/queryBuilder/operations/ReturningOperation.js +30 -0
  97. package/lib/queryBuilder/operations/RunAfterOperation.js +29 -0
  98. package/lib/queryBuilder/operations/RunBeforeOperation.js +29 -0
  99. package/lib/queryBuilder/operations/UnrelateOperation.js +23 -0
  100. package/lib/queryBuilder/operations/UpdateAndFetchOperation.js +80 -0
  101. package/lib/queryBuilder/operations/UpdateOperation.js +155 -0
  102. package/lib/queryBuilder/operations/UpsertGraphAndFetchOperation.js +45 -0
  103. package/lib/queryBuilder/operations/UpsertGraphOperation.js +66 -0
  104. package/lib/queryBuilder/operations/WhereCompositeOperation.js +57 -0
  105. package/lib/queryBuilder/operations/WhereInOperation.js +48 -0
  106. package/lib/queryBuilder/operations/eager/EagerOperation.js +61 -0
  107. package/lib/queryBuilder/operations/eager/JoinEagerOperation.js +51 -0
  108. package/lib/queryBuilder/operations/eager/NaiveEagerOperation.js +13 -0
  109. package/lib/queryBuilder/operations/eager/WhereInEagerOperation.js +285 -0
  110. package/lib/queryBuilder/operations/jsonApi/WhereJsonHasOperation.js +36 -0
  111. package/lib/queryBuilder/operations/jsonApi/WhereJsonNotObjectOperation.js +53 -0
  112. package/lib/queryBuilder/operations/jsonApi/WhereJsonOperation.js +31 -0
  113. package/lib/queryBuilder/operations/jsonApi/WhereJsonOverlapsOperation.js +31 -0
  114. package/lib/queryBuilder/operations/jsonApi/mysqlJsonApi.js +167 -0
  115. package/lib/queryBuilder/operations/jsonApi/postgresJsonApi.js +164 -0
  116. package/lib/queryBuilder/operations/select/SelectOperation.js +66 -0
  117. package/lib/queryBuilder/operations/select/Selection.js +123 -0
  118. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeMsSqlOperation.js +117 -0
  119. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeOperation.js +100 -0
  120. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeSqliteOperation.js +104 -0
  121. package/lib/queryBuilder/parsers/jsonFieldExpressionParser.js +886 -0
  122. package/lib/queryBuilder/parsers/jsonFieldExpressionParser.pegjs +97 -0
  123. package/lib/queryBuilder/parsers/relationExpressionParser.js +1042 -0
  124. package/lib/queryBuilder/parsers/relationExpressionParser.pegjs +141 -0
  125. package/lib/queryBuilder/transformations/CompositeQueryTransformation.js +22 -0
  126. package/lib/queryBuilder/transformations/QueryTransformation.js +11 -0
  127. package/lib/queryBuilder/transformations/WrapMysqlModifySubqueryTransformation.js +71 -0
  128. package/lib/queryBuilder/transformations/index.js +15 -0
  129. package/lib/queryBuilder/whereScopes.js +227 -0
  130. package/lib/relations/Relation.js +401 -0
  131. package/lib/relations/RelationDeleteOperation.js +29 -0
  132. package/lib/relations/RelationFindOperation.js +149 -0
  133. package/lib/relations/RelationInsertOperation.js +33 -0
  134. package/lib/relations/RelationOwner.js +236 -0
  135. package/lib/relations/RelationProperty.js +247 -0
  136. package/lib/relations/RelationUpdateOperation.js +30 -0
  137. package/lib/relations/belongsToOne/BelongsToOneDeleteOperation.js +23 -0
  138. package/lib/relations/belongsToOne/BelongsToOneInsertOperation.js +44 -0
  139. package/lib/relations/belongsToOne/BelongsToOneRelateOperation.js +50 -0
  140. package/lib/relations/belongsToOne/BelongsToOneRelation.js +53 -0
  141. package/lib/relations/belongsToOne/BelongsToOneUnrelateOperation.js +61 -0
  142. package/lib/relations/hasMany/HasManyInsertOperation.js +61 -0
  143. package/lib/relations/hasMany/HasManyRelateOperation.js +64 -0
  144. package/lib/relations/hasMany/HasManyRelation.js +49 -0
  145. package/lib/relations/hasMany/HasManyUnrelateOperation.js +33 -0
  146. package/lib/relations/hasOne/HasOneRelation.js +13 -0
  147. package/lib/relations/hasOneThrough/HasOneThroughRelation.js +13 -0
  148. package/lib/relations/manyToMany/ManyToManyModifyMixin.js +105 -0
  149. package/lib/relations/manyToMany/ManyToManyRelation.js +507 -0
  150. package/lib/relations/manyToMany/ManyToManySqliteModifyMixin.js +36 -0
  151. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperation.js +10 -0
  152. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperationBase.js +26 -0
  153. package/lib/relations/manyToMany/delete/ManyToManyDeleteSqliteOperation.js +12 -0
  154. package/lib/relations/manyToMany/find/ManyToManyFindOperation.js +105 -0
  155. package/lib/relations/manyToMany/insert/ManyToManyInsertOperation.js +52 -0
  156. package/lib/relations/manyToMany/relate/ManyToManyRelateOperation.js +81 -0
  157. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperation.js +14 -0
  158. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperationBase.js +34 -0
  159. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateSqliteOperation.js +16 -0
  160. package/lib/relations/manyToMany/update/ManyToManyUpdateOperation.js +10 -0
  161. package/lib/relations/manyToMany/update/ManyToManyUpdateOperationBase.js +82 -0
  162. package/lib/relations/manyToMany/update/ManyToManyUpdateSqliteOperation.js +12 -0
  163. package/lib/transaction.js +96 -0
  164. package/lib/utils/assert.js +25 -0
  165. package/lib/utils/buildUtils.js +21 -0
  166. package/lib/utils/classUtils.js +13 -0
  167. package/lib/utils/clone.js +2329 -0
  168. package/lib/utils/createModifier.js +42 -0
  169. package/lib/utils/deprecate.js +15 -0
  170. package/lib/utils/identifierMapping.js +227 -0
  171. package/lib/utils/internalPropUtils.js +11 -0
  172. package/lib/utils/knexUtils.js +76 -0
  173. package/lib/utils/mixin.js +25 -0
  174. package/lib/utils/mysqlJsonPath.js +55 -0
  175. package/lib/utils/normalizeIds.js +144 -0
  176. package/lib/utils/objectUtils.js +416 -0
  177. package/lib/utils/parseFieldExpression.js +51 -0
  178. package/lib/utils/postgresJsonPath.js +110 -0
  179. package/lib/utils/promiseUtils/after.js +17 -0
  180. package/lib/utils/promiseUtils/afterReturn.js +17 -0
  181. package/lib/utils/promiseUtils/index.js +17 -0
  182. package/lib/utils/promiseUtils/isPromise.js +11 -0
  183. package/lib/utils/promiseUtils/map.js +110 -0
  184. package/lib/utils/promiseUtils/mapAfterAllReturn.js +29 -0
  185. package/lib/utils/promiseUtils/try.js +22 -0
  186. package/lib/utils/resolveModel.js +107 -0
  187. package/lib/utils/tmpColumnUtils.js +16 -0
  188. package/package.json +86 -4
  189. package/typings/objection/index.d.ts +4104 -0
  190. package/typings/objection/relation-expression.d.ts +237 -0
@@ -0,0 +1,141 @@
1
+ {
2
+ function assertDuplicateRelation(node, expr) {
3
+ if (expr.$name in node) {
4
+ console.warn(`Duplicate relation "${expr.$name}" in a relation expression. You should use "a.[b, c]" instead of "[a.b, a.c]". This will cause an error in objection 2.0`);
5
+
6
+ // TODO: enable for v2.0.
7
+ // const err = new Error();
8
+ // err.duplicateRelationName = expr.$name;
9
+ // throw err;
10
+ }
11
+ }
12
+
13
+ function newNode() {
14
+ return {
15
+ $name: null,
16
+ $relation: null,
17
+ $modify: [],
18
+ $recursive: false,
19
+ $allRecursive: false,
20
+ $childNames: []
21
+ };
22
+ }
23
+ }
24
+
25
+ start =
26
+ expr:expression {
27
+ const node = newNode()
28
+
29
+ if (expr.$name === '*') {
30
+ node.$allRecursive = true;
31
+ } else {
32
+ assertDuplicateRelation(node, expr);
33
+ node[expr.$name] = expr;
34
+ node.$childNames.push(expr.$name)
35
+ }
36
+
37
+ return node;
38
+ }
39
+ /
40
+ list:listExpression {
41
+ const node = newNode()
42
+
43
+ list.forEach(expr => {
44
+ assertDuplicateRelation(node, expr);
45
+ node[expr.$name] = expr;
46
+ node.$childNames.push(expr.$name)
47
+ });
48
+
49
+ return node;
50
+ }
51
+
52
+ expression =
53
+ name:name args:args? alias:alias? list:subListExpression {
54
+ const node = newNode()
55
+
56
+ node.$name = alias || name;
57
+ node.$relation = name;
58
+ node.$modify = args || [];
59
+
60
+ list.forEach(expr => {
61
+ assertDuplicateRelation(node, expr);
62
+ node[expr.$name] = expr;
63
+ node.$childNames.push(expr.$name)
64
+ });
65
+
66
+ return node;
67
+ }
68
+ /
69
+ name:name args:args? alias:alias? expr:subExpression? {
70
+ const node = newNode()
71
+
72
+ node.$name = alias || name;
73
+ node.$relation = name;
74
+ node.$modify = args || [];
75
+
76
+ if (expr) {
77
+ const match = /^\^(\d*)$/.exec(expr.$name);
78
+
79
+ if (match) {
80
+ if (match[1]) {
81
+ node.$recursive = parseInt(match[1], 10);
82
+ } else {
83
+ node.$recursive = true;
84
+ }
85
+ } else if (expr.$name === '*') {
86
+ node.$allRecursive = true;
87
+ } else {
88
+ assertDuplicateRelation(node, expr);
89
+ node[expr.$name] = expr;
90
+ node.$childNames.push(expr.$name)
91
+ }
92
+ }
93
+
94
+ return node;
95
+ }
96
+
97
+ alias =
98
+ ws+ "as" ws+ alias:name {
99
+ return alias;
100
+ }
101
+
102
+ name =
103
+ name:char+ {
104
+ return name.join('');
105
+ }
106
+
107
+ char =
108
+ [^\[\]\(\),\. \t\r\n]
109
+
110
+ args =
111
+ ws* "(" args:argListItem* ws* ")" {
112
+ return args;
113
+ }
114
+
115
+ argListItem =
116
+ ws* arg:name ws* ","? {
117
+ return arg;
118
+ }
119
+
120
+ ws =
121
+ [ \t\r\n]
122
+
123
+ subListExpression =
124
+ ws* "." list:listExpression {
125
+ return list;
126
+ }
127
+
128
+ listExpression =
129
+ ws* "[" items:listExpressionItem* ws* "]" ws* {
130
+ return items;
131
+ }
132
+
133
+ listExpressionItem =
134
+ ws* expr:expression ws* ","? {
135
+ return expr;
136
+ }
137
+
138
+ subExpression =
139
+ ws* "." ws* sub:expression ws* {
140
+ return sub;
141
+ }
@@ -0,0 +1,22 @@
1
+ 'use strict';
2
+
3
+ const { QueryTransformation } = require('./QueryTransformation');
4
+
5
+ class CompositeQueryTransformation extends QueryTransformation {
6
+ constructor(transformations) {
7
+ super();
8
+ this.transformations = transformations;
9
+ }
10
+
11
+ onConvertQueryBuilderBase(item, builder) {
12
+ for (const transformation of this.transformations) {
13
+ item = transformation.onConvertQueryBuilderBase(item, builder);
14
+ }
15
+
16
+ return item;
17
+ }
18
+ }
19
+
20
+ module.exports = {
21
+ CompositeQueryTransformation,
22
+ };
@@ -0,0 +1,11 @@
1
+ 'use strict';
2
+
3
+ class QueryTransformation {
4
+ onConvertQueryBuilderBase(item, builder) {
5
+ return item;
6
+ }
7
+ }
8
+
9
+ module.exports = {
10
+ QueryTransformation,
11
+ };
@@ -0,0 +1,71 @@
1
+ 'use strict';
2
+
3
+ const { QueryTransformation } = require('./QueryTransformation');
4
+ const { isMySql } = require('../../utils/knexUtils');
5
+
6
+ /**
7
+ * Mysql doesn't allow queries like this:
8
+ *
9
+ * update foo set bar = 1 where id in (select id from foo)
10
+ *
11
+ * because the subquery is for the same table `foo` as the parent update query.
12
+ * The same goes for delete queries too.
13
+ *
14
+ * This transformation wraps those subqueries like this:
15
+ *
16
+ * update foo set bar = 1 where id in (select * from (select id from foo))
17
+ */
18
+ class WrapMysqlModifySubqueryTransformation extends QueryTransformation {
19
+ onConvertQueryBuilderBase(query, parentQuery) {
20
+ const knex = parentQuery.unsafeKnex();
21
+
22
+ // Cannot detect anything if, for whatever reason, a knex instance
23
+ // or a transaction is not registered at this point.
24
+ if (!knex) {
25
+ return query;
26
+ }
27
+
28
+ // This transformation only applies to MySQL.
29
+ if (!isMySql(knex)) {
30
+ return query;
31
+ }
32
+
33
+ // A subquery in a join callback belongs to the query of the join.
34
+ while (parentQuery && typeof parentQuery.isUpdate !== 'function') {
35
+ parentQuery = parentQuery.parentQuery();
36
+ }
37
+
38
+ // This transformation only applies to update and delete queries.
39
+ if (!parentQuery || (!parentQuery.isUpdate() && !parentQuery.isDelete())) {
40
+ return query;
41
+ }
42
+
43
+ // If the subquery is for another table and the query doesn't join the
44
+ // parent query's table, we're good to go.
45
+ if (
46
+ parentQuery.tableName() !== query.tableName() &&
47
+ !hasJoinsToTable(query, parentQuery.tableName())
48
+ ) {
49
+ return query;
50
+ }
51
+
52
+ return query.modelClass().query().from(query.as('mysql_subquery_fix'));
53
+ }
54
+ }
55
+
56
+ function hasJoinsToTable(query, tableName) {
57
+ let found = false;
58
+
59
+ query.forEachOperation(query.constructor.JoinSelector, (op) => {
60
+ if (op.args[0] === tableName) {
61
+ found = true;
62
+ return false;
63
+ }
64
+ });
65
+
66
+ return found;
67
+ }
68
+
69
+ module.exports = {
70
+ WrapMysqlModifySubqueryTransformation,
71
+ };
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ const { CompositeQueryTransformation } = require('./CompositeQueryTransformation');
4
+
5
+ const {
6
+ WrapMysqlModifySubqueryTransformation,
7
+ } = require('./WrapMysqlModifySubqueryTransformation');
8
+
9
+ const transformation = new CompositeQueryTransformation([
10
+ new WrapMysqlModifySubqueryTransformation(),
11
+ ]);
12
+
13
+ module.exports = {
14
+ transformation,
15
+ };
@@ -0,0 +1,227 @@
1
+ 'use strict';
2
+
3
+ const { isObject, isFunction } = require('../utils/objectUtils');
4
+ const { isKnexRaw } = require('../utils/knexUtils');
5
+
6
+ // Where clauses objection adds on its own, like the owner condition of a relation
7
+ // query or the id condition of `$query()`, are tagged with a "where scope". When
8
+ // a query has where clauses from more than one scope, the clauses of each scope
9
+ // are wrapped in parentheses so that an `orWhere` in one scope can't escape the
10
+ // conditions of the others. Without this, `$relatedQuery('pets').where(a).orWhere(b)`
11
+ // would produce `owner and a or b` and match other owners' pets.
12
+ //
13
+ // The scopes are only used when the knex query is built. The operation tree is
14
+ // never modified.
15
+
16
+ const WhereSelector = /^(where|orWhere|andWhere|find\w+)/;
17
+
18
+ // Where operations that only ever produce a single predicate or predicates
19
+ // joined with `and`. A scope that only contains these (and no raw arguments)
20
+ // doesn't need to be wrapped in parentheses.
21
+ const AND_ONLY_OPERATIONS = new Set([
22
+ 'where',
23
+ 'andWhere',
24
+ 'whereNot',
25
+ 'andWhereNot',
26
+ 'whereIn',
27
+ 'whereNotIn',
28
+ 'whereNull',
29
+ 'whereNotNull',
30
+ 'whereBetween',
31
+ 'whereNotBetween',
32
+ 'whereExists',
33
+ 'whereNotExists',
34
+ 'whereColumn',
35
+ 'andWhereColumn',
36
+ 'whereNotColumn',
37
+ 'andWhereNotColumn',
38
+ 'whereLike',
39
+ 'whereILike',
40
+ 'whereWrapped',
41
+ 'whereComposite',
42
+ 'whereInComposite',
43
+ 'whereJsonSupersetOf',
44
+ 'whereJsonSubsetOf',
45
+ 'whereJsonNotSupersetOf',
46
+ 'whereJsonNotSubsetOf',
47
+ 'whereJsonHasAny',
48
+ 'whereJsonHasAll',
49
+ 'whereJsonNotArray',
50
+ 'whereJsonNotObject',
51
+ 'whereJsonOverlaps',
52
+ 'whereJsonNotOverlaps',
53
+ 'whereJsonObject',
54
+ 'whereNotJsonObject',
55
+ 'whereJsonPath',
56
+ 'findById',
57
+ 'findByIds',
58
+ ]);
59
+
60
+ function withWhereScope(builder, callback) {
61
+ const previous = builder._whereScope;
62
+ // A fresh object works as a unique token.
63
+ builder._whereScope = {};
64
+
65
+ try {
66
+ return callback();
67
+ } finally {
68
+ builder._whereScope = previous;
69
+ }
70
+ }
71
+
72
+ function effectiveWhereScope(op) {
73
+ while (op) {
74
+ if (op.whereScope !== null) {
75
+ return op.whereScope;
76
+ }
77
+
78
+ op = op.parentOperation;
79
+ }
80
+
81
+ return null;
82
+ }
83
+
84
+ // Returns null if no where clauses need to be grouped. Otherwise returns an
85
+ // object that tells, for each operation, whether the operation is built as
86
+ // part of a group.
87
+ function createWhereGrouping(builder) {
88
+ const scopes = new Map();
89
+
90
+ builder.forEachOperation(WhereSelector, (op) => {
91
+ if (!hasWhereAncestor(op)) {
92
+ const scope = effectiveWhereScope(op);
93
+ const ops = scopes.get(scope) || [];
94
+
95
+ ops.push(op);
96
+ scopes.set(scope, ops);
97
+ }
98
+ });
99
+
100
+ if (scopes.size < 2) {
101
+ return null;
102
+ }
103
+
104
+ const groupByFirstOp = new Map();
105
+ const groupedOps = new Set();
106
+
107
+ for (const ops of scopes.values()) {
108
+ if (ops.every(isAndOnlyTree)) {
109
+ continue;
110
+ }
111
+
112
+ groupByFirstOp.set(ops[0], ops);
113
+
114
+ for (const op of ops) {
115
+ groupedOps.add(op);
116
+ op.forEachDescendantOperation((it) => {
117
+ groupedOps.add(it);
118
+ });
119
+ }
120
+ }
121
+
122
+ if (groupedOps.size === 0) {
123
+ return null;
124
+ }
125
+
126
+ return {
127
+ isGrouped(op) {
128
+ return groupedOps.has(op);
129
+ },
130
+
131
+ // Builds the whole group if `op` is the first operation of a group.
132
+ build(op, knexBuilder) {
133
+ const ops = groupByFirstOp.get(op);
134
+
135
+ if (!ops) {
136
+ return knexBuilder;
137
+ }
138
+
139
+ return knexBuilder.where(function () {
140
+ let groupBuilder = this;
141
+
142
+ for (const groupOp of ops) {
143
+ groupBuilder = buildOperationTree(builder, groupOp, groupBuilder);
144
+ }
145
+ });
146
+ },
147
+ };
148
+ }
149
+
150
+ function buildOperationTree(builder, op, knexBuilder) {
151
+ const ops = [op];
152
+
153
+ op.forEachDescendantOperation((it) => {
154
+ ops.push(it);
155
+ });
156
+
157
+ for (const it of ops) {
158
+ if (it.hasOnBuildKnex()) {
159
+ knexBuilder =
160
+ builder.callOperationMethod(it, 'onBuildKnex', [knexBuilder, builder]) || knexBuilder;
161
+ }
162
+ }
163
+
164
+ return knexBuilder;
165
+ }
166
+
167
+ function hasWhereAncestor(op) {
168
+ for (let parent = op.parentOperation; parent; parent = parent.parentOperation) {
169
+ if (WhereSelector.test(parent.name)) {
170
+ return true;
171
+ }
172
+ }
173
+
174
+ return false;
175
+ }
176
+
177
+ function isAndOnlyTree(op) {
178
+ if (!isAndOnly(op)) {
179
+ return false;
180
+ }
181
+
182
+ let andOnly = true;
183
+
184
+ op.forEachDescendantOperation((it) => {
185
+ if (it.hasOnBuildKnex() && !isAndOnly(it)) {
186
+ andOnly = false;
187
+ return false;
188
+ }
189
+ });
190
+
191
+ return andOnly;
192
+ }
193
+
194
+ function isAndOnly(op) {
195
+ return AND_ONLY_OPERATIONS.has(op.name) && !containsRaw(op.args);
196
+ }
197
+
198
+ function containsRaw(value) {
199
+ if (Array.isArray(value)) {
200
+ return value.some(containsRaw);
201
+ } else if (!isObject(value)) {
202
+ return false;
203
+ } else if (value.isObjectionReferenceBuilder) {
204
+ // A reference is always a single (possibly casted) column or json path.
205
+ return false;
206
+ } else if (value.isObjectionFunctionBuilder) {
207
+ // `fn()` calls and expressions like `ref('a').eq(1)` are wrapped in parentheses,
208
+ // so only their arguments can contain anything.
209
+ return containsRaw(value._args);
210
+ } else if (isKnexRaw(value) || isFunction(value.toKnexRaw)) {
211
+ // Raw sql (and anything that is converted into it) can contain anything.
212
+ return true;
213
+ } else if (value.isObjectionQueryBuilderBase || isFunction(value.toSQL)) {
214
+ // Subqueries are always wrapped in parentheses.
215
+ return false;
216
+ } else if (Object.getPrototypeOf(value) === Object.prototype) {
217
+ return Object.values(value).some(containsRaw);
218
+ } else {
219
+ return false;
220
+ }
221
+ }
222
+
223
+ module.exports = {
224
+ withWhereScope,
225
+ effectiveWhereScope,
226
+ createWhereGrouping,
227
+ };