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