@abedmurrar/objection 0.0.0-stage → 4.0.0-beta.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 +105 -2
  3. package/lib/index.mjs +6 -0
  4. package/lib/initialize.js +11 -0
  5. package/lib/model/AjvValidator.js +278 -0
  6. package/lib/model/Model.js +772 -0
  7. package/lib/model/ModifierNotFoundError.js +10 -0
  8. package/lib/model/NotFoundError.js +19 -0
  9. package/lib/model/RelationDoesNotExistError.js +11 -0
  10. package/lib/model/ValidationError.js +46 -0
  11. package/lib/model/Validator.js +20 -0
  12. package/lib/model/getModel.js +7 -0
  13. package/lib/model/graph/ModelGraph.js +60 -0
  14. package/lib/model/graph/ModelGraphBuilder.js +188 -0
  15. package/lib/model/graph/ModelGraphEdge.js +40 -0
  16. package/lib/model/graph/ModelGraphNode.js +201 -0
  17. package/lib/model/inheritModel.js +19 -0
  18. package/lib/model/modelBindKnex.js +69 -0
  19. package/lib/model/modelClone.js +102 -0
  20. package/lib/model/modelColPropMap.js +24 -0
  21. package/lib/model/modelConcurrency.js +24 -0
  22. package/lib/model/modelId.js +57 -0
  23. package/lib/model/modelJsonAttributes.js +72 -0
  24. package/lib/model/modelParseRelations.js +83 -0
  25. package/lib/model/modelQueryProps.js +116 -0
  26. package/lib/model/modelSet.js +116 -0
  27. package/lib/model/modelTableMetadata.js +71 -0
  28. package/lib/model/modelToJson.js +157 -0
  29. package/lib/model/modelUtils.js +40 -0
  30. package/lib/model/modelValidate.js +40 -0
  31. package/lib/model/modelValues.js +113 -0
  32. package/lib/model/modelVisitor.js +34 -0
  33. package/lib/objection.js +89 -0
  34. package/lib/queryBuilder/FunctionBuilder.js +291 -0
  35. package/lib/queryBuilder/InternalOptions.js +24 -0
  36. package/lib/queryBuilder/JoinBuilder.js +124 -0
  37. package/lib/queryBuilder/QueryBuilder.js +1136 -0
  38. package/lib/queryBuilder/QueryBuilderBase.js +666 -0
  39. package/lib/queryBuilder/QueryBuilderContext.js +20 -0
  40. package/lib/queryBuilder/QueryBuilderContextBase.js +26 -0
  41. package/lib/queryBuilder/QueryBuilderOperationSupport.js +484 -0
  42. package/lib/queryBuilder/QueryBuilderUserContext.js +25 -0
  43. package/lib/queryBuilder/RawBuilder.js +78 -0
  44. package/lib/queryBuilder/ReferenceBuilder.js +246 -0
  45. package/lib/queryBuilder/RelationExpression.js +373 -0
  46. package/lib/queryBuilder/StaticHookArguments.js +122 -0
  47. package/lib/queryBuilder/ValueBuilder.js +115 -0
  48. package/lib/queryBuilder/expressions.js +121 -0
  49. package/lib/queryBuilder/functions/mysql.js +762 -0
  50. package/lib/queryBuilder/graph/GraphAction.js +54 -0
  51. package/lib/queryBuilder/graph/GraphData.js +12 -0
  52. package/lib/queryBuilder/graph/GraphFetcher.js +155 -0
  53. package/lib/queryBuilder/graph/GraphNodeDbExistence.js +146 -0
  54. package/lib/queryBuilder/graph/GraphOperation.js +21 -0
  55. package/lib/queryBuilder/graph/GraphOptions.js +165 -0
  56. package/lib/queryBuilder/graph/GraphUpsert.js +231 -0
  57. package/lib/queryBuilder/graph/delete/GraphDelete.js +15 -0
  58. package/lib/queryBuilder/graph/delete/GraphDeleteAction.js +56 -0
  59. package/lib/queryBuilder/graph/insert/GraphInsert.js +116 -0
  60. package/lib/queryBuilder/graph/insert/GraphInsertAction.js +183 -0
  61. package/lib/queryBuilder/graph/insert/JoinRowGraphInsertAction.js +70 -0
  62. package/lib/queryBuilder/graph/patch/GraphPatch.js +15 -0
  63. package/lib/queryBuilder/graph/patch/GraphPatchAction.js +205 -0
  64. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsert.js +26 -0
  65. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsertAction.js +96 -0
  66. package/lib/queryBuilder/join/JoinResultColumn.js +19 -0
  67. package/lib/queryBuilder/join/JoinResultParser.js +106 -0
  68. package/lib/queryBuilder/join/RelationJoiner.js +258 -0
  69. package/lib/queryBuilder/join/TableNode.js +136 -0
  70. package/lib/queryBuilder/join/TableTree.js +69 -0
  71. package/lib/queryBuilder/join/utils.js +19 -0
  72. package/lib/queryBuilder/operations/DelegateOperation.js +101 -0
  73. package/lib/queryBuilder/operations/DeleteOperation.js +47 -0
  74. package/lib/queryBuilder/operations/FindByIdOperation.js +29 -0
  75. package/lib/queryBuilder/operations/FindByIdsOperation.js +23 -0
  76. package/lib/queryBuilder/operations/FindOperation.js +147 -0
  77. package/lib/queryBuilder/operations/FirstOperation.js +22 -0
  78. package/lib/queryBuilder/operations/FromOperation.js +91 -0
  79. package/lib/queryBuilder/operations/InsertAndFetchOperation.js +38 -0
  80. package/lib/queryBuilder/operations/InsertGraphAndFetchOperation.js +35 -0
  81. package/lib/queryBuilder/operations/InsertGraphOperation.js +87 -0
  82. package/lib/queryBuilder/operations/InsertOperation.js +173 -0
  83. package/lib/queryBuilder/operations/InstanceDeleteOperation.js +37 -0
  84. package/lib/queryBuilder/operations/InstanceFindOperation.js +17 -0
  85. package/lib/queryBuilder/operations/InstanceInsertOperation.js +20 -0
  86. package/lib/queryBuilder/operations/InstanceUpdateOperation.js +45 -0
  87. package/lib/queryBuilder/operations/JoinRelatedOperation.js +83 -0
  88. package/lib/queryBuilder/operations/KnexOperation.js +11 -0
  89. package/lib/queryBuilder/operations/MergeOperation.js +43 -0
  90. package/lib/queryBuilder/operations/ObjectionToKnexConvertingOperation.js +173 -0
  91. package/lib/queryBuilder/operations/OnBuildKnexOperation.js +23 -0
  92. package/lib/queryBuilder/operations/OnBuildOperation.js +23 -0
  93. package/lib/queryBuilder/operations/OnErrorOperation.js +23 -0
  94. package/lib/queryBuilder/operations/QueryBuilderOperation.js +258 -0
  95. package/lib/queryBuilder/operations/RangeOperation.js +37 -0
  96. package/lib/queryBuilder/operations/RelateOperation.js +20 -0
  97. package/lib/queryBuilder/operations/ReturningOperation.js +24 -0
  98. package/lib/queryBuilder/operations/RunAfterOperation.js +23 -0
  99. package/lib/queryBuilder/operations/RunBeforeOperation.js +23 -0
  100. package/lib/queryBuilder/operations/UnrelateOperation.js +18 -0
  101. package/lib/queryBuilder/operations/UpdateAndFetchOperation.js +63 -0
  102. package/lib/queryBuilder/operations/UpdateOperation.js +130 -0
  103. package/lib/queryBuilder/operations/UpsertGraphAndFetchOperation.js +35 -0
  104. package/lib/queryBuilder/operations/UpsertGraphOperation.js +47 -0
  105. package/lib/queryBuilder/operations/WhereCompositeOperation.js +48 -0
  106. package/lib/queryBuilder/operations/WhereInOperation.js +46 -0
  107. package/lib/queryBuilder/operations/eager/EagerOperation.js +46 -0
  108. package/lib/queryBuilder/operations/eager/JoinEagerOperation.js +41 -0
  109. package/lib/queryBuilder/operations/eager/NaiveEagerOperation.js +10 -0
  110. package/lib/queryBuilder/operations/eager/WhereInEagerOperation.js +227 -0
  111. package/lib/queryBuilder/operations/jsonApi/WhereJsonHasOperation.js +29 -0
  112. package/lib/queryBuilder/operations/jsonApi/WhereJsonNotObjectOperation.js +37 -0
  113. package/lib/queryBuilder/operations/jsonApi/WhereJsonOperation.js +30 -0
  114. package/lib/queryBuilder/operations/jsonApi/WhereJsonOverlapsOperation.js +33 -0
  115. package/lib/queryBuilder/operations/jsonApi/mysqlJsonApi.js +155 -0
  116. package/lib/queryBuilder/operations/jsonApi/postgresJsonApi.js +135 -0
  117. package/lib/queryBuilder/operations/select/SelectOperation.js +50 -0
  118. package/lib/queryBuilder/operations/select/Selection.js +112 -0
  119. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeMsSqlOperation.js +84 -0
  120. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeOperation.js +90 -0
  121. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeSqliteOperation.js +95 -0
  122. package/lib/queryBuilder/parsers/jsonFieldExpressionParser.js +787 -0
  123. package/lib/queryBuilder/parsers/relationExpressionParser.js +930 -0
  124. package/lib/queryBuilder/transformations/CompositeQueryTransformation.js +17 -0
  125. package/lib/queryBuilder/transformations/QueryTransformation.js +9 -0
  126. package/lib/queryBuilder/transformations/WrapMysqlModifySubqueryTransformation.js +57 -0
  127. package/lib/queryBuilder/transformations/index.js +9 -0
  128. package/lib/queryBuilder/whereScopes.js +199 -0
  129. package/lib/relations/Relation.js +317 -0
  130. package/lib/relations/RelationDeleteOperation.js +23 -0
  131. package/lib/relations/RelationFindOperation.js +116 -0
  132. package/lib/relations/RelationInsertOperation.js +25 -0
  133. package/lib/relations/RelationOwner.js +199 -0
  134. package/lib/relations/RelationProperty.js +207 -0
  135. package/lib/relations/RelationUpdateOperation.js +23 -0
  136. package/lib/relations/belongsToOne/BelongsToOneDeleteOperation.js +18 -0
  137. package/lib/relations/belongsToOne/BelongsToOneInsertOperation.js +33 -0
  138. package/lib/relations/belongsToOne/BelongsToOneRelateOperation.js +39 -0
  139. package/lib/relations/belongsToOne/BelongsToOneRelation.js +45 -0
  140. package/lib/relations/belongsToOne/BelongsToOneUnrelateOperation.js +46 -0
  141. package/lib/relations/hasMany/HasManyInsertOperation.js +45 -0
  142. package/lib/relations/hasMany/HasManyRelateOperation.js +48 -0
  143. package/lib/relations/hasMany/HasManyRelation.js +41 -0
  144. package/lib/relations/hasMany/HasManyUnrelateOperation.js +26 -0
  145. package/lib/relations/hasOne/HasOneRelation.js +10 -0
  146. package/lib/relations/hasOneThrough/HasOneThroughRelation.js +10 -0
  147. package/lib/relations/manyToMany/ManyToManyModifyMixin.js +82 -0
  148. package/lib/relations/manyToMany/ManyToManyRelation.js +405 -0
  149. package/lib/relations/manyToMany/ManyToManySqliteModifyMixin.js +29 -0
  150. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperation.js +8 -0
  151. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperationBase.js +20 -0
  152. package/lib/relations/manyToMany/delete/ManyToManyDeleteSqliteOperation.js +8 -0
  153. package/lib/relations/manyToMany/find/ManyToManyFindOperation.js +82 -0
  154. package/lib/relations/manyToMany/insert/ManyToManyInsertOperation.js +40 -0
  155. package/lib/relations/manyToMany/relate/ManyToManyRelateOperation.js +64 -0
  156. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperation.js +11 -0
  157. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperationBase.js +27 -0
  158. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateSqliteOperation.js +11 -0
  159. package/lib/relations/manyToMany/update/ManyToManyUpdateOperation.js +8 -0
  160. package/lib/relations/manyToMany/update/ManyToManyUpdateOperationBase.js +65 -0
  161. package/lib/relations/manyToMany/update/ManyToManyUpdateSqliteOperation.js +8 -0
  162. package/lib/transaction.js +66 -0
  163. package/lib/utils/assert.js +19 -0
  164. package/lib/utils/buildUtils.js +19 -0
  165. package/lib/utils/classUtils.js +9 -0
  166. package/lib/utils/cloneDeep.js +365 -0
  167. package/lib/utils/createModifier.js +37 -0
  168. package/lib/utils/deprecate.js +11 -0
  169. package/lib/utils/identifierMapping.js +188 -0
  170. package/lib/utils/internalPropUtils.js +7 -0
  171. package/lib/utils/knexUtils.js +81 -0
  172. package/lib/utils/mixin.js +18 -0
  173. package/lib/utils/mysqlJsonPath.js +70 -0
  174. package/lib/utils/normalizeIds.js +127 -0
  175. package/lib/utils/objectUtils.js +314 -0
  176. package/lib/utils/parseFieldExpression.js +73 -0
  177. package/lib/utils/postgresJsonPath.js +96 -0
  178. package/lib/utils/promiseUtils/after.js +14 -0
  179. package/lib/utils/promiseUtils/afterReturn.js +14 -0
  180. package/lib/utils/promiseUtils/index.js +15 -0
  181. package/lib/utils/promiseUtils/isPromise.js +8 -0
  182. package/lib/utils/promiseUtils/map.js +96 -0
  183. package/lib/utils/promiseUtils/mapAfterAllReturn.js +23 -0
  184. package/lib/utils/promiseUtils/try.js +19 -0
  185. package/lib/utils/resolveModel.js +104 -0
  186. package/lib/utils/tmpColumnUtils.js +7 -0
  187. package/package.json +113 -4
  188. package/typings/objection/index.d.mts +362 -0
  189. package/typings/objection/index.d.ts +4131 -0
  190. package/typings/objection/relation-expression.d.ts +237 -0
