objection 3.9.1 → 4.0.0-rc.2

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 (250) 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 +314 -0
  81. package/lib/queryBuilder/graph/GraphNode.js +241 -0
  82. package/lib/queryBuilder/graph/GraphOptions.js +55 -248
  83. package/lib/queryBuilder/graph/GraphPlan.js +431 -0
  84. package/lib/queryBuilder/graph/GraphSchedule.js +513 -0
  85. package/lib/queryBuilder/graph/GraphUpsert.js +519 -412
  86. package/lib/queryBuilder/graph/GraphWriter.js +508 -0
  87. package/lib/queryBuilder/graph/graphKeys.js +929 -0
  88. package/lib/queryBuilder/join/JoinResultColumn.js +1 -7
  89. package/lib/queryBuilder/join/JoinResultParser.js +6 -11
  90. package/lib/queryBuilder/join/RelationJoiner.js +66 -84
  91. package/lib/queryBuilder/join/TableNode.js +2 -8
  92. package/lib/queryBuilder/join/TableTree.js +3 -9
  93. package/lib/queryBuilder/join/utils.js +5 -15
  94. package/lib/queryBuilder/jsonDialects/JsonDialect.js +51 -0
  95. package/lib/queryBuilder/jsonDialects/MySqlJsonDialect.js +81 -0
  96. package/lib/queryBuilder/jsonDialects/PostgresJsonDialect.js +45 -0
  97. package/lib/queryBuilder/jsonDialects/SqliteJsonDialect.js +67 -0
  98. package/lib/queryBuilder/jsonDialects/index.js +44 -0
  99. package/lib/queryBuilder/operations/DelegateOperation.js +2 -8
  100. package/lib/queryBuilder/operations/DeleteOperation.js +10 -39
  101. package/lib/queryBuilder/operations/FindByIdOperation.js +7 -12
  102. package/lib/queryBuilder/operations/FindByIdsOperation.js +4 -8
  103. package/lib/queryBuilder/operations/FindOperation.js +14 -34
  104. package/lib/queryBuilder/operations/FirstOperation.js +6 -10
  105. package/lib/queryBuilder/operations/FromOperation.js +3 -9
  106. package/lib/queryBuilder/operations/InsertAndFetchOperation.js +13 -12
  107. package/lib/queryBuilder/operations/InsertGraphAndFetchOperation.js +4 -10
  108. package/lib/queryBuilder/operations/InsertGraphOperation.js +7 -18
  109. package/lib/queryBuilder/operations/InsertOperation.js +118 -45
  110. package/lib/queryBuilder/operations/InstanceDeleteOperation.js +5 -12
  111. package/lib/queryBuilder/operations/InstanceFindOperation.js +4 -11
  112. package/lib/queryBuilder/operations/InstanceInsertOperation.js +2 -8
  113. package/lib/queryBuilder/operations/InstanceUpdateOperation.js +7 -14
  114. package/lib/queryBuilder/operations/JoinRelatedOperation.js +5 -11
  115. package/lib/queryBuilder/operations/KnexOperation.js +2 -8
  116. package/lib/queryBuilder/operations/LimitPerParentOperation.js +7 -69
  117. package/lib/queryBuilder/operations/MergeOperation.js +5 -11
  118. package/lib/queryBuilder/operations/NoneOperation.js +2 -8
  119. package/lib/queryBuilder/operations/ObjectionToKnexConvertingOperation.js +20 -49
  120. package/lib/queryBuilder/operations/OnBuildKnexOperation.js +2 -8
  121. package/lib/queryBuilder/operations/OnBuildOperation.js +2 -8
  122. package/lib/queryBuilder/operations/OnErrorOperation.js +2 -8
  123. package/lib/queryBuilder/operations/QueryBuilderOperation.js +1 -7
  124. package/lib/queryBuilder/operations/RangeOperation.js +11 -26
  125. package/lib/queryBuilder/operations/RelateOperation.js +2 -8
  126. package/lib/queryBuilder/operations/ReturningOperation.js +3 -9
  127. package/lib/queryBuilder/operations/RunAfterOperation.js +2 -12
  128. package/lib/queryBuilder/operations/RunBeforeOperation.js +2 -8
  129. package/lib/queryBuilder/operations/UnrelateOperation.js +2 -8
  130. package/lib/queryBuilder/operations/UpdateAndFetchOperation.js +14 -17
  131. package/lib/queryBuilder/operations/UpdateOperation.js +32 -132
  132. package/lib/queryBuilder/operations/UpsertGraphAndFetchOperation.js +8 -11
  133. package/lib/queryBuilder/operations/UpsertGraphOperation.js +6 -12
  134. package/lib/queryBuilder/operations/WhereCompositeOperation.js +3 -9
  135. package/lib/queryBuilder/operations/WhereGroupOperation.js +2 -8
  136. package/lib/queryBuilder/operations/eager/EagerOperation.js +3 -9
  137. package/lib/queryBuilder/operations/eager/JoinEagerOperation.js +72 -10
  138. package/lib/queryBuilder/operations/eager/NaiveEagerOperation.js +2 -8
  139. package/lib/queryBuilder/operations/eager/WhereInEagerOperation.js +23 -44
  140. package/lib/queryBuilder/operations/fieldExpressions.js +122 -0
  141. package/lib/queryBuilder/operations/jsonApi/WhereJsonHasOperation.js +20 -0
  142. package/lib/queryBuilder/operations/jsonApi/WhereJsonOperation.js +44 -0
  143. package/lib/queryBuilder/operations/jsonApi/WhereJsonTypeOperation.js +14 -0
  144. package/lib/queryBuilder/operations/select/SelectOperation.js +11 -21
  145. package/lib/queryBuilder/operations/select/Selection.js +19 -17
  146. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeMsSqlOperation.js +4 -10
  147. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeOperation.js +4 -10
  148. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeSqliteOperation.js +4 -10
  149. package/lib/queryBuilder/operations/windowOrder.js +56 -0
  150. package/lib/queryBuilder/parsers/jsonFieldExpressionParser.js +3 -7
  151. package/lib/queryBuilder/parsers/relationExpressionParser.js +42 -43
  152. package/lib/queryBuilder/parsers/relationExpressionParser.pegjs +39 -36
  153. package/lib/queryBuilder/transformations/CompositeQueryTransformation.js +2 -8
  154. package/lib/queryBuilder/transformations/QueryTransformation.js +1 -7
  155. package/lib/queryBuilder/transformations/WrapMysqlModifySubqueryTransformation.js +3 -9
  156. package/lib/queryBuilder/transformations/index.js +3 -11
  157. package/lib/queryBuilder/whereGroups.js +9 -24
  158. package/lib/queryBuilder/withoutOrder.js +4 -11
  159. package/lib/relations/Relation.js +47 -28
  160. package/lib/relations/RelationDeleteOperation.js +4 -14
  161. package/lib/relations/RelationFindOperation.js +119 -90
  162. package/lib/relations/RelationInsertOperation.js +2 -8
  163. package/lib/relations/RelationOwner.js +5 -11
  164. package/lib/relations/RelationProperty.js +4 -10
  165. package/lib/relations/RelationUpdateOperation.js +4 -14
  166. package/lib/relations/RelationWriteResultOperation.js +15 -0
  167. package/lib/relations/belongsToMany/BelongsToManyDeleteOperation.js +23 -0
  168. package/lib/relations/belongsToMany/BelongsToManyFindOperation.js +35 -0
  169. package/lib/relations/belongsToMany/BelongsToManyInsertOperation.js +28 -0
  170. package/lib/relations/belongsToMany/BelongsToManyRelateOperation.js +16 -0
  171. package/lib/relations/belongsToMany/BelongsToManyRelation.js +276 -0
  172. package/lib/relations/belongsToMany/BelongsToManyUnrelateOperation.js +11 -0
  173. package/lib/relations/belongsToOne/BelongsToOneDeleteOperation.js +2 -8
  174. package/lib/relations/belongsToOne/BelongsToOneInsertOperation.js +6 -11
  175. package/lib/relations/belongsToOne/BelongsToOneRelateOperation.js +3 -9
  176. package/lib/relations/belongsToOne/BelongsToOneRelation.js +8 -19
  177. package/lib/relations/belongsToOne/BelongsToOneUnrelateOperation.js +53 -27
  178. package/lib/relations/hasMany/HasManyInsertOperation.js +5 -10
  179. package/lib/relations/hasMany/HasManyRelateOperation.js +5 -11
  180. package/lib/relations/hasMany/HasManyRelation.js +9 -11
  181. package/lib/relations/hasMany/HasManyUnrelateOperation.js +3 -9
  182. package/lib/relations/hasOne/HasOneRelation.js +2 -8
  183. package/lib/relations/hasOneThrough/HasOneThroughRelation.js +2 -8
  184. package/lib/relations/manyToMany/ManyToManyModifyMixin.js +10 -15
  185. package/lib/relations/manyToMany/ManyToManyMySqlModifyMixin.js +2 -8
  186. package/lib/relations/manyToMany/ManyToManyRelation.js +82 -50
  187. package/lib/relations/manyToMany/ManyToManySqliteModifyMixin.js +2 -8
  188. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperation.js +5 -9
  189. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperationBase.js +2 -8
  190. package/lib/relations/manyToMany/delete/ManyToManyDeleteSqliteOperation.js +3 -9
  191. package/lib/relations/manyToMany/find/ManyToManyFindOperation.js +20 -59
  192. package/lib/relations/manyToMany/insert/ManyToManyInsertOperation.js +6 -11
  193. package/lib/relations/manyToMany/relate/ManyToManyRelateOperation.js +4 -10
  194. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateMySqlOperation.js +3 -9
  195. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperation.js +5 -9
  196. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperationBase.js +3 -9
  197. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateSqliteOperation.js +3 -9
  198. package/lib/relations/manyToMany/update/ManyToManyUpdateMySqlOperation.js +3 -9
  199. package/lib/relations/manyToMany/update/ManyToManyUpdateOperation.js +5 -9
  200. package/lib/relations/manyToMany/update/ManyToManyUpdateOperationBase.js +64 -72
  201. package/lib/relations/manyToMany/update/ManyToManyUpdateSqliteOperation.js +3 -9
  202. package/lib/transaction.js +3 -9
  203. package/lib/utils/assert.js +3 -11
  204. package/lib/utils/buildUtils.js +2 -8
  205. package/lib/utils/classUtils.js +1 -7
  206. package/lib/utils/createModifier.js +2 -8
  207. package/lib/utils/identifierMapping.js +23 -27
  208. package/lib/utils/internalPropUtils.js +1 -7
  209. package/lib/utils/knexUtils.js +84 -40
  210. package/lib/utils/mixin.js +3 -10
  211. package/lib/utils/normalizeIds.js +2 -8
  212. package/lib/utils/objectUtils.js +41 -60
  213. package/lib/utils/parseFieldExpression.js +16 -16
  214. package/lib/utils/promiseUtils/after.js +2 -8
  215. package/lib/utils/promiseUtils/afterReturn.js +2 -8
  216. package/lib/utils/promiseUtils/index.js +7 -16
  217. package/lib/utils/promiseUtils/isPromise.js +2 -8
  218. package/lib/utils/promiseUtils/map.js +2 -8
  219. package/lib/utils/promiseUtils/mapAfterAllReturn.js +2 -8
  220. package/lib/utils/promiseUtils/try.js +2 -8
  221. package/lib/utils/resolveModel.js +10 -17
  222. package/lib/utils/tmpColumnUtils.js +2 -9
  223. package/lib/utils/warnings.js +2 -14
  224. package/package.json +25 -17
  225. package/typings/objection/index.d.ts +3217 -2179
  226. package/lib/.eslintrc.json +0 -8
  227. package/lib/model/graph/ModelGraph.js +0 -80
  228. package/lib/model/graph/ModelGraphBuilder.js +0 -241
  229. package/lib/model/graph/ModelGraphEdge.js +0 -52
  230. package/lib/model/graph/ModelGraphNode.js +0 -238
  231. package/lib/queryBuilder/graph/GraphAction.js +0 -69
  232. package/lib/queryBuilder/graph/GraphData.js +0 -53
  233. package/lib/queryBuilder/graph/GraphFetcher.js +0 -197
  234. package/lib/queryBuilder/graph/GraphNodeDbExistence.js +0 -184
  235. package/lib/queryBuilder/graph/GraphOperation.js +0 -27
  236. package/lib/queryBuilder/graph/delete/GraphDelete.js +0 -73
  237. package/lib/queryBuilder/graph/delete/GraphDeleteAction.js +0 -88
  238. package/lib/queryBuilder/graph/insert/DeferredRelationGraphInsertAction.js +0 -58
  239. package/lib/queryBuilder/graph/insert/GraphInsert.js +0 -296
  240. package/lib/queryBuilder/graph/insert/GraphInsertAction.js +0 -233
  241. package/lib/queryBuilder/graph/insert/JoinRowGraphInsertAction.js +0 -92
  242. package/lib/queryBuilder/graph/patch/GraphPatch.js +0 -20
  243. package/lib/queryBuilder/graph/patch/GraphPatchAction.js +0 -289
  244. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsert.js +0 -31
  245. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsertAction.js +0 -126
  246. package/lib/queryBuilder/operations/jsonApi/WhereJsonHasPostgresOperation.js +0 -30
  247. package/lib/queryBuilder/operations/jsonApi/WhereJsonNotObjectPostgresOperation.js +0 -37
  248. package/lib/queryBuilder/operations/jsonApi/WhereJsonPostgresOperation.js +0 -62
  249. package/lib/queryBuilder/operations/jsonApi/postgresJsonApi.js +0 -192
  250. package/lib/utils/wrapDbError.js +0 -64
