objection 3.9.0 → 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 +43 -27
  57. package/lib/model/modelSet.js +89 -41
  58. package/lib/model/modelTableMetadata.js +4 -11
  59. package/lib/model/modelToJson.js +8 -23
  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 -410
  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 +13 -35
  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 -43
  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 +39 -125
  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 +8 -9
  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 +79 -64
  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 +29 -14
  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 +25 -14
  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 -253
  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 -199
  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 -57
  237. package/lib/queryBuilder/graph/insert/GraphInsert.js +0 -257
  238. package/lib/queryBuilder/graph/insert/GraphInsertAction.js +0 -238
  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 -277
  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 -50
@@ -1,10 +1,8 @@
1
- 'use strict';
1
+ import { inheritModel } from './inheritModel.js';
2
+ import { staticHiddenProps } from './modelUtils.js';
3
+ import { defineNonEnumerableProperty } from './modelUtils.js';
2
4
 
3
- const { inheritModel } = require('./inheritModel');
4
- const { staticHiddenProps } = require('./modelUtils');
5
- const { defineNonEnumerableProperty } = require('./modelUtils');
6
-
7
- function bindKnex(modelClass, knex) {
5
+ export function bindKnex(modelClass, knex) {
8
6
  let BoundModelClass = getBoundModelFromCache(modelClass, knex);
9
7
 
10
8
  if (BoundModelClass === null) {
@@ -77,7 +75,3 @@ function bindRelations(modelClass, BoundModelClass, knex) {
77
75
 
78
76
  return BoundModelClass;
79
77
  }
80
-
81
- module.exports = {
82
- bindKnex,
83
- };
@@ -1,11 +1,9 @@
1
- 'use strict';
1
+ import { isObject, cloneDeep } from '../utils/objectUtils.js';
2
+ import { hiddenProps } from './modelUtils.js';
3
+ import { defineNonEnumerableProperty } from './modelUtils.js';
4
+ import { isInternalProp } from '../utils/internalPropUtils.js';
2
5
 
3
- const { isObject, cloneDeep } = require('../utils/objectUtils');
4
- const { hiddenProps } = require('./modelUtils');
5
- const { defineNonEnumerableProperty } = require('./modelUtils');
6
- const { isInternalProp } = require('../utils/internalPropUtils');
7
-
8
- function clone(model, shallow, stripInternal) {
6
+ export function clone(model, shallow, stripInternal) {
9
7
  let clone = null;
10
8
 
11
9
  const omitFromJson = model.$omitFromJson();
@@ -113,7 +111,3 @@ function copyHiddenProps(model, clone) {
113
111
 
114
112
  return clone;
115
113
  }
116
-
117
- module.exports = {
118
- clone,
119
- };
@@ -1,8 +1,6 @@
1
- 'use strict';
1
+ import { difference } from '../utils/objectUtils.js';
2
2
 
3
- const { difference } = require('../utils/objectUtils');
4
-
5
- function columnNameToPropertyName(modelClass, columnName) {
3
+ export function columnNameToPropertyName(modelClass, columnName) {
6
4
  const model = new modelClass();
7
5
  const addedProps = Object.keys(model.$parseDatabaseJson({}));
8
6
 
@@ -15,7 +13,7 @@ function columnNameToPropertyName(modelClass, columnName) {
15
13
  return propertyName || columnName;
16
14
  }
17
15
 
18
- function propertyNameToColumnName(modelClass, propertyName) {
16
+ export function propertyNameToColumnName(modelClass, propertyName) {
19
17
  const model = new modelClass();
20
18
  const addedCols = Object.keys(model.$formatDatabaseJson({}));
21
19
 
@@ -27,8 +25,3 @@ function propertyNameToColumnName(modelClass, propertyName) {
27
25
 
28
26
  return columnName || propertyName;
29
27
  }
30
-
31
- module.exports = {
32
- columnNameToPropertyName,
33
- propertyNameToColumnName,
34
- };
@@ -1,8 +1,6 @@
1
- 'use strict';
1
+ import { assertHasIdColumn } from '../utils/assert.js';
2
2
 
3
- const { assertHasIdColumn } = require('../utils/assert');
4
-
5
- function getSetId(model, maybeId) {
3
+ export function getSetId(model, maybeId) {
6
4
  if (maybeId !== undefined) {
7
5
  return setId(model, maybeId);
8
6
  } else {
@@ -10,7 +8,7 @@ function getSetId(model, maybeId) {
10
8
  }
11
9
  }
12
10
 
13
- function hasId(model) {
11
+ export function hasId(model) {
14
12
  const idProps = model.constructor.getIdPropertyArray();
15
13
  // Models without an `idColumn` never have an id.
16
14
  return idProps.length > 0 && model.$hasProps(idProps);
@@ -63,8 +61,3 @@ function getId(model) {
63
61
  return model[idProp];
64
62
  }
65
63
  }
66
-
67
- module.exports = {
68
- getSetId,
69
- hasId,
70
- };
@@ -1,12 +1,12 @@
1
- 'use strict';
1
+ import { asArray, isObject, flatten, isString } from '../utils/objectUtils.js';
2
+ import { isQueryProp } from './modelQueryProps.js';
3
+ import { isJsonParsedByDriver } from '../utils/knexUtils.js';
2
4
 
3
- const { asArray, isObject, flatten, isString } = require('../utils/objectUtils');
4
- const { isQueryProp } = require('./modelQueryProps');
5
-
6
- function parseJsonAttributes(json, modelClass) {
5
+ export function parseJsonAttributes(json, modelClass, knex) {
7
6
  const jsonAttr = modelClass.getJsonAttributes();
7
+ const format = getJsonColumnFormat(modelClass, knex);
8
8
 
9
- if (jsonAttr.length) {
9
+ if (jsonAttr.length && format !== 'parsed') {
10
10
  // JSON attributes may be returned as strings depending on the database and
11
11
  // the database client. Convert them to objects here.
12
12
  for (let i = 0, l = jsonAttr.length; i < l; ++i) {
@@ -14,7 +14,7 @@ function parseJsonAttributes(json, modelClass) {
14
14
  const value = json[attr];
15
15
 
16
16
  if (isString(value)) {
17
- const parsed = tryParseJson(value);
17
+ const parsed = format === 'text' ? parseJson(value, attr, modelClass) : tryParseJson(value);
18
18
 
19
19
  // tryParseJson returns undefined if parsing failed.
20
20
  if (parsed !== undefined) {
@@ -27,7 +27,7 @@ function parseJsonAttributes(json, modelClass) {
27
27
  return json;
28
28
  }
29
29
 
30
- function formatJsonAttributes(json, modelClass) {
30
+ export function formatJsonAttributes(json, modelClass) {
31
31
  const jsonAttr = modelClass.getJsonAttributes();
32
32
 
33
33
  if (jsonAttr.length) {
@@ -46,7 +46,7 @@ function formatJsonAttributes(json, modelClass) {
46
46
  return json;
47
47
  }
48
48
 
49
- function getJsonAttributes(modelClass) {
49
+ export function getJsonAttributes(modelClass) {
50
50
  let jsonAttributes = modelClass.jsonAttributes;
51
51
 
52
52
  if (Array.isArray(jsonAttributes)) {
@@ -85,6 +85,32 @@ function getPropertyTypes(prop) {
85
85
  return types;
86
86
  }
87
87
 
88
+ // Resolve 'auto' to 'parsed' for drivers that return JSON columns parsed, or
89
+ // else to `null`: JSON attributes may be text then, and are parsed leniently.
90
+ function getJsonColumnFormat(modelClass, knex) {
91
+ const { jsonColumnFormat } = modelClass;
92
+
93
+ if (jsonColumnFormat === 'auto') {
94
+ return knex && isJsonParsedByDriver(knex) ? 'parsed' : null;
95
+ } else if (jsonColumnFormat === 'text' || jsonColumnFormat === 'parsed') {
96
+ return jsonColumnFormat;
97
+ } else {
98
+ throw new Error(
99
+ `Invalid jsonColumnFormat of model '${modelClass.name}': '${jsonColumnFormat}'.`,
100
+ );
101
+ }
102
+ }
103
+
104
+ function parseJson(str, attr, modelClass) {
105
+ try {
106
+ return JSON.parse(str);
107
+ } catch (err) {
108
+ throw new Error(
109
+ `Invalid JSON in JSON attribute '${attr}' of model '${modelClass.name}': ${err.message}`,
110
+ );
111
+ }
112
+ }
113
+
88
114
  function tryParseJson(maybeJsonStr) {
89
115
  try {
90
116
  return JSON.parse(maybeJsonStr);
@@ -92,10 +118,3 @@ function tryParseJson(maybeJsonStr) {
92
118
  return undefined;
93
119
  }
94
120
  }
95
-
96
- module.exports = {
97
- parseJsonAttributes,
98
- formatJsonAttributes,
99
- getJsonAttributes,
100
- getPropertyTypes,
101
- };
@@ -1,8 +1,6 @@
1
- 'use strict';
1
+ import { isObject } from '../utils/objectUtils.js';
2
2
 
3
- const { isObject } = require('../utils/objectUtils');
4
-
5
- function parseRelationsIntoModelInstances(model, json, options = {}) {
3
+ export function parseRelationsIntoModelInstances(model, json, options = {}) {
6
4
  if (!options.cache) {
7
5
  options = Object.assign({}, options, {
8
6
  cache: new Map(),
@@ -76,7 +74,3 @@ function parseRelationObject(json, relation, options) {
76
74
  return json;
77
75
  }
78
76
  }
79
-
80
- module.exports = {
81
- parseRelationsIntoModelInstances,
82
- };
@@ -1,29 +1,41 @@
1
- 'use strict';
2
-
3
- const { isObject, isFunction, omit } = require('../utils/objectUtils');
4
- const { defineNonEnumerableProperty } = require('./modelUtils');
5
- const { isKnexRaw, isKnexQueryBuilder } = require('../utils/knexUtils');
6
- const { parseFieldExpression, isFieldExpressionKey } = require('../utils/parseFieldExpression');
1
+ import { isObject, isFunction, omit } from '../utils/objectUtils.js';
2
+ import { defineNonEnumerableProperty } from './modelUtils.js';
3
+ import { isKnexRaw, isKnexQueryBuilder } from '../utils/knexUtils.js';
4
+ import { getFieldExpressionColumn } from '../utils/parseFieldExpression.js';
7
5
 
8
6
  const QUERY_PROPS_PROPERTY = '$$queryProps';
7
+ // The keys of the field expression query properties like `'data:a'` that were
8
+ // given while their json column `data` had a value:
9
+ const COMBINED_QUERY_PROPS_PROPERTY = '$$combinedQueryProps';
9
10
 
10
11
  // Moves the query properties of `json` into a hidden property of `model` so
11
12
  // that they can be later merged back to its database json. A key holds either
12
13
  // a value or a query property, so the keys given in `json` replace the ones
13
14
  // that the model holds as the other kind.
14
- function splitQueryProps(model, json) {
15
+ export function splitQueryProps(model, json) {
15
16
  const keys = Object.keys(json);
16
17
  const oldQueryProps = model[QUERY_PROPS_PROPERTY];
17
18
 
18
19
  if (!json.$isObjectionModel && hasQueryProps(json, keys)) {
19
20
  const queryProps = Object.assign({}, oldQueryProps);
21
+ const combinedKeys = new Set(model[COMBINED_QUERY_PROPS_PROPERTY]);
20
22
  const modelProps = {};
23
+ const jsonSchema = model.constructor.getJsonSchema();
24
+ const properties = jsonSchema && jsonSchema.properties;
21
25
 
22
26
  for (let i = 0, l = keys.length; i < l; ++i) {
23
27
  const key = keys[i];
24
28
  const value = json[key];
25
29
 
26
30
  if (isQueryProp(value)) {
31
+ const column = getFieldExpressionColumn(key, properties);
32
+
33
+ if (column !== null && (json[column] !== undefined || model[column] !== undefined)) {
34
+ combinedKeys.add(key);
35
+ } else {
36
+ combinedKeys.delete(key);
37
+ }
38
+
27
39
  queryProps[key] = value;
28
40
  delete model[key];
29
41
  } else {
@@ -33,6 +45,7 @@ function splitQueryProps(model, json) {
33
45
  }
34
46
 
35
47
  defineNonEnumerableProperty(model, QUERY_PROPS_PROPERTY, queryProps);
48
+ defineNonEnumerableProperty(model, COMBINED_QUERY_PROPS_PROPERTY, [...combinedKeys]);
36
49
 
37
50
  return modelProps;
38
51
  } else {
@@ -46,7 +59,7 @@ function splitQueryProps(model, json) {
46
59
 
47
60
  // Omits the values that parsing and validation add to `json` for the keys that
48
61
  // `model` holds query properties for, like Ajv defaults.
49
- function omitQueryProps(model, json) {
62
+ export function omitQueryProps(model, json) {
50
63
  const keys = getQueryPropKeys(model);
51
64
  return keys.length > 0 ? omit(json, keys) : json;
52
65
  }
@@ -55,19 +68,22 @@ function omitQueryProps(model, json) {
55
68
  // assignment, `$set()` or a write that fetched the value from the database. We
56
69
  // do this when the model is passed to a write, and not when its database json
57
70
  // is built, so that the values set by its hooks don't override them.
58
- function removeOverriddenQueryProps(model) {
71
+ export function removeOverriddenQueryProps(model) {
59
72
  const queryProps = model[QUERY_PROPS_PROPERTY];
60
73
 
61
74
  if (queryProps) {
62
75
  const jsonSchema = model.constructor.getJsonSchema();
63
76
  const properties = jsonSchema && jsonSchema.properties;
64
- // The json column of a field expression key like `data:a` overrides it too:
65
- const keys = Object.keys(queryProps).filter(
66
- (key) =>
77
+ const combinedKeys = model[COMBINED_QUERY_PROPS_PROPERTY] || [];
78
+ const keys = Object.keys(queryProps).filter((key) => {
79
+ const column = getFieldExpressionColumn(key, properties);
80
+ return (
67
81
  model[key] !== undefined ||
68
- (isFieldExpressionKey(key, properties) &&
69
- model[parseFieldExpression(key).column] !== undefined),
70
- );
82
+ // The json column of a field expression key like `data:a` overrides it
83
+ // too, unless it was given while the column had a value (#206):
84
+ (column !== null && !combinedKeys.includes(key) && model[column] !== undefined)
85
+ );
86
+ });
71
87
 
72
88
  if (keys.length > 0) {
73
89
  defineNonEnumerableProperty(model, QUERY_PROPS_PROPERTY, omit(queryProps, keys));
@@ -75,6 +91,15 @@ function removeOverriddenQueryProps(model) {
75
91
  }
76
92
  }
77
93
 
94
+ // Removes the values that the hooks of a write set for the keys that `model`
95
+ // holds query properties for. The query properties are written instead, so the
96
+ // values must not count as given in later writes.
97
+ export function removeOverriddenValues(model) {
98
+ for (const key of getQueryPropKeys(model)) {
99
+ delete model[key];
100
+ }
101
+ }
102
+
78
103
  function hasQueryProps(json, keys) {
79
104
  for (let i = 0, l = keys.length; i < l; ++i) {
80
105
  if (isQueryProp(json[keys[i]])) {
@@ -85,7 +110,7 @@ function hasQueryProps(json, keys) {
85
110
  return false;
86
111
  }
87
112
 
88
- function isQueryProp(value) {
113
+ export function isQueryProp(value) {
89
114
  if (!isObject(value)) {
90
115
  return false;
91
116
  }
@@ -99,7 +124,7 @@ function isQueryProp(value) {
99
124
  }
100
125
 
101
126
  // Merges and converts `model`'s query properties into `json`.
102
- function mergeQueryProps(model, json, omitProps, builder) {
127
+ export function mergeQueryProps(model, json, omitProps, builder) {
103
128
  json = convertExistingQueryProps(json, builder);
104
129
  json = convertAndMergeHiddenQueryProps(model, json, omitProps, builder);
105
130
 
@@ -150,7 +175,7 @@ function convertAndMergeHiddenQueryProps(model, json, omitProps, builder) {
150
175
  }
151
176
 
152
177
  // Returns the keys of the query properties that were split from `model`.
153
- function getQueryPropKeys(model) {
178
+ export function getQueryPropKeys(model) {
154
179
  const queryProps = model[QUERY_PROPS_PROPERTY];
155
180
  return queryProps ? Object.keys(queryProps) : [];
156
181
  }
@@ -187,12 +212,3 @@ function buildKnexRawConvertable(convertable, builder) {
187
212
  function isKnexRawConvertable(queryProp) {
188
213
  return isFunction(queryProp.toKnexRaw);
189
214
  }
190
-
191
- module.exports = {
192
- splitQueryProps,
193
- omitQueryProps,
194
- removeOverriddenQueryProps,
195
- mergeQueryProps,
196
- getQueryPropKeys,
197
- isQueryProp,
198
- };
@@ -1,11 +1,9 @@
1
- 'use strict';
1
+ import { isInternalProp } from '../utils/internalPropUtils.js';
2
+ import { splitQueryProps, omitQueryProps } from './modelQueryProps.js';
3
+ import { asArray, isFunction, isString, isPlainObject } from '../utils/objectUtils.js';
4
+ import { parseRelationsIntoModelInstances } from './modelParseRelations.js';
2
5
 
3
- const { isInternalProp } = require('../utils/internalPropUtils');
4
- const { splitQueryProps, omitQueryProps } = require('./modelQueryProps');
5
- const { isFunction, isString, isPlainObject } = require('../utils/objectUtils');
6
- const { parseRelationsIntoModelInstances } = require('./modelParseRelations');
7
-
8
- function setJson(model, json, options) {
6
+ export function setJson(model, json, options) {
9
7
  json = json || {};
10
8
  options = options || {};
11
9
 
@@ -34,8 +32,8 @@ function setJson(model, json, options) {
34
32
  return model;
35
33
  }
36
34
 
37
- function setDatabaseJson(model, json) {
38
- json = model.$parseDatabaseJson(json);
35
+ export function setDatabaseJson(model, json, options) {
36
+ json = model.$parseDatabaseJson(json, options);
39
37
 
40
38
  if (json) {
41
39
  const keys = Object.keys(json);
@@ -49,7 +47,7 @@ function setDatabaseJson(model, json) {
49
47
  return model;
50
48
  }
51
49
 
52
- function setFast(model, obj) {
50
+ export function setFast(model, obj) {
53
51
  if (obj) {
54
52
  // Don't try to set read-only properties. They can easily get here
55
53
  // through `fromJson` when parsing an object that was previously
@@ -75,16 +73,39 @@ function setFast(model, obj) {
75
73
  return model;
76
74
  }
77
75
 
78
- function setRelated(model, relation, models) {
76
+ export function setRelated(model, relation, models) {
77
+ relation = ensureRelation(model, relation);
78
+ const previous = model[relation.name];
79
+ assignRelated(model, relation, models);
80
+ syncForeignKeys(model, relation, model[relation.name], { previous });
81
+ return model;
82
+ }
83
+
84
+ export function appendRelated(model, relation, models) {
79
85
  relation = ensureRelation(model, relation);
80
86
 
81
87
  if (relation.isOneToOne()) {
88
+ return model.$setRelated(relation, models);
89
+ } else {
90
+ assignRelated(model, relation, models, { append: true });
91
+ syncForeignKeys(model, relation, models, { append: true });
92
+ }
93
+
94
+ return model;
95
+ }
96
+
97
+ // Assigns related models without syncing foreign keys, for the relation queries
98
+ // that set the keys themselves:
99
+ export function assignRelated(model, relation, models, { append = false } = {}) {
100
+ if (append && model[relation.name] && !relation.isOneToOne()) {
82
101
  if (Array.isArray(models)) {
83
- if (models.length === 0) {
84
- model[relation.name] = null;
85
- } else {
86
- model[relation.name] = models[0] || null;
87
- }
102
+ models.forEach((it) => model[relation.name].push(it));
103
+ } else if (models) {
104
+ model[relation.name].push(models);
105
+ }
106
+ } else if (relation.isOneToOne()) {
107
+ if (Array.isArray(models)) {
108
+ model[relation.name] = models[0] || null;
88
109
  } else {
89
110
  model[relation.name] = models || null;
90
111
  }
@@ -97,24 +118,6 @@ function setRelated(model, relation, models) {
97
118
  model[relation.name] = [models];
98
119
  }
99
120
  }
100
-
101
- return model;
102
- }
103
-
104
- function appendRelated(model, relation, models) {
105
- relation = ensureRelation(model, relation);
106
-
107
- if (!model[relation.name] || relation.isOneToOne()) {
108
- return model.$setRelated(relation, models);
109
- } else {
110
- if (Array.isArray(models)) {
111
- models.forEach((it) => model[relation.name].push(it));
112
- } else if (models) {
113
- model[relation.name].push(models);
114
- }
115
- }
116
-
117
- return model;
118
121
  }
119
122
 
120
123
  function ensureRelation(model, relation) {
@@ -125,10 +128,55 @@ function ensureRelation(model, relation) {
125
128
  }
126
129
  }
127
130
 
128
- module.exports = {
129
- setFast,
130
- setJson,
131
- setDatabaseJson,
132
- setRelated,
133
- appendRelated,
134
- };
131
+ // Let the foreign keys follow the relation: a `BelongsToOneRelation` points the
132
+ // owner to the related model, a `BelongsToManyRelation` to the related models,
133
+ // `HasOneRelation` and `HasManyRelation` point the related models to the owner,
134
+ // and the models that leave them to nothing. The keys of `ManyToManyRelation`
135
+ // and `HasOneThroughRelation` live in the join table.
136
+ function syncForeignKeys(model, relation, related, { previous = null, append = false } = {}) {
137
+ const { ownerProp, relatedProp } = relation;
138
+
139
+ if (relation.isObjectionBelongsToOneRelation) {
140
+ copyKey(relatedProp, related, ownerProp, model);
141
+ } else if (relation.isObjectionBelongsToManyRelation) {
142
+ // Models without a key are left out of the array:
143
+ const keys = asModels(related).map((it) => relatedProp.getProp(it, 0));
144
+
145
+ ownerProp.setProp(
146
+ model,
147
+ 0,
148
+ relation.changeKeys(append ? relation.getKeys(model) : [], { add: keys }),
149
+ );
150
+ } else if (relation.isObjectionHasManyRelation) {
151
+ const models = asModels(related);
152
+
153
+ for (const it of models) {
154
+ copyKey(ownerProp, model, relatedProp, it);
155
+ }
156
+
157
+ if (ownerProp.hasProps(model)) {
158
+ const key = ownerProp.propKey(model);
159
+
160
+ for (const it of asModels(previous)) {
161
+ // Only clear the keys that still point to the owner, not the keys of
162
+ // models that moved to another owner in the meantime:
163
+ if (!models.includes(it) && relatedProp.propKey(it) === key) {
164
+ copyKey(ownerProp, null, relatedProp, it);
165
+ }
166
+ }
167
+ }
168
+ }
169
+ }
170
+
171
+ // Copies the key of `source` to `target`, or clears it if there's none to copy:
172
+ function copyKey(sourceProp, source, targetProp, target) {
173
+ const hasKey = !!source && sourceProp.hasProps(source);
174
+
175
+ targetProp.forEach((i) => {
176
+ targetProp.setProp(target, i, hasKey ? sourceProp.getProp(source, i) : null);
177
+ });
178
+ }
179
+
180
+ function asModels(value) {
181
+ return asArray(value).filter(Boolean);
182
+ }
@@ -1,11 +1,9 @@
1
- 'use strict';
2
-
3
- const { defineNonEnumerableProperty } = require('./modelUtils');
4
- const { isPromise } = require('../utils/promiseUtils');
1
+ import { defineNonEnumerableProperty } from './modelUtils.js';
2
+ import { isPromise } from '../utils/promiseUtils/index.js';
5
3
 
6
4
  const TABLE_METADATA = '$$tableMetadata';
7
5
 
8
- function fetchTableMetadata(
6
+ export function fetchTableMetadata(
9
7
  modelClass,
10
8
  { parentBuilder = null, knex = null, force = false, table = null } = {},
11
9
  ) {
@@ -63,7 +61,7 @@ function fetchTableMetadata(
63
61
  }
64
62
  }
65
63
 
66
- function tableMetadata(modelClass, { table } = {}) {
64
+ export function tableMetadata(modelClass, { table } = {}) {
67
65
  if (modelClass.hasOwnProperty(TABLE_METADATA)) {
68
66
  const metadata = modelClass[TABLE_METADATA].get(table || modelClass.getTableName());
69
67
 
@@ -76,8 +74,3 @@ function tableMetadata(modelClass, { table } = {}) {
76
74
  return null;
77
75
  }
78
76
  }
79
-
80
- module.exports = {
81
- fetchTableMetadata,
82
- tableMetadata,
83
- };
@@ -1,12 +1,10 @@
1
- 'use strict';
2
-
3
- const { isInternalProp } = require('../utils/internalPropUtils');
4
- const { mergeQueryProps } = require('./modelQueryProps');
5
- const { isObject, hasOwn, cloneDeep, isFunction } = require('../utils/objectUtils');
6
- const { parseFieldExpression, isFieldExpressionKey } = require('../utils/parseFieldExpression');
1
+ import { isInternalProp } from '../utils/internalPropUtils.js';
2
+ import { mergeQueryProps } from './modelQueryProps.js';
3
+ import { isObject, hasOwn, cloneDeep, isFunction } from '../utils/objectUtils.js';
4
+ import { getFieldExpressionColumn } from '../utils/parseFieldExpression.js';
7
5
  const EMPTY_ARRAY = [];
8
6
 
9
- function toJson(model, optIn) {
7
+ export function toJson(model, optIn) {
10
8
  const modelClass = model.constructor;
11
9
 
12
10
  const opt = {
@@ -25,7 +23,7 @@ function toJson(model, optIn) {
25
23
  return json;
26
24
  }
27
25
 
28
- function toDatabaseJson(model, builder) {
26
+ export function toDatabaseJson(model, builder) {
29
27
  const modelClass = model.constructor;
30
28
 
31
29
  const opt = {
@@ -140,16 +138,8 @@ function shouldPick(opt, key) {
140
138
 
141
139
  // Pick field expressions like `'meta:a'` by their json column.
142
140
  function isPickedFieldExpression(pick, key) {
143
- if (isFieldExpressionKey(key, pick)) {
144
- try {
145
- return hasOwn(pick, parseFieldExpression(key).column);
146
- } catch (err) {
147
- // Not a valid field expression.
148
- return false;
149
- }
150
- } else {
151
- return false;
152
- }
141
+ const column = getFieldExpressionColumn(key, pick);
142
+ return column !== null && hasOwn(pick, column);
153
143
  }
154
144
 
155
145
  function assignVirtualAttributes(json, model, vAttr, opt) {
@@ -196,8 +186,3 @@ function toJsonArray(value, opt) {
196
186
 
197
187
  return ret;
198
188
  }
199
-
200
- module.exports = {
201
- toJson,
202
- toDatabaseJson,
203
- };
@@ -1,8 +1,6 @@
1
- 'use strict';
1
+ export const hiddenProps = ['$$queryProps', '$$combinedQueryProps', '$$isFromDatabase'];
2
2
 
3
- const hiddenProps = ['$$queryProps'];
4
-
5
- const staticHiddenProps = [
3
+ export const staticHiddenProps = [
6
4
  '$$knex',
7
5
  '$$validator',
8
6
  '$$jsonSchema',
@@ -19,7 +17,7 @@ const staticHiddenProps = [
19
17
  '$$virtualAttributes',
20
18
  ];
21
19
 
22
- function defineNonEnumerableProperty(obj, prop, value) {
20
+ export function defineNonEnumerableProperty(obj, prop, value) {
23
21
  Object.defineProperty(obj, prop, {
24
22
  enumerable: false,
25
23
  writable: true,
@@ -28,7 +26,17 @@ function defineNonEnumerableProperty(obj, prop, value) {
28
26
  });
29
27
  }
30
28
 
31
- function keyByProps(models, props) {
29
+ // Give `model` back the props that it left out of its database JSON, as
30
+ // returned by `$omitFromDatabaseJson()` before more were left out.
31
+ export function restoreOmitFromDatabaseJson(model, props) {
32
+ if (props) {
33
+ defineNonEnumerableProperty(model, '$$omitFromDatabaseJson', props);
34
+ } else {
35
+ delete model.$$omitFromDatabaseJson;
36
+ }
37
+ }
38
+
39
+ export function keyByProps(models, props) {
32
40
  const map = new Map();
33
41
 
34
42
  for (let i = 0, l = models.length; i < l; ++i) {
@@ -38,10 +46,3 @@ function keyByProps(models, props) {
38
46
 
39
47
  return map;
40
48
  }
41
-
42
- module.exports = {
43
- hiddenProps,
44
- staticHiddenProps,
45
- defineNonEnumerableProperty,
46
- keyByProps,
47
- };