objection 3.9.1 → 4.0.0-rc.1

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 (248) hide show
  1. package/lib/dbErrors/LICENSE +21 -0
  2. package/lib/dbErrors/errorCodes/mssql.js +19 -0
  3. package/lib/dbErrors/errorCodes/mysql.js +805 -0
  4. package/lib/dbErrors/errorCodes/postgres.js +241 -0
  5. package/lib/dbErrors/errors/CheckViolationError.js +10 -0
  6. package/lib/dbErrors/errors/ConstraintViolationError.js +3 -0
  7. package/lib/dbErrors/errors/DBError.js +9 -0
  8. package/lib/dbErrors/errors/DataError.js +3 -0
  9. package/lib/dbErrors/errors/ForeignKeyViolationError.js +11 -0
  10. package/lib/dbErrors/errors/NotNullViolationError.js +12 -0
  11. package/lib/dbErrors/errors/UniqueViolationError.js +12 -0
  12. package/lib/dbErrors/index.js +59 -0
  13. package/lib/dbErrors/parsers/mssql/DBError/CheckViolationError/parser.js +28 -0
  14. package/lib/dbErrors/parsers/mssql/DBError/DataError/parser.js +25 -0
  15. package/lib/dbErrors/parsers/mssql/DBError/ForeignKeyViolationError/parser.js +39 -0
  16. package/lib/dbErrors/parsers/mssql/DBError/NotNullViolationError/parser.js +30 -0
  17. package/lib/dbErrors/parsers/mssql/DBError/UniqueViolationError/parser.js +53 -0
  18. package/lib/dbErrors/parsers/mssql/DBError/parser.js +51 -0
  19. package/lib/dbErrors/parsers/mssql/DBError/util.js +16 -0
  20. package/lib/dbErrors/parsers/mysql/DBError/ConstraintViolationError/ForeignKeyViolationError/parser.js +43 -0
  21. package/lib/dbErrors/parsers/mysql/DBError/ConstraintViolationError/NotNullViolationError/parser.js +29 -0
  22. package/lib/dbErrors/parsers/mysql/DBError/ConstraintViolationError/UniqueViolationError/parser.js +27 -0
  23. package/lib/dbErrors/parsers/mysql/DBError/ConstraintViolationError/parser.js +23 -0
  24. package/lib/dbErrors/parsers/mysql/DBError/DataError/parser.js +24 -0
  25. package/lib/dbErrors/parsers/mysql/DBError/parser.js +28 -0
  26. package/lib/dbErrors/parsers/postgres/DBError/ConstraintViolationError/CheckViolationError/parser.js +18 -0
  27. package/lib/dbErrors/parsers/postgres/DBError/ConstraintViolationError/ForeignKeyViolationError/parser.js +18 -0
  28. package/lib/dbErrors/parsers/postgres/DBError/ConstraintViolationError/NotNullViolationError/parser.js +18 -0
  29. package/lib/dbErrors/parsers/postgres/DBError/ConstraintViolationError/UniqueViolationError/parser.js +40 -0
  30. package/lib/dbErrors/parsers/postgres/DBError/ConstraintViolationError/parser.js +25 -0
  31. package/lib/dbErrors/parsers/postgres/DBError/DataError/parser.js +16 -0
  32. package/lib/dbErrors/parsers/postgres/DBError/parser.js +27 -0
  33. package/lib/dbErrors/parsers/sqlite/DBError/ConstraintViolationError/CheckViolationError/parser.js +20 -0
  34. package/lib/dbErrors/parsers/sqlite/DBError/ConstraintViolationError/ForeignKeyViolationError/parser.js +20 -0
  35. package/lib/dbErrors/parsers/sqlite/DBError/ConstraintViolationError/NotNullViolationError/parser.js +27 -0
  36. package/lib/dbErrors/parsers/sqlite/DBError/ConstraintViolationError/UniqueViolationError/parser.js +28 -0
  37. package/lib/dbErrors/parsers/sqlite/DBError/ConstraintViolationError/parser.js +24 -0
  38. package/lib/dbErrors/parsers/sqlite/DBError/parser.js +23 -0
  39. package/lib/dbErrors/utils/sqlState.js +3 -0
  40. package/lib/initialize.js +1 -7
  41. package/lib/model/AjvValidator.js +51 -117
  42. package/lib/model/Model.js +84 -59
  43. package/lib/model/ModifierNotFoundError.js +1 -7
  44. package/lib/model/NotFoundError.js +1 -7
  45. package/lib/model/RelationDoesNotExistError.js +1 -7
  46. package/lib/model/ValidationError.js +3 -10
  47. package/lib/model/Validator.js +1 -7
  48. package/lib/model/getModel.js +7 -6
  49. package/lib/model/inheritModel.js +1 -7
  50. package/lib/model/modelBindKnex.js +4 -10
  51. package/lib/model/modelClone.js +5 -11
  52. package/lib/model/modelColPropMap.js +3 -10
  53. package/lib/model/modelId.js +3 -10
  54. package/lib/model/modelJsonAttributes.js +35 -16
  55. package/lib/model/modelParseRelations.js +2 -8
  56. package/lib/model/modelQueryProps.js +11 -23
  57. package/lib/model/modelSet.js +89 -41
  58. package/lib/model/modelTableMetadata.js +4 -11
  59. package/lib/model/modelToJson.js +6 -13
  60. package/lib/model/modelUtils.js +14 -13
  61. package/lib/model/modelValidate.js +3 -9
  62. package/lib/model/modelValues.js +5 -14
  63. package/lib/model/modelVisitor.js +1 -7
  64. package/lib/objection.js +33 -71
  65. package/lib/queryBuilder/FunctionBuilder.js +4 -11
  66. package/lib/queryBuilder/InternalOptions.js +4 -9
  67. package/lib/queryBuilder/JoinBuilder.js +5 -8
  68. package/lib/queryBuilder/QueryBuilder.js +126 -95
  69. package/lib/queryBuilder/QueryBuilderBase.js +41 -123
  70. package/lib/queryBuilder/QueryBuilderContext.js +2 -8
  71. package/lib/queryBuilder/QueryBuilderContextBase.js +2 -8
  72. package/lib/queryBuilder/QueryBuilderOperationSupport.js +7 -21
  73. package/lib/queryBuilder/QueryBuilderUserContext.js +1 -7
  74. package/lib/queryBuilder/RawBuilder.js +5 -13
  75. package/lib/queryBuilder/ReferenceBuilder.js +20 -48
  76. package/lib/queryBuilder/RelationExpression.js +18 -16
  77. package/lib/queryBuilder/StaticHookArguments.js +74 -16
  78. package/lib/queryBuilder/ValueBuilder.js +11 -13
  79. package/lib/queryBuilder/getJoinBuilder.js +10 -0
  80. package/lib/queryBuilder/graph/GraphLoader.js +304 -0
  81. package/lib/queryBuilder/graph/GraphNode.js +235 -0
  82. package/lib/queryBuilder/graph/GraphOptions.js +55 -248
  83. package/lib/queryBuilder/graph/GraphPlan.js +395 -0
  84. package/lib/queryBuilder/graph/GraphUpsert.js +466 -414
  85. package/lib/queryBuilder/graph/GraphWriter.js +1263 -0
  86. package/lib/queryBuilder/join/JoinResultColumn.js +1 -7
  87. package/lib/queryBuilder/join/JoinResultParser.js +6 -11
  88. package/lib/queryBuilder/join/RelationJoiner.js +66 -84
  89. package/lib/queryBuilder/join/TableNode.js +2 -8
  90. package/lib/queryBuilder/join/TableTree.js +3 -9
  91. package/lib/queryBuilder/join/utils.js +5 -15
  92. package/lib/queryBuilder/jsonDialects/JsonDialect.js +51 -0
  93. package/lib/queryBuilder/jsonDialects/MySqlJsonDialect.js +81 -0
  94. package/lib/queryBuilder/jsonDialects/PostgresJsonDialect.js +45 -0
  95. package/lib/queryBuilder/jsonDialects/SqliteJsonDialect.js +67 -0
  96. package/lib/queryBuilder/jsonDialects/index.js +44 -0
  97. package/lib/queryBuilder/operations/DelegateOperation.js +2 -8
  98. package/lib/queryBuilder/operations/DeleteOperation.js +10 -39
  99. package/lib/queryBuilder/operations/FindByIdOperation.js +7 -12
  100. package/lib/queryBuilder/operations/FindByIdsOperation.js +4 -8
  101. package/lib/queryBuilder/operations/FindOperation.js +14 -34
  102. package/lib/queryBuilder/operations/FirstOperation.js +6 -10
  103. package/lib/queryBuilder/operations/FromOperation.js +3 -9
  104. package/lib/queryBuilder/operations/InsertAndFetchOperation.js +13 -12
  105. package/lib/queryBuilder/operations/InsertGraphAndFetchOperation.js +4 -10
  106. package/lib/queryBuilder/operations/InsertGraphOperation.js +7 -18
  107. package/lib/queryBuilder/operations/InsertOperation.js +118 -45
  108. package/lib/queryBuilder/operations/InstanceDeleteOperation.js +5 -12
  109. package/lib/queryBuilder/operations/InstanceFindOperation.js +4 -11
  110. package/lib/queryBuilder/operations/InstanceInsertOperation.js +2 -8
  111. package/lib/queryBuilder/operations/InstanceUpdateOperation.js +7 -14
  112. package/lib/queryBuilder/operations/JoinRelatedOperation.js +5 -11
  113. package/lib/queryBuilder/operations/KnexOperation.js +2 -8
  114. package/lib/queryBuilder/operations/LimitPerParentOperation.js +7 -69
  115. package/lib/queryBuilder/operations/MergeOperation.js +5 -11
  116. package/lib/queryBuilder/operations/NoneOperation.js +2 -8
  117. package/lib/queryBuilder/operations/ObjectionToKnexConvertingOperation.js +20 -49
  118. package/lib/queryBuilder/operations/OnBuildKnexOperation.js +2 -8
  119. package/lib/queryBuilder/operations/OnBuildOperation.js +2 -8
  120. package/lib/queryBuilder/operations/OnErrorOperation.js +2 -8
  121. package/lib/queryBuilder/operations/QueryBuilderOperation.js +1 -7
  122. package/lib/queryBuilder/operations/RangeOperation.js +11 -26
  123. package/lib/queryBuilder/operations/RelateOperation.js +2 -8
  124. package/lib/queryBuilder/operations/ReturningOperation.js +3 -9
  125. package/lib/queryBuilder/operations/RunAfterOperation.js +2 -12
  126. package/lib/queryBuilder/operations/RunBeforeOperation.js +2 -8
  127. package/lib/queryBuilder/operations/UnrelateOperation.js +2 -8
  128. package/lib/queryBuilder/operations/UpdateAndFetchOperation.js +14 -17
  129. package/lib/queryBuilder/operations/UpdateOperation.js +32 -132
  130. package/lib/queryBuilder/operations/UpsertGraphAndFetchOperation.js +8 -11
  131. package/lib/queryBuilder/operations/UpsertGraphOperation.js +6 -12
  132. package/lib/queryBuilder/operations/WhereCompositeOperation.js +3 -9
  133. package/lib/queryBuilder/operations/WhereGroupOperation.js +2 -8
  134. package/lib/queryBuilder/operations/eager/EagerOperation.js +3 -9
  135. package/lib/queryBuilder/operations/eager/JoinEagerOperation.js +72 -10
  136. package/lib/queryBuilder/operations/eager/NaiveEagerOperation.js +2 -8
  137. package/lib/queryBuilder/operations/eager/WhereInEagerOperation.js +23 -44
  138. package/lib/queryBuilder/operations/fieldExpressions.js +122 -0
  139. package/lib/queryBuilder/operations/jsonApi/WhereJsonHasOperation.js +20 -0
  140. package/lib/queryBuilder/operations/jsonApi/WhereJsonOperation.js +44 -0
  141. package/lib/queryBuilder/operations/jsonApi/WhereJsonTypeOperation.js +14 -0
  142. package/lib/queryBuilder/operations/select/SelectOperation.js +11 -21
  143. package/lib/queryBuilder/operations/select/Selection.js +19 -17
  144. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeMsSqlOperation.js +4 -10
  145. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeOperation.js +4 -10
  146. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeSqliteOperation.js +4 -10
  147. package/lib/queryBuilder/operations/windowOrder.js +56 -0
  148. package/lib/queryBuilder/parsers/jsonFieldExpressionParser.js +3 -7
  149. package/lib/queryBuilder/parsers/relationExpressionParser.js +42 -43
  150. package/lib/queryBuilder/parsers/relationExpressionParser.pegjs +39 -36
  151. package/lib/queryBuilder/transformations/CompositeQueryTransformation.js +2 -8
  152. package/lib/queryBuilder/transformations/QueryTransformation.js +1 -7
  153. package/lib/queryBuilder/transformations/WrapMysqlModifySubqueryTransformation.js +3 -9
  154. package/lib/queryBuilder/transformations/index.js +3 -11
  155. package/lib/queryBuilder/whereGroups.js +9 -24
  156. package/lib/queryBuilder/withoutOrder.js +4 -11
  157. package/lib/relations/Relation.js +47 -28
  158. package/lib/relations/RelationDeleteOperation.js +4 -14
  159. package/lib/relations/RelationFindOperation.js +119 -90
  160. package/lib/relations/RelationInsertOperation.js +2 -8
  161. package/lib/relations/RelationOwner.js +5 -11
  162. package/lib/relations/RelationProperty.js +4 -10
  163. package/lib/relations/RelationUpdateOperation.js +4 -14
  164. package/lib/relations/RelationWriteResultOperation.js +15 -0
  165. package/lib/relations/belongsToMany/BelongsToManyDeleteOperation.js +23 -0
  166. package/lib/relations/belongsToMany/BelongsToManyFindOperation.js +35 -0
  167. package/lib/relations/belongsToMany/BelongsToManyInsertOperation.js +28 -0
  168. package/lib/relations/belongsToMany/BelongsToManyRelateOperation.js +16 -0
  169. package/lib/relations/belongsToMany/BelongsToManyRelation.js +276 -0
  170. package/lib/relations/belongsToMany/BelongsToManyUnrelateOperation.js +11 -0
  171. package/lib/relations/belongsToOne/BelongsToOneDeleteOperation.js +2 -8
  172. package/lib/relations/belongsToOne/BelongsToOneInsertOperation.js +6 -11
  173. package/lib/relations/belongsToOne/BelongsToOneRelateOperation.js +3 -9
  174. package/lib/relations/belongsToOne/BelongsToOneRelation.js +8 -19
  175. package/lib/relations/belongsToOne/BelongsToOneUnrelateOperation.js +53 -27
  176. package/lib/relations/hasMany/HasManyInsertOperation.js +5 -10
  177. package/lib/relations/hasMany/HasManyRelateOperation.js +5 -11
  178. package/lib/relations/hasMany/HasManyRelation.js +9 -11
  179. package/lib/relations/hasMany/HasManyUnrelateOperation.js +3 -9
  180. package/lib/relations/hasOne/HasOneRelation.js +2 -8
  181. package/lib/relations/hasOneThrough/HasOneThroughRelation.js +2 -8
  182. package/lib/relations/manyToMany/ManyToManyModifyMixin.js +10 -15
  183. package/lib/relations/manyToMany/ManyToManyMySqlModifyMixin.js +2 -8
  184. package/lib/relations/manyToMany/ManyToManyRelation.js +82 -50
  185. package/lib/relations/manyToMany/ManyToManySqliteModifyMixin.js +2 -8
  186. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperation.js +5 -9
  187. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperationBase.js +2 -8
  188. package/lib/relations/manyToMany/delete/ManyToManyDeleteSqliteOperation.js +3 -9
  189. package/lib/relations/manyToMany/find/ManyToManyFindOperation.js +20 -59
  190. package/lib/relations/manyToMany/insert/ManyToManyInsertOperation.js +6 -11
  191. package/lib/relations/manyToMany/relate/ManyToManyRelateOperation.js +4 -10
  192. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateMySqlOperation.js +3 -9
  193. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperation.js +5 -9
  194. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperationBase.js +3 -9
  195. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateSqliteOperation.js +3 -9
  196. package/lib/relations/manyToMany/update/ManyToManyUpdateMySqlOperation.js +3 -9
  197. package/lib/relations/manyToMany/update/ManyToManyUpdateOperation.js +5 -9
  198. package/lib/relations/manyToMany/update/ManyToManyUpdateOperationBase.js +64 -72
  199. package/lib/relations/manyToMany/update/ManyToManyUpdateSqliteOperation.js +3 -9
  200. package/lib/transaction.js +3 -9
  201. package/lib/utils/assert.js +3 -11
  202. package/lib/utils/buildUtils.js +2 -8
  203. package/lib/utils/classUtils.js +1 -7
  204. package/lib/utils/createModifier.js +2 -8
  205. package/lib/utils/identifierMapping.js +23 -27
  206. package/lib/utils/internalPropUtils.js +1 -7
  207. package/lib/utils/knexUtils.js +84 -40
  208. package/lib/utils/mixin.js +3 -10
  209. package/lib/utils/normalizeIds.js +2 -8
  210. package/lib/utils/objectUtils.js +41 -60
  211. package/lib/utils/parseFieldExpression.js +16 -16
  212. package/lib/utils/promiseUtils/after.js +2 -8
  213. package/lib/utils/promiseUtils/afterReturn.js +2 -8
  214. package/lib/utils/promiseUtils/index.js +7 -16
  215. package/lib/utils/promiseUtils/isPromise.js +2 -8
  216. package/lib/utils/promiseUtils/map.js +2 -8
  217. package/lib/utils/promiseUtils/mapAfterAllReturn.js +2 -8
  218. package/lib/utils/promiseUtils/try.js +2 -8
  219. package/lib/utils/resolveModel.js +10 -17
  220. package/lib/utils/tmpColumnUtils.js +2 -9
  221. package/lib/utils/warnings.js +2 -14
  222. package/package.json +25 -17
  223. package/typings/objection/index.d.ts +3217 -2179
  224. package/lib/.eslintrc.json +0 -8
  225. package/lib/model/graph/ModelGraph.js +0 -80
  226. package/lib/model/graph/ModelGraphBuilder.js +0 -241
  227. package/lib/model/graph/ModelGraphEdge.js +0 -52
  228. package/lib/model/graph/ModelGraphNode.js +0 -238
  229. package/lib/queryBuilder/graph/GraphAction.js +0 -69
  230. package/lib/queryBuilder/graph/GraphData.js +0 -53
  231. package/lib/queryBuilder/graph/GraphFetcher.js +0 -197
  232. package/lib/queryBuilder/graph/GraphNodeDbExistence.js +0 -184
  233. package/lib/queryBuilder/graph/GraphOperation.js +0 -27
  234. package/lib/queryBuilder/graph/delete/GraphDelete.js +0 -73
  235. package/lib/queryBuilder/graph/delete/GraphDeleteAction.js +0 -88
  236. package/lib/queryBuilder/graph/insert/DeferredRelationGraphInsertAction.js +0 -58
  237. package/lib/queryBuilder/graph/insert/GraphInsert.js +0 -296
  238. package/lib/queryBuilder/graph/insert/GraphInsertAction.js +0 -233
  239. package/lib/queryBuilder/graph/insert/JoinRowGraphInsertAction.js +0 -92
  240. package/lib/queryBuilder/graph/patch/GraphPatch.js +0 -20
  241. package/lib/queryBuilder/graph/patch/GraphPatchAction.js +0 -289
  242. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsert.js +0 -31
  243. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsertAction.js +0 -126
  244. package/lib/queryBuilder/operations/jsonApi/WhereJsonHasPostgresOperation.js +0 -30
  245. package/lib/queryBuilder/operations/jsonApi/WhereJsonNotObjectPostgresOperation.js +0 -37
  246. package/lib/queryBuilder/operations/jsonApi/WhereJsonPostgresOperation.js +0 -62
  247. package/lib/queryBuilder/operations/jsonApi/postgresJsonApi.js +0 -192
  248. package/lib/utils/wrapDbError.js +0 -64