@@ -0,0 +1,122 @@
1
+ import { ref } from '../ReferenceBuilder.js';
2
+ import { isObject } from '../../utils/objectUtils.js';
3
+ import { getFieldExpressionColumn } from '../../utils/parseFieldExpression.js';
4
+ import { isKnexRaw, isKnexQueryBuilder } from '../../utils/knexUtils.js';
5
+ import { getJsonDialect } from '../jsonDialects/index.js';
6
+ import { ValidationErrorType } from '../../model/ValidationError.js';
7
+ import { getQueryPropKeys } from '../../model/modelQueryProps.js';
8
+
9
+ // Inserts and updates write whole values, so they can't write into json
10
+ // columns with field expressions like `'meta:color'`. Keys with a ':' that don't
11
+ // parse as field expressions are columns, as in the query properties.
12
+ export function checkFieldExpressions(modelClass, model, operation) {
13
+ const keys = getFieldExpressionKeys(modelClass, [
14
+ ...Object.keys(model),
15
+ ...getQueryPropKeys(model),
16
+ ]);
17
+
18
+ if (keys.length > 0) {
19
+ throw modelClass.createValidationError({
20
+ type: ValidationErrorType.ModelValidation,
21
+ data: Object.fromEntries(
22
+ keys.map((key) => [
23
+ key,
24
+ [{ message: `field expressions can only be used in patch, not in ${operation}` }],
25
+ ]),
26
+ ),
27
+ });
28
+ }
29
+ }
30
+
31
+ // Field expressions only describe the writes into json columns, they aren't
32
+ // properties of the models that the writes return:
33
+ export function removeFieldExpressions(modelClass, model) {
34
+ for (const key of getFieldExpressionKeys(modelClass, Object.keys(model))) {
35
+ delete model[key];
36
+ }
37
+ }
38
+
39
+ export function convertFieldExpressionsToRaw(builder, json) {
40
+ const knex = builder.knex();
41
+ const dialect = getJsonDialect(knex);
42
+ const modelClass = builder.modelClass();
43
+ const declaredColumns = getDeclaredColumns(modelClass);
44
+ const convertedJson = {};
45
+
46
+ for (const key of Object.keys(json)) {
47
+ let val = json[key];
48
+
49
+ if (getFieldExpressionColumn(key, declaredColumns) !== null) {
50
+ // 'col:attr' : ref('other:lol') is transformed to
51
+ // "col" : raw(`jsonb_set("table"."col", '{attr}', to_jsonb("other"#>'{lol}'), true)`)
52
+ // on Postgres, with the column qualified, as it is ambiguous with
53
+ // `excluded` in merge().
54
+ dialect.checkSupport();
55
+
56
+ let parsed = ref(key);
57
+
58
+ // The field expression would be lost or produce invalid SQL next to a
59
+ // value for the whole json column. Report it with the property names:
60
+ if (Object.prototype.hasOwnProperty.call(json, parsed.column)) {
61
+ const property = modelClass.columnNameToPropertyName(parsed.column);
62
+ throw modelClass.createValidationError({
63
+ type: ValidationErrorType.ModelValidation,
64
+ data: {
65
+ [modelClass.columnNameToPropertyName(key)]: [
66
+ {
67
+ message: `can't be combined with a value for the json column '${property}'`,
68
+ keyword: null,
69
+ params: { property },
70
+ },
71
+ ],
72
+ },
73
+ });
74
+ }
75
+
76
+ let valuePlaceholder;
77
+
78
+ if (isKnexQueryBuilder(val) || isKnexRaw(val)) {
79
+ valuePlaceholder = dialect.toJson('?');
80
+ } else {
81
+ valuePlaceholder = dialect.json('?');
82
+ val = JSON.stringify(val);
83
+ }
84
+
85
+ convertedJson[parsed.column] = knex.raw(
86
+ dialect.set('??', parsed.parsedExpr.access, valuePlaceholder),
87
+ [convertedJson[parsed.column] || `${builder.tableRef()}.${parsed.column}`, val],
88
+ );
89
+ } else {
90
+ convertedJson[key] = val;
91
+ }
92
+ }
93
+
94
+ return convertedJson;
95
+ }
96
+
97
+ function getFieldExpressionKeys(modelClass, keys) {
98
+ const jsonSchema = modelClass.getJsonSchema();
99
+ return keys.filter((key) => getFieldExpressionColumn(key, jsonSchema?.properties) !== null);
100
+ }
101
+
102
+ const declaredColumnsByModelClass = new WeakMap();
103
+
104
+ // The keys of `json` are column names, so map the properties with a ':' that the
105
+ // schema declares to their columns, once per model class. Properties that only
106
+ // the schema returned by `$beforeValidate()` declares aren't known here.
107
+ export function getDeclaredColumns(modelClass) {
108
+ let declaredColumns = declaredColumnsByModelClass.get(modelClass);
109
+
110
+ if (!declaredColumns) {
111
+ const jsonSchema = modelClass.getJsonSchema();
112
+ const properties = jsonSchema && jsonSchema.properties;
113
+ declaredColumns = Object.fromEntries(
114
+ (isObject(properties) ? Object.keys(properties) : [])
115
+ .filter((key) => key.includes(':'))
116
+ .map((key) => [modelClass.propertyNameToColumnName(key), true]),
117
+ );
118
+ declaredColumnsByModelClass.set(modelClass, declaredColumns);
119
+ }
120
+
121
+ return declaredColumns;
122
+ }
@@ -0,0 +1,20 @@
1
+ import { WhereJsonOperation } from './WhereJsonOperation.js';
2
+ import { parseFieldExpression } from '../../../utils/parseFieldExpression.js';
3
+ import { asArray, isString } from '../../../utils/objectUtils.js';
4
+
5
+ // `whereJsonHasAny()`, `whereJsonHasAll()` and their variants.
6
+ export class WhereJsonHasOperation extends WhereJsonOperation {
7
+ // @override
8
+ buildWhere(dialect, [fieldExpression, keys]) {
9
+ const { columnName, access } = parseFieldExpression(fieldExpression);
10
+ keys = asArray(keys);
11
+
12
+ if (keys.length === 0) {
13
+ throw new Error('At least one key to find is required.');
14
+ } else if (!keys.every(isString)) {
15
+ throw new Error('All keys to find must be strings.');
16
+ }
17
+
18
+ return dialect.hasKeys(columnName, access, keys, this.opt.all);
19
+ }
20
+ }
@@ -0,0 +1,44 @@
1
+ import { ObjectionToKnexConvertingOperation } from '../ObjectionToKnexConvertingOperation.js';
2
+ import { getJsonDialect } from '../../jsonDialects/index.js';
3
+ import { parseFieldExpression } from '../../../utils/parseFieldExpression.js';
4
+ import { isObject, isString } from '../../../utils/objectUtils.js';
5
+ import { isKnexRaw, isKnexQueryBuilder } from '../../../utils/knexUtils.js';
6
+
7
+ // `whereJsonSupersetOf()`, `whereJsonSubsetOf()` and their variants, and the
8
+ // base class of the operations of the other `whereJson*()` methods.
9
+ export class WhereJsonOperation extends ObjectionToKnexConvertingOperation {
10
+ onBuildKnex(knexBuilder, builder) {
11
+ const dialect = getJsonDialect(builder.knex());
12
+ dialect.checkSupport();
13
+ const [sql, bindings] = this.buildWhere(dialect, this.getKnexArgs(builder));
14
+
15
+ if (this.opt.bool === 'or') {
16
+ return knexBuilder.orWhereRaw(sql, bindings);
17
+ } else {
18
+ return knexBuilder.whereRaw(sql, bindings);
19
+ }
20
+ }
21
+
22
+ // @overridable
23
+ buildWhere(dialect, args) {
24
+ const [left, right] = args.map((arg) => toJsonOperand(dialect, arg));
25
+ const [sql, bindings] = this.opt.subset
26
+ ? dialect.subset(left, right)
27
+ : dialect.superset(left, right);
28
+ return [this.opt.not ? `not ${sql}` : sql, bindings];
29
+ }
30
+ }
31
+
32
+ function toJsonOperand(dialect, value) {
33
+ if (isString(value)) {
34
+ const { columnName, access } = parseFieldExpression(value);
35
+ return [dialect.jsonOperand(dialect.field('??', access)), [columnName]];
36
+ } else if (isKnexRaw(value) || isKnexQueryBuilder(value)) {
37
+ // ref(), val(), raw() and subqueries, already converted to knex by the operation.
38
+ return [dialect.jsonOperand('?'), [value]];
39
+ } else if (isObject(value)) {
40
+ return [dialect.jsonOperand(dialect.json('?')), [JSON.stringify(value)]];
41
+ } else {
42
+ throw new Error('Invalid right hand expression.');
43
+ }
44
+ }
@@ -0,0 +1,14 @@
1
+ import { WhereJsonOperation } from './WhereJsonOperation.js';
2
+ import { parseFieldExpression } from '../../../utils/parseFieldExpression.js';
3
+
4
+ // `whereJsonIsArray()`, `whereJsonNotArray()`, `whereJsonIsObject()`,
5
+ // `whereJsonNotObject()` and their variants.
6
+ export class WhereJsonTypeOperation extends WhereJsonOperation {
7
+ // @override
8
+ buildWhere(dialect, [fieldExpression]) {
9
+ const { columnName, access } = parseFieldExpression(fieldExpression);
10
+ const sql = dialect.isType('??', access, this.opt.type);
11
+ // Missing values and json `null` are neither arrays nor objects:
12
+ return [this.opt.not ? `not coalesce(${sql}, false)` : sql, [columnName]];
13
+ }
14
+ }
@@ -1,8 +1,6 @@
1
- 'use strict';
2
-
3
- const { flatten, isString, isPlainObject } = require('../../../utils/objectUtils');
4
- const { Selection } = require('./Selection');
5
- const { ObjectionToKnexConvertingOperation } = require('../ObjectionToKnexConvertingOperation');
1
+ import { flatten, isString, isPlainObject } from '../../../utils/objectUtils.js';
2
+ import { Selection } from './Selection.js';
3
+ import { ObjectionToKnexConvertingOperation } from '../ObjectionToKnexConvertingOperation.js';
6
4
 
