@abedmurrar/objection 0.0.0-stage → 4.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +69 -2
  3. package/lib/.eslintrc.json +8 -0
  4. package/lib/initialize.js +14 -0
  5. package/lib/model/AjvValidator.js +325 -0
  6. package/lib/model/Model.js +942 -0
  7. package/lib/model/ModifierNotFoundError.js +12 -0
  8. package/lib/model/NotFoundError.js +23 -0
  9. package/lib/model/RelationDoesNotExistError.js +14 -0
  10. package/lib/model/ValidationError.js +54 -0
  11. package/lib/model/Validator.js +26 -0
  12. package/lib/model/getModel.js +9 -0
  13. package/lib/model/graph/ModelGraph.js +80 -0
  14. package/lib/model/graph/ModelGraphBuilder.js +241 -0
  15. package/lib/model/graph/ModelGraphEdge.js +52 -0
  16. package/lib/model/graph/ModelGraphNode.js +240 -0
  17. package/lib/model/inheritModel.js +28 -0
  18. package/lib/model/modelBindKnex.js +83 -0
  19. package/lib/model/modelClone.js +121 -0
  20. package/lib/model/modelColPropMap.js +34 -0
  21. package/lib/model/modelId.js +62 -0
  22. package/lib/model/modelJsonAttributes.js +92 -0
  23. package/lib/model/modelParseRelations.js +82 -0
  24. package/lib/model/modelQueryProps.js +147 -0
  25. package/lib/model/modelSet.js +136 -0
  26. package/lib/model/modelTableMetadata.js +83 -0
  27. package/lib/model/modelToJson.js +187 -0
  28. package/lib/model/modelUtils.js +47 -0
  29. package/lib/model/modelValidate.js +48 -0
  30. package/lib/model/modelValues.js +126 -0
  31. package/lib/model/modelVisitor.js +41 -0
  32. package/lib/objection.js +114 -0
  33. package/lib/queryBuilder/FunctionBuilder.js +339 -0
  34. package/lib/queryBuilder/InternalOptions.js +29 -0
  35. package/lib/queryBuilder/JoinBuilder.js +157 -0
  36. package/lib/queryBuilder/QueryBuilder.js +1398 -0
  37. package/lib/queryBuilder/QueryBuilderBase.js +884 -0
  38. package/lib/queryBuilder/QueryBuilderContext.js +27 -0
  39. package/lib/queryBuilder/QueryBuilderContextBase.js +35 -0
  40. package/lib/queryBuilder/QueryBuilderOperationSupport.js +558 -0
  41. package/lib/queryBuilder/QueryBuilderUserContext.js +31 -0
  42. package/lib/queryBuilder/RawBuilder.js +93 -0
  43. package/lib/queryBuilder/ReferenceBuilder.js +284 -0
  44. package/lib/queryBuilder/RelationExpression.js +431 -0
  45. package/lib/queryBuilder/StaticHookArguments.js +134 -0
  46. package/lib/queryBuilder/ValueBuilder.js +127 -0
  47. package/lib/queryBuilder/expressions.js +151 -0
  48. package/lib/queryBuilder/functions/mysql.js +817 -0
  49. package/lib/queryBuilder/graph/GraphAction.js +69 -0
  50. package/lib/queryBuilder/graph/GraphData.js +14 -0
  51. package/lib/queryBuilder/graph/GraphFetcher.js +191 -0
  52. package/lib/queryBuilder/graph/GraphNodeDbExistence.js +184 -0
  53. package/lib/queryBuilder/graph/GraphOperation.js +27 -0
  54. package/lib/queryBuilder/graph/GraphOptions.js +207 -0
  55. package/lib/queryBuilder/graph/GraphUpsert.js +305 -0
  56. package/lib/queryBuilder/graph/delete/GraphDelete.js +20 -0
  57. package/lib/queryBuilder/graph/delete/GraphDeleteAction.js +74 -0
  58. package/lib/queryBuilder/graph/insert/GraphInsert.js +145 -0
  59. package/lib/queryBuilder/graph/insert/GraphInsertAction.js +225 -0
  60. package/lib/queryBuilder/graph/insert/JoinRowGraphInsertAction.js +92 -0
  61. package/lib/queryBuilder/graph/patch/GraphPatch.js +20 -0
  62. package/lib/queryBuilder/graph/patch/GraphPatchAction.js +258 -0
  63. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsert.js +31 -0
  64. package/lib/queryBuilder/graph/recursiveUpsert/GraphRecursiveUpsertAction.js +126 -0
  65. package/lib/queryBuilder/join/JoinResultColumn.js +23 -0
  66. package/lib/queryBuilder/join/JoinResultParser.js +119 -0
  67. package/lib/queryBuilder/join/RelationJoiner.js +341 -0
  68. package/lib/queryBuilder/join/TableNode.js +163 -0
  69. package/lib/queryBuilder/join/TableTree.js +85 -0
  70. package/lib/queryBuilder/join/utils.js +25 -0
  71. package/lib/queryBuilder/operations/DelegateOperation.js +141 -0
  72. package/lib/queryBuilder/operations/DeleteOperation.js +51 -0
  73. package/lib/queryBuilder/operations/FindByIdOperation.js +37 -0
  74. package/lib/queryBuilder/operations/FindByIdsOperation.js +29 -0
  75. package/lib/queryBuilder/operations/FindOperation.js +164 -0
  76. package/lib/queryBuilder/operations/FirstOperation.js +27 -0
  77. package/lib/queryBuilder/operations/FromOperation.js +110 -0
  78. package/lib/queryBuilder/operations/InsertAndFetchOperation.js +49 -0
  79. package/lib/queryBuilder/operations/InsertGraphAndFetchOperation.js +45 -0
  80. package/lib/queryBuilder/operations/InsertGraphOperation.js +108 -0
  81. package/lib/queryBuilder/operations/InsertOperation.js +206 -0
  82. package/lib/queryBuilder/operations/InstanceDeleteOperation.js +46 -0
  83. package/lib/queryBuilder/operations/InstanceFindOperation.js +21 -0
  84. package/lib/queryBuilder/operations/InstanceInsertOperation.js +24 -0
  85. package/lib/queryBuilder/operations/InstanceUpdateOperation.js +59 -0
  86. package/lib/queryBuilder/operations/JoinRelatedOperation.js +103 -0
  87. package/lib/queryBuilder/operations/KnexOperation.js +14 -0
  88. package/lib/queryBuilder/operations/MergeOperation.js +56 -0
  89. package/lib/queryBuilder/operations/ObjectionToKnexConvertingOperation.js +192 -0
  90. package/lib/queryBuilder/operations/OnBuildKnexOperation.js +29 -0
  91. package/lib/queryBuilder/operations/OnBuildOperation.js +29 -0
  92. package/lib/queryBuilder/operations/OnErrorOperation.js +29 -0
  93. package/lib/queryBuilder/operations/QueryBuilderOperation.js +297 -0
  94. package/lib/queryBuilder/operations/RangeOperation.js +47 -0
  95. package/lib/queryBuilder/operations/RelateOperation.js +27 -0
  96. package/lib/queryBuilder/operations/ReturningOperation.js +30 -0
  97. package/lib/queryBuilder/operations/RunAfterOperation.js +29 -0
  98. package/lib/queryBuilder/operations/RunBeforeOperation.js +29 -0
  99. package/lib/queryBuilder/operations/UnrelateOperation.js +23 -0
  100. package/lib/queryBuilder/operations/UpdateAndFetchOperation.js +80 -0
  101. package/lib/queryBuilder/operations/UpdateOperation.js +155 -0
  102. package/lib/queryBuilder/operations/UpsertGraphAndFetchOperation.js +45 -0
  103. package/lib/queryBuilder/operations/UpsertGraphOperation.js +66 -0
  104. package/lib/queryBuilder/operations/WhereCompositeOperation.js +57 -0
  105. package/lib/queryBuilder/operations/WhereInOperation.js +48 -0
  106. package/lib/queryBuilder/operations/eager/EagerOperation.js +61 -0
  107. package/lib/queryBuilder/operations/eager/JoinEagerOperation.js +51 -0
  108. package/lib/queryBuilder/operations/eager/NaiveEagerOperation.js +13 -0
  109. package/lib/queryBuilder/operations/eager/WhereInEagerOperation.js +285 -0
  110. package/lib/queryBuilder/operations/jsonApi/WhereJsonHasOperation.js +36 -0
  111. package/lib/queryBuilder/operations/jsonApi/WhereJsonNotObjectOperation.js +53 -0
  112. package/lib/queryBuilder/operations/jsonApi/WhereJsonOperation.js +31 -0
  113. package/lib/queryBuilder/operations/jsonApi/WhereJsonOverlapsOperation.js +31 -0
  114. package/lib/queryBuilder/operations/jsonApi/mysqlJsonApi.js +167 -0
  115. package/lib/queryBuilder/operations/jsonApi/postgresJsonApi.js +164 -0
  116. package/lib/queryBuilder/operations/select/SelectOperation.js +66 -0
  117. package/lib/queryBuilder/operations/select/Selection.js +123 -0
  118. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeMsSqlOperation.js +117 -0
  119. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeOperation.js +100 -0
  120. package/lib/queryBuilder/operations/whereInComposite/WhereInCompositeSqliteOperation.js +104 -0
  121. package/lib/queryBuilder/parsers/jsonFieldExpressionParser.js +886 -0
  122. package/lib/queryBuilder/parsers/jsonFieldExpressionParser.pegjs +97 -0
  123. package/lib/queryBuilder/parsers/relationExpressionParser.js +1042 -0
  124. package/lib/queryBuilder/parsers/relationExpressionParser.pegjs +141 -0
  125. package/lib/queryBuilder/transformations/CompositeQueryTransformation.js +22 -0
  126. package/lib/queryBuilder/transformations/QueryTransformation.js +11 -0
  127. package/lib/queryBuilder/transformations/WrapMysqlModifySubqueryTransformation.js +71 -0
  128. package/lib/queryBuilder/transformations/index.js +15 -0
  129. package/lib/queryBuilder/whereScopes.js +227 -0
  130. package/lib/relations/Relation.js +401 -0
  131. package/lib/relations/RelationDeleteOperation.js +29 -0
  132. package/lib/relations/RelationFindOperation.js +149 -0
  133. package/lib/relations/RelationInsertOperation.js +33 -0
  134. package/lib/relations/RelationOwner.js +236 -0
  135. package/lib/relations/RelationProperty.js +247 -0
  136. package/lib/relations/RelationUpdateOperation.js +30 -0
  137. package/lib/relations/belongsToOne/BelongsToOneDeleteOperation.js +23 -0
  138. package/lib/relations/belongsToOne/BelongsToOneInsertOperation.js +44 -0
  139. package/lib/relations/belongsToOne/BelongsToOneRelateOperation.js +50 -0
  140. package/lib/relations/belongsToOne/BelongsToOneRelation.js +53 -0
  141. package/lib/relations/belongsToOne/BelongsToOneUnrelateOperation.js +61 -0
  142. package/lib/relations/hasMany/HasManyInsertOperation.js +61 -0
  143. package/lib/relations/hasMany/HasManyRelateOperation.js +64 -0
  144. package/lib/relations/hasMany/HasManyRelation.js +49 -0
  145. package/lib/relations/hasMany/HasManyUnrelateOperation.js +33 -0
  146. package/lib/relations/hasOne/HasOneRelation.js +13 -0
  147. package/lib/relations/hasOneThrough/HasOneThroughRelation.js +13 -0
  148. package/lib/relations/manyToMany/ManyToManyModifyMixin.js +105 -0
  149. package/lib/relations/manyToMany/ManyToManyRelation.js +507 -0
  150. package/lib/relations/manyToMany/ManyToManySqliteModifyMixin.js +36 -0
  151. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperation.js +10 -0
  152. package/lib/relations/manyToMany/delete/ManyToManyDeleteOperationBase.js +26 -0
  153. package/lib/relations/manyToMany/delete/ManyToManyDeleteSqliteOperation.js +12 -0
  154. package/lib/relations/manyToMany/find/ManyToManyFindOperation.js +105 -0
  155. package/lib/relations/manyToMany/insert/ManyToManyInsertOperation.js +52 -0
  156. package/lib/relations/manyToMany/relate/ManyToManyRelateOperation.js +81 -0
  157. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperation.js +14 -0
  158. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateOperationBase.js +34 -0
  159. package/lib/relations/manyToMany/unrelate/ManyToManyUnrelateSqliteOperation.js +16 -0
  160. package/lib/relations/manyToMany/update/ManyToManyUpdateOperation.js +10 -0
  161. package/lib/relations/manyToMany/update/ManyToManyUpdateOperationBase.js +82 -0
  162. package/lib/relations/manyToMany/update/ManyToManyUpdateSqliteOperation.js +12 -0
  163. package/lib/transaction.js +96 -0
  164. package/lib/utils/assert.js +25 -0
  165. package/lib/utils/buildUtils.js +21 -0
  166. package/lib/utils/classUtils.js +13 -0
  167. package/lib/utils/clone.js +2329 -0
  168. package/lib/utils/createModifier.js +42 -0
  169. package/lib/utils/deprecate.js +15 -0
  170. package/lib/utils/identifierMapping.js +227 -0
  171. package/lib/utils/internalPropUtils.js +11 -0
  172. package/lib/utils/knexUtils.js +76 -0
  173. package/lib/utils/mixin.js +25 -0
  174. package/lib/utils/mysqlJsonPath.js +55 -0
  175. package/lib/utils/normalizeIds.js +144 -0
  176. package/lib/utils/objectUtils.js +416 -0
  177. package/lib/utils/parseFieldExpression.js +51 -0
  178. package/lib/utils/postgresJsonPath.js +110 -0
  179. package/lib/utils/promiseUtils/after.js +17 -0
  180. package/lib/utils/promiseUtils/afterReturn.js +17 -0
  181. package/lib/utils/promiseUtils/index.js +17 -0
  182. package/lib/utils/promiseUtils/isPromise.js +11 -0
  183. package/lib/utils/promiseUtils/map.js +110 -0
  184. package/lib/utils/promiseUtils/mapAfterAllReturn.js +29 -0
  185. package/lib/utils/promiseUtils/try.js +22 -0
  186. package/lib/utils/resolveModel.js +107 -0
  187. package/lib/utils/tmpColumnUtils.js +16 -0
  188. package/package.json +86 -4
  189. package/typings/objection/index.d.ts +4104 -0
  190. package/typings/objection/relation-expression.d.ts +237 -0
