@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,82 @@
1
+ 'use strict';
2
+
3
+ const { isObject } = require('../utils/objectUtils');
4
+
5
+ function parseRelationsIntoModelInstances(model, json, options = {}) {
6
+ if (!options.cache) {
7
+ options = Object.assign({}, options, {
8
+ cache: new Map(),
9
+ });
10
+ }
11
+
12
+ options.cache.set(json, model);
13
+
14
+ for (const relationName of model.constructor.getRelationNames()) {
15
+ const relationJson = json[relationName];
16
+
17
+ if (relationJson !== undefined) {
18
+ const relation = model.constructor.getRelation(relationName);
19
+ const relationModel = parseRelation(relationJson, relation, options);
20
+
21
+ if (relationModel !== relationJson) {
22
+ model[relation.name] = relationModel;
23
+ }
24
+ }
25
+ }
26
+
27
+ return model;
28
+ }
29
+
30
+ function parseRelation(json, relation, options) {
31
+ if (Array.isArray(json)) {
32
+ return parseRelationArray(json, relation, options);
33
+ } else if (json) {
34
+ return parseRelationObject(json, relation, options);
35
+ } else {
36
+ return null;
37
+ }
38
+ }
39
+
40
+ function parseRelationArray(json, relation, options) {
41
+ const models = new Array(json.length);
42
+ let didChange = false;
43
+
44
+ for (let i = 0, l = json.length; i < l; ++i) {
45
+ const model = parseRelationObject(json[i], relation, options);
46
+
47
+ if (model !== json[i]) {
48
+ didChange = true;
49
+ }
50
+
51
+ models[i] = model;
52
+ }
53
+
54
+ if (didChange) {
55
+ return models;
56
+ } else {
57
+ return json;
58
+ }
59
+ }
60
+
61
+ function parseRelationObject(json, relation, options) {
62
+ if (isObject(json)) {
63
+ const modelClass = relation.relatedModelClass;
64
+ let model = options.cache.get(json);
65
+
66
+ if (model === undefined) {
67
+ if (json instanceof modelClass) {
68
+ model = parseRelationsIntoModelInstances(json, json, options);
69
+ } else {
70
+ model = modelClass.fromJson(json, options);
71
+ }
72
+ }
73
+
74
+ return model;
75
+ } else {
76
+ return json;
77
+ }
78
+ }
79
+
80
+ module.exports = {
81
+ parseRelationsIntoModelInstances,
82
+ };
@@ -0,0 +1,147 @@
1
+ 'use strict';
2
+
3
+ const { isObject, isFunction } = require('../utils/objectUtils');
4
+ const { defineNonEnumerableProperty } = require('./modelUtils');
5
+ const { isKnexRaw, isKnexQueryBuilder } = require('../utils/knexUtils');
6
+
7
+ const QUERY_PROPS_PROPERTY = '$$queryProps';
8
+
9
+ // Removes query properties from `json` and stores them into a hidden property
10
+ // inside `model` so that they can be later merged back to `json`.
11
+ function splitQueryProps(model, json) {
12
+ const keys = Object.keys(json);
13
+
14
+ if (hasQueryProps(json, keys)) {
15
+ const queryProps = {};
16
+ const modelProps = {};
17
+
18
+ for (let i = 0, l = keys.length; i < l; ++i) {
19
+ const key = keys[i];
20
+ const value = json[key];
21
+
22
+ if (isQueryProp(value)) {
23
+ queryProps[key] = value;
24
+ } else {
25
+ modelProps[key] = value;
26
+ }
27
+ }
28
+
29
+ defineNonEnumerableProperty(model, QUERY_PROPS_PROPERTY, queryProps);
30
+
31
+ return modelProps;
32
+ } else {
33
+ return json;
34
+ }
35
+ }
36
+
37
+ function hasQueryProps(json, keys) {
38
+ for (let i = 0, l = keys.length; i < l; ++i) {
39
+ if (isQueryProp(json[keys[i]])) {
40
+ return true;
41
+ }
42
+ }
43
+
44
+ return false;
45
+ }
46
+
47
+ function isQueryProp(value) {
48
+ if (!isObject(value)) {
49
+ return false;
50
+ }
51
+
52
+ return (
53
+ isKnexQueryBuilder(value) ||
54
+ isKnexRaw(value) ||
55
+ isKnexRawConvertable(value) ||
56
+ value.isObjectionQueryBuilderBase
57
+ );
58
+ }
59
+
60
+ // Merges and converts `model`'s query properties into `json`.
61
+ function mergeQueryProps(model, json, omitProps, builder) {
62
+ json = convertExistingQueryProps(json, builder);
63
+ json = convertAndMergeHiddenQueryProps(model, json, omitProps, builder);
64
+
65
+ return json;
66
+ }
67
+
68
+ // Converts the query properties in `json` to knex raw instances.
69
+ // `json` may have query properties even though we removed them.
70
+ // For example they may have been added in lifecycle hooks.
71
+ function convertExistingQueryProps(json, builder) {
72
+ const keys = Object.keys(json);
73
+
74
+ for (let i = 0, l = keys.length; i < l; ++i) {
75
+ const key = keys[i];
76
+ const value = json[key];
77
+
78
+ if (isQueryProp(value)) {
79
+ json[key] = queryPropToKnexRaw(value, builder);
80
+ }
81
+ }
82
+
83
+ return json;
84
+ }
85
+
86
+ // Converts and merges the query props that were split from the model
87
+ // and stored into QUERY_PROPS_PROPERTY.
88
+ function convertAndMergeHiddenQueryProps(model, json, omitProps, builder) {
89
+ const queryProps = model[QUERY_PROPS_PROPERTY];
90
+
91
+ if (!queryProps) {
92
+ // The model has no query properties.
93
+ return json;
94
+ }
95
+
96
+ const modelClass = model.constructor;
97
+ const keys = Object.keys(queryProps);
98
+
99
+ for (let i = 0, l = keys.length; i < l; ++i) {
100
+ const key = keys[i];
101
+
102
+ if (!omitProps || !omitProps.includes(key)) {
103
+ const queryProp = queryPropToKnexRaw(queryProps[key], builder);
104
+ json[modelClass.propertyNameToColumnName(key)] = queryProp;
105
+ }
106
+ }
107
+
108
+ return json;
109
+ }
110
+
111
+ // Converts a query property into a knex `raw` instance.
112
+ function queryPropToKnexRaw(queryProp, builder) {
113
+ if (!queryProp) {
114
+ return queryProp;
115
+ }
116
+
117
+ if (queryProp.isObjectionQueryBuilderBase) {
118
+ return buildObjectionQueryBuilder(queryProp, builder);
119
+ } else if (isKnexRawConvertable(queryProp)) {
120
+ return buildKnexRawConvertable(queryProp, builder);
121
+ } else {
122
+ return queryProp;
123
+ }
124
+ }
125
+
126
+ function buildObjectionQueryBuilder(builder, parentBuilder) {
127
+ return builder.subqueryOf(parentBuilder).toKnexQuery();
128
+ }
129
+
130
+ function buildKnexRawConvertable(convertable, builder) {
131
+ if (!builder) {
132
+ throw new Error(
133
+ 'toDatabaseJson called without a query builder instance for a model with query properties',
134
+ );
135
+ }
136
+
137
+ return convertable.toKnexRaw(builder);
138
+ }
139
+
140
+ function isKnexRawConvertable(queryProp) {
141
+ return isFunction(queryProp.toKnexRaw);
142
+ }
143
+
144
+ module.exports = {
145
+ splitQueryProps,
146
+ mergeQueryProps,
147
+ };
@@ -0,0 +1,136 @@
1
+ 'use strict';
2
+
3
+ const { isInternalProp } = require('../utils/internalPropUtils');
4
+ const { splitQueryProps } = require('./modelQueryProps');
5
+ const { isFunction, isString, isPlainObject } = require('../utils/objectUtils');
6
+ const { parseRelationsIntoModelInstances } = require('./modelParseRelations');
7
+
8
+ function setJson(model, json, options) {
9
+ json = json || {};
10
+ options = options || {};
11
+
12
+ if (Object.prototype.toString.call(json) !== '[object Object]') {
13
+ throw new Error(
14
+ 'You should only pass objects to $setJson method. ' +
15
+ '$setJson method was given an invalid value ' +
16
+ json,
17
+ );
18
+ }
19
+
20
+ if (!json.$isObjectionModel) {
21
+ // json can contain "query properties" like `raw` instances, query builders etc.
22
+ // We take them out of `json` and store them to a hidden property $$queryProps
23
+ // in the model instance for later use.
24
+ json = splitQueryProps(model, json);
25
+ }
26
+
27
+ json = model.$parseJson(json, options);
28
+ json = model.$validate(json, options);
29
+
30
+ model.$set(json);
31
+
32
+ if (!options.skipParseRelations) {
33
+ parseRelationsIntoModelInstances(model, json, options);
34
+ }
35
+
36
+ return model;
37
+ }
38
+
39
+ function setDatabaseJson(model, json) {
40
+ json = model.$parseDatabaseJson(json);
41
+
42
+ if (json) {
43
+ const keys = Object.keys(json);
44
+
45
+ for (let i = 0, l = keys.length; i < l; ++i) {
46
+ const key = keys[i];
47
+ model[key] = json[key];
48
+ }
49
+ }
50
+
51
+ return model;
52
+ }
53
+
54
+ function setFast(model, obj) {
55
+ if (obj) {
56
+ // Don't try to set read-only properties. They can easily get here
57
+ // through `fromJson` when parsing an object that was previously
58
+ // serialized from a model instance.
59
+ const readOnlyAttr = model.constructor.getReadOnlyAttributes();
60
+ const keys = Object.keys(obj);
61
+
62
+ for (let i = 0, l = keys.length; i < l; ++i) {
63
+ const key = keys[i];
64
+ const value = obj[key];
65
+
66
+ if (
67
+ (value !== undefined || isPlainObject(obj)) &&
68
+ !isInternalProp(key) &&
69
+ !isFunction(value) &&
70
+ !readOnlyAttr.includes(key)
71
+ ) {
72
+ model[key] = value;
73
+ }
74
+ }
75
+ }
76
+
77
+ return model;
78
+ }
79
+
80
+ function setRelated(model, relation, models) {
81
+ relation = ensureRelation(model, relation);
82
+
83
+ if (relation.isOneToOne()) {
84
+ if (Array.isArray(models)) {
85
+ if (models.length === 0) {
86
+ model[relation.name] = null;
87
+ } else {
88
+ model[relation.name] = models[0] || null;
89
+ }
90
+ } else {
91
+ model[relation.name] = models || null;
92
+ }
93
+ } else {
94
+ if (!models) {
95
+ model[relation.name] = [];
96
+ } else if (Array.isArray(models)) {
97
+ model[relation.name] = models;
98
+ } else {
99
+ model[relation.name] = [models];
100
+ }
101
+ }
102
+
103
+ return model;
104
+ }
105
+
106
+ function appendRelated(model, relation, models) {
107
+ relation = ensureRelation(model, relation);
108
+
109
+ if (!model[relation.name] || relation.isOneToOne()) {
110
+ return model.$setRelated(relation, models);
111
+ } else {
112
+ if (Array.isArray(models)) {
113
+ models.forEach((it) => model[relation.name].push(it));
114
+ } else if (models) {
115
+ model[relation.name].push(models);
116
+ }
117
+ }
118
+
119
+ return model;
120
+ }
121
+
122
+ function ensureRelation(model, relation) {
123
+ if (isString(relation)) {
124
+ return model.constructor.getRelation(relation);
125
+ } else {
126
+ return relation;
127
+ }
128
+ }
129
+
130
+ module.exports = {
131
+ setFast,
132
+ setJson,
133
+ setDatabaseJson,
134
+ setRelated,
135
+ appendRelated,
136
+ };
@@ -0,0 +1,83 @@
1
+ 'use strict';
2
+
3
+ const { defineNonEnumerableProperty } = require('./modelUtils');
4
+ const { isPromise } = require('../utils/promiseUtils');
5
+
6
+ const TABLE_METADATA = '$$tableMetadata';
7
+
8
+ function fetchTableMetadata(
9
+ modelClass,
10
+ { parentBuilder = null, knex = null, force = false, table = null } = {},
11
+ ) {
12
+ // The table isn't necessarily same as `modelClass.getTableName()` for example if
13
+ // a view is queried instead.
14
+ if (!table) {
15
+ if (parentBuilder) {
16
+ table = parentBuilder.tableNameFor(modelClass);
17
+ } else {
18
+ table = modelClass.getTableName();
19
+ }
20
+ }
21
+
22
+ // Call tableMetadata first instead of accessing the cache directly beause
23
+ // tableMetadata may have been overriden.
24
+ let metadata = modelClass.tableMetadata({ table });
25
+
26
+ if (!force && metadata) {
27
+ return Promise.resolve(metadata);
28
+ }
29
+
30
+ // Memoize metadata but only for modelClass. The hasOwnProperty check
31
+ // will fail for subclasses and the value gets recreated.
32
+ if (!modelClass.hasOwnProperty(TABLE_METADATA)) {
33
+ defineNonEnumerableProperty(modelClass, TABLE_METADATA, new Map());
34
+ }
35
+
36
+ // The cache needs to be checked in addition to calling tableMetadata
37
+ // because the cache may contain a temporary promise in which case
38
+ // tableMetadata returns null.
39
+ metadata = modelClass[TABLE_METADATA].get(table);
40
+
41
+ if (!force && metadata) {
42
+ return Promise.resolve(metadata);
43
+ } else {
44
+ const promise = modelClass
45
+ .query(knex)
46
+ .childQueryOf(parentBuilder)
47
+ .columnInfo({ table })
48
+ .then((columnInfo) => {
49
+ const metadata = {
50
+ columns: Object.keys(columnInfo),
51
+ };
52
+
53
+ modelClass[TABLE_METADATA].set(table, metadata);
54
+ return metadata;
55
+ })
56
+ .catch((err) => {
57
+ modelClass[TABLE_METADATA].delete(table);
58
+ throw err;
59
+ });
60
+
61
+ modelClass[TABLE_METADATA].set(table, promise);
62
+ return promise;
63
+ }
64
+ }
65
+
66
+ function tableMetadata(modelClass, { table } = {}) {
67
+ if (modelClass.hasOwnProperty(TABLE_METADATA)) {
68
+ const metadata = modelClass[TABLE_METADATA].get(table || modelClass.getTableName());
69
+
70
+ if (isPromise(metadata)) {
71
+ return null;
72
+ } else {
73
+ return metadata;
74
+ }
75
+ } else {
76
+ return null;
77
+ }
78
+ }
79
+
80
+ module.exports = {
81
+ fetchTableMetadata,
82
+ tableMetadata,
83
+ };
@@ -0,0 +1,187 @@
1
+ 'use strict';
2
+
3
+ const { isInternalProp } = require('../utils/internalPropUtils');
4
+ const { mergeQueryProps } = require('./modelQueryProps');
5
+ const { isObject, cloneDeep, isFunction } = require('../utils/objectUtils');
6
+ const EMPTY_ARRAY = [];
7
+
8
+ function toJson(model, optIn) {
9
+ const modelClass = model.constructor;
10
+
11
+ const opt = {
12
+ virtuals: getVirtuals(optIn),
13
+ shallow: isShallow(optIn),
14
+ omit: getOmit(optIn, modelClass),
15
+ pick: null,
16
+ omitFromJson: model.$omitFromJson() || null,
17
+ cloneObjects: modelClass.cloneObjectAttributes,
18
+ };
19
+
20
+ let json = toExternalJsonImpl(model, opt);
21
+ json = model.$formatJson(json);
22
+
23
+ return json;
24
+ }
25
+
26
+ function toDatabaseJson(model, builder) {
27
+ const modelClass = model.constructor;
28
+
29
+ const opt = {
30
+ virtuals: false,
31
+ shallow: true,
32
+ omit: modelClass.getRelationNames(),
33
+ pick: getPick(modelClass),
34
+ omitFromJson: model.$omitFromDatabaseJson() || null,
35
+ cloneObjects: modelClass.cloneObjectAttributes,
36
+ };
37
+
38
+ let json = toDatabaseJsonImpl(model, opt);
39
+ json = model.$formatDatabaseJson(json);
40
+
41
+ return mergeQueryProps(model, json, opt.omitFromJson, builder);
42
+ }
43
+
44
+ function getVirtuals(opt) {
45
+ if (!opt) {
46
+ return true;
47
+ } else if (Array.isArray(opt.virtuals)) {
48
+ return opt.virtuals;
49
+ } else {
50
+ return opt.virtuals !== false;
51
+ }
52
+ }
53
+
54
+ function isShallow(opt) {
55
+ return !!opt && !!opt.shallow;
56
+ }
57
+
58
+ function getOmit(opt, modelClass) {
59
+ return isShallow(opt) ? modelClass.getRelationNames() : null;
60
+ }
61
+
62
+ function getPick(modelClass) {
63
+ const jsonSchema = modelClass.getJsonSchema();
64
+ return (jsonSchema && modelClass.pickJsonSchemaProperties && jsonSchema.properties) || null;
65
+ }
66
+
67
+ function toExternalJsonImpl(model, opt) {
68
+ const json = {};
69
+ const keys = Object.keys(model);
70
+ const vAttr = getVirtualAttributes(model, opt);
71
+
72
+ for (let i = 0, l = keys.length; i < l; ++i) {
73
+ const key = keys[i];
74
+ const value = model[key];
75
+
76
+ assignJsonValue(json, key, value, opt);
77
+ }
78
+
79
+ if (vAttr.length !== 0) {
80
+ assignVirtualAttributes(json, model, vAttr, opt);
81
+ }
82
+
83
+ return json;
84
+ }
85
+
86
+ function getVirtualAttributes(model, opt) {
87
+ if (Array.isArray(opt.virtuals)) {
88
+ return opt.virtuals;
89
+ } else if (opt.virtuals === true) {
90
+ return model.constructor.getVirtualAttributes();
91
+ } else {
92
+ return EMPTY_ARRAY;
93
+ }
94
+ }
95
+
96
+ function toDatabaseJsonImpl(model, opt) {
97
+ const json = {};
98
+ const keys = Object.keys(model);
99
+
100
+ for (let i = 0, l = keys.length; i < l; ++i) {
101
+ const key = keys[i];
102
+ const value = model[key];
103
+
104
+ assignJsonValue(json, key, value, opt);
105
+ }
106
+
107
+ return json;
108
+ }
109
+
110
+ function assignJsonValue(json, key, value, opt) {
111
+ const type = typeof value;
112
+
113
+ if (
114
+ type !== 'function' &&
115
+ type !== 'undefined' &&
116
+ !isInternalProp(key) &&
117
+ !shouldOmit(opt, key) &&
118
+ shouldPick(opt, key)
119
+ ) {
120
+ if (isObject(value)) {
121
+ json[key] = toJsonObject(value, opt);
122
+ } else {
123
+ json[key] = value;
124
+ }
125
+ }
126
+ }
127
+
128
+ function shouldOmit(opt, key) {
129
+ return (
130
+ (opt.omit !== null && opt.omit.includes(key)) ||
131
+ (opt.omitFromJson !== null && opt.omitFromJson.includes(key))
132
+ );
133
+ }
134
+
135
+ function shouldPick(opt, key) {
136
+ return opt.pick === null || key in opt.pick;
137
+ }
138
+
139
+ function assignVirtualAttributes(json, model, vAttr, opt) {
140
+ for (let i = 0, l = vAttr.length; i < l; ++i) {
141
+ const key = vAttr[i];
142
+ let value = model[key];
143
+
144
+ if (isFunction(value)) {
145
+ value = value.call(model);
146
+ }
147
+
148
+ assignJsonValue(json, key, value, opt);
149
+ }
150
+ }
151
+
152
+ function toJsonObject(value, opt) {
153
+ if (Array.isArray(value)) {
154
+ return toJsonArray(value, opt);
155
+ } else if (value.$isObjectionModel) {
156
+ // No branch for $toDatabaseJson here since there is never a need
157
+ // to have nested models in database rows.
158
+ return value.$toJson(opt);
159
+ } else if (Buffer.isBuffer(value)) {
160
+ return value;
161
+ } else if (opt.cloneObjects) {
162
+ return cloneDeep(value);
163
+ } else {
164
+ return value;
165
+ }
166
+ }
167
+
168
+ function toJsonArray(value, opt) {
169
+ const ret = new Array(value.length);
170
+
171
+ for (let i = 0, l = ret.length; i < l; ++i) {
172
+ const item = value[i];
173
+
174
+ if (isObject(item)) {
175
+ ret[i] = toJsonObject(item, opt);
176
+ } else {
177
+ ret[i] = item;
178
+ }
179
+ }
180
+
181
+ return ret;
182
+ }
183
+
184
+ module.exports = {
185
+ toJson,
186
+ toDatabaseJson,
187
+ };
@@ -0,0 +1,47 @@
1
+ 'use strict';
2
+
3
+ const hiddenProps = ['$$queryProps'];
4
+
5
+ const staticHiddenProps = [
6
+ '$$knex',
7
+ '$$validator',
8
+ '$$jsonSchema',
9
+ '$$colToProp',
10
+ '$$propToCol',
11
+ '$$relationMappings',
12
+ '$$relations',
13
+ '$$relationNames',
14
+ '$$jsonAttributes',
15
+ '$$columnNameMappers',
16
+ '$$tableMetadata',
17
+ '$$readOnlyAttributes',
18
+ '$$idRelationProperty',
19
+ '$$virtualAttributes',
20
+ ];
21
+
22
+ function defineNonEnumerableProperty(obj, prop, value) {
23
+ Object.defineProperty(obj, prop, {
24
+ enumerable: false,
25
+ writable: true,
26
+ configurable: true,
27
+ value,
28
+ });
29
+ }
30
+
31
+ function keyByProps(models, props) {
32
+ const map = new Map();
33
+
34
+ for (let i = 0, l = models.length; i < l; ++i) {
35
+ const model = models[i];
36
+ map.set(model.$propKey(props), model);
37
+ }
38
+
39
+ return map;
40
+ }
41
+
42
+ module.exports = {
43
+ hiddenProps,
44
+ staticHiddenProps,
45
+ defineNonEnumerableProperty,
46
+ keyByProps,
47
+ };