@@ -0,0 +1,246 @@
1
+ 'use strict';
2
+ const { parseFieldExpression } = require('../utils/parseFieldExpression');
3
+ const { isObject } = require('../utils/objectUtils');
4
+ const { isMySql, isMariaDb } = require('../utils/knexUtils');
5
+ const { toPgJsonPathLiteral, getJsonDialect } = require('../utils/postgresJsonPath');
6
+ const { toMySqlJsonPath, toMySqlCastType, isBooleanType, toJsonSql, } = require('../utils/mysqlJsonPath');
7
+ const { addExpressionMethods } = require('./expressions');
8
+ class ReferenceBuilder {
9
+ constructor(expr) {
10
+ this._expr = expr;
11
+ this._parsedExpr = null;
12
+ this._column = null;
13
+ this._table = null;
14
+ this._cast = null;
15
+ this._toJson = false;
16
+ this._table = null;
17
+ this._alias = null;
18
+ this._modelClass = null;
19
+ // This `if` makes it possible for `clone` to skip
20
+ // parsing the expression again.
21
+ if (expr !== null) {
22
+ this._parseExpression(expr);
23
+ }
24
+ }
25
+ get parsedExpr() {
26
+ return this._parsedExpr;
27
+ }
28
+ get column() {
29
+ return this._column;
30
+ }
31
+ set column(column) {
32
+ this._column = column;
33
+ }
34
+ get alias() {
35
+ return this._alias;
36
+ }
37
+ set alias(alias) {
38
+ this._alias = alias;
39
+ }
40
+ get tableName() {
41
+ return this._table;
42
+ }
43
+ set tableName(table) {
44
+ this._table = table;
45
+ }
46
+ get modelClass() {
47
+ return this._modelClass;
48
+ }
49
+ set modelClass(modelClass) {
50
+ this._modelClass = modelClass;
51
+ }
52
+ get isPlainColumnRef() {
53
+ return ((!this._parsedExpr || this._parsedExpr.access.length === 0) && !this._cast && !this._toJson);
54
+ }
55
+ get expression() {
56
+ return this._expr;
57
+ }
58
+ get cast() {
59
+ return this._cast;
60
+ }
61
+ fullColumn(builder) {
62
+ const table = this.tableName
63
+ ? this.tableName
64
+ : this.modelClass
65
+ ? builder.tableRefFor(this.modelClass)
66
+ : null;
67
+ if (table) {
68
+ return `${table}.${this.column}`;
69
+ }
70
+ else {
71
+ return this.column;
72
+ }
73
+ }
74
+ castText() {
75
+ return this.castTo('text');
76
+ }
77
+ castInt() {
78
+ return this.castTo('integer');
79
+ }
80
+ castBigInt() {
81
+ return this.castTo('bigint');
82
+ }
83
+ castFloat() {
84
+ return this.castTo('float');
85
+ }
86
+ castDecimal() {
87
+ return this.castTo('decimal');
88
+ }
89
+ castReal() {
90
+ return this.castTo('real');
91
+ }
92
+ castBool() {
93
+ return this.castTo('boolean');
94
+ }
95
+ castJson() {
96
+ this._toJson = true;
97
+ return this;
98
+ }
99
+ castTo(sqlType) {
100
+ this._cast = sqlType;
101
+ return this;
102
+ }
103
+ from(table) {
104
+ this._table = table;
105
+ return this;
106
+ }
107
+ table(table) {
108
+ this._table = table;
109
+ return this;
110
+ }
111
+ model(modelClass) {
112
+ this._modelClass = modelClass;
113
+ return this;
114
+ }
115
+ as(alias) {
116
+ this._alias = alias;
117
+ return this;
118
+ }
119
+ clone() {
120
+ const clone = new this.constructor(null);
121
+ clone._expr = this._expr;
122
+ clone._parsedExpr = this._parsedExpr;
123
+ clone._column = this._column;
124
+ clone._table = this._table;
125
+ clone._cast = this._cast;
126
+ clone._toJson = this._toJson;
127
+ clone._alias = this._alias;
128
+ clone._modelClass = this._modelClass;
129
+ return clone;
130
+ }
131
+ toKnexRaw(builder) {
132
+ return builder.knex().raw(...this._createRawArgs(builder));
133
+ }
134
+ _parseExpression(expr) {
135
+ this._parsedExpr = parseFieldExpression(expr);
136
+ this._column = this._parsedExpr.column;
137
+ this._table = this._parsedExpr.table;
138
+ }
139
+ _createRawArgs(builder) {
140
+ const knex = builder.unsafeKnex();
141
+ const mysql = isMySql(knex);
142
+ const bindings = [];
143
+ let sql = this._createReferenceSql(builder, bindings);
144
+ sql = this._maybeCast(sql, mysql, knex);
145
+ sql = this._maybeToJsonb(sql, mysql, knex);
146
+ sql = this._maybeAlias(sql, bindings);
147
+ return [sql, bindings];
148
+ }
149
+ _createReferenceSql(builder, bindings) {
150
+ const access = this._parsedExpr.access;
151
+ bindings.push(this.fullColumn(builder));
152
+ if (access.length === 0) {
153
+ return '??';
154
+ }
155
+ if (getJsonDialect(builder.unsafeKnex(), this._expr) === 'mysql') {
156
+ bindings.push(toMySqlJsonPath(access));
157
+ // Casts need the unquoted value: `abc` instead of the JSON string `"abc"`.
158
+ if (this._cast) {
159
+ return 'JSON_UNQUOTE(JSON_EXTRACT(??, ?))';
160
+ }
161
+ // MariaDB's JSON_EXTRACT() returns the JSON with spaces, so it would never
162
+ // be equal to a value like `val({ a: 1 })`, which is compact.
163
+ return isMariaDb(builder.unsafeKnex())
164
+ ? 'JSON_COMPACT(JSON_EXTRACT(??, ?))'
165
+ : 'JSON_EXTRACT(??, ?)';
166
+ }
167
+ const extractor = this._cast ? '#>>' : '#>';
168
+ return `??${extractor}${toPgJsonPathLiteral(access)}`;
169
+ }
170
+ _maybeCast(sql, mysql, knex) {
171
+ if (!this._cast) {
172
+ return sql;
173
+ }
174
+ else if (!mysql) {
175
+ return `CAST(${sql} AS ${this._cast})`;
176
+ }
177
+ const isJsonField = this._parsedExpr.access.length > 0;
178
+ // MySQL can't cast to a boolean.
179
+ if (isBooleanType(this._cast)) {
180
+ return isJsonField ? `(${sql} IN ('true', '1'))` : `(${sql} <> 0)`;
181
+ }
182
+ const type = toMySqlCastType(this._cast);
183
+ // `JSON_UNQUOTE()` already returns text. Casting it would change its collation
184
+ // from the case sensitive one `->>` also uses.
185
+ if (isJsonField && type === 'CHAR') {
186
+ return sql;
187
+ }
188
+ if (type === 'JSON') {
189
+ return toJsonSql(sql, knex);
190
+ }
191
+ return `CAST(${sql} AS ${type})`;
192
+ }
193
+ _maybeToJsonb(sql, mysql, knex) {
194
+ if (!this._toJson) {
195
+ return sql;
196
+ }
197
+ else if (mysql) {
198
+ return toJsonSql(sql, knex);
199
+ }
200
+ else {
201
+ return `to_jsonb(${sql})`;
202
+ }
203
+ }
204
+ _maybeAlias(sql, bindings) {
205
+ if (this._shouldAlias()) {
206
+ bindings.push(this._alias);
207
+ return `${sql} as ??`;
208
+ }
209
+ else {
210
+ return sql;
211
+ }
212
+ }
213
+ _shouldAlias() {
214
+ if (!this._alias) {
215
+ return false;
216
+ }
217
+ else if (!this.isPlainColumnRef) {
218
+ return true;
219
+ }
220
+ else {
221
+ // No need to alias if we are dealing with a simple column reference
222
+ // and the alias is the same as the column name.
223
+ return this._alias !== this._column;
224
+ }
225
+ }
226
+ }
227
+ Object.defineProperties(ReferenceBuilder.prototype, {
228
+ isObjectionReferenceBuilder: {
229
+ enumerable: false,
230
+ writable: false,
231
+ value: true,
232
+ },
233
+ });
234
+ addExpressionMethods(ReferenceBuilder.prototype);
235
+ const ref = (reference) => {
236
+ if (isObject(reference) && reference.isObjectionReferenceBuilder) {
237
+ return reference;
238
+ }
239
+ else {
240
+ return new ReferenceBuilder(reference);
241
+ }
242
+ };
243
+ module.exports = {
244
+ ReferenceBuilder,
245
+ ref,
246
+ };
@@ -0,0 +1,373 @@
1
+ 'use strict';
2
+ const parser = require('./parsers/relationExpressionParser');
3
+ const { isObject, isNumber, isString, union } = require('../utils/objectUtils');
4
+ const { RelationDoesNotExistError } = require('../model/RelationDoesNotExistError');
5
+ class RelationExpressionParseError extends Error {
6
+ }
7
+ class DuplicateRelationError extends RelationExpressionParseError {
8
+ constructor(relationName) {
9
+ super();
10
+ this.relationName = relationName;
11
+ }
12
+ }
13
+ class RelationExpression {
14
+ constructor(node = newNode(), recursionDepth = 0) {
15
+ this.node = node;
16
+ this.recursionDepth = recursionDepth;
17
+ }
18
+ // Create a relation expression from a string, a pojo or another
19
+ // RelationExpression instance.
20
+ static create(expr) {
21
+ if (isObject(expr)) {
22
+ if (expr.isObjectionRelationExpression) {
23
+ return expr;
24
+ }
25
+ else {
26
+ return new RelationExpression(normalizeNode(expr));
27
+ }
28
+ }
29
+ else if (isString(expr)) {
30
+ if (expr.trim().length === 0) {
31
+ return new RelationExpression();
32
+ }
33
+ else {
34
+ try {
35
+ return new RelationExpression(parse(expr));
36
+ }
37
+ catch (err) {
38
+ if (err.duplicateRelationName) {
39
+ throw new DuplicateRelationError(err.duplicateRelationName);
40
+ }
41
+ else {
42
+ throw new RelationExpressionParseError(err.message);
43
+ }
44
+ }
45
+ }
46
+ }
47
+ else {
48
+ return new RelationExpression();
49
+ }
50
+ }
51
+ // Create a relation expression from a model graph.
52
+ static fromModelGraph(graph) {
53
+ if (!graph) {
54
+ return new RelationExpression();
55
+ }
56
+ else {
57
+ return new RelationExpression(modelGraphToNode(graph, newNode()));
58
+ }
59
+ }
60
+ get maxRecursionDepth() {
61
+ if (isNumber(this.node.$recursive)) {
62
+ return this.node.$recursive;
63
+ }
64
+ else {
65
+ return this.node.$recursive ? Number.MAX_SAFE_INTEGER : 0;
66
+ }
67
+ }
68
+ get numChildren() {
69
+ return this.node.$childNames.length;
70
+ }
71
+ get isEmpty() {
72
+ return this.numChildren === 0;
73
+ }
74
+ // Merges this relation expression with another. `expr` can be a string,
75
+ // a pojo, or a RelationExpression instance.
76
+ merge(expr) {
77
+ expr = RelationExpression.create(expr);
78
+ if (this.isEmpty) {
79
+ // Nothing to merge.
80
+ return expr;
81
+ }
82
+ return new RelationExpression(mergeNodes(this.node, expr.node));
83
+ }
84
+ // Returns true if `expr` is contained by this expression. For example
85
+ // `a.b` is contained by `a.[b, c]`.
86
+ isSubExpression(expr) {
87
+ expr = RelationExpression.create(expr);
88
+ if (this.node.$allRecursive) {
89
+ return true;
90
+ }
91
+ if (expr.node.$allRecursive) {
92
+ return this.node.$allRecursive;
93
+ }
94
+ if (this.node.$relation !== expr.node.$relation) {
95
+ return false;
96
+ }
97
+ const maxRecursionDepth = expr.maxRecursionDepth;
98
+ if (maxRecursionDepth > 0) {
99
+ return this.node.$allRecursive || this.maxRecursionDepth >= maxRecursionDepth;
100
+ }
101
+ for (const childName of expr.node.$childNames) {
102
+ const ownSubExpression = this.childExpression(childName);
103
+ const subExpression = expr.childExpression(childName);
104
+ if (!ownSubExpression || !ownSubExpression.isSubExpression(subExpression)) {
105
+ return false;
106
+ }
107
+ }
108
+ return true;
109
+ }
110
+ // Returns a RelationExpression for a child node or null if there
111
+ // is no child with the given name `childName`.
112
+ childExpression(childName) {
113
+ if (this.node.$allRecursive ||
114
+ (childName === this.node.$name && this.recursionDepth < this.maxRecursionDepth - 1)) {
115
+ return new RelationExpression(this.node, this.recursionDepth + 1);
116
+ }
117
+ const child = this.node[childName];
118
+ if (child) {
119
+ return new RelationExpression(child);
120
+ }
121
+ else {
122
+ return null;
123
+ }
124
+ }
125
+ // Loops throught all first level children.
126
+ forEachChildExpression(modelClass, cb) {
127
+ const maxRecursionDepth = this.maxRecursionDepth;
128
+ if (this.node.$allRecursive) {
129
+ for (const relationName of modelClass.getRelationNames()) {
130
+ const node = newNode(relationName, true);
131
+ const relation = modelClass.getRelationUnsafe(relationName);
132
+ const childExpr = new RelationExpression(node);
133
+ cb(childExpr, relation);
134
+ }
135
+ }
136
+ else if (this.recursionDepth < maxRecursionDepth - 1) {
137
+ const relation = modelClass.getRelationUnsafe(this.node.$relation) || null;
138
+ const childExpr = new RelationExpression(this.node, this.recursionDepth + 1);
139
+ cb(childExpr, relation);
140
+ }
141
+ else if (maxRecursionDepth === 0) {
142
+ for (const childName of this.node.$childNames) {
143
+ const node = this.node[childName];
144
+ const relation = modelClass.getRelationUnsafe(node.$relation);
145
+ if (!relation) {
146
+ throw new RelationDoesNotExistError(node.$relation);
147
+ }
148
+ const childExpr = new RelationExpression(node);
149
+ cb(childExpr, relation);
150
+ }
151
+ }
152
+ }
153
+ expressionsAtPath(path) {
154
+ return findExpressionsAtPath(this, RelationExpression.create(path), []);
155
+ }
156
+ clone() {
157
+ return new RelationExpression(cloneNode(this.node), this.recursionDepth);
158
+ }
159
+ toString() {
160
+ return toString(this.node);
161
+ }
162
+ toPojo() {
163
+ return cloneNode(this.node);
164
+ }
165
+ toJSON() {
166
+ return this.toPojo();
167
+ }
168
+ }
169
+ const parseCache = new Map();
170
+ function parse(str) {
171
+ const cachedNode = parseCache.get(str);
172
+ if (cachedNode) {
173
+ return cloneNode(cachedNode);
174
+ }
175
+ else {
176
+ const node = parser.parse(str);
177
+ parseCache.set(str, cloneNode(node));
178
+ return node;
179
+ }
180
+ }
181
+ // All enumerable properties of a node that don't start with `$`
182
+ // are child nodes.
183
+ function getChildNames(node) {
184
+ if (!node) {
185
+ return [];
186
+ }
187
+ const childNames = [];
188
+ for (const key of Object.keys(node)) {
189
+ if (key[0] !== '$') {
190
+ childNames.push(key);
191
+ }
192
+ }
193
+ return childNames;
194
+ }
195
+ function toString(node) {
196
+ const childNames = node.$childNames;
197
+ let childExpr = childNames.map((childName) => node[childName]).map(toString);
198
+ let str = node.$relation;
199
+ if (node.$recursive) {
200
+ if (isNumber(node.$recursive)) {
201
+ str += '.^' + node.$recursive;
202
+ }
203
+ else {
204
+ str += '.^';
205
+ }
206
+ }
207
+ else if (node.$allRecursive) {
208
+ str += '.*';
209
+ }
210
+ if (childExpr.length > 1) {
211
+ childExpr = `[${childExpr.join(', ')}]`;
212
+ }
213
+ else {
214
+ childExpr = childExpr[0];
215
+ }
216
+ if (node.$modify.length) {
217
+ str += `(${node.$modify.join(', ')})`;
218
+ }
219
+ if (node.$name !== node.$relation) {
220
+ str += ` as ${node.$name}`;
221
+ }
222
+ if (childExpr) {
223
+ if (str) {
224
+ return `${str}.${childExpr}`;
225
+ }
226
+ else {
227
+ return childExpr;
228
+ }
229
+ }
230
+ else {
231
+ return str;
232
+ }
233
+ }
234
+ function cloneNode(node) {
235
+ return normalizeNode(node);
236
+ }
237
+ function modelGraphToNode(models, node) {
238
+ if (!models) {
239
+ return;
240
+ }
241
+ if (Array.isArray(models)) {
242
+ for (let i = 0, l = models.length; i < l; ++i) {
243
+ modelToNode(models[i], node);
244
+ }
245
+ }
246
+ else {
247
+ modelToNode(models, node);
248
+ }
249
+ return node;
250
+ }
251
+ function modelToNode(model, node) {
252
+ const modelClass = model.constructor;
253
+ const relationNames = modelClass.getRelationNames();
254
+ for (let r = 0, lr = relationNames.length; r < lr; ++r) {
255
+ const relName = relationNames[r];
256
+ if (model[relName] !== undefined) {
257
+ let childNode = node[relName];
258
+ if (!childNode) {
259
+ childNode = newNode(relName);
260
+ node[relName] = childNode;
261
+ node.$childNames.push(relName);
262
+ }
263
+ modelGraphToNode(model[relName], childNode);
264
+ }
265
+ }
266
+ }
267
+ function newNode(name = null, allRecusive = false) {
268
+ return normalizeNode(null, name, allRecusive);
269
+ }
270
+ function normalizeNode(node = null, name = null, allRecusive = false) {
271
+ const normalized = {
272
+ $name: normalizeName(node, name),
273
+ $relation: normalizeRelation(node, name),
274
+ $modify: normalizeModify(node),
275
+ $recursive: normalizeRecursive(node),
276
+ $allRecursive: normalizeAllRecursive(node, allRecusive),
277
+ $childNames: normalizeChildNames(node),
278
+ };
279
+ for (const childName of normalized.$childNames) {
280
+ const childNode = node[childName];
281
+ if (isObject(childNode) || childNode === true) {
282
+ normalized[childName] = normalizeNode(childNode, childName);
283
+ }
284
+ }
285
+ return normalized;
286
+ }
287
+ function normalizeName(node, name) {
288
+ return (node && node.$name) || name || null;
289
+ }
290
+ function normalizeRelation(node, name) {
291
+ return (node && node.$relation) || name || null;
292
+ }
293
+ function normalizeModify(node) {
294
+ if (!node || !node.$modify) {
295
+ return [];
296
+ }
297
+ return Array.isArray(node.$modify) ? node.$modify.slice() : [node.$modify];
298
+ }
299
+ function normalizeRecursive(node) {
300
+ return (node && node.$recursive) || false;
301
+ }
302
+ function normalizeAllRecursive(node, allRecusive) {
303
+ return (node && node.$allRecursive) || allRecusive || false;
304
+ }
305
+ function normalizeChildNames(node) {
306
+ return (node && node.$childNames && node.$childNames.slice()) || getChildNames(node);
307
+ }
308
+ function findExpressionsAtPath(target, path, results) {
309
+ if (path.node.$childNames.length == 0) {
310
+ // Path leaf reached, add target node to result set.
311
+ results.push(target);
312
+ }
313
+ else {
314
+ for (const childName of path.node.$childNames) {
315
+ const pathChild = path.childExpression(childName);
316
+ const targetChild = target.childExpression(childName);
317
+ if (targetChild) {
318
+ findExpressionsAtPath(targetChild, pathChild, results);
319
+ }
320
+ }
321
+ }
322
+ return results;
323
+ }
324
+ function mergeNodes(node1, node2) {
325
+ const node = {
326
+ $name: node1.$name,
327
+ $relation: node1.$relation,
328
+ $modify: union(node1.$modify, node2.$modify),
329
+ $recursive: mergeRecursion(node1.$recursive, node2.$recursive),
330
+ $allRecursive: node1.$allRecursive || node2.$allRecursive,
331
+ $childNames: null,
332
+ };
333
+ if (!node.$recursive && !node.$allRecursive) {
334
+ node.$childNames = union(node1.$childNames, node2.$childNames);
335
+ for (const childName of node.$childNames) {
336
+ const child1 = node1[childName];
337
+ const child2 = node2[childName];
338
+ if (child1 && child2) {
339
+ node[childName] = mergeNodes(child1, child2);
340
+ }
341
+ else {
342
+ node[childName] = child1 || child2;
343
+ }
344
+ }
345
+ }
346
+ else {
347
+ node.$childNames = [];
348
+ }
349
+ return node;
350
+ }
351
+ function mergeRecursion(rec1, rec2) {
352
+ if (rec1 === true || rec2 === true) {
353
+ return true;
354
+ }
355
+ else if (isNumber(rec1) && isNumber(rec2)) {
356
+ return Math.max(rec1, rec2);
357
+ }
358
+ else {
359
+ return rec1 || rec2;
360
+ }
361
+ }
362
+ Object.defineProperties(RelationExpression.prototype, {
363
+ isObjectionRelationExpression: {
364
+ enumerable: false,
365
+ writable: false,
366
+ value: true,
367
+ },
368
+ });
369
+ module.exports = {
370
+ RelationExpression,
371
+ RelationExpressionParseError,
372
+ DuplicateRelationError,
373
+ };