@abedmurrar/objection 4.0.0-alpha.0 → 4.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/README.md +103 -67
  2. package/lib/index.mjs +6 -0
  3. package/lib/initialize.js +6 -9
  4. package/lib/model/AjvValidator.js +235 -282
  5. package/lib/model/Model.js +653 -823
  6. package/lib/model/ModifierNotFoundError.js +5 -7
  7. package/lib/model/NotFoundError.js +14 -18
  8. package/lib/model/RelationDoesNotExistError.js +6 -9
  9. package/lib/model/ValidationError.js +33 -41
  10. package/lib/model/Validator.js +15 -21
  11. package/lib/model/getModel.js +1 -3
  12. package/lib/model/graph/ModelGraph.js +44 -64
  13. package/lib/model/graph/ModelGraphBuilder.js +164 -217
  14. package/lib/model/graph/ModelGraphEdge.js +31 -43
  15. package/lib/model/graph/ModelGraphNode.js +192 -231
  16. package/lib/model/inheritModel.js +9 -18
  17. package/lib/model/modelBindKnex.js +48 -62
  18. package/lib/model/modelClone.js +79 -98
  19. package/lib/model/modelColPropMap.js +16 -26
  20. package/lib/model/modelConcurrency.js +24 -0
  21. package/lib/model/modelId.js +44 -49
  22. package/lib/model/modelJsonAttributes.js +56 -76
  23. package/lib/model/modelParseRelations.js +68 -67
  24. package/lib/model/modelQueryProps.js +76 -107
  25. package/lib/model/modelSet.js +92 -112
  26. package/lib/model/modelTableMetadata.js +60 -72
  27. package/lib/model/modelToJson.js +120 -150
  28. package/lib/model/modelUtils.js +30 -37
  29. package/lib/model/modelValidate.js +34 -42
  30. package/lib/model/modelValues.js +78 -91
  31. package/lib/model/modelVisitor.js +22 -29
  32. package/lib/objection.js +42 -67
  33. package/lib/queryBuilder/FunctionBuilder.js +231 -279
  34. package/lib/queryBuilder/InternalOptions.js +19 -24
  35. package/lib/queryBuilder/JoinBuilder.js +116 -149
  36. package/lib/queryBuilder/QueryBuilder.js +1009 -1271
  37. package/lib/queryBuilder/QueryBuilderBase.js +647 -865
  38. package/lib/queryBuilder/QueryBuilderContext.js +14 -21
  39. package/lib/queryBuilder/QueryBuilderContextBase.js +20 -29
  40. package/lib/queryBuilder/QueryBuilderOperationSupport.js +462 -536
  41. package/lib/queryBuilder/QueryBuilderUserContext.js +19 -25
  42. package/lib/queryBuilder/RawBuilder.js +58 -73
  43. package/lib/queryBuilder/ReferenceBuilder.js +232 -270
  44. package/lib/queryBuilder/RelationExpression.js +322 -380
  45. package/lib/queryBuilder/StaticHookArguments.js +94 -106
  46. package/lib/queryBuilder/ValueBuilder.js +100 -112
  47. package/lib/queryBuilder/expressions.js +86 -116
  48. package/lib/queryBuilder/functions/mysql.js +642 -697
  49. package/lib/queryBuilder/graph/GraphAction.js +44 -59
  50. package/lib/queryBuilder/graph/GraphData.js +7 -9
  51. package/lib/queryBuilder/graph/GraphFetcher.js +115 -151
  52. package/lib/queryBuilder/graph/GraphNodeDbExistence.js +114 -152
  53. package/lib/queryBuilder/graph/GraphOperation.js +16 -22
  54. package/lib/queryBuilder/graph/GraphOptions.js +143 -185
  55. package/lib/queryBuilder/graph/GraphUpsert.js +167 -241
  56. package/lib/queryBuilder/graph/delete/GraphDelete.js +8 -13
  57. package/lib/queryBuilder/graph/delete/GraphDeleteAction.js +44 -62
  58. package/lib/queryBuilder/graph/insert/GraphInsert.js +99 -128
  59. package/lib/queryBuilder/graph/insert/GraphInsertAction.js +151 -193
  60. package/lib/queryBuilder/graph/insert/JoinRowGraphInsertAction.js +57 -79
  61. package/lib/queryBuilder/graph/patch/GraphPatch.js +8 -13
  62. package/lib/queryBuilder/graph/patch/GraphPatchAction.js +181 -234
  63. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsert.js +16 -21
  64. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsertAction.js +80 -110
  65. package/lib/queryBuilder/join/JoinResultColumn.js +14 -18
  66. package/lib/queryBuilder/join/JoinResultParser.js +88 -101
  67. package/lib/queryBuilder/join/RelationJoiner.js +205 -288
  68. package/lib/queryBuilder/join/TableNode.js +117 -144
  69. package/lib/queryBuilder/join/TableTree.js +60 -76
  70. package/lib/queryBuilder/join/utils.js +10 -16
  71. package/lib/queryBuilder/operations/DelegateOperation.js +93 -133
  72. package/lib/queryBuilder/operations/DeleteOperation.js +33 -37
  73. package/lib/queryBuilder/operations/FindByIdOperation.js +20 -28
  74. package/lib/queryBuilder/operations/FindByIdsOperation.js +17 -23
  75. package/lib/queryBuilder/operations/FindOperation.js +114 -131
  76. package/lib/queryBuilder/operations/FirstOperation.js +14 -19
  77. package/lib/queryBuilder/operations/FromOperation.js +69 -88
  78. package/lib/queryBuilder/operations/InsertAndFetchOperation.js +28 -39
  79. package/lib/queryBuilder/operations/InsertGraphAndFetchOperation.js +25 -35
  80. package/lib/queryBuilder/operations/InsertGraphOperation.js +77 -98
  81. package/lib/queryBuilder/operations/InsertOperation.js +132 -165
  82. package/lib/queryBuilder/operations/InstanceDeleteOperation.js +27 -36
  83. package/lib/queryBuilder/operations/InstanceFindOperation.js +9 -13
  84. package/lib/queryBuilder/operations/InstanceInsertOperation.js +13 -17
  85. package/lib/queryBuilder/operations/InstanceUpdateOperation.js +32 -46
  86. package/lib/queryBuilder/operations/JoinRelatedOperation.js +66 -86
  87. package/lib/queryBuilder/operations/KnexOperation.js +4 -7
  88. package/lib/queryBuilder/operations/MergeOperation.js +32 -45
  89. package/lib/queryBuilder/operations/ObjectionToKnexConvertingOperation.js +131 -150
  90. package/lib/queryBuilder/operations/OnBuildKnexOperation.js +17 -23
  91. package/lib/queryBuilder/operations/OnBuildOperation.js +17 -23
  92. package/lib/queryBuilder/operations/OnErrorOperation.js +17 -23
  93. package/lib/queryBuilder/operations/QueryBuilderOperation.js +231 -270
  94. package/lib/queryBuilder/operations/RangeOperation.js +30 -40
  95. package/lib/queryBuilder/operations/RelateOperation.js +14 -21
  96. package/lib/queryBuilder/operations/ReturningOperation.js +12 -18
  97. package/lib/queryBuilder/operations/RunAfterOperation.js +17 -23
  98. package/lib/queryBuilder/operations/RunBeforeOperation.js +17 -23
  99. package/lib/queryBuilder/operations/UnrelateOperation.js +12 -17
  100. package/lib/queryBuilder/operations/UpdateAndFetchOperation.js +48 -65
  101. package/lib/queryBuilder/operations/UpdateOperation.js +104 -129
  102. package/lib/queryBuilder/operations/UpsertGraphAndFetchOperation.js +25 -35
  103. package/lib/queryBuilder/operations/UpsertGraphOperation.js +36 -55
  104. package/lib/queryBuilder/operations/WhereCompositeOperation.js +30 -39
  105. package/lib/queryBuilder/operations/WhereInOperation.js +34 -36
  106. package/lib/queryBuilder/operations/eager/EagerOperation.js +37 -52
  107. package/lib/queryBuilder/operations/eager/JoinEagerOperation.js +34 -44
  108. package/lib/queryBuilder/operations/eager/NaiveEagerOperation.js +4 -7
  109. package/lib/queryBuilder/operations/eager/WhereInEagerOperation.js +193 -251
  110. package/lib/queryBuilder/operations/jsonApi/WhereJsonHasOperation.js +18 -25
  111. package/lib/queryBuilder/operations/jsonApi/WhereJsonNotObjectOperation.js +25 -41
  112. package/lib/queryBuilder/operations/jsonApi/WhereJsonOperation.js +19 -20
  113. package/lib/queryBuilder/operations/jsonApi/WhereJsonOverlapsOperation.js +23 -21
  114. package/lib/queryBuilder/operations/jsonApi/mysqlJsonApi.js +106 -118
  115. package/lib/queryBuilder/operations/jsonApi/postgresJsonApi.js +79 -108
  116. package/lib/queryBuilder/operations/select/SelectOperation.js +37 -53
  117. package/lib/queryBuilder/operations/select/Selection.js +94 -105
  118. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeMsSqlOperation.js +68 -101
  119. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeOperation.js +65 -75
  120. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeSqliteOperation.js +75 -84
  121. package/lib/queryBuilder/parsers/jsonFieldExpressionParser.js +760 -859
  122. package/lib/queryBuilder/parsers/relationExpressionParser.js +840 -952
  123. package/lib/queryBuilder/transformations/CompositeQueryTransformation.js +10 -15
  124. package/lib/queryBuilder/transformations/QueryTransformation.js +4 -6
  125. package/lib/queryBuilder/transformations/WrapMysqlModifySubqueryTransformation.js +35 -49
  126. package/lib/queryBuilder/transformations/index.js +3 -9
  127. package/lib/queryBuilder/whereScopes.js +158 -186
  128. package/lib/relations/Relation.js +279 -363
  129. package/lib/relations/RelationDeleteOperation.js +16 -22
  130. package/lib/relations/RelationFindOperation.js +100 -133
  131. package/lib/relations/RelationInsertOperation.js +19 -27
  132. package/lib/relations/RelationOwner.js +167 -204
  133. package/lib/relations/RelationProperty.js +177 -217
  134. package/lib/relations/RelationUpdateOperation.js +16 -23
  135. package/lib/relations/belongsToOne/BelongsToOneDeleteOperation.js +11 -16
  136. package/lib/relations/belongsToOne/BelongsToOneInsertOperation.js +24 -35
  137. package/lib/relations/belongsToOne/BelongsToOneRelateOperation.js +30 -41
  138. package/lib/relations/belongsToOne/BelongsToOneRelation.js +33 -41
  139. package/lib/relations/belongsToOne/BelongsToOneUnrelateOperation.js +38 -53
  140. package/lib/relations/hasMany/HasManyInsertOperation.js +35 -51
  141. package/lib/relations/hasMany/HasManyRelateOperation.js +38 -54
  142. package/lib/relations/hasMany/HasManyRelation.js +30 -38
  143. package/lib/relations/hasMany/HasManyUnrelateOperation.js +19 -26
  144. package/lib/relations/hasOne/HasOneRelation.js +4 -7
  145. package/lib/relations/hasOneThrough/HasOneThroughRelation.js +4 -7
  146. package/lib/relations/manyToMany/ManyToManyModifyMixin.js +67 -90
  147. package/lib/relations/manyToMany/ManyToManyRelation.js +349 -451
  148. package/lib/relations/manyToMany/ManyToManySqliteModifyMixin.js +19 -26
  149. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperation.js +3 -5
  150. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperationBase.js +14 -20
  151. package/lib/relations/manyToMany/delete/ManyToManyDeleteSqliteOperation.js +3 -7
  152. package/lib/relations/manyToMany/find/ManyToManyFindOperation.js +71 -94
  153. package/lib/relations/manyToMany/insert/ManyToManyInsertOperation.js +31 -43
  154. package/lib/relations/manyToMany/relate/ManyToManyRelateOperation.js +50 -67
  155. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperation.js +4 -7
  156. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperationBase.js +20 -27
  157. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateSqliteOperation.js +5 -10
  158. package/lib/relations/manyToMany/update/ManyToManyUpdateOperation.js +3 -5
  159. package/lib/relations/manyToMany/update/ManyToManyUpdateOperationBase.js +55 -72
  160. package/lib/relations/manyToMany/update/ManyToManyUpdateSqliteOperation.js +3 -7
  161. package/lib/transaction.js +53 -83
  162. package/lib/utils/assert.js +15 -21
  163. package/lib/utils/buildUtils.js +17 -19
  164. package/lib/utils/classUtils.js +7 -11
  165. package/lib/utils/cloneDeep.js +365 -0
  166. package/lib/utils/createModifier.js +36 -41
  167. package/lib/utils/deprecate.js +8 -12
  168. package/lib/utils/identifierMapping.js +153 -192
  169. package/lib/utils/internalPropUtils.js +4 -8
  170. package/lib/utils/knexUtils.js +61 -56
  171. package/lib/utils/mixin.js +16 -23
  172. package/lib/utils/mysqlJsonPath.js +55 -40
  173. package/lib/utils/normalizeIds.js +110 -127
  174. package/lib/utils/objectUtils.js +236 -338
  175. package/lib/utils/parseFieldExpression.js +66 -44
  176. package/lib/utils/postgresJsonPath.js +48 -62
  177. package/lib/utils/promiseUtils/after.js +10 -13
  178. package/lib/utils/promiseUtils/afterReturn.js +10 -13
  179. package/lib/utils/promiseUtils/index.js +15 -17
  180. package/lib/utils/promiseUtils/isPromise.js +6 -9
  181. package/lib/utils/promiseUtils/map.js +75 -89
  182. package/lib/utils/promiseUtils/mapAfterAllReturn.js +17 -23
  183. package/lib/utils/promiseUtils/try.js +15 -18
  184. package/lib/utils/resolveModel.js +91 -94
  185. package/lib/utils/tmpColumnUtils.js +4 -13
  186. package/package.json +50 -23
  187. package/typings/objection/index.d.mts +362 -0
  188. package/typings/objection/index.d.ts +36 -9
  189. package/lib/.eslintrc.json +0 -8
  190. package/lib/queryBuilder/parsers/jsonFieldExpressionParser.pegjs +0 -97
  191. package/lib/queryBuilder/parsers/relationExpressionParser.pegjs +0 -141
  192. package/lib/utils/clone.js +0 -2329
