@abedmurrar/objection 4.0.0-alpha.0 → 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 (192) hide show
  1. package/README.md +103 -67
  2. package/lib/index.mjs +6 -0
  3. package/lib/initialize.js +6 -9
  4. package/lib/model/AjvValidator.js +235 -282
  5. package/lib/model/Model.js +653 -823
  6. package/lib/model/ModifierNotFoundError.js +5 -7
  7. package/lib/model/NotFoundError.js +14 -18
  8. package/lib/model/RelationDoesNotExistError.js +6 -9
  9. package/lib/model/ValidationError.js +33 -41
  10. package/lib/model/Validator.js +15 -21
  11. package/lib/model/getModel.js +1 -3
  12. package/lib/model/graph/ModelGraph.js +44 -64
  13. package/lib/model/graph/ModelGraphBuilder.js +164 -217
  14. package/lib/model/graph/ModelGraphEdge.js +31 -43
  15. package/lib/model/graph/ModelGraphNode.js +192 -231
  16. package/lib/model/inheritModel.js +9 -18
  17. package/lib/model/modelBindKnex.js +48 -62
  18. package/lib/model/modelClone.js +79 -98
  19. package/lib/model/modelColPropMap.js +16 -26
  20. package/lib/model/modelConcurrency.js +24 -0
  21. package/lib/model/modelId.js +44 -49
  22. package/lib/model/modelJsonAttributes.js +56 -76
  23. package/lib/model/modelParseRelations.js +68 -67
  24. package/lib/model/modelQueryProps.js +76 -107
  25. package/lib/model/modelSet.js +92 -112
  26. package/lib/model/modelTableMetadata.js +60 -72
  27. package/lib/model/modelToJson.js +120 -150
  28. package/lib/model/modelUtils.js +30 -37
  29. package/lib/model/modelValidate.js +34 -42
  30. package/lib/model/modelValues.js +78 -91
  31. package/lib/model/modelVisitor.js +22 -29
  32. package/lib/objection.js +42 -67
  33. package/lib/queryBuilder/FunctionBuilder.js +231 -279
  34. package/lib/queryBuilder/InternalOptions.js +19 -24
  35. package/lib/queryBuilder/JoinBuilder.js +116 -149
  36. package/lib/queryBuilder/QueryBuilder.js +1009 -1271
  37. package/lib/queryBuilder/QueryBuilderBase.js +647 -865
  38. package/lib/queryBuilder/QueryBuilderContext.js +14 -21
  39. package/lib/queryBuilder/QueryBuilderContextBase.js +20 -29
  40. package/lib/queryBuilder/QueryBuilderOperationSupport.js +462 -536
  41. package/lib/queryBuilder/QueryBuilderUserContext.js +19 -25
  42. package/lib/queryBuilder/RawBuilder.js +58 -73
  43. package/lib/queryBuilder/ReferenceBuilder.js +232 -270
  44. package/lib/queryBuilder/RelationExpression.js +322 -380
  45. package/lib/queryBuilder/StaticHookArguments.js +94 -106
  46. package/lib/queryBuilder/ValueBuilder.js +100 -112
  47. package/lib/queryBuilder/expressions.js +86 -116
  48. package/lib/queryBuilder/functions/mysql.js +642 -697
  49. package/lib/queryBuilder/graph/GraphAction.js +44 -59
  50. package/lib/queryBuilder/graph/GraphData.js +7 -9
  51. package/lib/queryBuilder/graph/GraphFetcher.js +115 -151
  52. package/lib/queryBuilder/graph/GraphNodeDbExistence.js +114 -152
  53. package/lib/queryBuilder/graph/GraphOperation.js +16 -22
  54. package/lib/queryBuilder/graph/GraphOptions.js +143 -185
  55. package/lib/queryBuilder/graph/GraphUpsert.js +167 -241
  56. package/lib/queryBuilder/graph/delete/GraphDelete.js +8 -13
  57. package/lib/queryBuilder/graph/delete/GraphDeleteAction.js +44 -62
  58. package/lib/queryBuilder/graph/insert/GraphInsert.js +99 -128
  59. package/lib/queryBuilder/graph/insert/GraphInsertAction.js +151 -193
  60. package/lib/queryBuilder/graph/insert/JoinRowGraphInsertAction.js +57 -79
  61. package/lib/queryBuilder/graph/patch/GraphPatch.js +8 -13
  62. package/lib/queryBuilder/graph/patch/GraphPatchAction.js +181 -234
  63. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsert.js +16 -21
  64. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsertAction.js +80 -110
  65. package/lib/queryBuilder/join/JoinResultColumn.js +14 -18
  66. package/lib/queryBuilder/join/JoinResultParser.js +88 -101
  67. package/lib/queryBuilder/join/RelationJoiner.js +205 -288
  68. package/lib/queryBuilder/join/TableNode.js +117 -144
  69. package/lib/queryBuilder/join/TableTree.js +60 -76
  70. package/lib/queryBuilder/join/utils.js +10 -16
  71. package/lib/queryBuilder/operations/DelegateOperation.js +93 -133
  72. package/lib/queryBuilder/operations/DeleteOperation.js +33 -37
  73. package/lib/queryBuilder/operations/FindByIdOperation.js +20 -28
  74. package/lib/queryBuilder/operations/FindByIdsOperation.js +17 -23
  75. package/lib/queryBuilder/operations/FindOperation.js +114 -131
  76. package/lib/queryBuilder/operations/FirstOperation.js +14 -19
  77. package/lib/queryBuilder/operations/FromOperation.js +69 -88
  78. package/lib/queryBuilder/operations/InsertAndFetchOperation.js +28 -39
  79. package/lib/queryBuilder/operations/InsertGraphAndFetchOperation.js +25 -35
  80. package/lib/queryBuilder/operations/InsertGraphOperation.js +77 -98
  81. package/lib/queryBuilder/operations/InsertOperation.js +132 -165
  82. package/lib/queryBuilder/operations/InstanceDeleteOperation.js +27 -36
  83. package/lib/queryBuilder/operations/InstanceFindOperation.js +9 -13
  84. package/lib/queryBuilder/operations/InstanceInsertOperation.js +13 -17
  85. package/lib/queryBuilder/operations/InstanceUpdateOperation.js +32 -46
  86. package/lib/queryBuilder/operations/JoinRelatedOperation.js +66 -86
  87. package/lib/queryBuilder/operations/KnexOperation.js +4 -7
  88. package/lib/queryBuilder/operations/MergeOperation.js +32 -45
  89. package/lib/queryBuilder/operations/ObjectionToKnexConvertingOperation.js +131 -150
  90. package/lib/queryBuilder/operations/OnBuildKnexOperation.js +17 -23
  91. package/lib/queryBuilder/operations/OnBuildOperation.js +17 -23
  92. package/lib/queryBuilder/operations/OnErrorOperation.js +17 -23
  93. package/lib/queryBuilder/operations/QueryBuilderOperation.js +231 -270
  94. package/lib/queryBuilder/operations/RangeOperation.js +30 -40
  95. package/lib/queryBuilder/operations/RelateOperation.js +14 -21
  96. package/lib/queryBuilder/operations/ReturningOperation.js +12 -18
  97. package/lib/queryBuilder/operations/RunAfterOperation.js +17 -23
  98. package/lib/queryBuilder/operations/RunBeforeOperation.js +17 -23
  99. package/lib/queryBuilder/operations/UnrelateOperation.js +12 -17
  100. package/lib/queryBuilder/operations/UpdateAndFetchOperation.js +48 -65
  101. package/lib/queryBuilder/operations/UpdateOperation.js +104 -129
  102. package/lib/queryBuilder/operations/UpsertGraphAndFetchOperation.js +25 -35
  103. package/lib/queryBuilder/operations/UpsertGraphOperation.js +36 -55
  104. package/lib/queryBuilder/operations/WhereCompositeOperation.js +30 -39
  105. package/lib/queryBuilder/operations/WhereInOperation.js +34 -36
  106. package/lib/queryBuilder/operations/eager/EagerOperation.js +37 -52
  107. package/lib/queryBuilder/operations/eager/JoinEagerOperation.js +34 -44
  108. package/lib/queryBuilder/operations/eager/NaiveEagerOperation.js +4 -7
  109. package/lib/queryBuilder/operations/eager/WhereInEagerOperation.js +193 -251
  110. package/lib/queryBuilder/operations/jsonApi/WhereJsonHasOperation.js +18 -25
  111. package/lib/queryBuilder/operations/jsonApi/WhereJsonNotObjectOperation.js +25 -41
  112. package/lib/queryBuilder/operations/jsonApi/WhereJsonOperation.js +19 -20
  113. package/lib/queryBuilder/operations/jsonApi/WhereJsonOverlapsOperation.js +23 -21
  114. package/lib/queryBuilder/operations/jsonApi/mysqlJsonApi.js +106 -118
  115. package/lib/queryBuilder/operations/jsonApi/postgresJsonApi.js +79 -108
  116. package/lib/queryBuilder/operations/select/SelectOperation.js +37 -53
  117. package/lib/queryBuilder/operations/select/Selection.js +94 -105
  118. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeMsSqlOperation.js +68 -101
  119. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeOperation.js +65 -75
  120. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeSqliteOperation.js +75 -84
  121. package/lib/queryBuilder/parsers/jsonFieldExpressionParser.js +760 -859
  122. package/lib/queryBuilder/parsers/relationExpressionParser.js +840 -952
  123. package/lib/queryBuilder/transformations/CompositeQueryTransformation.js +10 -15
  124. package/lib/queryBuilder/transformations/QueryTransformation.js +4 -6
  125. package/lib/queryBuilder/transformations/WrapMysqlModifySubqueryTransformation.js +35 -49
  126. package/lib/queryBuilder/transformations/index.js +3 -9
  127. package/lib/queryBuilder/whereScopes.js +158 -186
  128. package/lib/relations/Relation.js +279 -363
  129. package/lib/relations/RelationDeleteOperation.js +16 -22
  130. package/lib/relations/RelationFindOperation.js +100 -133
  131. package/lib/relations/RelationInsertOperation.js +19 -27
  132. package/lib/relations/RelationOwner.js +167 -204
  133. package/lib/relations/RelationProperty.js +177 -217
  134. package/lib/relations/RelationUpdateOperation.js +16 -23
  135. package/lib/relations/belongsToOne/BelongsToOneDeleteOperation.js +11 -16
  136. package/lib/relations/belongsToOne/BelongsToOneInsertOperation.js +24 -35
  137. package/lib/relations/belongsToOne/BelongsToOneRelateOperation.js +30 -41
  138. package/lib/relations/belongsToOne/BelongsToOneRelation.js +33 -41
  139. package/lib/relations/belongsToOne/BelongsToOneUnrelateOperation.js +38 -53
  140. package/lib/relations/hasMany/HasManyInsertOperation.js +35 -51
  141. package/lib/relations/hasMany/HasManyRelateOperation.js +38 -54
  142. package/lib/relations/hasMany/HasManyRelation.js +30 -38
  143. package/lib/relations/hasMany/HasManyUnrelateOperation.js +19 -26
  144. package/lib/relations/hasOne/HasOneRelation.js +4 -7
  145. package/lib/relations/hasOneThrough/HasOneThroughRelation.js +4 -7
  146. package/lib/relations/manyToMany/ManyToManyModifyMixin.js +67 -90
  147. package/lib/relations/manyToMany/ManyToManyRelation.js +349 -451
  148. package/lib/relations/manyToMany/ManyToManySqliteModifyMixin.js +19 -26
  149. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperation.js +3 -5
  150. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperationBase.js +14 -20
  151. package/lib/relations/manyToMany/delete/ManyToManyDeleteSqliteOperation.js +3 -7
  152. package/lib/relations/manyToMany/find/ManyToManyFindOperation.js +71 -94
  153. package/lib/relations/manyToMany/insert/ManyToManyInsertOperation.js +31 -43
  154. package/lib/relations/manyToMany/relate/ManyToManyRelateOperation.js +50 -67
  155. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperation.js +4 -7
  156. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperationBase.js +20 -27
  157. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateSqliteOperation.js +5 -10
  158. package/lib/relations/manyToMany/update/ManyToManyUpdateOperation.js +3 -5
  159. package/lib/relations/manyToMany/update/ManyToManyUpdateOperationBase.js +55 -72
  160. package/lib/relations/manyToMany/update/ManyToManyUpdateSqliteOperation.js +3 -7
  161. package/lib/transaction.js +53 -83
  162. package/lib/utils/assert.js +15 -21
  163. package/lib/utils/buildUtils.js +17 -19
  164. package/lib/utils/classUtils.js +7 -11
  165. package/lib/utils/cloneDeep.js +365 -0
  166. package/lib/utils/createModifier.js +36 -41
  167. package/lib/utils/deprecate.js +8 -12
  168. package/lib/utils/identifierMapping.js +153 -192
  169. package/lib/utils/internalPropUtils.js +4 -8
  170. package/lib/utils/knexUtils.js +61 -56
  171. package/lib/utils/mixin.js +16 -23
  172. package/lib/utils/mysqlJsonPath.js +55 -40
  173. package/lib/utils/normalizeIds.js +110 -127
  174. package/lib/utils/objectUtils.js +236 -338
  175. package/lib/utils/parseFieldExpression.js +66 -44
  176. package/lib/utils/postgresJsonPath.js +48 -62
  177. package/lib/utils/promiseUtils/after.js +10 -13
  178. package/lib/utils/promiseUtils/afterReturn.js +10 -13
  179. package/lib/utils/promiseUtils/index.js +15 -17
  180. package/lib/utils/promiseUtils/isPromise.js +6 -9
  181. package/lib/utils/promiseUtils/map.js +75 -89
  182. package/lib/utils/promiseUtils/mapAfterAllReturn.js +17 -23
  183. package/lib/utils/promiseUtils/try.js +15 -18
  184. package/lib/utils/resolveModel.js +91 -94
  185. package/lib/utils/tmpColumnUtils.js +4 -13
  186. package/package.json +50 -23
  187. package/typings/objection/index.d.mts +362 -0
  188. package/typings/objection/index.d.ts +36 -9
  189. package/lib/.eslintrc.json +0 -8
  190. package/lib/queryBuilder/parsers/jsonFieldExpressionParser.pegjs +0 -97
  191. package/lib/queryBuilder/parsers/relationExpressionParser.pegjs +0 -141
  192. package/lib/utils/clone.js +0 -2329