@@ -1,20 +1,18 @@
1
- 'use strict';
2
-
3
- const Ajv = require('ajv');
4
- const addFormats = require('ajv-formats');
5
- const { Validator } = require('./Validator');
6
- const { ValidationErrorType } = require('../model/ValidationError');
7
- const {
1
+ import Ajv from 'ajv';
2
+ import addFormats from 'ajv-formats';
3
+ import { Validator } from './Validator.js';
4
+ import { ValidationErrorType } from '../model/ValidationError.js';
5
+ import {
8
6
  isObject,
9
7
  hasOwn,
10
8
  once,
11
- cloneDeep: lodashCloneDeep,
9
+ cloneDeep as lodashCloneDeep,
12
10
  omit,
13
- } = require('../utils/objectUtils');
14
- const { parseFieldExpression, isFieldExpressionKey } = require('../utils/parseFieldExpression');
15
- const { getQueryPropKeys } = require('./modelQueryProps');
11
+ } from '../utils/objectUtils.js';
12
+ import { parseFieldExpression, isFieldExpressionKey } from '../utils/parseFieldExpression.js';
13
+ import { getQueryPropKeys } from './modelQueryProps.js';
16
14
 
17
- class AjvValidator extends Validator {
15
+ export class AjvValidator extends Validator {
18
16
  static init(self, conf) {
19
17
  super.init(self, conf);
20
18
 
@@ -85,60 +83,27 @@ class AjvValidator extends Validator {
85
83
  return json;
86
84
  }
87
85
 
86
+ const modelClass = model.constructor;
87
+ const validator = this.getValidator(
88
+ modelClass,
89
+ ctx.jsonSchema,
90
+ !!options.patch,
91
+ options.patch ? null : getMissingQueryPropKeys(model, json, ctx.jsonSchema),
92
+ );
93
+
88
94
  // We need to clone the input json if we are about to set default values.
89
95
  if (!options.mutable && !options.patch && setsDefaultValues(ctx.jsonSchema)) {
90
96
  json = cloneDeep(json);
91
97
  }
92
98
 
93
- // Patch and update objects can contain field expression keys like `'meta:b'`
94
- // that update a single property inside a json column. Validate them against
95
- // the nested schema by converting them into nested objects like
96
- // `{ meta: { b: value } }`.
97
- const queryPropKeys = getQueryPropKeys(model);
98
- const fieldExpressions = nestFieldExpressions(json, queryPropKeys, ctx.jsonSchema);
99
- let validationJson = fieldExpressions ? fieldExpressions.json : json;
99
+ // Patch objects can contain field expression keys like `'meta:b'` that update
100
+ // a single property inside a json column. Validate them against the nested
101
+ // schema by converting them into nested objects like `{ meta: { b: value } }`.
102
+ const fieldExpressions = options.patch ? nestFieldExpressions(json, ctx.jsonSchema) : null;
103
+ const validationJson = fieldExpressions ? fieldExpressions.json : json;
100
104
 
101
- const modelClass = model.constructor;
102
- const validate = (json, isPatchObject, givenKeys = []) => {
103
- const validator = this.getValidator(
104
- modelClass,
105
- ctx.jsonSchema,
106
- isPatchObject,
107
- isPatchObject ? null : getRequiredKeysGivenOutside(json, ctx.jsonSchema, givenKeys),
108
- );
109
- validator.call(model, json);
110
- return validator.errors || [];
111
- };
112
-
113
- let errors;
114
-
115
- if (options.patch) {
116
- errors = validate(validationJson, true);
117
- } else if (fieldExpressions && fieldExpressions.columns.length > 0) {
118
- // Field expressions only write parts of their json columns. Validate these
119
- // parts like patches, and the rest normally, with the columns counted as
120
- // present like the query properties.
121
- const { columns } = fieldExpressions;
122
- const columnsJson = Object.fromEntries(
123
- columns
124
- .filter((column) => hasOwn(validationJson, column))
125
- .map((column) => [column, validationJson[column]]),
126
- );
127
- const restJson = omit(validationJson, columns);
128
-
129
- errors = [
130
- ...validate(columnsJson, true),
131
- ...validate(restJson, false, [...queryPropKeys, ...columns]),
132
- ];
133
-
134
- // Combine the parts again, without the defaults that Ajv set for the
135
- // columns in `restJson`.
136
- validationJson = Object.assign(restJson, columnsJson);
137
- } else {
138
- errors = validate(validationJson, false, queryPropKeys);
139
- }
140
-
141
- const error = parseValidationError(errors, modelClass, options, this.ajvOptions);
105
+ validator.call(model, validationJson);
106
+ const error = parseValidationError(validator.errors, modelClass, options, this.ajvOptions);
142
107
 
143
108
  if (error) {
144
109
  throw error;
@@ -146,7 +111,7 @@ class AjvValidator extends Validator {
146
111
 
147
112
  if (fieldExpressions) {
148
113
  // Copy back the changes made by Ajv options like `coerceTypes` and `removeAdditional`.
149
- unnestFieldExpressions(json, validationJson, fieldExpressions);
114
+ unnestFieldExpressions(json, fieldExpressions);
150
115
  }
151
116
 
152
117
  return json;
@@ -187,8 +152,7 @@ class AjvValidator extends Validator {
187
152
  normalValidator: null,
188
153
 
189
154
  // Validators created for the schema object without the `required`
190
- // properties that are given outside the json, as query properties or
191
- // json columns written by field expressions, keyed by their names.
155
+ // properties that are given as query properties, keyed by their names.
192
156
  queryPropValidators: null,
193
157
  };
194
158
 
@@ -318,7 +282,7 @@ function parseValidationError(errors, modelClass, options, ajvOptions) {
318
282
  }
319
283
  }
320
284
 
321
- const key = `${options.dataPath || ''}${path}`.substring(1);
285
+ const key = `${options.dataPath || ''}${path}`.replace(/^\./, '');
322
286
 
323
287
  // More than one error can occur for the same key in Ajv, merge them in the array:
324
288
  const array = errorHash[key] || (errorHash[key] = []);
@@ -352,11 +316,11 @@ function parseValidationError(errors, modelClass, options, ajvOptions) {
352
316
  });
353
317
  }
354
318
 
355
- function nestFieldExpressions(json, queryPropKeys, jsonSchema) {
319
+ function nestFieldExpressions(json, jsonSchema) {
356
320
  const isFieldExpression = (key) => isFieldExpressionKey(key, jsonSchema.properties);
357
321
  const keys = Object.keys(json);
358
322
 
359
- if (!keys.some(isFieldExpression) && !queryPropKeys.some(isFieldExpression)) {
323
+ if (!keys.some(isFieldExpression)) {
360
324
  return null;
361
325
  }
362
326
 
@@ -365,15 +329,6 @@ function nestFieldExpressions(json, queryPropKeys, jsonSchema) {
365
329
  // The objects created here for the nested paths. Other objects are values
366
330
  // of the input json and must not be modified.
367
331
  const createdObjects = new Set();
368
- // The json columns that are only written partially, by field expressions in
369
- // the json or the query properties.
370
- const columns = new Set();
371
-
372
- const addColumn = (expression) => {
373
- if (expression && !hasOwn(json, expression.column)) {
374
- columns.add(expression.column);
375
- }
376
- };
377
332
 
378
333
  for (const key of keys) {
379
334
  if (!isFieldExpression(key)) {
@@ -384,10 +339,7 @@ function nestFieldExpressions(json, queryPropKeys, jsonSchema) {
384
339
 
385
340
  for (const key of keys) {
386
341
  if (isFieldExpression(key)) {
387
- const expression = parseFieldExpressionKey(key);
388
- // Not a valid field expression, validate it as a top-level property:
389
- const path = expression ? expression.path : [key];
390
- addColumn(expression);
342
+ const path = fieldExpressionPath(key);
391
343
 
392
344
  // Field expressions with array access, and those that conflict with other
393
345
  // keys of the patch, can't be validated without the current value of the
@@ -398,16 +350,10 @@ function nestFieldExpressions(json, queryPropKeys, jsonSchema) {
398
350
  }
399
351
  }
400
352
 
401
- for (const key of queryPropKeys) {
402
- if (isFieldExpression(key)) {
403
- addColumn(parseFieldExpressionKey(key));
404
- }
405
- }
406
-
407
- return { json: nested, paths, columns: [...columns] };
353
+ return { json: nested, paths };
408
354
  }
409
355
 
410
- function unnestFieldExpressions(json, nested, { paths, columns }) {
356
+ function unnestFieldExpressions(json, { json: nested, paths }) {
411
357
  for (const [key, path] of paths) {
412
358
  let value = nested;
413
359
  let found = true;
@@ -429,35 +375,25 @@ function unnestFieldExpressions(json, nested, { paths, columns }) {
429
375
  json[key] = value;
430
376
  }
431
377
  }
432
-
433
- // Copy over the default values that Ajv set for missing properties, but not
434
- // the json columns written by the field expressions.
435
- for (const key of Object.keys(nested)) {
436
- if (!paths.has(key) && !columns.includes(key)) {
437
- json[key] = nested[key];
438
- }
439
- }
440
378
  }
441
379
 
442
- // Parse a field expression key into its json column and nested path, with the
443
- // path set to `null` if the key accesses array elements.
444
- function parseFieldExpressionKey(key) {
380
+ function fieldExpressionPath(key) {
445
381
  let parsed;
446
382
 
447
383
  try {
448
384
  parsed = parseFieldExpression(key);
449
385
  } catch (err) {
450
- return null;
386
+ // Not a valid field expression, validate it as a top-level property.
387
+ return [key];
451
388
  }
452
389
 
453
- const { column, access } = parsed;
454
390
  // Numeric keys like the `0` in `tags:0` also access array elements when the
455
391
  // json value is an array, so treat them like `[0]`.
456
- const isArrayAccess = access.some(({ type, ref }) => type !== 'object' || /^-?\d+$/.test(ref));
457
- return {
458
- column,
459
- path: isArrayAccess ? null : [column, ...access.map(({ ref }) => String(ref))],
460
- };
392
+ if (parsed.access.some((access) => access.type !== 'object' || /^-?\d+$/.test(access.ref))) {
393
+ return null;
394
+ }
395
+
396
+ return [parsed.column, ...parsed.access.map((access) => String(access.ref))];
461
397
  }
462
398
 
463
399
  function setPath(obj, path, value, createdObjects) {
@@ -537,20 +473,22 @@ function objectHasDefaults(obj) {
537
473
  return false;
538
474
  }
539
475
 
540
- // Returns the `keys` that are required by the schema but given outside of
541
- // `json`, sorted, or `null` if there are none. Query properties (`raw()`,
542
- // `val()`, `ref()`, subqueries...) are split from the json before validation,
543
- // but they do provide a value for the property, and so do field expressions
544
- // for their json columns.
545
- function getRequiredKeysGivenOutside(json, jsonSchema, keys) {
476
+ // Returns the keys of the query properties of `model` (`raw()`, `val()`,
477
+ // `ref()`, subqueries...) that are required by the schema but missing from
478
+ // `json`, sorted, or `null` if there are none. Query properties are split from
479
+ // the json before validation, but they do provide a value for the property.
480
+ function getMissingQueryPropKeys(model, json, jsonSchema) {
546
481
  const required = jsonSchema.required;
547
482
 
548
483
  if (!Array.isArray(required) || required.length === 0) {
549
484
  return null;
550
485
  }
551
486
 
552
- const givenKeys = required.filter((key) => keys.includes(key) && !hasOwn(json, key));
553
- return givenKeys.length > 0 ? givenKeys.sort() : null;
487
+ const keys = getQueryPropKeys(model).filter(
488
+ (key) => required.includes(key) && !hasOwn(json, key),
489
+ );
490
+
491
+ return keys.length > 0 ? keys.sort() : null;
554
492
  }
555
493
 
556
494
  function jsonSchemaWithoutRequiredKeys(jsonSchema, keys) {
@@ -647,7 +585,3 @@ function subSchemaWithoutRequired(jsonSchema, prop) {
647
585
  function matchesAnything(schema) {
648
586
  return schema === true || (isObject(schema) && Object.keys(schema).length === 0);
649
587
  }
650
-
651
- module.exports = {
652
- AjvValidator,
653
- };
@@ -1,51 +1,54 @@
1
- 'use strict';
2
-
3
- const { clone } = require('./modelClone');
4
- const { bindKnex } = require('./modelBindKnex');
5
- const { validate } = require('./modelValidate');
6
- const { isMsSql } = require('../utils/knexUtils');
7
- const { visitModels } = require('./modelVisitor');
8
- const { hasId, getSetId } = require('./modelId');
9
- const { map: promiseMap } = require('../utils/promiseUtils');
10
- const { toJson, toDatabaseJson } = require('./modelToJson');
11
- const { values, propKey, hasProps } = require('./modelValues');
12
- const { defineNonEnumerableProperty } = require('./modelUtils');
13
- const { parseRelationsIntoModelInstances } = require('./modelParseRelations');
14
- const { removeOverriddenQueryProps } = require('./modelQueryProps');
15
- const { fetchTableMetadata, tableMetadata } = require('./modelTableMetadata');
16
- const { asArray, isFunction, isString, asSingle } = require('../utils/objectUtils');
17
- const { setJson, setFast, setRelated, appendRelated, setDatabaseJson } = require('./modelSet');
18
- const {
1
+ import { clone } from './modelClone.js';
2
+ import { bindKnex } from './modelBindKnex.js';
3
+ import { validate } from './modelValidate.js';
4
+ import { isMsSql } from '../utils/knexUtils.js';
5
+ import { visitModels } from './modelVisitor.js';
6
+ import { hasId, getSetId } from './modelId.js';
7
+ import { map as promiseMap } from '../utils/promiseUtils/index.js';
8
+ import { toJson, toDatabaseJson } from './modelToJson.js';
9
+ import { values, propKey, hasProps } from './modelValues.js';
10
+ import { defineNonEnumerableProperty } from './modelUtils.js';
11
+ import { parseRelationsIntoModelInstances } from './modelParseRelations.js';
12
+ import { removeOverriddenQueryProps } from './modelQueryProps.js';
13
+ import { isFieldExpressionKey } from '../utils/parseFieldExpression.js';
14
+ import { fetchTableMetadata, tableMetadata } from './modelTableMetadata.js';
15
+ import { asArray, isFunction, isString, asSingle } from '../utils/objectUtils.js';
16
+ import { setJson, setFast, setRelated, appendRelated, setDatabaseJson } from './modelSet.js';
17
+ import {
19
18
  getJsonAttributes,
20
19
  parseJsonAttributes,
21
20
  formatJsonAttributes,
22
- } = require('./modelJsonAttributes');
23
- const { columnNameToPropertyName, propertyNameToColumnName } = require('./modelColPropMap');
24
-
25
- const { raw } = require('../queryBuilder/RawBuilder');
26
- const { ref } = require('../queryBuilder/ReferenceBuilder');
27
- const { fn } = require('../queryBuilder/FunctionBuilder');
28
-
29
- const { AjvValidator } = require('./AjvValidator');
30
- const { QueryBuilder } = require('../queryBuilder/QueryBuilder');
31
- const { NotFoundError } = require('./NotFoundError');
32
- const { ValidationError } = require('./ValidationError');
33
- const { ModifierNotFoundError } = require('./ModifierNotFoundError');
34
- const { RelationProperty } = require('../relations/RelationProperty');
35
- const { RelationOwner } = require('../relations/RelationOwner');
36
-
37
- const { HasOneRelation } = require('../relations/hasOne/HasOneRelation');
38
- const { HasManyRelation } = require('../relations/hasMany/HasManyRelation');
39
- const { ManyToManyRelation } = require('../relations/manyToMany/ManyToManyRelation');
40
- const { BelongsToOneRelation } = require('../relations/belongsToOne/BelongsToOneRelation');
41
- const { HasOneThroughRelation } = require('../relations/hasOneThrough/HasOneThroughRelation');
42
-
43
- const { InstanceFindOperation } = require('../queryBuilder/operations/InstanceFindOperation');
44
- const { InstanceInsertOperation } = require('../queryBuilder/operations/InstanceInsertOperation');
45
- const { InstanceUpdateOperation } = require('../queryBuilder/operations/InstanceUpdateOperation');
46
- const { InstanceDeleteOperation } = require('../queryBuilder/operations/InstanceDeleteOperation');
47
-
48
- class Model {
21
+ } from './modelJsonAttributes.js';
22
+ import { columnNameToPropertyName, propertyNameToColumnName } from './modelColPropMap.js';
23
+
24
+ import { raw } from '../queryBuilder/RawBuilder.js';
25
+ import { ref } from '../queryBuilder/ReferenceBuilder.js';
26
+ import { fn } from '../queryBuilder/FunctionBuilder.js';
27
+
28
+ import { AjvValidator } from './AjvValidator.js';
29
+ import { QueryBuilder } from '../queryBuilder/QueryBuilder.js';
30
+ import { NotFoundError } from './NotFoundError.js';
31
+ import { ValidationError } from './ValidationError.js';
32
+ import { ModifierNotFoundError } from './ModifierNotFoundError.js';
33
+ import { RelationProperty } from '../relations/RelationProperty.js';
34
+ import { RelationOwner } from '../relations/RelationOwner.js';
35
+ import { RelationWriteResultOperation } from '../relations/RelationWriteResultOperation.js';
36
+
37
+ import { HasOneRelation } from '../relations/hasOne/HasOneRelation.js';
38
+ import { HasManyRelation } from '../relations/hasMany/HasManyRelation.js';
39
+ import { ManyToManyRelation } from '../relations/manyToMany/ManyToManyRelation.js';
40
+ import { BelongsToOneRelation } from '../relations/belongsToOne/BelongsToOneRelation.js';
41
+ import { HasOneThroughRelation } from '../relations/hasOneThrough/HasOneThroughRelation.js';
42
+ import { BelongsToManyRelation } from '../relations/belongsToMany/BelongsToManyRelation.js';
43
+
44
+ import { InstanceFindOperation } from '../queryBuilder/operations/InstanceFindOperation.js';
45
+ import { InstanceInsertOperation } from '../queryBuilder/operations/InstanceInsertOperation.js';
46
+ import { InstanceUpdateOperation } from '../queryBuilder/operations/InstanceUpdateOperation.js';
47
+ import { InstanceDeleteOperation } from '../queryBuilder/operations/InstanceDeleteOperation.js';
48
+ import { transaction } from '../transaction.js';
49
+ import { setModel } from './getModel.js';
50
+
51
+ export class Model {
49
52
  get $modelClass() {
50
53
  return this.constructor;
51
54
  }
@@ -95,23 +98,27 @@ class Model {
95
98
  // Do nothing by default.
96
99
  }
97
100
 
98
- $parseDatabaseJson(json) {
101
+ // Queries pass their `knex` in `options`, to parse JSON attributes depending on
102
+ // the driver. Without it, the source of `json` is unknown.
103
+ $parseDatabaseJson(json, options) {
99
104
  const columnNameMappers = this.constructor.getColumnNameMappers();
100
105
 
101
106
  if (columnNameMappers) {
102
107
  json = columnNameMappers.parse(json);
103
108
  }
104
109
 
105
- return parseJsonAttributes(json, this.constructor);
110
+ return parseJsonAttributes(json, this.constructor, options?.knex);
106
111
  }
107
112
 
108
113
  $formatDatabaseJson(json) {
109
- const columnNameMappers = this.constructor.getColumnNameMappers();
114
+ const modelClass = this.constructor;
115
+ const columnNameMappers = modelClass.getColumnNameMappers();
110
116
 
111
- json = formatJsonAttributes(json, this.constructor);
117
+ json = formatJsonAttributes(json, modelClass);
112
118
 
113
119
  if (columnNameMappers) {
114
- json = columnNameMappers.format(json);
120
+ const properties = modelClass.getJsonSchema()?.properties;
121
+ json = columnNameMappers.format(json, (key) => isFieldExpressionKey(key, properties));
115
122
  }
116
123
 
117
124
  return json;
@@ -129,8 +136,8 @@ class Model {
129
136
  return setJson(this, json, options);
130
137
  }
131
138
 
132
- $setDatabaseJson(json) {
133
- return setDatabaseJson(this, json);
139
+ $setDatabaseJson(json, options) {
140
+ return setDatabaseJson(this, json, options);
134
141
  }
135
142
 
136
143
  $set(obj) {
@@ -266,9 +273,12 @@ class Model {
266
273
  return model;
267
274
  }
268
275
 
269
- static fromDatabaseJson(json) {
276
+ static fromDatabaseJson(json, options) {
270
277
  const model = new this();
271
- model.$setDatabaseJson(json || {});
278
+ model.$setDatabaseJson(json || {}, options);
279
+ // Mark models loaded from the database, as their missing properties weren't
280
+ // selected, e.g. the join properties of relations (#1832).
281
+ defineNonEnumerableProperty(model, '$$isFromDatabase', true);
272
282
  return model;
273
283
  }
274
284
 
@@ -531,7 +541,6 @@ class Model {
531
541
  }
532
542
 
533
543
  static startTransaction(knexOrTrx) {
534
- const { transaction } = require('../transaction');
535
544
  return transaction.start(knexOrTrx || this.knex());
536
545
  }
537
546
 
@@ -702,11 +711,14 @@ Object.defineProperties(Model.prototype, {
702
711
 
703
712
  Model.QueryBuilder = QueryBuilder;
704
713
 
714
+ setModel(Model);
715
+
705
716
  Model.HasOneRelation = HasOneRelation;
706
717
  Model.HasManyRelation = HasManyRelation;
707
718
  Model.ManyToManyRelation = ManyToManyRelation;
708
719
  Model.BelongsToOneRelation = BelongsToOneRelation;
709
720
  Model.HasOneThroughRelation = HasOneThroughRelation;
721
+ Model.BelongsToManyRelation = BelongsToManyRelation;
710
722
 
711
723
  Model.JoinEagerAlgorithm = 'JoinEagerAlgorithm';
712
724
  Model.NaiveEagerAlgorithm = 'NaiveEagerAlgorithm';
@@ -735,6 +747,7 @@ Model.defaultGraphOptions = null;
735
747
  Model.defaultFindOptions = Object.freeze({});
736
748
  Model.modifiers = null;
737
749
  Model.useLimitInFirst = false;
750
+ Model.jsonColumnFormat = 'auto';
738
751
  Model.columnNameMappers = null;
739
752
  Model.relatedFindQueryMutates = false;
740
753
  Model.relatedInsertQueryMutates = false;
@@ -774,6 +787,13 @@ function instanceQuery({ instance, transaction }) {
774
787
  function relatedQuery({ modelClass, relationName, transaction, alwaysReturnArray } = {}) {
775
788
  const relation = modelClass.getRelation(relationName);
776
789
  const relatedModelClass = relation.relatedModelClass;
790
+ // Writes to a to-one relation of one owner resolve to one model with
791
+ // `returning()`, like its finds:
792
+ const addWriteResult = (builder) => {
793
+ if (!alwaysReturnArray && relation.isOneToOne()) {
794
+ builder.addOperation(new RelationWriteResultOperation('relationWriteResult'), []);
795
+ }
796
+ };
777
797
 
778
798
  return relatedModelClass
779
799
  .query(transaction)
@@ -789,6 +809,12 @@ function relatedQuery({ modelClass, relationName, transaction, alwaysReturnArray
789
809
  operation.alwaysReturnArray = alwaysReturnArray;
790
810
  operation.alias = isSubQuery ? relation.name : null;
791
811
 
812
+ if (operation.assignResultToOwner) {
813
+ // Assign what the query returns last, after all other `runAfter()`
814
+ // callbacks of the query.
815
+ builder.runAfter((result, builder) => operation.assignResult(builder, result));
816
+ }
817
+
792
818
  return operation;
793
819
  })
794
820
  .insertOperationFactory((builder) => {
@@ -800,14 +826,17 @@ function relatedQuery({ modelClass, relationName, transaction, alwaysReturnArray
800
826
  })
801
827
  .updateOperationFactory((builder) => {
802
828
  const owner = RelationOwner.create(builder.for());
829
+ addWriteResult(builder);
803
830
  return relation.update(builder, owner);
804
831
  })
805
832
  .patchOperationFactory((builder) => {
806
833
  const owner = RelationOwner.create(builder.for());
834
+ addWriteResult(builder);
807
835
  return relation.patch(builder, owner);
808
836
  })
809
837
  .deleteOperationFactory((builder) => {
810
838
  const owner = RelationOwner.create(builder.for());
839
+ addWriteResult(builder);
811
840
  return relation.delete(builder, owner);
812
841
  })
813
842
  .relateOperationFactory((builder) => {
@@ -923,7 +952,3 @@ function asPropsArray(props) {
923
952
  }
924
953
  return props;
925
954
  }
926
-
927
- module.exports = {
928
- Model,
929
- };
@@ -1,12 +1,6 @@
1
- 'use strict';
2
-
3
- class ModifierNotFoundError extends Error {
1
+ export class ModifierNotFoundError extends Error {
4
2
  constructor(modifierName) {
5
3
  super(`Unable to determine modify function from provided value: "${modifierName}".`);
6
4
  this.modifierName = modifierName;
7
5
  }
8
6
  }
9
-
10
- module.exports = {
11
- ModifierNotFoundError,
12
- };
@@ -1,6 +1,4 @@
1
- 'use strict';
2
-
3
- class NotFoundError extends Error {
1
+ export class NotFoundError extends Error {
4
2
  constructor({ modelClass, data = {}, statusCode = 404, ...rest } = {}) {
5
3
  super(rest.message || 'NotFoundError');
6
4
 
@@ -17,7 +15,3 @@ class NotFoundError extends Error {
17
15
  });
18
16
  }
19
17
  }
20
-
21
- module.exports = {
22
- NotFoundError,
23
- };
@@ -1,6 +1,4 @@
1
- 'use strict';
2
-
3
- class RelationDoesNotExistError extends Error {
1
+ export class RelationDoesNotExistError extends Error {
4
2
  constructor(relationName) {
5
3
  super(`unknown relation "${relationName}" in a relation expression`);
6
4
 
@@ -8,7 +6,3 @@ class RelationDoesNotExistError extends Error {
8
6
  this.relationName = relationName;
9
7
  }
10
8
  }
11
-
12
- module.exports = {
13
- RelationDoesNotExistError,
14
- };
@@ -1,15 +1,13 @@
1
- 'use strict';
1
+ import { asArray, isString } from '../utils/objectUtils.js';
2
2
 
3
- const { asArray, isString } = require('../utils/objectUtils');
4
-
5
- const ValidationErrorType = {
3
+ export const ValidationErrorType = {
6
4
  ModelValidation: 'ModelValidation',
7
5
  RelationExpression: 'RelationExpression',
8
6
  UnallowedRelation: 'UnallowedRelation',
9
7
  InvalidGraph: 'InvalidGraph',
10
8
  };
11
9
 
12
- class ValidationError extends Error {
10
+ export class ValidationError extends Error {
13
11
  static get Type() {
14
12
  return ValidationErrorType;
15
13
  }
@@ -47,8 +45,3 @@ function message(it) {
47
45
  return it.message;
48
46
  }
49
47
  }
50
-
51
- module.exports = {
52
- ValidationError,
53
- ValidationErrorType,
54
- };
@@ -1,6 +1,4 @@
1
- 'use strict';
2
-
3
- class Validator {
1
+ export class Validator {
4
2
  constructor(...args) {
5
3
  this.constructor.init(this, ...args);
6
4
  }
@@ -20,7 +18,3 @@ class Validator {
20
18
  model.$afterValidate(json, options);
21
19
  }
22
20
  }
23
-
24
- module.exports = {
25
- Validator,
26
- };
@@ -1,9 +1,10 @@
1
- 'use strict';
2
-
3
- // A small helper method for cached lazy-importing of the Model class.
1
+ // A small helper for lazy access to the Model class, for modules that the Model
2
+ // module imports itself. Importing Model.js there would create a circular import,
3
+ // so Model.js registers itself here instead.
4
4
  let Model;
5
- const getModel = () => Model || (Model = require('./Model').Model);
6
5
 
7
- module.exports = {
8
- getModel,
6
+ export const getModel = () => Model;
7
+
8
+ export const setModel = (model) => {
9
+ Model = model;
9
10
  };
@@ -1,8 +1,6 @@
1
- 'use strict';
2
-
3
1
  const cache = new Map();
4
2
 
5
- function inheritModel(modelClass) {
3
+ export function inheritModel(modelClass) {
6
4
  let inherit = cache.get(modelClass.name);
7
5
 
8
6
  if (!inherit) {
@@ -22,7 +20,3 @@ function createClassInheritor(className) {
22
20
  `,
23
21
  );
24
22
  }
25
-
26
- module.exports = {
27
- inheritModel,
28
- };