7
5
  const COUNT_REGEX = /count/i;
8
6
  const ALIAS_REGEX = /\s+as\s+/i;
@@ -18,13 +16,12 @@ const AGGREGATE_METHODS = new Set([
18
16
  'avgDistinct',
19
17
  ]);
20
18
 
21
- class SelectOperation extends ObjectionToKnexConvertingOperation {
19
+ export class SelectOperation extends ObjectionToKnexConvertingOperation {
22
20
  constructor(name, opt) {
23
21
  super(name, opt);
24
22
  this.selections = [];
25
- // The selections that aggregates select, by their aliases. `null` for
26
- // non-aggregate operations.
27
- this.aggregateSelections = AGGREGATE_METHODS.has(name) ? [] : null;
23
+ // Aggregates select their aliases, not the columns they're passed.
24
+ this.isAggregate = AGGREGATE_METHODS.has(name);
28
25
  // `distinctOn()` makes the rows distinct on its columns, it doesn't select them.
29
26
  this.isDistinctOn = name === 'distinctOn';
30
27
  }
@@ -40,7 +37,11 @@ class SelectOperation extends ObjectionToKnexConvertingOperation {
40
37
 
41
38
  const ret = super.onAdd(builder, selections);
42
39
 
43
- if (!this.isDistinctOn) {
40
+ if (this.isAggregate) {
41
+ this.selections = getAggregateAliases(selections).map(
42
+ (alias) => new Selection(null, null, alias),
43
+ );
44
+ } else if (!this.isDistinctOn) {
44
45
  for (const selection of selections) {
45
46
  const selectionInstance = Selection.create(selection);
46
47
 
@@ -50,12 +51,6 @@ class SelectOperation extends ObjectionToKnexConvertingOperation {
50
51
  }
51
52
  }
52
53
 
53
- if (this.aggregateSelections) {
54
- this.aggregateSelections = getAggregateAliases(selections).map(
55
- (alias) => new Selection(null, null, alias),
56
- );
57
- }
58
-
59
54
  return ret;
60
55
  }
61
56
 
@@ -82,7 +77,6 @@ class SelectOperation extends ObjectionToKnexConvertingOperation {
82
77
  clone() {
83
78
  const clone = super.clone();
84
79
  clone.selections = this.selections.slice();
85
- clone.aggregateSelections = this.aggregateSelections && this.aggregateSelections.slice();
86
80
  return clone;
87
81
  }
88
82
  }
@@ -102,7 +96,3 @@ function getAggregateAliases([column, options]) {
102
96
  return [];
103
97
  }
104
98
  }
105
-
106
- module.exports = {
107
- SelectOperation,
108
- };
@@ -1,7 +1,5 @@
1
- 'use strict';
2
-
3
- const { isString, isObject, isPlainObject } = require('../../../utils/objectUtils');
4
- const { isKnexQueryBuilder, isKnexRaw } = require('../../../utils/knexUtils');
1
+ import { isString, isObject, isPlainObject } from '../../../utils/objectUtils.js';
2
+ import { isKnexQueryBuilder, isKnexRaw } from '../../../utils/knexUtils.js';
5
3
 
6
4
  const ALIAS_REGEX = /\s+as\s+/i;
7
5
 
@@ -10,7 +8,7 @@ const ALIAS_REGEX = /\s+as\s+/i;
10
8
  const RAW_ALIAS_REGEX =
11
9
  /\s+as\s+(?:"([^"]+)"|`([^`]+)`|\[([^\]]+)\]|(\?\?)|:(\w+):|([a-z_][\w$]*))\s*$/i;
12
10
 
13
- class Selection {
11
+ export class Selection {
14
12
  constructor(table, column, alias) {
15
13
  this.table = table;
16
14
  this.column = column;
@@ -97,10 +95,22 @@ Object.defineProperties(Selection.prototype, {
97
95
  },
98
96
  });
99
97
 
98
+ // A selection without a column, of an aggregate, raw SQL or a subquery, selects
99
+ // the column that its alias names, e.g. `max('ownerId as ownerId')` the join
100
+ // column that the related models are assigned by. Selecting the column once
101
+ // more would replace its value.
102
+ export function hasAliasSelection(builder, alias) {
103
+ return builder
104
+ .findAllSelections()
105
+ .some(
106
+ (selection) => selection.column === null && isSameIdentifier(builder, selection.alias, alias),
107
+ );
108
+ }
109
+
100
110
  // Identifiers that only differ in a way that knex's `wrapIdentifier` mapping
101
111
  // (for example `knexSnakeCaseMappers()`) cancels out are the same identifier:
102
112
  // `dataExtension` and `data_extension` both end up as `data_extension`.
103
- function isSameIdentifier(builder, identifier1, identifier2) {
113
+ export function isSameIdentifier(builder, identifier1, identifier2) {
104
114
  if (identifier1 === identifier2) {
105
115
  return true;
106
116
  } else if (!identifier1 || !identifier2) {
@@ -112,7 +122,7 @@ function isSameIdentifier(builder, identifier1, identifier2) {
112
122
 
113
123
  // As in SQL, a table name without a schema refers to the table with a schema:
114
124
  // `persons` and `public.persons` are the same table.
115
- function isSameTable(builder, table1, table2) {
125
+ export function isSameTable(builder, table1, table2) {
116
126
  if (isSameIdentifier(builder, table1, table2)) {
117
127
  return true;
118
128
  } else if (!table1 || !table2 || hasSchema(table1) === hasSchema(table2)) {
@@ -126,11 +136,11 @@ function hasSchema(table) {
126
136
  return table.includes('.');
127
137
  }
128
138
 
129
- function withoutSchema(table) {
139
+ export function withoutSchema(table) {
130
140
  return table.slice(table.lastIndexOf('.') + 1);
131
141
  }
132
142
 
133
- function mapIdentifier(builder, identifier) {
143
+ export function mapIdentifier(builder, identifier) {
134
144
  const knex = builder.unsafeKnex();
135
145
  const wrapIdentifier = knex && knex.client && knex.client.config.wrapIdentifier;
136
146
 
@@ -227,11 +237,3 @@ function createSelectionFromString(selection) {
227
237
 
228
238
  return new Selection(table, column, alias);
229
239
  }
230
-
231
- module.exports = {
232
- Selection,
233
- isSameIdentifier,
234
- isSameTable,
235
- mapIdentifier,
236
- withoutSchema,
237
- };
@@ -1,10 +1,8 @@
1
- 'use strict';
1
+ import { ObjectionToKnexConvertingOperation } from '../ObjectionToKnexConvertingOperation.js';
2
+ import { flatten, zipObject, isString } from '../../../utils/objectUtils.js';
3
+ import { getTempColumn } from '../../../utils/tmpColumnUtils.js';
2
4
 
3
- const { ObjectionToKnexConvertingOperation } = require('../ObjectionToKnexConvertingOperation');
4
- const { flatten, zipObject, isString } = require('../../../utils/objectUtils');
5
- const { getTempColumn } = require('../../../utils/tmpColumnUtils');
6
-
7
- class WhereInCompositeMsSqlOperation extends ObjectionToKnexConvertingOperation {
5
+ export class WhereInCompositeMsSqlOperation extends ObjectionToKnexConvertingOperation {
8
6
  constructor(name, opt) {
9
7
  super(name, opt);
10
8
  this.prefix = this.opt.prefix || null;
@@ -119,7 +117,3 @@ function pickNonNull(values, output) {
119
117
 
120
118
  return output;
121
119
  }
122
-
123
- module.exports = {
124
- WhereInCompositeMsSqlOperation,
125
- };
@@ -1,10 +1,8 @@
1
- 'use strict';
1
+ import { ObjectionToKnexConvertingOperation } from '../ObjectionToKnexConvertingOperation.js';
2
+ import { isObject, asSingle } from '../../../utils/objectUtils.js';
3
+ import { isKnexQueryBuilder } from '../../../utils/knexUtils.js';
2
4
 
3
- const { ObjectionToKnexConvertingOperation } = require('../ObjectionToKnexConvertingOperation');
4
- const { isObject, asSingle } = require('../../../utils/objectUtils');
5
- const { isKnexQueryBuilder } = require('../../../utils/knexUtils');
6
-
7
- class WhereInCompositeOperation extends ObjectionToKnexConvertingOperation {
5
+ export class WhereInCompositeOperation extends ObjectionToKnexConvertingOperation {
8
6
  constructor(name, opt) {
9
7
  super(name, opt);
10
8
  this.prefix = this.opt.prefix || null;
@@ -98,7 +96,3 @@ function pickNonNull(values, output) {
98
96
 
99
97
  return output;
100
98
  }
101
-
102
- module.exports = {
103
- WhereInCompositeOperation,
104
- };
@@ -1,10 +1,8 @@
1
- 'use strict';
1
+ import { ObjectionToKnexConvertingOperation } from '../ObjectionToKnexConvertingOperation.js';
2
+ import { isKnexQueryBuilder } from '../../../utils/knexUtils.js';
3
+ import { asSingle } from '../../../utils/objectUtils.js';
2
4
 
3
- const { ObjectionToKnexConvertingOperation } = require('../ObjectionToKnexConvertingOperation');
4
- const { isKnexQueryBuilder } = require('../../../utils/knexUtils');
5
- const { asSingle } = require('../../../utils/objectUtils');
6
-
7
- class WhereInCompositeSqliteOperation extends ObjectionToKnexConvertingOperation {
5
+ export class WhereInCompositeSqliteOperation extends ObjectionToKnexConvertingOperation {
8
6
  constructor(name, opt) {
9
7
  super(name, opt);
10
8
  this.prefix = this.opt.prefix || null;
@@ -102,7 +100,3 @@ function pickNonNull(values, output) {
102
100
 
103
101
  return output;
104
102
  }
105
-
106
- module.exports = {
107
- WhereInCompositeSqliteOperation,
108
- };
@@ -0,0 +1,56 @@
1
+ import { isString } from '../../utils/objectUtils.js';
2
+ import { isKnexRaw } from '../../utils/knexUtils.js';
3
+ import { Selection, isSameTable } from './select/Selection.js';
4
+
5
+ // Without underscores, so that column name mappers don't change it.
6
+ export const rowNumberColumn = 'objectiontmprownum';
7
+
8
+ // Convert the `orderBy()` and `orderByRaw()` calls of the query to the order
9
+ // of knex's window functions, which refer to the query's table by `table`.
10
+ // Bare columns are qualified with it too, as the window can be in a query that
11
+ // joins tables with the same columns.
12
+ export function getWindowOrder(builder, knex, table) {
13
+ const order = [];
14
+ const tableRef = builder.tableRef();
15
+
16
+ const getAliasedColumn = (column) => {
17
+ const selection = isString(column) && Selection.create(column);
18
+ return selection && (!selection.table || isSameTable(builder, selection.table, tableRef))
19
+ ? `${table}.${selection.column}`
20
+ : column;
21
+ };
22
+
23
+ builder.forEachOperation(builder.constructor.OrderBySelector, (op) => {
24
+ const args = op.getKnexArgs(builder);
25
+
26
+ if (op.name === 'orderByRaw') {
27
+ const [sql, bindings] = args;
28
+ order.push({ column: isKnexRaw(sql) ? sql : knex.raw(sql, bindings) });
29
+ } else {
30
+ const [column, direction, nulls] = args;
31
+ const items = Array.isArray(column)
32
+ ? column.map((item) => (isString(item) ? { column: item } : item))
33
+ : [{ column, order: direction, nulls }];
34
+
35
+ for (const item of items) {
36
+ const aliasedColumn = getAliasedColumn(item.column);
37
+
38
+ if (item.nulls) {
39
+ // Not all databases support `nulls first` and `nulls last`:
40
+ order.push({
41
+ column: knex.raw('(case when ? is null then 0 else 1 end)', [
42
+ isString(aliasedColumn) ? knex.ref(aliasedColumn) : aliasedColumn,
43
+ ]),
44
+ order: item.nulls === 'first' ? 'asc' : 'desc',
45
+ });
46
+ }
47
+
48
+ // Unlike in `orderBy()`, knex adds the direction to the window as it is:
49
+ order.push({ column: aliasedColumn, order: /^desc$/i.test(item.order) ? 'desc' : 'asc' });
50
+ }
51
+ }
52
+ });
53
+
54
+ // SQL Server requires an order in the window function:
55
+ return order.length ? order : [{ column: knex.raw('(select null)') }];
56
+ }
@@ -2,8 +2,6 @@
2
2
  //
3
3
  // https://peggyjs.org/
4
4
 
5
- 'use strict';
6
-
7
5
  class peg$SyntaxError extends SyntaxError {
8
6
  constructor(message, expected, found, location) {
9
7
  super(message);
@@ -987,8 +985,6 @@ function peg$parse(input, options) {
987
985
  }
988
986
  }
989
987
 
990
- module.exports = {
991
- StartRules: ['start'],
992
- SyntaxError: peg$SyntaxError,
993
- parse: peg$parse,
994
- };
988
+ const peg$allowedStartRules = ['start'];
989
+
990
+ export { peg$allowedStartRules as StartRules, peg$SyntaxError as SyntaxError, peg$parse as parse };
@@ -2,10 +2,6 @@
2
2
  //
3
3
  // https://peggyjs.org/
4
4
 
5
- 'use strict';
6
-
7
- const { warnOnce } = require('../../utils/warnings');
8
-
9
5
  class peg$SyntaxError extends SyntaxError {
10
6
  constructor(message, expected, found, location) {
11
7
  super(message);
@@ -216,12 +212,11 @@ function peg$parse(input, options) {
216
212
  function peg$f0(expr) {
217
213
  const node = newNode();
218
214
 
219
- if (expr.$name === '*') {
215
+ if (expr.$relation === '*') {
216
+ assertPlainToken(expr);
220
217
  node.$allRecursive = true;
221
218
  } else {
222
- assertDuplicateRelation(node, expr);
223
- node[expr.$name] = expr;
224
- node.$childNames.push(expr.$name);
219
+ addChild(node, expr);
225
220
  }
226
221
 
227
222
  return node;
@@ -229,11 +224,7 @@ function peg$parse(input, options) {
229
224
  function peg$f1(list) {
230
225
  const node = newNode();
231
226
 
232
- list.forEach((expr) => {
233
- assertDuplicateRelation(node, expr);
234
- node[expr.$name] = expr;
235
- node.$childNames.push(expr.$name);
236
- });
227
+ list.forEach((expr) => addChild(node, expr));
237
228
 
238
229
  return node;
239
230
  }
@@ -244,11 +235,7 @@ function peg$parse(input, options) {
244
235
  node.$relation = name;
245
236
  node.$modify = args || [];
246
237
 
247
- list.forEach((expr) => {
248
- assertDuplicateRelation(node, expr);
249
- node[expr.$name] = expr;
250
- node.$childNames.push(expr.$name);
251
- });
238
+ list.forEach((expr) => addChild(node, expr));
252
239
 
253
240
  return node;
254
241
  }
@@ -260,20 +247,14 @@ function peg$parse(input, options) {
260
247
  node.$modify = args || [];
261
248
 
262
249
  if (expr) {
263
- const match = /^\^(\d*)$/.exec(expr.$name);
264
-
265
- if (match) {
266
- if (match[1]) {
267
- node.$recursive = parseInt(match[1], 10);
268
- } else {
269
- node.$recursive = true;
270
- }
271
- } else if (expr.$name === '*') {
250
+ if (expr.$relation === '*') {
251
+ assertPlainToken(expr);
272
252
  node.$allRecursive = true;
253
+ } else if (isToken(expr.$relation)) {
254
+ assertPlainToken(expr);
255
+ node.$recursive = expr.$relation === '^' ? true : parseInt(expr.$relation.slice(1), 10);
273
256
  } else {
274
- assertDuplicateRelation(node, expr);
275
- node[expr.$name] = expr;
276
- node.$childNames.push(expr.$name);
257
+ addChild(node, expr);
277
258
  }
278
259
  }
279
260
 
@@ -944,19 +925,39 @@ function peg$parse(input, options) {
944
925
  return s0;
945
926
  }
946
927
 
947
- function assertDuplicateRelation(node, expr) {
928
+ function addChild(node, expr) {
929
+ if (isToken(expr.$relation)) {
930
+ throwMisplacedToken(expr.$relation);
931
+ }
932
+
948
933
  if (Object.prototype.hasOwnProperty.call(node, expr.$name)) {
949
- warnOnce(
950
- `Duplicate relation "${expr.$name}" in a relation expression, only the last one is used. Use "a.[b, c]" instead of "[a.b, a.c]". This will throw an error in objection 4.0.`,
951
- );
934
+ const err = new Error();
935
+ err.duplicateRelationName = expr.$name;
936
+ throw err;
937
+ }
952
938
 
953
- // Throws in objection 4.0, see ditojs/objection#53.
954
- // const err = new Error();
955
- // err.duplicateRelationName = expr.$name;
956
- // throw err;
939
+ node[expr.$name] = expr;
940
+ node.$childNames.push(expr.$name);
941
+ }
942
+
943
+ // `*` and `^` end a relation path, without modifiers, aliases or relations
944
+ // after them.
945
+ function isToken(name) {
946
+ return /^(\*|\^\d*)$/.test(name);
947
+ }
948
+
949
+ function assertPlainToken(expr) {
950
+ if (expr.$childNames.length > 0 || expr.$modify.length > 0 || expr.$name !== expr.$relation) {
951
+ throwMisplacedToken(expr.$relation);
957
952
  }
958
953
  }
959
954
 
955
+ function throwMisplacedToken(token) {
956
+ const err = new Error();
957
+ err.misplacedToken = token;
958
+ throw err;
959
+ }
960
+
960
961
  function newNode() {
961
962
  return {
962
963
  $name: null,
@@ -1002,8 +1003,6 @@ function peg$parse(input, options) {
1002
1003
  }
1003
1004
  }
1004
1005
 
1005
- module.exports = {
1006
- StartRules: ['start'],
1007
- SyntaxError: peg$SyntaxError,
1008
- parse: peg$parse,
1009
- };
1006
+ const peg$allowedStartRules = ['start'];
1007
+
1008
+ export { peg$allowedStartRules as StartRules, peg$SyntaxError as SyntaxError, peg$parse as parse };