@@ -1,126 +1,96 @@
1
1
  'use strict';
2
-
3
2
  const { GraphAction } = require('../GraphAction');
4
3
  const { groupBy, get, set } = require('../../../utils/objectUtils');
5
4
  const { forEachPropertyReference } = require('../../../model/graph/ModelGraphBuilder');
6
5
  const promiseUtils = require('../../../utils/promiseUtils');
7
-
8
6
  class GraphRecursiveUpsertAction extends GraphAction {
9
- constructor(graphData, { nodes }) {
10
- super(graphData);
11
- // Nodes to upsert.
12
- this.nodes = nodes;
13
- }
14
-
15
- run(builder) {
16
- const builders = this._createUpsertBuilders(builder, this.nodes);
17
-
18
- return promiseUtils.map(builders, (builder) => builder.execute(), {
19
- concurrency: this._getConcurrency(builder, this.nodes),
20
- });
21
- }
22
-
23
- _createUpsertBuilders(parentBuilder, nodesToUpsert) {
24
- const nodesByRelation = groupBy(nodesToUpsert, getRelation);
25
- const builders = [];
26
-
27
- nodesByRelation.forEach((nodes) => {
28
- const nodesByParent = groupBy(nodes, getParent);
29
-
30
- nodesByParent.forEach((nodes) => {
31
- for (const node of nodes) {
32
- this._resolveReferences(node);
33
- node.userData.upserted = true;
34
- }
35
-
36
- builders.push(
37
- nodes[0].modelClass
38
- .query()
39
- .childQueryOf(parentBuilder)
40
- .copyFrom(parentBuilder, GraphAction.ReturningAllSelector)
41
- .upsertGraph(
42
- nodes.map((node) => node.obj),
43
- this.graphOptions.rebasedOptions(nodes[0]),
44
- ),
45
- );
46
- });
47
- });
48
-
49
- return builders;
50
- }
51
-
52
- /**
53
- * The nodes inside the subgraph we are about to recursively upsert may
54
- * have references outside that graph that won't be available during the
55
- * recursive upsertGraph call. This method resolves the references.
56
- *
57
- * TODO: This doesn't work if a recursively upserted node refers to
58
- * a node inside another recursively upsertable graph.
59
- */
60
- _resolveReferences(node) {
61
- node.obj.$traverse((obj) => this._resolveReferencesForObject(obj));
62
- }
63
-
64
- _resolveReferencesForObject(obj) {
65
- this._resolveObjectReference(obj);
66
- this._resolvePropertyReferences(obj);
67
- }
68
-
69
- _resolveObjectReference(obj) {
70
- const modelClass = obj.constructor;
71
- const ref = obj[modelClass.uidRefProp];
72
-
73
- if (!ref) {
74
- return;
7
+ constructor(graphData, { nodes }) {
8
+ super(graphData);
9
+ // Nodes to upsert.
10
+ this.nodes = nodes;
11
+ }
12
+ run(builder) {
13
+ const builders = this._createUpsertBuilders(builder, this.nodes);
14
+ return promiseUtils.map(builders, (builder) => builder.execute(), {
15
+ concurrency: this._getConcurrency(builder, this.nodes),
16
+ });
17
+ }
18
+ _createUpsertBuilders(parentBuilder, nodesToUpsert) {
19
+ const nodesByRelation = groupBy(nodesToUpsert, getRelation);
20
+ const builders = [];
21
+ nodesByRelation.forEach((nodes) => {
22
+ const nodesByParent = groupBy(nodes, getParent);
23
+ nodesByParent.forEach((nodes) => {
24
+ for (const node of nodes) {
25
+ this._resolveReferences(node);
26
+ node.userData.upserted = true;
27
+ }
28
+ builders.push(nodes[0].modelClass
29
+ .query()
30
+ .childQueryOf(parentBuilder)
31
+ .copyFrom(parentBuilder, GraphAction.ReturningAllSelector)
32
+ .upsertGraph(nodes.map((node) => node.obj), this.graphOptions.rebasedOptions(nodes[0])));
33
+ });
34
+ });
35
+ return builders;
36
+ }
37
+ /**
38
+ * The nodes inside the subgraph we are about to recursively upsert may
39
+ * have references outside that graph that won't be available during the
40
+ * recursive upsertGraph call. This method resolves the references.
41
+ *
42
+ * TODO: This doesn't work if a recursively upserted node refers to
43
+ * a node inside another recursively upsertable graph.
44
+ */
45
+ _resolveReferences(node) {
46
+ node.obj.$traverse((obj) => this._resolveReferencesForObject(obj));
75
47
  }
76
-
77
- const referencedNode = this.graph.nodes.find((it) => it.uid === ref);
78
-
79
- if (!referencedNode) {
80
- return;
48
+ _resolveReferencesForObject(obj) {
49
+ this._resolveObjectReference(obj);
50
+ this._resolvePropertyReferences(obj);
51
+ }
52
+ _resolveObjectReference(obj) {
53
+ const modelClass = obj.constructor;
54
+ const ref = obj[modelClass.uidRefProp];
55
+ if (!ref) {
56
+ return;
57
+ }
58
+ const referencedNode = this.graph.nodes.find((it) => it.uid === ref);
59
+ if (!referencedNode) {
60
+ return;
61
+ }
62
+ const relationNames = referencedNode.modelClass.getRelationNames();
63
+ for (const prop of Object.keys(referencedNode.obj)) {
64
+ if (relationNames.includes(prop)) {
65
+ continue;
66
+ }
67
+ obj[prop] = referencedNode.obj[prop];
68
+ }
69
+ delete obj[modelClass.uidRefProp];
81
70
  }
82
-
83
- const relationNames = referencedNode.modelClass.getRelationNames();
84
-
85
- for (const prop of Object.keys(referencedNode.obj)) {
86
- if (relationNames.includes(prop)) {
87
- continue;
88
- }
89
-
90
- obj[prop] = referencedNode.obj[prop];
71
+ _resolvePropertyReferences(obj) {
72
+ forEachPropertyReference(obj, ({ path, refMatch, ref, refPath }) => {
73
+ const referencedNode = this.graph.nodes.find((it) => it.uid === ref);
74
+ if (!referencedNode) {
75
+ return;
76
+ }
77
+ const referencedValue = get(referencedNode.obj, refPath);
78
+ const value = get(obj, path);
79
+ if (value === refMatch) {
80
+ set(obj, path, referencedValue);
81
+ }
82
+ else {
83
+ set(obj, path, value.replace(refMatch, referencedValue));
84
+ }
85
+ });
91
86
  }
92
-
93
- delete obj[modelClass.uidRefProp];
94
- }
95
-
96
- _resolvePropertyReferences(obj) {
97
- forEachPropertyReference(obj, ({ path, refMatch, ref, refPath }) => {
98
- const referencedNode = this.graph.nodes.find((it) => it.uid === ref);
99
-
100
- if (!referencedNode) {
101
- return;
102
- }
103
-
104
- const referencedValue = get(referencedNode.obj, refPath);
105
- const value = get(obj, path);
106
-
107
- if (value === refMatch) {
108
- set(obj, path, referencedValue);
109
- } else {
110
- set(obj, path, value.replace(refMatch, referencedValue));
111
- }
112
- });
113
- }
114
87
  }
115
-
116
88
  function getRelation(node) {
117
- return node.parentEdge.relation;
89
+ return node.parentEdge.relation;
118
90
  }
119
-
120
91
  function getParent(node) {
121
- return node.parentNode;
92
+ return node.parentNode;
122
93
  }
123
-
124
94
  module.exports = {
125
- GraphRecursiveUpsertAction,
95
+ GraphRecursiveUpsertAction,
126
96
  };
@@ -1,23 +1,19 @@
1
1
  'use strict';
2
-
3
2
  class JoinResultColumn {
4
- constructor({ columnAlias, tableNode, name }) {
5
- this.columnAlias = columnAlias;
6
- this.tableNode = tableNode;
7
- this.name = name;
8
- }
9
-
10
- static create({ tableTree, columnAlias }) {
11
- const tableNode = tableTree.getNodeForColumnAlias(columnAlias);
12
-
13
- return new JoinResultColumn({
14
- columnAlias,
15
- tableNode,
16
- name: tableNode.getColumnForColumnAlias(columnAlias),
17
- });
18
- }
3
+ constructor({ columnAlias, tableNode, name }) {
4
+ this.columnAlias = columnAlias;
5
+ this.tableNode = tableNode;
6
+ this.name = name;
7
+ }
8
+ static create({ tableTree, columnAlias }) {
9
+ const tableNode = tableTree.getNodeForColumnAlias(columnAlias);
10
+ return new JoinResultColumn({
11
+ columnAlias,
12
+ tableNode,
13
+ name: tableNode.getColumnForColumnAlias(columnAlias),
14
+ });
15
+ }
19
16
  }
20
-
21
17
  module.exports = {
22
- JoinResultColumn,
18
+ JoinResultColumn,
23
19
  };
@@ -1,119 +1,106 @@
1
1
  'use strict';
2
-
3
2
  const { JoinResultColumn } = require('./JoinResultColumn');
4
3
  const { groupBy } = require('../../utils/objectUtils');
5
-
6
4
  class JoinResultParser {
7
- constructor({ tableTree, omitColumnAliases = [] }) {
8
- this.tableTree = tableTree;
9
- this.omitColumnAliases = new Set(omitColumnAliases);
10
-
11
- this.columnsByTableNode = null;
12
- this.parentMap = null;
13
- this.rootModels = null;
14
- }
15
-
16
- static create(args) {
17
- return new JoinResultParser(args);
18
- }
19
-
20
- parse(flatRows) {
21
- if (!Array.isArray(flatRows) || flatRows.length === 0) {
22
- return flatRows;
5
+ constructor({ tableTree, omitColumnAliases = [] }) {
6
+ this.tableTree = tableTree;
7
+ this.omitColumnAliases = new Set(omitColumnAliases);
8
+ this.columnsByTableNode = null;
9
+ this.rootModelsById = null;
10
+ this.rootModels = null;
23
11
  }
24
-
25
- this.columnsByTableNode = this._createColumns(flatRows[0]);
26
- this.parentMap = new Map();
27
- this.rootModels = [];
28
-
29
- for (const flatRow of flatRows) {
30
- this._parseNode(this.tableTree.rootNode, flatRow);
12
+ static create(args) {
13
+ return new JoinResultParser(args);
31
14
  }
32
-
33
- return this.rootModels;
34
- }
35
-
36
- _parseNode(tableNode, flatRow, parentModel = null, parentKey = null) {
37
- const id = tableNode.getIdFromFlatRow(flatRow);
38
-
39
- if (id === null) {
40
- return;
41
- }
42
-
43
- const key = getKey(parentKey, id, tableNode);
44
- let model = this.parentMap.get(key);
45
-
46
- if (!model) {
47
- model = this._createModel(tableNode, flatRow);
48
-
49
- this._addToParent(tableNode, model, parentModel);
50
- this.parentMap.set(key, model);
15
+ parse(flatRows) {
16
+ if (!Array.isArray(flatRows) || flatRows.length === 0) {
17
+ return flatRows;
18
+ }
19
+ this.columnsByTableNode = this._createColumns(flatRows[0]);
20
+ this.rootModelsById = new Map();
21
+ this.rootModels = [];
22
+ for (const flatRow of flatRows) {
23
+ this._parseNode(this.tableTree.rootNode, flatRow, null, this.rootModelsById);
24
+ }
25
+ return this.rootModels;
51
26
  }
52
-
53
- for (const childNode of tableNode.childNodes) {
54
- this._parseNode(childNode, flatRow, model, key);
27
+ // `modelsById` holds the models of `tableNode` that were already created
28
+ // under `parentModel`. Every created model gets a map like it for each of
29
+ // its child nodes.
30
+ _parseNode(tableNode, flatRow, parentModel, modelsById) {
31
+ const id = tableNode.getIdFromFlatRow(flatRow);
32
+ if (id === null) {
33
+ return;
34
+ }
35
+ let entry = modelsById.get(id);
36
+ if (entry === undefined) {
37
+ const model = this._createModel(tableNode, flatRow);
38
+ this._addToParent(tableNode, model, parentModel);
39
+ entry = { model, childModelsById: createChildMaps(tableNode) };
40
+ modelsById.set(id, entry);
41
+ }
42
+ const childNodes = tableNode.childNodes;
43
+ for (let i = 0, l = childNodes.length; i < l; ++i) {
44
+ this._parseNode(childNodes[i], flatRow, entry.model, entry.childModelsById[i]);
45
+ }
55
46
  }
56
- }
57
-
58
- _createModel(tableNode, flatRow) {
59
- const row = {};
60
- const columns = this.columnsByTableNode.get(tableNode);
61
-
62
- if (columns) {
63
- for (const column of columns) {
64
- if (!this.omitColumnAliases.has(column.columnAlias)) {
65
- row[column.name] = flatRow[column.columnAlias];
47
+ _createModel(tableNode, flatRow) {
48
+ const row = {};
49
+ const columns = this.columnsByTableNode.get(tableNode);
50
+ if (columns) {
51
+ for (let i = 0, l = columns.length; i < l; ++i) {
52
+ const column = columns[i];
53
+ row[column.name] = flatRow[column.columnAlias];
54
+ }
66
55
  }
67
- }
56
+ const model = tableNode.modelClass.fromDatabaseJson(row);
57
+ for (const childNode of tableNode.childNodes) {
58
+ if (childNode.relation.isOneToOne()) {
59
+ model[childNode.relationProperty] = null;
60
+ }
61
+ else {
62
+ model[childNode.relationProperty] = [];
63
+ }
64
+ }
65
+ return model;
68
66
  }
69
-
70
- const model = tableNode.modelClass.fromDatabaseJson(row);
71
-
72
- for (const childNode of tableNode.childNodes) {
73
- if (childNode.relation.isOneToOne()) {
74
- model[childNode.relationProperty] = null;
75
- } else {
76
- model[childNode.relationProperty] = [];
77
- }
67
+ _addToParent(tableNode, model, parentModel) {
68
+ if (tableNode.parentNode) {
69
+ if (tableNode.relation.isOneToOne()) {
70
+ parentModel[tableNode.relationProperty] = model;
71
+ }
72
+ else {
73
+ parentModel[tableNode.relationProperty].push(model);
74
+ }
75
+ }
76
+ else {
77
+ // Root model. Add to root list.
78
+ this.rootModels.push(model);
79
+ }
78
80
  }
79
-
80
- return model;
81
- }
82
-
83
- _addToParent(tableNode, model, parentModel) {
84
- if (tableNode.parentNode) {
85
- if (tableNode.relation.isOneToOne()) {
86
- parentModel[tableNode.relationProperty] = model;
87
- } else {
88
- parentModel[tableNode.relationProperty].push(model);
89
- }
90
- } else {
91
- // Root model. Add to root list.
92
- this.rootModels.push(model);
81
+ _createColumns(row) {
82
+ const columns = Object.keys(row)
83
+ .map((columnAlias) => JoinResultColumn.create({ tableTree: this.tableTree, columnAlias }))
84
+ // The omitted columns are filtered here once instead of for every model.
85
+ .filter((column) => !this.omitColumnAliases.has(column.columnAlias));
86
+ return groupBy(columns, getTableNode);
93
87
  }
94
- }
95
-
96
- _createColumns(row) {
97
- const columns = Object.keys(row).map((columnAlias) =>
98
- JoinResultColumn.create({ tableTree: this.tableTree, columnAlias }),
99
- );
100
-
101
- return groupBy(columns, getTableNode);
102
- }
103
88
  }
104
-
105
89
  function getTableNode(column) {
106
- return column.tableNode;
90
+ return column.tableNode;
107
91
  }
108
-
109
- function getKey(parentKey, id, tableNode) {
110
- if (parentKey !== null) {
111
- return `${parentKey}/${tableNode.relationProperty}/${id}`;
112
- } else {
113
- return `/${id}`;
114
- }
92
+ const NO_CHILD_MAPS = [];
93
+ function createChildMaps(tableNode) {
94
+ const childNodes = tableNode.childNodes;
95
+ if (childNodes.length === 0) {
96
+ return NO_CHILD_MAPS;
97
+ }
98
+ const maps = new Array(childNodes.length);
99
+ for (let i = 0, l = childNodes.length; i < l; ++i) {
100
+ maps[i] = new Map();
101
+ }
102
+ return maps;
115
103
  }
116
-
117
104
  module.exports = {
118
- JoinResultParser,
105
+ JoinResultParser,
119
106
  };