@@ -1,339 +1,291 @@
1
1
  'use strict';
2
-
3
2
  const { RawBuilder, normalizeRawArgs } = require('./RawBuilder');
4
3
  const { ref } = require('./ReferenceBuilder');
5
4
  const { expression } = require('./expressions');
6
5
  const { asArray, asSingle, isNumber, isObject, isPlainObject } = require('../utils/objectUtils');
7
- const { getDialect, isMySql } = require('../utils/knexUtils');
8
- const { FUNCTIONS, buildOrderBy } = require('./functions/mysql');
9
-
6
+ const { getDialect, isMySql, isMariaDb } = require('../utils/knexUtils');
7
+ const { jsonCastsForDialect, JSON_CAST } = require('../utils/mysqlJsonPath');
8
+ const { FUNCTIONS, MARIADB_UNSUPPORTED, buildOrderBy } = require('./functions/mysql');
10
9
  class FunctionBuilder extends RawBuilder {
11
- constructor(sql, args) {
12
- super(sql, args);
13
- // The name of the `fn` helper of a MySQL only function.
14
- this._mysqlFunction = null;
15
- // For aggregate functions, the number of the first `?`s that are aggregated,
16
- // or '*' for `COUNT(*)`.
17
- this._aggregated = null;
18
- // The name of the `fn` helper of a window function.
19
- this._windowFunction = null;
20
- this._filters = [];
21
- this._over = null;
22
- }
23
-
24
- // Only aggregates the rows that match `condition`:
25
- //
26
- // fn.count().filter(Pet.ref('species').eq('dog'))
27
- //
28
- // is `COUNT(CASE WHEN species = 'dog' THEN 1 END)`. That works on every
29
- // database, unlike `FILTER (WHERE ...)`.
30
- filter(condition) {
31
- if (this._aggregated === null) {
32
- throw new Error(
33
- 'filter() only works with the aggregate functions of fn, like fn.count() and fn.sum().',
34
- );
10
+ constructor(sql, args) {
11
+ super(sql, args);
12
+ // The name of the `fn` helper of a MySQL only function.
13
+ this._mysqlFunction = null;
14
+ // Why the helper can't be used on MariaDB, if it can't.
15
+ this._mariaDbError = null;
16
+ // For aggregate functions, the number of the first `?`s that are aggregated,
17
+ // or '*' for `COUNT(*)`.
18
+ this._aggregated = null;
19
+ // The name of the `fn` helper of a window function.
20
+ this._windowFunction = null;
21
+ this._filters = [];
22
+ this._over = null;
35
23
  }
36
-
37
- this._filters.push(condition);
38
- return this;
39
- }
40
-
41
- // `fn.rowNumber().over({ partitionBy: 'ownerId', orderBy: ['createdAt', 'desc'] })`.
42
- over(window = {}) {
43
- for (const key of Object.keys(window)) {
44
- if (key !== 'partitionBy' && key !== 'orderBy') {
45
- throw new Error(`over(): unknown option "${key}". Use partitionBy and orderBy.`);
46
- }
24
+ // Only aggregates the rows that match `condition`:
25
+ //
26
+ // fn.count().filter(Pet.ref('species').eq('dog'))
27
+ //
28
+ // is `COUNT(CASE WHEN species = 'dog' THEN 1 END)`. That works on every
29
+ // database, unlike `FILTER (WHERE ...)`.
30
+ filter(condition) {
31
+ if (this._aggregated === null) {
32
+ throw new Error('filter() only works with the aggregate functions of fn, like fn.count() and fn.sum().');
33
+ }
34
+ this._filters.push(condition);
35
+ return this;
47
36
  }
48
-
49
- this._over = window;
50
- return this;
51
- }
52
-
53
- toKnexRaw(builder) {
54
- const knex = builder.unsafeKnex();
55
-
56
- if (this._mysqlFunction && knex && !isMySql(knex)) {
57
- throw new Error(
58
- `fn.${this._mysqlFunction}() is a MySQL function and can't be used with ${getDialect(knex)}.`,
59
- );
37
+ // `fn.rowNumber().over({ partitionBy: 'ownerId', orderBy: ['createdAt', 'desc'] })`.
38
+ over(window = {}) {
39
+ for (const key of Object.keys(window)) {
40
+ if (key !== 'partitionBy' && key !== 'orderBy') {
41
+ throw new Error(`over(): unknown option "${key}". Use partitionBy and orderBy.`);
42
+ }
43
+ }
44
+ this._over = window;
45
+ return this;
60
46
  }
61
-
62
- if (this._windowFunction && !this._over) {
63
- throw new Error(`fn.${this._windowFunction}() is a window function and needs over().`);
47
+ toKnexRaw(builder) {
48
+ const knex = builder.unsafeKnex();
49
+ if (this._mysqlFunction && knex && !isMySql(knex)) {
50
+ throw new Error(`fn.${this._mysqlFunction}() is a MySQL function and can't be used with ${getDialect(knex)}.`);
51
+ }
52
+ // The SQL of the helpers is created before the database is known.
53
+ if (knex && isMariaDb(knex) && this._sql.includes(JSON_CAST)) {
54
+ const copy = Object.assign(Object.create(Object.getPrototypeOf(this)), this);
55
+ copy._sql = jsonCastsForDialect(this._sql, knex);
56
+ return copy.toKnexRaw(builder);
57
+ }
58
+ if (this._mariaDbError && knex && isMariaDb(knex)) {
59
+ throw new Error(this._mariaDbError);
60
+ }
61
+ if (this._windowFunction && !this._over) {
62
+ throw new Error(`fn.${this._windowFunction}() is a window function and needs over().`);
63
+ }
64
+ if (this._filters.length === 0 && !this._over) {
65
+ return super.toKnexRaw(builder);
66
+ }
67
+ return new RawBuilder(...this._buildFilterAndOver()).as(this._as).toKnexRaw(builder);
64
68
  }
65
-
66
- if (this._filters.length === 0 && !this._over) {
67
- return super.toKnexRaw(builder);
69
+ _buildFilterAndOver() {
70
+ let sql = this._sql;
71
+ let args = this._args;
72
+ if (this._filters.length !== 0) {
73
+ const condition = this._filters.length === 1
74
+ ? this._filters[0]
75
+ : expression(`(${this._filters.map(() => '?').join(' AND ')})`, this._filters);
76
+ if (this._aggregated === '*') {
77
+ sql = sql.replace('*', 'CASE WHEN ? THEN 1 END');
78
+ args = [condition];
79
+ }
80
+ else {
81
+ const filtered = [];
82
+ let i = 0;
83
+ sql = sql.replace(/\?/g, () => {
84
+ const arg = args[i++];
85
+ if (i <= this._aggregated) {
86
+ filtered.push(condition, arg);
87
+ return 'CASE WHEN ? THEN ? END';
88
+ }
89
+ else {
90
+ filtered.push(arg);
91
+ return '?';
92
+ }
93
+ });
94
+ args = filtered;
95
+ }
96
+ }
97
+ if (this._over) {
98
+ const [overSql, overArgs] = buildOver(this._over);
99
+ sql = `${sql} OVER (${overSql})`;
100
+ args = [...args, ...overArgs];
101
+ }
102
+ return [sql, args];
68
103
  }
69
-
70
- return new RawBuilder(...this._buildFilterAndOver()).as(this._as).toKnexRaw(builder);
71
- }
72
-
73
- _buildFilterAndOver() {
74
- let sql = this._sql;
75
- let args = this._args;
76
-
77
- if (this._filters.length !== 0) {
78
- const condition =
79
- this._filters.length === 1
80
- ? this._filters[0]
81
- : expression(`(${this._filters.map(() => '?').join(' AND ')})`, this._filters);
82
-
83
- if (this._aggregated === '*') {
84
- sql = sql.replace('*', 'CASE WHEN ? THEN 1 END');
85
- args = [condition];
86
- } else {
87
- const filtered = [];
88
- let i = 0;
89
-
90
- sql = sql.replace(/\?/g, () => {
91
- const arg = args[i++];
92
-
93
- if (i <= this._aggregated) {
94
- filtered.push(condition, arg);
95
- return 'CASE WHEN ? THEN ? END';
96
- } else {
97
- filtered.push(arg);
98
- return '?';
99
- }
100
- });
101
-
102
- args = filtered;
103
- }
104
- }
105
-
106
- if (this._over) {
107
- const [overSql, overArgs] = buildOver(this._over);
108
- sql = `${sql} OVER (${overSql})`;
109
- args = [...args, ...overArgs];
110
- }
111
-
112
- return [sql, args];
113
- }
114
104
  }
115
-
116
105
  // `fn.case()` is `CASE WHEN condition THEN result ... END` and `fn.case(value)` is
117
106
  // `CASE value WHEN other THEN result ... END`.
118
107
  class CaseBuilder extends FunctionBuilder {
119
- constructor(hasValue, value) {
120
- super('', []);
121
- this._hasValue = hasValue;
122
- this._value = value;
123
- this._whens = [];
124
- this._hasElse = false;
125
- this._else = null;
126
- }
127
-
128
- when(condition, result) {
129
- this._whens.push([condition, result]);
130
- return this;
131
- }
132
-
133
- else(result) {
134
- this._hasElse = true;
135
- this._else = result;
136
- return this;
137
- }
138
-
139
- toKnexRaw(builder) {
140
- if (this._whens.length === 0) {
141
- throw new Error('fn.case() needs at least one when().');
108
+ constructor(hasValue, value) {
109
+ super('', []);
110
+ this._hasValue = hasValue;
111
+ this._value = value;
112
+ this._whens = [];
113
+ this._hasElse = false;
114
+ this._else = null;
115
+ }
116
+ when(condition, result) {
117
+ this._whens.push([condition, result]);
118
+ return this;
142
119
  }
143
-
144
- const args = this._hasValue ? [this._value] : [];
145
- let sql = this._hasValue ? '(CASE ?' : '(CASE';
146
-
147
- for (const [condition, result] of this._whens) {
148
- sql += ' WHEN ? THEN ?';
149
- args.push(condition, result);
120
+ else(result) {
121
+ this._hasElse = true;
122
+ this._else = result;
123
+ return this;
150
124
  }
151
-
152
- if (this._hasElse) {
153
- sql += ' ELSE ?';
154
- args.push(this._else);
125
+ toKnexRaw(builder) {
126
+ if (this._whens.length === 0) {
127
+ throw new Error('fn.case() needs at least one when().');
128
+ }
129
+ const args = this._hasValue ? [this._value] : [];
130
+ let sql = this._hasValue ? '(CASE ?' : '(CASE';
131
+ for (const [condition, result] of this._whens) {
132
+ sql += ' WHEN ? THEN ?';
133
+ args.push(condition, result);
134
+ }
135
+ if (this._hasElse) {
136
+ sql += ' ELSE ?';
137
+ args.push(this._else);
138
+ }
139
+ this._sql = `${sql} END)`;
140
+ this._args = args;
141
+ return super.toKnexRaw(builder);
155
142
  }
156
-
157
- this._sql = `${sql} END)`;
158
- this._args = args;
159
-
160
- return super.toKnexRaw(builder);
161
- }
162
143
  }
163
-
164
144
  // The value an upsert tried to insert: `VALUES(col)` on MySQL, `excluded.col` on
165
145
  // postgres and SQLite.
166
146
  class ExcludedBuilder extends FunctionBuilder {
167
- constructor(column) {
168
- super('', []);
169
-
170
- if (isObject(column) && column.isObjectionReferenceBuilder) {
171
- column = column.column;
147
+ constructor(column) {
148
+ super('', []);
149
+ if (isObject(column) && column.isObjectionReferenceBuilder) {
150
+ column = column.column;
151
+ }
152
+ if (typeof column !== 'string') {
153
+ throw new Error('fn.excluded() takes a column name.');
154
+ }
155
+ this._column = column;
172
156
  }
173
-
174
- if (typeof column !== 'string') {
175
- throw new Error('fn.excluded() takes a column name.');
157
+ toKnexRaw(builder) {
158
+ if (isMySql(builder.unsafeKnex())) {
159
+ this._sql = 'VALUES(??)';
160
+ this._args = [this._column];
161
+ }
162
+ else {
163
+ this._sql = '??';
164
+ this._args = [`excluded.${this._column}`];
165
+ }
166
+ return super.toKnexRaw(builder);
176
167
  }
177
-
178
- this._column = column;
179
- }
180
-
181
- toKnexRaw(builder) {
182
- if (isMySql(builder.unsafeKnex())) {
183
- this._sql = 'VALUES(??)';
184
- this._args = [this._column];
185
- } else {
186
- this._sql = '??';
187
- this._args = [`excluded.${this._column}`];
188
- }
189
-
190
- return super.toKnexRaw(builder);
191
- }
192
168
  }
193
-
194
169
  function buildOver({ partitionBy, orderBy }) {
195
- const parts = [];
196
- const args = [];
197
-
198
- if (partitionBy !== undefined) {
199
- const columns = asArray(partitionBy).map((it) => (typeof it === 'string' ? ref(it) : it));
200
- parts.push(`PARTITION BY ${columns.map(() => '?').join(', ')}`);
201
- args.push(...columns);
202
- }
203
-
204
- if (orderBy !== undefined) {
205
- const [orderBySql, orderByArgs] = buildOrderBy('over()', orderBy);
206
- parts.push(`ORDER BY ${orderBySql}`);
207
- args.push(...orderByArgs);
208
- }
209
-
210
- return [parts.join(' '), args];
170
+ const parts = [];
171
+ const args = [];
172
+ if (partitionBy !== undefined) {
173
+ const columns = asArray(partitionBy).map((it) => (typeof it === 'string' ? ref(it) : it));
174
+ parts.push(`PARTITION BY ${columns.map(() => '?').join(', ')}`);
175
+ args.push(...columns);
176
+ }
177
+ if (orderBy !== undefined) {
178
+ const [orderBySql, orderByArgs] = buildOrderBy('over()', orderBy);
179
+ parts.push(`ORDER BY ${orderBySql}`);
180
+ args.push(...orderByArgs);
181
+ }
182
+ return [parts.join(' '), args];
211
183
  }
212
-
213
184
  function fn(...argsIn) {
214
- const { sql, args } = normalizeRawArgs(argsIn);
215
- return new FunctionBuilder(`${sql}(${args.map(() => '?').join(', ')})`, args);
185
+ const { sql, args } = normalizeRawArgs(argsIn);
186
+ return new FunctionBuilder(`${sql}(${args.map(() => '?').join(', ')})`, args);
216
187
  }
217
-
218
188
  for (const func of ['coalesce', 'concat', 'upper', 'lower']) {
219
- fn[func] = (...args) => fn(func.toUpperCase(), args);
189
+ fn[func] = (...args) => fn(func.toUpperCase(), args);
220
190
  }
221
-
222
191
  for (const func of ['sum', 'avg', 'min', 'max']) {
223
- fn[func] = (...args) => aggregate(fn(func.toUpperCase(), args), args.length);
192
+ fn[func] = (...args) => aggregate(fn(func.toUpperCase(), args), args.length);
224
193
  }
225
-
226
194
  // `fn.count()` and `fn.count('*')` are `COUNT(*)`.
227
195
  fn.count = (...args) => {
228
- if (args.length === 0 || (args.length === 1 && args[0] === '*')) {
229
- return aggregate(new FunctionBuilder('COUNT(*)', []), '*');
230
- }
231
-
232
- return aggregate(fn('COUNT', args), args.length);
196
+ if (args.length === 0 || (args.length === 1 && args[0] === '*')) {
197
+ return aggregate(new FunctionBuilder('COUNT(*)', []), '*');
198
+ }
199
+ return aggregate(fn('COUNT', args), args.length);
233
200
  };
234
-
235
201
  fn.now = (precision) => {
236
- precision = parseInt(asSingle(precision), 10);
237
-
238
- if (isNaN(precision) || !isNumber(precision)) {
239
- precision = 6;
240
- }
241
-
242
- // We need to use a literal precision instead of a binding here
243
- // for the CURRENT_TIMESTAMP to work. This is okay here since we
244
- // make sure `precision` is a number. There's no chance of SQL
245
- // injection here.
246
- return new FunctionBuilder(`CURRENT_TIMESTAMP(${precision})`, []);
202
+ precision = parseInt(asSingle(precision), 10);
203
+ if (isNaN(precision) || !isNumber(precision)) {
204
+ precision = 6;
205
+ }
206
+ // We need to use a literal precision instead of a binding here
207
+ // for the CURRENT_TIMESTAMP to work. This is okay here since we
208
+ // make sure `precision` is a number. There's no chance of SQL
209
+ // injection here.
210
+ return new FunctionBuilder(`CURRENT_TIMESTAMP(${precision})`, []);
247
211
  };
248
-
249
212
  fn.case = (...args) => new CaseBuilder(args.length !== 0, args[0]);
250
-
251
213
  fn.exists = (subquery) => {
252
- if (!isObject(subquery) || !subquery.isObjectionQueryBuilderBase) {
253
- throw new Error('fn.exists() takes a query.');
254
- }
255
-
256
- return new FunctionBuilder('(EXISTS ?)', [subquery]);
214
+ if (!isObject(subquery) || !subquery.isObjectionQueryBuilderBase) {
215
+ throw new Error('fn.exists() takes a query.');
216
+ }
217
+ return new FunctionBuilder('(EXISTS ?)', [subquery]);
257
218
  };
258
-
259
219
  fn.excluded = (column) => new ExcludedBuilder(column);
260
-
261
220
  for (const [name, sql, , , options = {}] of FUNCTIONS) {
262
- // `defineProperty` since `fn.length` is a read-only property of functions.
263
- Object.defineProperty(fn, name, {
264
- configurable: true,
265
- enumerable: true,
266
- writable: true,
267
- value: createMySqlFunction(name, sql, options),
268
- });
221
+ // `defineProperty` since `fn.length` is a read-only property of functions.
222
+ Object.defineProperty(fn, name, {
223
+ configurable: true,
224
+ enumerable: true,
225
+ writable: true,
226
+ value: createMySqlFunction(name, sql, options),
227
+ });
269
228
  }
270
-
271
229
  function createMySqlFunction(name, sql, options) {
272
- return (...args) => {
273
- const [text, values] = options.build
274
- ? options.build(name, sql, args)
275
- : [`${sql}(${args.map(() => '?').join(', ')})`, args];
276
-
277
- const builder = createWithJsonArgs(text, values, options.json);
278
-
279
- if (!options.portable) {
280
- builder._mysqlFunction = name;
281
- }
282
-
283
- if (options.window) {
284
- builder._windowFunction = name;
285
- }
286
-
287
- if (options.aggregate) {
288
- aggregate(builder, options.aggregate === true ? args.length : options.aggregate(args));
289
- }
290
-
291
- return builder;
292
- };
230
+ return (...args) => {
231
+ const [text, values] = options.build
232
+ ? options.build(name, sql, args)
233
+ : [`${sql}(${args.map(() => '?').join(', ')})`, args];
234
+ const builder = createWithJsonArgs(text, values, options.json);
235
+ if (!options.portable) {
236
+ builder._mysqlFunction = name;
237
+ }
238
+ const mariaDbReason = MARIADB_UNSUPPORTED[name] && MARIADB_UNSUPPORTED[name](args);
239
+ if (mariaDbReason) {
240
+ builder._mariaDbError = `fn.${name}() ${mariaDbReason}.`;
241
+ }
242
+ if (options.window) {
243
+ builder._windowFunction = name;
244
+ }
245
+ if (options.aggregate) {
246
+ aggregate(builder, options.aggregate === true ? args.length : options.aggregate(args));
247
+ }
248
+ return builder;
249
+ };
293
250
  }
294
-
295
251
  function aggregate(builder, aggregated) {
296
- builder._aggregated = aggregated;
297
- return builder;
252
+ builder._aggregated = aggregated;
253
+ return builder;
298
254
  }
299
-
300
255
  // Objects and arrays passed as JSON documents are cast to JSON. Without the cast
301
256
  // MySQL would get a string (or knex would expand an array into a list).
302
257
  function createWithJsonArgs(text, values, json) {
303
- const casts = values.map((value, i) => isJsonArg(json, i) && isJsonValue(value));
304
- let i = 0;
305
-
306
- text = text.replace(/\?/g, () => (casts[i++] ? 'CAST(? AS JSON)' : '?'));
307
- values = values.map((value, i) => (casts[i] ? JSON.stringify(value) : value));
308
-
309
- return new FunctionBuilder(text, values);
258
+ const casts = values.map((value, i) => isJsonArg(json, i) && isJsonValue(value));
259
+ let i = 0;
260
+ text = text.replace(/\?/g, () => (casts[i++] ? 'CAST(? AS JSON)' : '?'));
261
+ values = values.map((value, i) => (casts[i] ? JSON.stringify(value) : value));
262
+ return new FunctionBuilder(text, values);
310
263
  }
311
-
312
264
  function isJsonArg(json, i) {
313
- if (json === 'all') {
314
- return true;
315
- } else if (json === 'even') {
316
- return i % 2 === 0;
317
- } else if (json === 'odd') {
318
- return i % 2 === 1;
319
- } else {
320
- return Array.isArray(json) && json.includes(i);
321
- }
265
+ if (json === 'all') {
266
+ return true;
267
+ }
268
+ else if (json === 'even') {
269
+ return i % 2 === 0;
270
+ }
271
+ else if (json === 'odd') {
272
+ return i % 2 === 1;
273
+ }
274
+ else {
275
+ return Array.isArray(json) && json.includes(i);
276
+ }
322
277
  }
323
-
324
278
  function isJsonValue(value) {
325
- return Array.isArray(value) || isPlainObject(value);
279
+ return Array.isArray(value) || isPlainObject(value);
326
280
  }
327
-
328
281
  Object.defineProperties(FunctionBuilder.prototype, {
329
- isObjectionFunctionBuilder: {
330
- enumerable: false,
331
- writable: false,
332
- value: true,
333
- },
282
+ isObjectionFunctionBuilder: {
283
+ enumerable: false,
284
+ writable: false,
285
+ value: true,
286
+ },
334
287
  });
335
-
336
288
  module.exports = {
337
- FunctionBuilder,
338
- fn,
289
+ FunctionBuilder,
290
+ fn,
339
291
  };
@@ -1,29 +1,24 @@
1
1
  'use strict';
2
-
3
2
  class InternalOptions {
4
- constructor() {
5
- this.skipUndefined = false;
6
- this.keepImplicitJoinProps = false;
7
- this.returnImmediatelyValue = undefined;
8
- this.isInternalQuery = false;
9
- this.debug = false;
10
- this.schema = undefined;
11
- }
12
-
13
- clone() {
14
- const copy = new this.constructor();
15
-
16
- copy.skipUndefined = this.skipUndefined;
17
- copy.keepImplicitJoinProps = this.keepImplicitJoinProps;
18
- copy.returnImmediatelyValue = this.returnImmediatelyValue;
19
- copy.isInternalQuery = this.isInternalQuery;
20
- copy.debug = this.debug;
21
- copy.schema = this.schema;
22
-
23
- return copy;
24
- }
3
+ constructor() {
4
+ this.skipUndefined = false;
5
+ this.keepImplicitJoinProps = false;
6
+ this.returnImmediatelyValue = undefined;
7
+ this.isInternalQuery = false;
8
+ this.debug = false;
9
+ this.schema = undefined;
10
+ }
11
+ clone() {
12
+ const copy = new this.constructor();
13
+ copy.skipUndefined = this.skipUndefined;
14
+ copy.keepImplicitJoinProps = this.keepImplicitJoinProps;
15
+ copy.returnImmediatelyValue = this.returnImmediatelyValue;
16
+ copy.isInternalQuery = this.isInternalQuery;
17
+ copy.debug = this.debug;
18
+ copy.schema = this.schema;
19
+ return copy;
20
+ }
25
21
  }
26
-
27
22
  module.exports = {
28
- InternalOptions,
23
+ InternalOptions,
29
24
  };