@@ -0,0 +1,817 @@
1
+ 'use strict';
2
+
3
+ const { ref } = require('../ReferenceBuilder');
4
+
5
+ // The MySQL 8.4 built-in functions, as `fn.*` helpers.
6
+ //
7
+ // Each entry is `[name, sql, params, result, options]`:
8
+ //
9
+ // name the name of the helper: `fn.dateFormat()`
10
+ // sql the name of the SQL function: `DATE_FORMAT`
11
+ // params the parameters, as TypeScript
12
+ // result the type of the result, as TypeScript
13
+ // options `json`: the arguments that are JSON documents. Objects and arrays
14
+ // passed to them are cast to JSON. An array of indexes,
15
+ // 'all', or 'even' (0, 2, 4, ...) / 'odd' (1, 3, 5, ...).
16
+ // `portable`: the function works the same on postgres, so it
17
+ // isn't limited to MySQL.
18
+ // `build`: a function that builds the sql for functions with
19
+ // keywords in their syntax, like `TIMESTAMPDIFF(DAY, ?, ?)`.
20
+ // `aggregate`: the function is an aggregate that `filter()` works
21
+ // with. `true` when every argument is aggregated, or a
22
+ // function that returns how many of the first arguments are.
23
+ // `window`: the function is a window function, which needs `over()`.
24
+ //
25
+ // The arguments are bindings, so strings are values. Columns are passed with
26
+ // `ref()` or `Model.ref()`.
27
+ //
28
+ // The typings in `typings/objection/index.d.ts` are generated from this list
29
+ // with `node scripts/generate-fn-typings.js`.
30
+ //
31
+ // Not included: spatial functions, operators, `CASE`, `JSON_TABLE()`, internal functions and functions
32
+ // that are deprecated (`JSON_MERGE()`, `FOUND_ROWS()`, `VALUES()`,
33
+ // `MASTER_POS_WAIT()`) or that need a component (`VALIDATE_PASSWORD_STRENGTH()`).
34
+ // `fn('NAME', ...args)` calls any function.
35
+
36
+ const STR = 'string | null';
37
+ const NUM = 'number | null';
38
+ const DEC = 'FnNumeric | null';
39
+ const BOOL = '0 | 1 | null';
40
+ const DATE = 'Date | string | null';
41
+ const TIME = 'string | null';
42
+ const BIN = 'Buffer | null';
43
+ const ANY = 'unknown';
44
+
45
+ const X = 'x: FnArg';
46
+ const STRING = 'str: FnArg';
47
+ const DATE_ARG = 'date: FnArg';
48
+ const FSP = 'fsp?: number';
49
+ const LAG_PARAMS = 'x: FnArg, offset?: number, defaultValue?: FnArg';
50
+ const WINDOW = { portable: true, window: true };
51
+
52
+ const INTERVAL_UNITS = [
53
+ 'MICROSECOND',
54
+ 'SECOND',
55
+ 'MINUTE',
56
+ 'HOUR',
57
+ 'DAY',
58
+ 'WEEK',
59
+ 'MONTH',
60
+ 'QUARTER',
61
+ 'YEAR',
62
+ 'SECOND_MICROSECOND',
63
+ 'MINUTE_MICROSECOND',
64
+ 'MINUTE_SECOND',
65
+ 'HOUR_MICROSECOND',
66
+ 'HOUR_SECOND',
67
+ 'HOUR_MINUTE',
68
+ 'DAY_MICROSECOND',
69
+ 'DAY_SECOND',
70
+ 'DAY_MINUTE',
71
+ 'DAY_HOUR',
72
+ 'YEAR_MONTH',
73
+ ];
74
+
75
+ const TIMESTAMP_UNITS = INTERVAL_UNITS.slice(0, 9);
76
+ const CAST_TYPE =
77
+ /^((BINARY|CHAR|NCHAR)(\(\d+\))?( CHARACTER SET \w+)?|DATE|(DATETIME|TIME)(\(\d\))?|DECIMAL(\(\d+(, ?\d+)?\))?|DOUBLE|FLOAT(\(\d+\))?|JSON|REAL|(SIGNED|UNSIGNED)( INTEGER)?|YEAR)$/i;
78
+ const CHARSET = /^\w+$/;
79
+ const MATCH_MODES = {
80
+ natural: 'IN NATURAL LANGUAGE MODE',
81
+ 'natural with query expansion': 'IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION',
82
+ boolean: 'IN BOOLEAN MODE',
83
+ 'with query expansion': 'WITH QUERY EXPANSION',
84
+ };
85
+ const TRIM_SIDES = ['BOTH', 'LEADING', 'TRAILING'];
86
+ const DIRECTIONS = ['ASC', 'DESC'];
87
+ const FORMAT_TYPES = ['DATE', 'TIME', 'DATETIME', 'TIMESTAMP'];
88
+
89
+ const FUNCTIONS = [
90
+ // String functions.
91
+ ['ascii', 'ASCII', STRING, NUM, { portable: true }],
92
+ ['bin', 'BIN', 'n: FnArg', STR],
93
+ ['bitLength', 'BIT_LENGTH', STRING, NUM, { portable: true }],
94
+ [
95
+ 'char',
96
+ 'CHAR',
97
+ 'codes: FnArg | FnArg[], options?: { using?: string }',
98
+ BIN,
99
+ { build: buildChar },
100
+ ],
101
+ ['charLength', 'CHAR_LENGTH', STRING, NUM, { portable: true }],
102
+ ['characterLength', 'CHARACTER_LENGTH', STRING, NUM, { portable: true }],
103
+ ['concatWs', 'CONCAT_WS', 'separator: FnArg, ...strs: FnArg[]', STR, { portable: true }],
104
+ ['elt', 'ELT', 'n: FnArg, ...strs: FnArg[]', STR],
105
+ [
106
+ 'exportSet',
107
+ 'EXPORT_SET',
108
+ 'bits: FnArg, on: FnArg, off: FnArg, separator?: FnArg, numberOfBits?: FnArg',
109
+ STR,
110
+ ],
111
+ ['field', 'FIELD', 'str: FnArg, ...strs: FnArg[]', NUM],
112
+ ['findInSet', 'FIND_IN_SET', 'str: FnArg, strList: FnArg', NUM],
113
+ ['format', 'FORMAT', 'x: FnArg, decimals: FnArg, locale?: FnArg', STR],
114
+ ['fromBase64', 'FROM_BASE64', STRING, BIN],
115
+ ['hex', 'HEX', X, STR],
116
+ ['insert', 'INSERT', 'str: FnArg, pos: FnArg, len: FnArg, newStr: FnArg', STR],
117
+ ['instr', 'INSTR', 'str: FnArg, substr: FnArg', NUM],
118
+ ['lcase', 'LCASE', STRING, STR],
119
+ ['left', 'LEFT', 'str: FnArg, len: FnArg', STR, { portable: true }],
120
+ ['length', 'LENGTH', STRING, NUM, { portable: true }],
121
+ ['locate', 'LOCATE', 'substr: FnArg, str: FnArg, pos?: FnArg', NUM],
122
+ ['lpad', 'LPAD', 'str: FnArg, len: FnArg, padStr: FnArg', STR, { portable: true }],
123
+ ['ltrim', 'LTRIM', STRING, STR, { portable: true }],
124
+ ['makeSet', 'MAKE_SET', 'bits: FnArg, ...strs: FnArg[]', STR],
125
+ ['mid', 'MID', 'str: FnArg, pos: FnArg, len?: FnArg', STR],
126
+ ['oct', 'OCT', 'n: FnArg', STR],
127
+ ['octetLength', 'OCTET_LENGTH', STRING, NUM, { portable: true }],
128
+ ['ord', 'ORD', STRING, NUM],
129
+ [
130
+ 'position',
131
+ 'POSITION',
132
+ 'substr: FnArg, str: FnArg',
133
+ NUM,
134
+ { portable: true, build: buildPosition },
135
+ ],
136
+ ['quote', 'QUOTE', STRING, STR],
137
+ [
138
+ 'regexpInstr',
139
+ 'REGEXP_INSTR',
140
+ 'expr: FnArg, pattern: FnArg, pos?: FnArg, occurrence?: FnArg, returnOption?: FnArg, matchType?: FnArg',
141
+ NUM,
142
+ ],
143
+ ['regexpLike', 'REGEXP_LIKE', 'expr: FnArg, pattern: FnArg, matchType?: FnArg', BOOL],
144
+ [
145
+ 'regexpReplace',
146
+ 'REGEXP_REPLACE',
147
+ 'expr: FnArg, pattern: FnArg, replacement: FnArg, pos?: FnArg, occurrence?: FnArg, matchType?: FnArg',
148
+ STR,
149
+ ],
150
+ [
151
+ 'regexpSubstr',
152
+ 'REGEXP_SUBSTR',
153
+ 'expr: FnArg, pattern: FnArg, pos?: FnArg, occurrence?: FnArg, matchType?: FnArg',
154
+ STR,
155
+ ],
156
+ ['repeat', 'REPEAT', 'str: FnArg, count: FnArg', STR, { portable: true }],
157
+ ['replace', 'REPLACE', 'str: FnArg, from: FnArg, to: FnArg', STR, { portable: true }],
158
+ ['reverse', 'REVERSE', STRING, STR, { portable: true }],
159
+ ['right', 'RIGHT', 'str: FnArg, len: FnArg', STR, { portable: true }],
160
+ ['rpad', 'RPAD', 'str: FnArg, len: FnArg, padStr: FnArg', STR, { portable: true }],
161
+ ['rtrim', 'RTRIM', STRING, STR, { portable: true }],
162
+ ['soundex', 'SOUNDEX', STRING, STR],
163
+ ['space', 'SPACE', 'n: FnArg', STR],
164
+ ['strcmp', 'STRCMP', 'a: FnArg, b: FnArg', '-1 | 0 | 1 | null'],
165
+ ['substr', 'SUBSTR', 'str: FnArg, pos: FnArg, len?: FnArg', STR, { portable: true }],
166
+ ['substring', 'SUBSTRING', 'str: FnArg, pos: FnArg, len?: FnArg', STR, { portable: true }],
167
+ ['substringIndex', 'SUBSTRING_INDEX', 'str: FnArg, delimiter: FnArg, count: FnArg', STR],
168
+ ['toBase64', 'TO_BASE64', STRING, STR],
169
+ [
170
+ 'trim',
171
+ 'TRIM',
172
+ "str: FnArg, options?: { side?: 'both' | 'leading' | 'trailing'; remove?: FnArg }",
173
+ STR,
174
+ { portable: true, build: buildTrim },
175
+ ],
176
+ ['ucase', 'UCASE', STRING, STR],
177
+ ['unhex', 'UNHEX', STRING, BIN],
178
+ ['weightString', 'WEIGHT_STRING', STRING, BIN],
179
+ [
180
+ 'match',
181
+ 'MATCH',
182
+ "columns: FnArg | FnArg[], search: FnArg, options?: { mode?: 'natural' | 'natural with query expansion' | 'boolean' | 'with query expansion' }",
183
+ NUM,
184
+ { build: buildMatch },
185
+ ],
186
+
187
+ // Numeric functions.
188
+ ['abs', 'ABS', X, DEC, { portable: true }],
189
+ ['acos', 'ACOS', X, NUM, { portable: true }],
190
+ ['asin', 'ASIN', X, NUM, { portable: true }],
191
+ ['atan', 'ATAN', 'x: FnArg, y?: FnArg', NUM],
192
+ ['atan2', 'ATAN2', 'y: FnArg, x: FnArg', NUM, { portable: true }],
193
+ ['ceil', 'CEIL', X, DEC, { portable: true }],
194
+ ['ceiling', 'CEILING', X, DEC, { portable: true }],
195
+ ['conv', 'CONV', 'n: FnArg, fromBase: FnArg, toBase: FnArg', STR],
196
+ ['cos', 'COS', X, NUM, { portable: true }],
197
+ ['cot', 'COT', X, NUM, { portable: true }],
198
+ ['crc32', 'CRC32', X, NUM],
199
+ ['degrees', 'DEGREES', X, NUM, { portable: true }],
200
+ ['exp', 'EXP', X, NUM, { portable: true }],
201
+ ['floor', 'FLOOR', X, DEC, { portable: true }],
202
+ ['ln', 'LN', X, NUM, { portable: true }],
203
+ ['log', 'LOG', 'baseOrX: FnArg, x?: FnArg', NUM],
204
+ ['log10', 'LOG10', X, NUM],
205
+ ['log2', 'LOG2', X, NUM],
206
+ ['mod', 'MOD', 'n: FnArg, m: FnArg', DEC, { portable: true }],
207
+ ['pi', 'PI', '', NUM, { portable: true }],
208
+ ['pow', 'POW', 'x: FnArg, y: FnArg', NUM],
209
+ ['power', 'POWER', 'x: FnArg, y: FnArg', NUM, { portable: true }],
210
+ ['radians', 'RADIANS', X, NUM, { portable: true }],
211
+ ['rand', 'RAND', 'seed?: FnArg', NUM],
212
+ ['round', 'ROUND', 'x: FnArg, decimals?: FnArg', DEC, { portable: true }],
213
+ ['sign', 'SIGN', X, NUM, { portable: true }],
214
+ ['sin', 'SIN', X, NUM, { portable: true }],
215
+ ['sqrt', 'SQRT', X, NUM, { portable: true }],
216
+ ['tan', 'TAN', X, NUM, { portable: true }],
217
+ ['truncate', 'TRUNCATE', 'x: FnArg, decimals: FnArg', DEC],
218
+
219
+ // Date and time functions.
220
+ [
221
+ 'addDate',
222
+ 'ADDDATE',
223
+ 'date: FnArg, amount: FnArg, unit?: FnIntervalUnit',
224
+ DATE,
225
+ { build: buildDateAdd },
226
+ ],
227
+ ['addTime', 'ADDTIME', 'datetime: FnArg, time: FnArg', DATE],
228
+ ['convertTz', 'CONVERT_TZ', 'datetime: FnArg, fromTz: FnArg, toTz: FnArg', DATE],
229
+ ['curDate', 'CURDATE', '', DATE],
230
+ ['currentDate', 'CURRENT_DATE', '', DATE],
231
+ ['currentTime', 'CURRENT_TIME', FSP, TIME],
232
+ ['currentTimestamp', 'CURRENT_TIMESTAMP', FSP, DATE],
233
+ ['curTime', 'CURTIME', FSP, TIME],
234
+ ['date', 'DATE', X, DATE],
235
+ [
236
+ 'dateAdd',
237
+ 'DATE_ADD',
238
+ 'date: FnArg, amount: FnArg, unit: FnIntervalUnit',
239
+ DATE,
240
+ { build: buildDateAdd },
241
+ ],
242
+ ['dateDiff', 'DATEDIFF', 'a: FnArg, b: FnArg', NUM],
243
+ ['dateFormat', 'DATE_FORMAT', 'date: FnArg, format: FnArg', STR],
244
+ [
245
+ 'dateSub',
246
+ 'DATE_SUB',
247
+ 'date: FnArg, amount: FnArg, unit: FnIntervalUnit',
248
+ DATE,
249
+ { build: buildDateAdd },
250
+ ],
251
+ ['day', 'DAY', DATE_ARG, NUM],
252
+ ['dayName', 'DAYNAME', DATE_ARG, STR],
253
+ ['dayOfMonth', 'DAYOFMONTH', DATE_ARG, NUM],
254
+ ['dayOfWeek', 'DAYOFWEEK', DATE_ARG, NUM],
255
+ ['dayOfYear', 'DAYOFYEAR', DATE_ARG, NUM],
256
+ ['extract', 'EXTRACT', 'unit: FnIntervalUnit, date: FnArg', NUM, { build: buildExtract }],
257
+ ['fromDays', 'FROM_DAYS', 'days: FnArg', DATE],
258
+ ['fromUnixTime', 'FROM_UNIXTIME', 'timestamp: FnArg, format?: FnArg', DATE],
259
+ [
260
+ 'getFormat',
261
+ 'GET_FORMAT',
262
+ "type: 'DATE' | 'TIME' | 'DATETIME' | 'TIMESTAMP', locale: FnArg",
263
+ STR,
264
+ { build: buildGetFormat },
265
+ ],
266
+ ['hour', 'HOUR', 'time: FnArg', NUM],
267
+ ['lastDay', 'LAST_DAY', DATE_ARG, DATE],
268
+ ['localTime', 'LOCALTIME', FSP, DATE],
269
+ ['localTimestamp', 'LOCALTIMESTAMP', FSP, DATE],
270
+ ['makeDate', 'MAKEDATE', 'year: FnArg, dayOfYear: FnArg', DATE],
271
+ ['makeTime', 'MAKETIME', 'hour: FnArg, minute: FnArg, second: FnArg', TIME],
272
+ ['microsecond', 'MICROSECOND', 'time: FnArg', NUM],
273
+ ['minute', 'MINUTE', 'time: FnArg', NUM],
274
+ ['month', 'MONTH', DATE_ARG, NUM],
275
+ ['monthName', 'MONTHNAME', DATE_ARG, STR],
276
+ ['periodAdd', 'PERIOD_ADD', 'period: FnArg, months: FnArg', NUM],
277
+ ['periodDiff', 'PERIOD_DIFF', 'a: FnArg, b: FnArg', NUM],
278
+ ['quarter', 'QUARTER', DATE_ARG, NUM],
279
+ ['second', 'SECOND', 'time: FnArg', NUM],
280
+ ['secToTime', 'SEC_TO_TIME', 'seconds: FnArg', TIME],
281
+ ['strToDate', 'STR_TO_DATE', 'str: FnArg, format: FnArg', DATE],
282
+ [
283
+ 'subDate',
284
+ 'SUBDATE',
285
+ 'date: FnArg, amount: FnArg, unit?: FnIntervalUnit',
286
+ DATE,
287
+ { build: buildDateAdd },
288
+ ],
289
+ ['subTime', 'SUBTIME', 'datetime: FnArg, time: FnArg', DATE],
290
+ ['sysdate', 'SYSDATE', FSP, DATE],
291
+ ['time', 'TIME', X, TIME],
292
+ ['timeDiff', 'TIMEDIFF', 'a: FnArg, b: FnArg', TIME],
293
+ ['timestamp', 'TIMESTAMP', 'x: FnArg, time?: FnArg', DATE],
294
+ [
295
+ 'timestampAdd',
296
+ 'TIMESTAMPADD',
297
+ 'unit: FnTimestampUnit, amount: FnArg, date: FnArg',
298
+ DATE,
299
+ { build: buildTimestampFunction },
300
+ ],
301
+ [
302
+ 'timestampDiff',
303
+ 'TIMESTAMPDIFF',
304
+ 'unit: FnTimestampUnit, from: FnArg, to: FnArg',
305
+ NUM,
306
+ { build: buildTimestampFunction },
307
+ ],
308
+ ['timeFormat', 'TIME_FORMAT', 'time: FnArg, format: FnArg', STR],
309
+ ['timeToSec', 'TIME_TO_SEC', 'time: FnArg', NUM],
310
+ ['toDays', 'TO_DAYS', DATE_ARG, NUM],
311
+ ['toSeconds', 'TO_SECONDS', DATE_ARG, NUM],
312
+ ['unixTimestamp', 'UNIX_TIMESTAMP', 'date?: FnArg', DEC],
313
+ ['utcDate', 'UTC_DATE', '', DATE],
314
+ ['utcTime', 'UTC_TIME', FSP, TIME],
315
+ ['utcTimestamp', 'UTC_TIMESTAMP', FSP, DATE],
316
+ ['week', 'WEEK', 'date: FnArg, mode?: FnArg', NUM],
317
+ ['weekday', 'WEEKDAY', DATE_ARG, NUM],
318
+ ['weekOfYear', 'WEEKOFYEAR', DATE_ARG, NUM],
319
+ ['year', 'YEAR', DATE_ARG, NUM],
320
+ ['yearWeek', 'YEARWEEK', 'date: FnArg, mode?: FnArg', NUM],
321
+
322
+ // Aggregate functions. `fn.count()`, `fn.sum()`, `fn.avg()`, `fn.min()` and
323
+ // `fn.max()` already exist.
324
+ ['bitAnd', 'BIT_AND', X, DEC, { aggregate: true }],
325
+ ['bitOr', 'BIT_OR', X, DEC, { aggregate: true }],
326
+ ['bitXor', 'BIT_XOR', X, DEC, { aggregate: true }],
327
+ [
328
+ 'countDistinct',
329
+ 'COUNT',
330
+ '...exprs: FnArg[]',
331
+ 'number',
332
+ { build: buildCountDistinct, aggregate: true, portable: true },
333
+ ],
334
+ [
335
+ 'groupConcat',
336
+ 'GROUP_CONCAT',
337
+ 'exprs: FnArg | FnArg[], options?: { distinct?: boolean; orderBy?: FnOrderBy | FnOrderBy[]; separator?: string }',
338
+ STR,
339
+ { build: buildGroupConcat, aggregate: ([exprs]) => (Array.isArray(exprs) ? exprs.length : 1) },
340
+ ],
341
+ ['jsonArrayAgg', 'JSON_ARRAYAGG', X, 'unknown[] | null', { aggregate: true }],
342
+ ['jsonObjectAgg', 'JSON_OBJECTAGG', 'key: FnArg, value: FnArg', 'Record<string, unknown> | null'],
343
+ ['std', 'STD', X, NUM, { aggregate: true }],
344
+ ['stddev', 'STDDEV', X, NUM, { portable: true, aggregate: true }],
345
+ ['stddevPop', 'STDDEV_POP', X, NUM, { portable: true, aggregate: true }],
346
+ ['stddevSamp', 'STDDEV_SAMP', X, NUM, { portable: true, aggregate: true }],
347
+ ['variance', 'VARIANCE', X, NUM, { portable: true, aggregate: true }],
348
+ ['varPop', 'VAR_POP', X, NUM, { portable: true, aggregate: true }],
349
+ ['varSamp', 'VAR_SAMP', X, NUM, { portable: true, aggregate: true }],
350
+
351
+ // Window functions. They need `over()`: `fn.rowNumber().over({ orderBy })`.
352
+ // Aggregate functions work as window functions too.
353
+ ['rowNumber', 'ROW_NUMBER', '', 'number', WINDOW],
354
+ ['rank', 'RANK', '', 'number', WINDOW],
355
+ ['denseRank', 'DENSE_RANK', '', 'number', WINDOW],
356
+ ['percentRank', 'PERCENT_RANK', '', 'number', WINDOW],
357
+ ['cumeDist', 'CUME_DIST', '', 'number', WINDOW],
358
+ ['ntile', 'NTILE', 'buckets: number', 'number', { ...WINDOW, build: buildNtile }],
359
+ ['lag', 'LAG', LAG_PARAMS, ANY, { ...WINDOW, build: buildLagOrLead }],
360
+ ['lead', 'LEAD', LAG_PARAMS, ANY, { ...WINDOW, build: buildLagOrLead }],
361
+ ['firstValue', 'FIRST_VALUE', X, ANY, WINDOW],
362
+ ['lastValue', 'LAST_VALUE', X, ANY, WINDOW],
363
+ ['nthValue', 'NTH_VALUE', 'x: FnArg, n: number', ANY, { ...WINDOW, build: buildNthValue }],
364
+
365
+ // Comparison and flow control functions. `fn.coalesce()` already exists.
366
+ ['greatest', 'GREATEST', '...values: FnArg[]', ANY, { portable: true }],
367
+ ['if', 'IF', 'condition: FnArg, then: FnArg, otherwise: FnArg', ANY],
368
+ ['ifNull', 'IFNULL', 'value: FnArg, otherwise: FnArg', ANY],
369
+ ['interval', 'INTERVAL', 'n: FnArg, ...ns: FnArg[]', NUM],
370
+ ['isNull', 'ISNULL', X, BOOL],
371
+ ['least', 'LEAST', '...values: FnArg[]', ANY, { portable: true }],
372
+ ['nullIf', 'NULLIF', 'a: FnArg, b: FnArg', ANY, { portable: true }],
373
+
374
+ // Cast functions.
375
+ ['cast', 'CAST', 'x: FnArg, type: string', ANY, { build: buildCast }],
376
+ [
377
+ 'convert',
378
+ 'CONVERT',
379
+ 'x: FnArg, type: string | { using: string }',
380
+ ANY,
381
+ { build: buildConvert },
382
+ ],
383
+
384
+ // Information functions.
385
+ ['charset', 'CHARSET', STRING, STR],
386
+ ['coercibility', 'COERCIBILITY', STRING, NUM],
387
+ ['collation', 'COLLATION', STRING, STR],
388
+ ['connectionId', 'CONNECTION_ID', '', NUM],
389
+ ['currentRole', 'CURRENT_ROLE', '', STR],
390
+ ['currentUser', 'CURRENT_USER', '', STR],
391
+ ['database', 'DATABASE', '', STR],
392
+ ['icuVersion', 'ICU_VERSION', '', STR],
393
+ ['lastInsertId', 'LAST_INSERT_ID', 'x?: FnArg', NUM],
394
+ ['rolesGraphml', 'ROLES_GRAPHML', '', STR],
395
+ ['rowCount', 'ROW_COUNT', '', NUM],
396
+ ['schema', 'SCHEMA', '', STR],
397
+ ['sessionUser', 'SESSION_USER', '', STR],
398
+ ['systemUser', 'SYSTEM_USER', '', STR],
399
+ ['user', 'USER', '', STR],
400
+ ['version', 'VERSION', '', STR],
401
+
402
+ // Encryption and compression functions.
403
+ ['aesDecrypt', 'AES_DECRYPT', 'crypt: FnArg, key: FnArg, ...options: FnArg[]', BIN],
404
+ ['aesEncrypt', 'AES_ENCRYPT', 'str: FnArg, key: FnArg, ...options: FnArg[]', BIN],
405
+ ['compress', 'COMPRESS', STRING, BIN],
406
+ ['md5', 'MD5', STRING, STR, { portable: true }],
407
+ ['randomBytes', 'RANDOM_BYTES', 'length: FnArg', BIN],
408
+ ['sha1', 'SHA1', STRING, STR],
409
+ ['sha2', 'SHA2', 'str: FnArg, hashLength: FnArg', STR],
410
+ ['statementDigest', 'STATEMENT_DIGEST', 'statement: FnArg', STR],
411
+ ['statementDigestText', 'STATEMENT_DIGEST_TEXT', 'statement: FnArg', STR],
412
+ ['uncompress', 'UNCOMPRESS', STRING, BIN],
413
+ ['uncompressedLength', 'UNCOMPRESSED_LENGTH', STRING, NUM],
414
+
415
+ // Locking functions.
416
+ ['getLock', 'GET_LOCK', 'name: FnArg, timeout: FnArg', BOOL],
417
+ ['isFreeLock', 'IS_FREE_LOCK', 'name: FnArg', BOOL],
418
+ ['isUsedLock', 'IS_USED_LOCK', 'name: FnArg', NUM],
419
+ ['releaseAllLocks', 'RELEASE_ALL_LOCKS', '', NUM],
420
+ ['releaseLock', 'RELEASE_LOCK', 'name: FnArg', BOOL],
421
+
422
+ // Miscellaneous functions.
423
+ ['anyValue', 'ANY_VALUE', X, ANY],
424
+ ['binToUuid', 'BIN_TO_UUID', 'bin: FnArg, swap?: FnArg', STR],
425
+ ['default', 'DEFAULT', 'column: FnArg', ANY],
426
+ ['grouping', 'GROUPING', '...exprs: FnArg[]', NUM],
427
+ ['inet6Aton', 'INET6_ATON', 'address: FnArg', BIN],
428
+ ['inet6Ntoa', 'INET6_NTOA', 'address: FnArg', STR],
429
+ ['inetAton', 'INET_ATON', 'address: FnArg', NUM],
430
+ ['inetNtoa', 'INET_NTOA', 'address: FnArg', STR],
431
+ ['isIpv4', 'IS_IPV4', 'address: FnArg', BOOL],
432
+ ['isIpv4Compat', 'IS_IPV4_COMPAT', 'address: FnArg', BOOL],
433
+ ['isIpv4Mapped', 'IS_IPV4_MAPPED', 'address: FnArg', BOOL],
434
+ ['isIpv6', 'IS_IPV6', 'address: FnArg', BOOL],
435
+ ['isUuid', 'IS_UUID', 'uuid: FnArg', BOOL],
436
+ ['sleep', 'SLEEP', 'seconds: FnArg', NUM],
437
+ ['uuid', 'UUID', '', 'string'],
438
+ ['uuidShort', 'UUID_SHORT', '', 'FnNumeric'],
439
+ ['uuidToBin', 'UUID_TO_BIN', 'uuid: FnArg, swap?: FnArg', BIN],
440
+
441
+ // Bit, performance schema, GTID and XML functions.
442
+ ['bitCount', 'BIT_COUNT', X, NUM],
443
+ ['formatBytes', 'FORMAT_BYTES', 'bytes: FnArg', STR],
444
+ ['formatPicoTime', 'FORMAT_PICO_TIME', 'time: FnArg', STR],
445
+ ['psCurrentThreadId', 'PS_CURRENT_THREAD_ID', '', NUM],
446
+ ['psThreadId', 'PS_THREAD_ID', 'connectionId: FnArg', NUM],
447
+ ['gtidSubset', 'GTID_SUBSET', 'set1: FnArg, set2: FnArg', BOOL],
448
+ ['gtidSubtract', 'GTID_SUBTRACT', 'set1: FnArg, set2: FnArg', STR],
449
+ ['sourcePosWait', 'SOURCE_POS_WAIT', 'logName: FnArg, logPos: FnArg, ...options: FnArg[]', NUM],
450
+ ['waitForExecutedGtidSet', 'WAIT_FOR_EXECUTED_GTID_SET', 'gtidSet: FnArg, timeout?: FnArg', NUM],
451
+ ['extractValue', 'EXTRACTVALUE', 'xml: FnArg, xpath: FnArg', STR],
452
+ ['updateXml', 'UPDATEXML', 'xml: FnArg, xpath: FnArg, newXml: FnArg', STR],
453
+
454
+ // JSON functions. Objects and arrays passed as JSON documents are cast to JSON.
455
+ ['jsonArray', 'JSON_ARRAY', '...values: FnJsonArg[]', 'unknown[]', { json: 'all' }],
456
+ [
457
+ 'jsonArrayAppend',
458
+ 'JSON_ARRAY_APPEND',
459
+ 'doc: FnJsonArg, path: FnArg, value: FnJsonArg, ...pathsAndValues: FnJsonArg[]',
460
+ ANY,
461
+ { json: 'even' },
462
+ ],
463
+ [
464
+ 'jsonArrayInsert',
465
+ 'JSON_ARRAY_INSERT',
466
+ 'doc: FnJsonArg, path: FnArg, value: FnJsonArg, ...pathsAndValues: FnJsonArg[]',
467
+ ANY,
468
+ { json: 'even' },
469
+ ],
470
+ [
471
+ 'jsonContains',
472
+ 'JSON_CONTAINS',
473
+ 'target: FnJsonArg, candidate: FnJsonArg, path?: FnArg',
474
+ BOOL,
475
+ { json: [0, 1] },
476
+ ],
477
+ [
478
+ 'jsonContainsPath',
479
+ 'JSON_CONTAINS_PATH',
480
+ "doc: FnJsonArg, oneOrAll: 'one' | 'all', ...paths: FnArg[]",
481
+ BOOL,
482
+ { json: [0] },
483
+ ],
484
+ ['jsonDepth', 'JSON_DEPTH', 'doc: FnJsonArg', NUM, { json: [0] }],
485
+ ['jsonExtract', 'JSON_EXTRACT', 'doc: FnJsonArg, ...paths: FnArg[]', ANY, { json: [0] }],
486
+ [
487
+ 'jsonInsert',
488
+ 'JSON_INSERT',
489
+ 'doc: FnJsonArg, path: FnArg, value: FnJsonArg, ...pathsAndValues: FnJsonArg[]',
490
+ ANY,
491
+ { json: 'even' },
492
+ ],
493
+ ['jsonKeys', 'JSON_KEYS', 'doc: FnJsonArg, path?: FnArg', 'string[] | null', { json: [0] }],
494
+ ['jsonLength', 'JSON_LENGTH', 'doc: FnJsonArg, path?: FnArg', NUM, { json: [0] }],
495
+ ['jsonMergePatch', 'JSON_MERGE_PATCH', '...docs: FnJsonArg[]', ANY, { json: 'all' }],
496
+ ['jsonMergePreserve', 'JSON_MERGE_PRESERVE', '...docs: FnJsonArg[]', ANY, { json: 'all' }],
497
+ [
498
+ 'jsonObject',
499
+ 'JSON_OBJECT',
500
+ 'objectOrKeysAndValues?: { [key: string]: FnJsonArg } | FnJsonArg, ...keysAndValues: FnJsonArg[]',
501
+ 'Record<string, unknown>',
502
+ { json: 'odd', build: buildJsonObject },
503
+ ],
504
+ ['jsonOverlaps', 'JSON_OVERLAPS', 'a: FnJsonArg, b: FnJsonArg', BOOL, { json: [0, 1] }],
505
+ ['jsonPretty', 'JSON_PRETTY', 'doc: FnJsonArg', STR, { json: [0] }],
506
+ ['jsonQuote', 'JSON_QUOTE', STRING, STR],
507
+ ['jsonRemove', 'JSON_REMOVE', 'doc: FnJsonArg, ...paths: FnArg[]', ANY, { json: [0] }],
508
+ [
509
+ 'jsonReplace',
510
+ 'JSON_REPLACE',
511
+ 'doc: FnJsonArg, path: FnArg, value: FnJsonArg, ...pathsAndValues: FnJsonArg[]',
512
+ ANY,
513
+ { json: 'even' },
514
+ ],
515
+ [
516
+ 'jsonSchemaValid',
517
+ 'JSON_SCHEMA_VALID',
518
+ 'schema: FnJsonArg, doc: FnJsonArg',
519
+ BOOL,
520
+ { json: [0, 1] },
521
+ ],
522
+ [
523
+ 'jsonSchemaValidationReport',
524
+ 'JSON_SCHEMA_VALIDATION_REPORT',
525
+ 'schema: FnJsonArg, doc: FnJsonArg',
526
+ 'Record<string, unknown> | null',
527
+ { json: [0, 1] },
528
+ ],
529
+ [
530
+ 'jsonSearch',
531
+ 'JSON_SEARCH',
532
+ "doc: FnJsonArg, oneOrAll: 'one' | 'all', search: FnArg, escape?: FnArg, ...paths: FnArg[]",
533
+ 'string | string[] | null',
534
+ { json: [0] },
535
+ ],
536
+ [
537
+ 'jsonSet',
538
+ 'JSON_SET',
539
+ 'doc: FnJsonArg, path: FnArg, value: FnJsonArg, ...pathsAndValues: FnJsonArg[]',
540
+ ANY,
541
+ { json: 'even' },
542
+ ],
543
+ ['jsonStorageFree', 'JSON_STORAGE_FREE', 'doc: FnJsonArg', NUM, { json: [0] }],
544
+ ['jsonStorageSize', 'JSON_STORAGE_SIZE', 'doc: FnJsonArg', NUM, { json: [0] }],
545
+ ['jsonType', 'JSON_TYPE', 'value: FnJsonArg', STR, { json: [0] }],
546
+ ['jsonUnquote', 'JSON_UNQUOTE', STRING, STR],
547
+ ['jsonValid', 'JSON_VALID', 'value: FnArg', BOOL],
548
+ [
549
+ 'jsonValue',
550
+ 'JSON_VALUE',
551
+ 'doc: FnJsonArg, path: FnArg, options?: { returning?: string }',
552
+ ANY,
553
+ { json: [0], build: buildJsonValue },
554
+ ],
555
+ [
556
+ 'memberOf',
557
+ 'MEMBER OF',
558
+ 'value: FnJsonArg, array: FnJsonArg',
559
+ BOOL,
560
+ { json: [0, 1], build: buildMemberOf },
561
+ ],
562
+ ];
563
+
564
+ // Builders for the functions with keywords in their syntax. They return
565
+ // `[sql, args]`. Keywords are checked against lists, since they can't be bindings.
566
+
567
+ function buildDateAdd(name, sql, [date, amount, unit]) {
568
+ if (unit === undefined && (sql === 'ADDDATE' || sql === 'SUBDATE')) {
569
+ // The `ADDDATE(date, days)` form.
570
+ return [`${sql}(?, ?)`, [date, amount]];
571
+ }
572
+
573
+ return [`${sql}(?, INTERVAL ? ${keyword(name, 'unit', unit, INTERVAL_UNITS)})`, [date, amount]];
574
+ }
575
+
576
+ function buildTimestampFunction(name, sql, [unit, a, b]) {
577
+ return [`${sql}(${keyword(name, 'unit', unit, TIMESTAMP_UNITS)}, ?, ?)`, [a, b]];
578
+ }
579
+
580
+ function buildExtract(name, sql, [unit, date]) {
581
+ return [`EXTRACT(${keyword(name, 'unit', unit, INTERVAL_UNITS)} FROM ?)`, [date]];
582
+ }
583
+
584
+ function buildGetFormat(name, sql, [type, locale]) {
585
+ return [`GET_FORMAT(${keyword(name, 'type', type, FORMAT_TYPES)}, ?)`, [locale]];
586
+ }
587
+
588
+ function buildCast(name, sql, [value, type]) {
589
+ if (typeof type !== 'string' || !CAST_TYPE.test(type.trim())) {
590
+ throw new Error(`fn.cast(): invalid type ${JSON.stringify(type)}`);
591
+ }
592
+
593
+ return [`CAST(? AS ${type.trim().toUpperCase()})`, [value]];
594
+ }
595
+
596
+ function buildConvert(name, sql, [value, type]) {
597
+ if (type !== null && typeof type === 'object') {
598
+ if (typeof type.using !== 'string' || !CHARSET.test(type.using)) {
599
+ throw new Error(`fn.convert(): invalid character set ${JSON.stringify(type.using)}`);
600
+ }
601
+
602
+ return [`CONVERT(? USING ${type.using})`, [value]];
603
+ }
604
+
605
+ if (typeof type !== 'string' || !CAST_TYPE.test(type.trim())) {
606
+ throw new Error(`fn.convert(): invalid type ${JSON.stringify(type)}`);
607
+ }
608
+
609
+ return [`CONVERT(?, ${type.trim().toUpperCase()})`, [value]];
610
+ }
611
+
612
+ function buildPosition(name, sql, [substr, str]) {
613
+ return ['POSITION(? IN ?)', [substr, str]];
614
+ }
615
+
616
+ function buildTrim(name, sql, [str, options = {}]) {
617
+ if (options.side === undefined && options.remove === undefined) {
618
+ return ['TRIM(?)', [str]];
619
+ }
620
+
621
+ const side =
622
+ options.side === undefined ? 'BOTH' : keyword(name, 'side', options.side, TRIM_SIDES);
623
+
624
+ if (options.remove === undefined) {
625
+ return [`TRIM(${side} FROM ?)`, [str]];
626
+ } else {
627
+ return [`TRIM(${side} ? FROM ?)`, [options.remove, str]];
628
+ }
629
+ }
630
+
631
+ function buildChar(name, sql, [codes, options = {}]) {
632
+ codes = Array.isArray(codes) ? codes : [codes];
633
+ const placeholders = codes.map(() => '?').join(', ');
634
+
635
+ if (options.using === undefined) {
636
+ return [`CHAR(${placeholders})`, codes];
637
+ }
638
+
639
+ if (typeof options.using !== 'string' || !CHARSET.test(options.using)) {
640
+ throw new Error(`fn.char(): invalid character set ${JSON.stringify(options.using)}`);
641
+ }
642
+
643
+ return [`CHAR(${placeholders} USING ${options.using})`, codes];
644
+ }
645
+
646
+ function buildMatch(name, sql, [columns, search, options = {}]) {
647
+ columns = Array.isArray(columns) ? columns : [columns];
648
+ let mode = '';
649
+
650
+ if (options.mode !== undefined) {
651
+ mode = MATCH_MODES[options.mode];
652
+
653
+ if (!mode) {
654
+ throw new Error(`fn.match(): invalid mode ${JSON.stringify(options.mode)}`);
655
+ }
656
+
657
+ mode = ` ${mode}`;
658
+ }
659
+
660
+ return [`MATCH(${columns.map(() => '?').join(', ')}) AGAINST(?${mode})`, [...columns, search]];
661
+ }
662
+
663
+ function buildCountDistinct(name, sql, exprs) {
664
+ return [`COUNT(DISTINCT ${exprs.map(() => '?').join(', ')})`, exprs];
665
+ }
666
+
667
+ function buildGroupConcat(name, sql, [exprs, options = {}]) {
668
+ exprs = Array.isArray(exprs) ? exprs : [exprs];
669
+
670
+ let text = `GROUP_CONCAT(${options.distinct ? 'DISTINCT ' : ''}${exprs.map(() => '?').join(', ')}`;
671
+ const args = [...exprs];
672
+
673
+ if (options.orderBy !== undefined) {
674
+ const [orderBySql, orderByArgs] = buildOrderBy(name, options.orderBy);
675
+ text += ` ORDER BY ${orderBySql}`;
676
+ args.push(...orderByArgs);
677
+ }
678
+
679
+ if (options.separator !== undefined) {
680
+ text += ' SEPARATOR ?';
681
+ args.push(options.separator);
682
+ }
683
+
684
+ return [`${text})`, args];
685
+ }
686
+
687
+ // `orderBy` of `groupConcat()` and `over()`: a column, `[column, 'desc']` or a
688
+ // list of them. Strings are column names.
689
+ function buildOrderBy(name, orderBy) {
690
+ const list = Array.isArray(orderBy) && !isOrderByPair(orderBy) ? orderBy : [orderBy];
691
+ const args = [];
692
+
693
+ const sql = list
694
+ .map((it) => {
695
+ if (!Array.isArray(it)) {
696
+ args.push(toColumn(it));
697
+ return '?';
698
+ }
699
+
700
+ if (it.length !== 2) {
701
+ throw new Error(
702
+ `${label(name)}: invalid orderBy item. Use a column or [column, 'asc' | 'desc'].`,
703
+ );
704
+ }
705
+
706
+ args.push(toColumn(it[0]));
707
+ return `? ${keyword(name, 'direction', it[1], DIRECTIONS)}`;
708
+ })
709
+ .join(', ');
710
+
711
+ return [sql, args];
712
+ }
713
+
714
+ function toColumn(column) {
715
+ return typeof column === 'string' ? ref(column) : column;
716
+ }
717
+
718
+ function buildNtile(name, sql, [buckets]) {
719
+ return [`NTILE(${integer(name, 'buckets', buckets, 1)})`, []];
720
+ }
721
+
722
+ function buildLagOrLead(name, sql, [value, offset, defaultValue]) {
723
+ if (offset === undefined && defaultValue === undefined) {
724
+ return [`${sql}(?)`, [value]];
725
+ }
726
+
727
+ offset = offset === undefined ? 1 : integer(name, 'offset', offset, 0);
728
+
729
+ if (defaultValue === undefined) {
730
+ return [`${sql}(?, ${offset})`, [value]];
731
+ }
732
+
733
+ return [`${sql}(?, ${offset}, ?)`, [value, defaultValue]];
734
+ }
735
+
736
+ function buildNthValue(name, sql, [value, n]) {
737
+ return [`NTH_VALUE(?, ${integer(name, 'n', n, 1)})`, [value]];
738
+ }
739
+
740
+ // The integer arguments of window functions are checked and written into the
741
+ // sql, since they are part of the syntax rather than values.
742
+ function integer(name, what, value, min) {
743
+ if (!Number.isInteger(value) || value < min) {
744
+ throw new Error(
745
+ `fn.${name}(): ${what} must be an integer >= ${min}, got ${JSON.stringify(value)}`,
746
+ );
747
+ }
748
+
749
+ return value;
750
+ }
751
+
752
+ // `[column, 'desc']`, as opposed to a list of two columns.
753
+ function isOrderByPair(it) {
754
+ return (
755
+ Array.isArray(it) &&
756
+ it.length === 2 &&
757
+ typeof it[1] === 'string' &&
758
+ DIRECTIONS.includes(it[1].trim().toUpperCase())
759
+ );
760
+ }
761
+
762
+ function buildJsonValue(name, sql, [doc, path, options = {}]) {
763
+ if (options.returning === undefined) {
764
+ return ['JSON_VALUE(?, ?)', [doc, path]];
765
+ }
766
+
767
+ if (typeof options.returning !== 'string' || !CAST_TYPE.test(options.returning.trim())) {
768
+ throw new Error(`fn.jsonValue(): invalid type ${JSON.stringify(options.returning)}`);
769
+ }
770
+
771
+ return [`JSON_VALUE(?, ? RETURNING ${options.returning.trim().toUpperCase()})`, [doc, path]];
772
+ }
773
+
774
+ function buildMemberOf(name, sql, [value, array]) {
775
+ return ['(? MEMBER OF(?))', [value, array]];
776
+ }
777
+
778
+ function buildJsonObject(name, sql, args) {
779
+ // `fn.jsonObject({ a: ref('a'), b: 1 })` is `JSON_OBJECT('a', a, 'b', 1)`.
780
+ if (args.length === 1 && isPlainObjectArg(args[0])) {
781
+ args = Object.entries(args[0]).flat();
782
+ }
783
+
784
+ return [`JSON_OBJECT(${args.map(() => '?').join(', ')})`, args];
785
+ }
786
+
787
+ function isPlainObjectArg(value) {
788
+ return (
789
+ value !== null &&
790
+ typeof value === 'object' &&
791
+ (value.constructor === Object || value.constructor === undefined)
792
+ );
793
+ }
794
+
795
+ // `name` is the name of an `fn` helper, or a method like `over()`.
796
+ function label(name) {
797
+ return name.endsWith('()') ? name : `fn.${name}()`;
798
+ }
799
+
800
+ function keyword(name, what, value, allowed) {
801
+ const upper = typeof value === 'string' ? value.trim().toUpperCase() : null;
802
+
803
+ if (!allowed.includes(upper)) {
804
+ throw new Error(
805
+ `${label(name)}: invalid ${what} ${JSON.stringify(value)}. Use one of ${allowed.join(', ')}.`,
806
+ );
807
+ }
808
+
809
+ return upper;
810
+ }
811
+
812
+ module.exports = {
813
+ FUNCTIONS,
814
+ buildOrderBy,
815
+ INTERVAL_UNITS,
816
+ TIMESTAMP_UNITS,
817
+ };