relq 1.0.29 → 1.0.31
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.
- package/dist/cjs/cli/utils/ast/codegen/builder.cjs +338 -46
- package/dist/cjs/cli/utils/ast-codegen.cjs +78 -4
- package/dist/cjs/cli/utils/schema-to-ast.cjs +2 -2
- package/dist/cjs/schema-definition/column-types.cjs +329 -92
- package/dist/cjs/schema-definition/index.cjs +2 -1
- package/dist/cjs/schema-definition/pg-relations.cjs +4 -0
- package/dist/cjs/schema-definition/table-definition.cjs +43 -0
- package/dist/config.d.ts +11 -7
- package/dist/esm/cli/utils/ast/codegen/builder.js +336 -45
- package/dist/esm/cli/utils/ast-codegen.js +78 -4
- package/dist/esm/cli/utils/schema-to-ast.js +2 -2
- package/dist/esm/schema-definition/column-types.js +329 -92
- package/dist/esm/schema-definition/index.js +1 -1
- package/dist/esm/schema-definition/pg-relations.js +3 -0
- package/dist/esm/schema-definition/table-definition.js +43 -0
- package/dist/index.d.ts +15 -8
- package/dist/schema-builder.d.ts +420 -125
- package/package.json +3 -4
|
@@ -1,112 +1,384 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.KNOWN_BUILDER_FUNCTIONS = void 0;
|
|
3
|
+
exports.CHAINABLE_FUNCTIONS = exports.KNOWN_BUILDER_FUNCTIONS = void 0;
|
|
4
4
|
exports.mapFunctionToBuilder = mapFunctionToBuilder;
|
|
5
|
+
exports.isChainableFunction = isChainableFunction;
|
|
5
6
|
exports.astToBuilder = astToBuilder;
|
|
6
7
|
exports.formatGeneratedExpression = formatGeneratedExpression;
|
|
7
8
|
const utils_1 = require("./utils.cjs");
|
|
8
9
|
exports.KNOWN_BUILDER_FUNCTIONS = {
|
|
9
|
-
'setweight': 'setweight',
|
|
10
|
-
'to_tsvector': 'toTsvector',
|
|
11
|
-
'to_tsquery': 'toTsquery',
|
|
12
|
-
'plainto_tsquery': 'plainToTsquery',
|
|
13
|
-
'phraseto_tsquery': 'phraseToTsquery',
|
|
14
|
-
'websearch_to_tsquery': 'websearchToTsquery',
|
|
15
|
-
'ts_headline': 'tsHeadline',
|
|
16
|
-
'ts_rank': 'tsRank',
|
|
17
|
-
'ts_rank_cd': 'tsRankCd',
|
|
18
10
|
'coalesce': 'coalesce',
|
|
19
11
|
'nullif': 'nullif',
|
|
20
|
-
'greatest': 'greatest',
|
|
21
|
-
'least': 'least',
|
|
22
|
-
'concat': 'concat',
|
|
23
|
-
'concat_ws': 'concatWs',
|
|
24
12
|
'lower': 'lower',
|
|
25
13
|
'upper': 'upper',
|
|
26
14
|
'trim': 'trim',
|
|
27
15
|
'ltrim': 'ltrim',
|
|
28
16
|
'rtrim': 'rtrim',
|
|
17
|
+
'btrim': 'btrim',
|
|
18
|
+
'concat': 'concat',
|
|
19
|
+
'concat_ws': 'concatWs',
|
|
29
20
|
'length': 'length',
|
|
21
|
+
'char_length': 'length',
|
|
22
|
+
'character_length': 'length',
|
|
23
|
+
'octet_length': 'octetLength',
|
|
24
|
+
'bit_length': 'bitLength',
|
|
30
25
|
'substring': 'substring',
|
|
26
|
+
'substr': 'substring',
|
|
31
27
|
'replace': 'replace',
|
|
32
|
-
'
|
|
28
|
+
'lpad': 'lpad',
|
|
29
|
+
'rpad': 'rpad',
|
|
30
|
+
'left': 'left',
|
|
31
|
+
'right': 'right',
|
|
32
|
+
'reverse': 'reverse',
|
|
33
|
+
'repeat': 'repeat',
|
|
34
|
+
'initcap': 'initcap',
|
|
35
|
+
'ascii': 'ascii',
|
|
36
|
+
'chr': 'chr',
|
|
37
|
+
'position': 'position',
|
|
38
|
+
'strpos': 'position',
|
|
39
|
+
'overlay': 'overlay',
|
|
40
|
+
'translate': 'translate',
|
|
33
41
|
'split_part': 'splitPart',
|
|
42
|
+
'regexp_replace': 'regexpReplace',
|
|
43
|
+
'regexp_match': 'regexpMatch',
|
|
44
|
+
'regexp_matches': 'regexpMatches',
|
|
45
|
+
'format': 'format',
|
|
46
|
+
'quote_ident': 'quoteIdent',
|
|
47
|
+
'quote_literal': 'quoteLiteral',
|
|
48
|
+
'quote_nullable': 'quoteNullable',
|
|
49
|
+
'encode': 'encode',
|
|
50
|
+
'decode': 'decode',
|
|
51
|
+
'md5': 'md5',
|
|
52
|
+
'sha256': 'sha256',
|
|
53
|
+
'sha512': 'sha512',
|
|
54
|
+
'digest': 'digest',
|
|
55
|
+
'abs': 'abs',
|
|
56
|
+
'ceil': 'ceil',
|
|
57
|
+
'ceiling': 'ceil',
|
|
58
|
+
'floor': 'floor',
|
|
59
|
+
'round': 'round',
|
|
60
|
+
'trunc': 'trunc',
|
|
61
|
+
'truncate': 'trunc',
|
|
62
|
+
'sign': 'sign',
|
|
63
|
+
'sqrt': 'sqrt',
|
|
64
|
+
'cbrt': 'cbrt',
|
|
65
|
+
'exp': 'exp',
|
|
66
|
+
'ln': 'ln',
|
|
67
|
+
'log': 'log',
|
|
68
|
+
'log10': 'log10',
|
|
69
|
+
'power': 'power',
|
|
70
|
+
'pow': 'power',
|
|
71
|
+
'mod': 'mod',
|
|
72
|
+
'degrees': 'degrees',
|
|
73
|
+
'radians': 'radians',
|
|
74
|
+
'pi': 'pi',
|
|
75
|
+
'sin': 'sin',
|
|
76
|
+
'cos': 'cos',
|
|
77
|
+
'tan': 'tan',
|
|
78
|
+
'asin': 'asin',
|
|
79
|
+
'acos': 'acos',
|
|
80
|
+
'atan': 'atan',
|
|
81
|
+
'atan2': 'atan2',
|
|
82
|
+
'sinh': 'sinh',
|
|
83
|
+
'cosh': 'cosh',
|
|
84
|
+
'tanh': 'tanh',
|
|
85
|
+
'asinh': 'asinh',
|
|
86
|
+
'acosh': 'acosh',
|
|
87
|
+
'atanh': 'atanh',
|
|
88
|
+
'factorial': 'factorial',
|
|
89
|
+
'gcd': 'gcd',
|
|
90
|
+
'lcm': 'lcm',
|
|
91
|
+
'width_bucket': 'widthBucket',
|
|
92
|
+
'random': 'random',
|
|
93
|
+
'setseed': 'setseed',
|
|
94
|
+
'greatest': 'greatest',
|
|
95
|
+
'least': 'least',
|
|
96
|
+
'json_typeof': 'jsonTypeof',
|
|
97
|
+
'jsonb_typeof': 'jsonbTypeof',
|
|
98
|
+
'json_array_length': 'jsonArrayLength',
|
|
99
|
+
'jsonb_array_length': 'jsonbArrayLength',
|
|
100
|
+
'jsonb_object_keys': 'jsonbKeys',
|
|
101
|
+
'json_object_keys': 'jsonKeys',
|
|
102
|
+
'jsonb_pretty': 'jsonbPretty',
|
|
103
|
+
'jsonb_strip_nulls': 'jsonbStripNulls',
|
|
104
|
+
'to_json': 'toJson',
|
|
105
|
+
'to_jsonb': 'toJsonb',
|
|
106
|
+
'row_to_json': 'rowToJson',
|
|
107
|
+
'json_build_object': 'jsonBuildObject',
|
|
108
|
+
'jsonb_build_object': 'jsonbBuildObject',
|
|
109
|
+
'json_build_array': 'jsonBuildArray',
|
|
110
|
+
'jsonb_build_array': 'jsonbBuildArray',
|
|
111
|
+
'json_agg': 'jsonAgg',
|
|
112
|
+
'jsonb_agg': 'jsonbAgg',
|
|
113
|
+
'json_object_agg': 'jsonObjectAgg',
|
|
114
|
+
'jsonb_object_agg': 'jsonbObjectAgg',
|
|
115
|
+
'jsonb_set': 'jsonbSet',
|
|
116
|
+
'jsonb_insert': 'jsonbInsert',
|
|
117
|
+
'jsonb_path_query': 'jsonbPathQuery',
|
|
118
|
+
'jsonb_path_query_array': 'jsonbPathQueryArray',
|
|
119
|
+
'jsonb_path_query_first': 'jsonbPathQueryFirst',
|
|
120
|
+
'jsonb_path_exists': 'jsonbPathExists',
|
|
121
|
+
'array_length': 'arrayLength',
|
|
122
|
+
'array_position': 'arrayPosition',
|
|
123
|
+
'array_positions': 'arrayPositions',
|
|
124
|
+
'array_dims': 'arrayDims',
|
|
125
|
+
'array_lower': 'arrayLower',
|
|
126
|
+
'array_upper': 'arrayUpper',
|
|
127
|
+
'array_ndims': 'arrayNDims',
|
|
128
|
+
'array_to_string': 'arrayToString',
|
|
129
|
+
'string_to_array': 'stringToArray',
|
|
130
|
+
'array_append': 'arrayAppend',
|
|
131
|
+
'array_prepend': 'arrayPrepend',
|
|
132
|
+
'array_cat': 'arrayCat',
|
|
133
|
+
'array_remove': 'arrayRemove',
|
|
134
|
+
'array_replace': 'arrayReplace',
|
|
135
|
+
'unnest': 'unnest',
|
|
136
|
+
'cardinality': 'cardinality',
|
|
137
|
+
'array_agg': 'arrayAgg',
|
|
138
|
+
'to_tsvector': 'toTsvector',
|
|
139
|
+
'setweight': 'setWeight',
|
|
140
|
+
'to_tsquery': 'toTsquery',
|
|
141
|
+
'plainto_tsquery': 'plainToTsquery',
|
|
142
|
+
'phraseto_tsquery': 'phraseToTsquery',
|
|
143
|
+
'websearch_to_tsquery': 'websearchToTsquery',
|
|
144
|
+
'strip': 'tsStrip',
|
|
145
|
+
'numnode': 'numNode',
|
|
146
|
+
'querytree': 'queryTree',
|
|
147
|
+
'ts_rank': 'tsRank',
|
|
148
|
+
'ts_rank_cd': 'tsRankCd',
|
|
149
|
+
'ts_headline': 'tsHeadline',
|
|
150
|
+
'ts_rewrite': 'tsRewrite',
|
|
151
|
+
'ts_filter': 'tsFilter',
|
|
152
|
+
'ts_delete': 'tsDelete',
|
|
153
|
+
'tsvector_to_array': 'tsvectorToArray',
|
|
154
|
+
'extract': 'extract',
|
|
155
|
+
'date_part': 'datePart',
|
|
156
|
+
'date_trunc': 'dateTrunc',
|
|
157
|
+
'age': 'age',
|
|
158
|
+
'isfinite': 'isfinite',
|
|
159
|
+
'make_date': 'makeDate',
|
|
160
|
+
'make_time': 'makeTime',
|
|
161
|
+
'make_timestamp': 'makeTimestamp',
|
|
162
|
+
'make_timestamptz': 'makeTimestamptz',
|
|
163
|
+
'make_interval': 'makeInterval',
|
|
34
164
|
'now': 'now',
|
|
35
165
|
'current_timestamp': 'currentTimestamp',
|
|
36
166
|
'current_date': 'currentDate',
|
|
37
167
|
'current_time': 'currentTime',
|
|
38
|
-
'
|
|
39
|
-
'
|
|
40
|
-
'
|
|
41
|
-
'
|
|
168
|
+
'localtime': 'localtime',
|
|
169
|
+
'localtimestamp': 'localtimestamp',
|
|
170
|
+
'clock_timestamp': 'clockTimestamp',
|
|
171
|
+
'statement_timestamp': 'statementTimestamp',
|
|
172
|
+
'transaction_timestamp': 'transactionTimestamp',
|
|
173
|
+
'timeofday': 'timeofday',
|
|
174
|
+
'to_char': 'toChar',
|
|
175
|
+
'to_date': 'toDate',
|
|
176
|
+
'to_timestamp': 'toTimestamp',
|
|
42
177
|
'gen_random_uuid': 'genRandomUuid',
|
|
43
178
|
'uuid_generate_v4': 'uuidGenerateV4',
|
|
44
|
-
'
|
|
45
|
-
'jsonb_agg': 'jsonbAgg',
|
|
46
|
-
'json_agg': 'jsonAgg',
|
|
47
|
-
'array_agg': 'arrayAgg',
|
|
48
|
-
'string_agg': 'stringAgg',
|
|
179
|
+
'uuid_generate_v1': 'uuidGenerateV1',
|
|
49
180
|
'count': 'count',
|
|
50
181
|
'sum': 'sum',
|
|
51
182
|
'avg': 'avg',
|
|
52
183
|
'min': 'min',
|
|
53
184
|
'max': 'max',
|
|
54
|
-
'
|
|
55
|
-
'
|
|
56
|
-
'
|
|
57
|
-
'
|
|
58
|
-
'
|
|
59
|
-
'
|
|
60
|
-
'
|
|
61
|
-
'
|
|
185
|
+
'string_agg': 'stringAgg',
|
|
186
|
+
'bool_and': 'boolAnd',
|
|
187
|
+
'bool_or': 'boolOr',
|
|
188
|
+
'every': 'every',
|
|
189
|
+
'bit_and': 'bitAnd',
|
|
190
|
+
'bit_or': 'bitOr',
|
|
191
|
+
'inet_client_addr': 'inetClientAddr',
|
|
192
|
+
'inet_server_addr': 'inetServerAddr',
|
|
193
|
+
'host': 'host',
|
|
194
|
+
'hostmask': 'hostmask',
|
|
195
|
+
'netmask': 'netmask',
|
|
196
|
+
'network': 'network',
|
|
197
|
+
'broadcast': 'broadcast',
|
|
198
|
+
'masklen': 'masklen',
|
|
199
|
+
'family': 'family',
|
|
200
|
+
'area': 'area',
|
|
201
|
+
'center': 'center',
|
|
202
|
+
'diameter': 'diameter',
|
|
203
|
+
'height': 'height',
|
|
204
|
+
'width': 'width',
|
|
205
|
+
'isclosed': 'isclosed',
|
|
206
|
+
'isopen': 'isopen',
|
|
207
|
+
'npoints': 'npoints',
|
|
208
|
+
'pclose': 'pclose',
|
|
209
|
+
'popen': 'popen',
|
|
210
|
+
'radius': 'radius',
|
|
211
|
+
'lower_bound': 'lowerBound',
|
|
212
|
+
'upper_bound': 'upperBound',
|
|
213
|
+
'isempty': 'isempty',
|
|
214
|
+
'lower_inc': 'lowerInc',
|
|
215
|
+
'upper_inc': 'upperInc',
|
|
216
|
+
'lower_inf': 'lowerInf',
|
|
217
|
+
'upper_inf': 'upperInf',
|
|
218
|
+
'range_merge': 'rangeMerge',
|
|
62
219
|
};
|
|
63
220
|
function mapFunctionToBuilder(funcName) {
|
|
64
221
|
return exports.KNOWN_BUILDER_FUNCTIONS[funcName] || null;
|
|
65
222
|
}
|
|
223
|
+
exports.CHAINABLE_FUNCTIONS = new Set([
|
|
224
|
+
'lower', 'upper', 'trim', 'ltrim', 'rtrim', 'btrim',
|
|
225
|
+
'length', 'char_length', 'character_length',
|
|
226
|
+
'left', 'right', 'reverse', 'repeat', 'initcap',
|
|
227
|
+
'substring', 'substr', 'replace', 'translate',
|
|
228
|
+
'lpad', 'rpad', 'ascii', 'md5', 'sha256', 'sha512',
|
|
229
|
+
'encode', 'decode', 'quote_ident', 'quote_literal', 'quote_nullable',
|
|
230
|
+
'coalesce', 'nullif',
|
|
231
|
+
'json_typeof', 'jsonb_typeof',
|
|
232
|
+
'json_array_length', 'jsonb_array_length',
|
|
233
|
+
'jsonb_object_keys', 'json_object_keys',
|
|
234
|
+
'jsonb_pretty', 'jsonb_strip_nulls',
|
|
235
|
+
'to_json', 'to_jsonb',
|
|
236
|
+
'array_length', 'array_position', 'array_positions',
|
|
237
|
+
'array_dims', 'array_lower', 'array_upper', 'array_ndims',
|
|
238
|
+
'array_to_string', 'array_append', 'array_prepend',
|
|
239
|
+
'array_cat', 'array_remove', 'array_replace',
|
|
240
|
+
'unnest', 'cardinality',
|
|
241
|
+
'to_tsvector', 'setweight', 'strip',
|
|
242
|
+
'to_tsquery', 'plainto_tsquery', 'phraseto_tsquery', 'websearch_to_tsquery',
|
|
243
|
+
'ts_rank', 'ts_rank_cd', 'ts_headline',
|
|
244
|
+
'numnode', 'querytree', 'ts_rewrite', 'ts_filter', 'ts_delete',
|
|
245
|
+
'abs', 'ceil', 'ceiling', 'floor', 'round', 'trunc', 'truncate', 'sign',
|
|
246
|
+
'sqrt', 'cbrt', 'exp', 'ln', 'log', 'log10',
|
|
247
|
+
'sin', 'cos', 'tan', 'asin', 'acos', 'atan',
|
|
248
|
+
'sinh', 'cosh', 'tanh', 'degrees', 'radians',
|
|
249
|
+
'factorial',
|
|
250
|
+
'extract', 'date_part', 'date_trunc', 'age', 'isfinite',
|
|
251
|
+
]);
|
|
252
|
+
function isChainableFunction(funcName) {
|
|
253
|
+
return exports.CHAINABLE_FUNCTIONS.has(funcName.toLowerCase());
|
|
254
|
+
}
|
|
255
|
+
function isChainableNode(node) {
|
|
256
|
+
if (!node)
|
|
257
|
+
return false;
|
|
258
|
+
if (node.ColumnRef)
|
|
259
|
+
return true;
|
|
260
|
+
if (node.FuncCall)
|
|
261
|
+
return true;
|
|
262
|
+
if (node.CoalesceExpr)
|
|
263
|
+
return true;
|
|
264
|
+
if (node.TypeCast)
|
|
265
|
+
return isChainableNode(node.TypeCast.arg);
|
|
266
|
+
if (node.A_Expr)
|
|
267
|
+
return isChainableNode(node.A_Expr.lexpr) || isChainableNode(node.A_Expr.rexpr);
|
|
268
|
+
if (node.CaseExpr)
|
|
269
|
+
return true;
|
|
270
|
+
if (node.A_Const)
|
|
271
|
+
return false;
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
const SECOND_ARG_CHAINABLE_FUNCTIONS = new Set([
|
|
275
|
+
'to_tsvector',
|
|
276
|
+
'to_tsquery',
|
|
277
|
+
'plainto_tsquery',
|
|
278
|
+
'phraseto_tsquery',
|
|
279
|
+
'websearch_to_tsquery',
|
|
280
|
+
'setweight',
|
|
281
|
+
]);
|
|
66
282
|
function astToBuilder(node, prefixOrOptions = 'g') {
|
|
67
283
|
const opts = typeof prefixOrOptions === 'string'
|
|
68
284
|
? { prefix: prefixOrOptions }
|
|
69
285
|
: prefixOrOptions;
|
|
70
|
-
const { prefix = 'g', useCamelCase = false, useTableRef = false } = opts;
|
|
286
|
+
const { prefix = 'g', useCamelCase = false, useTableRef = false, chainable = false } = opts;
|
|
71
287
|
if (!node)
|
|
72
288
|
return "''";
|
|
73
289
|
if (node.FuncCall) {
|
|
74
290
|
const func = node.FuncCall;
|
|
75
291
|
const funcName = func.funcname?.map((n) => n.String?.sval).filter(Boolean).join('.') || '';
|
|
76
|
-
const
|
|
77
|
-
const
|
|
292
|
+
const funcNameLower = funcName.toLowerCase();
|
|
293
|
+
const rawArgs = func.args || [];
|
|
294
|
+
const args = rawArgs.map((a) => astToBuilder(a, opts));
|
|
295
|
+
const builderMethod = mapFunctionToBuilder(funcNameLower);
|
|
78
296
|
if (builderMethod) {
|
|
297
|
+
if (chainable && isChainableFunction(funcName) && args.length > 0) {
|
|
298
|
+
if (SECOND_ARG_CHAINABLE_FUNCTIONS.has(funcNameLower) && args.length >= 2) {
|
|
299
|
+
const firstArgIsChainable = isChainableNode(rawArgs[0]);
|
|
300
|
+
const secondArgIsChainable = isChainableNode(rawArgs[1]);
|
|
301
|
+
if (!firstArgIsChainable && secondArgIsChainable) {
|
|
302
|
+
const [configArg, baseArg, ...restArgs] = args;
|
|
303
|
+
if (restArgs.length > 0) {
|
|
304
|
+
return `${baseArg}.${builderMethod}(${configArg}, ${restArgs.join(', ')})`;
|
|
305
|
+
}
|
|
306
|
+
return `${baseArg}.${builderMethod}(${configArg})`;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
const firstArgIsChainable = isChainableNode(rawArgs[0]);
|
|
310
|
+
if (firstArgIsChainable) {
|
|
311
|
+
const [firstArg, ...restArgs] = args;
|
|
312
|
+
if (restArgs.length > 0) {
|
|
313
|
+
return `${firstArg}.${builderMethod}(${restArgs.join(', ')})`;
|
|
314
|
+
}
|
|
315
|
+
return `${firstArg}.${builderMethod}()`;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
79
318
|
return `${prefix}.${builderMethod}(${args.join(', ')})`;
|
|
80
319
|
}
|
|
81
|
-
throw new Error(`Unsupported function in generated expression: "${funcName}". Add this function to KNOWN_BUILDER_FUNCTIONS in
|
|
320
|
+
throw new Error(`Unsupported function in generated expression: "${funcName}". Add this function to KNOWN_BUILDER_FUNCTIONS in src/cli/utils/ast/codegen/builder.ts`);
|
|
82
321
|
}
|
|
83
322
|
if (node.CoalesceExpr) {
|
|
84
|
-
const
|
|
323
|
+
const rawArgs = node.CoalesceExpr.args || [];
|
|
324
|
+
const args = rawArgs.map((a) => astToBuilder(a, opts));
|
|
325
|
+
if (chainable && args.length > 0 && isChainableNode(rawArgs[0])) {
|
|
326
|
+
const [firstArg, ...restArgs] = args;
|
|
327
|
+
return `${firstArg}.coalesce(${restArgs.join(', ')})`;
|
|
328
|
+
}
|
|
85
329
|
return `${prefix}.coalesce(${args.join(', ')})`;
|
|
86
330
|
}
|
|
87
331
|
if (node.A_Expr) {
|
|
88
332
|
const expr = node.A_Expr;
|
|
89
333
|
const op = expr.name?.[0]?.String?.sval || '';
|
|
334
|
+
const leftIsChainable = isChainableNode(expr.lexpr);
|
|
90
335
|
const left = astToBuilder(expr.lexpr, opts);
|
|
91
336
|
const right = astToBuilder(expr.rexpr, opts);
|
|
92
337
|
switch (op) {
|
|
93
338
|
case '||':
|
|
339
|
+
if (chainable && leftIsChainable) {
|
|
340
|
+
return `${left}.concat(${right})`;
|
|
341
|
+
}
|
|
94
342
|
return `__CONCAT__[${left}, ${right}]`;
|
|
95
343
|
case '->>':
|
|
344
|
+
if (chainable && leftIsChainable) {
|
|
345
|
+
return `${left}.jsonbExtractText(${right})`;
|
|
346
|
+
}
|
|
96
347
|
return `${prefix}.jsonbExtractText(${left}, ${right})`;
|
|
97
348
|
case '->':
|
|
349
|
+
if (chainable && leftIsChainable) {
|
|
350
|
+
return `${left}.jsonbExtract(${right})`;
|
|
351
|
+
}
|
|
98
352
|
return `${prefix}.jsonbExtract(${left}, ${right})`;
|
|
99
353
|
case '@@':
|
|
354
|
+
if (chainable && leftIsChainable) {
|
|
355
|
+
return `${left}.tsMatch(${right})`;
|
|
356
|
+
}
|
|
100
357
|
return `${prefix}.tsMatch(${left}, ${right})`;
|
|
101
358
|
case '+':
|
|
359
|
+
if (chainable && leftIsChainable) {
|
|
360
|
+
return `${left}.add(${right})`;
|
|
361
|
+
}
|
|
102
362
|
return `${prefix}.add(${left}, ${right})`;
|
|
103
363
|
case '-':
|
|
364
|
+
if (chainable && leftIsChainable) {
|
|
365
|
+
return `${left}.subtract(${right})`;
|
|
366
|
+
}
|
|
104
367
|
return `${prefix}.subtract(${left}, ${right})`;
|
|
105
368
|
case '*':
|
|
369
|
+
if (chainable && leftIsChainable) {
|
|
370
|
+
return `${left}.multiply(${right})`;
|
|
371
|
+
}
|
|
106
372
|
return `${prefix}.multiply(${left}, ${right})`;
|
|
107
373
|
case '/':
|
|
374
|
+
if (chainable && leftIsChainable) {
|
|
375
|
+
return `${left}.divide(${right})`;
|
|
376
|
+
}
|
|
108
377
|
return `${prefix}.divide(${left}, ${right})`;
|
|
109
378
|
case '%':
|
|
379
|
+
if (chainable && leftIsChainable) {
|
|
380
|
+
return `${left}.mod(${right})`;
|
|
381
|
+
}
|
|
110
382
|
return `${prefix}.mod(${left}, ${right})`;
|
|
111
383
|
case '=':
|
|
112
384
|
case '<>':
|
|
@@ -115,9 +387,9 @@ function astToBuilder(node, prefixOrOptions = 'g') {
|
|
|
115
387
|
case '>':
|
|
116
388
|
case '<=':
|
|
117
389
|
case '>=':
|
|
118
|
-
if (useTableRef) {
|
|
390
|
+
if ((useTableRef || chainable) && leftIsChainable) {
|
|
119
391
|
const methodMap = {
|
|
120
|
-
'=': 'eq', '<>': 'ne', '!=': '
|
|
392
|
+
'=': 'eq', '<>': 'ne', '!=': 'ne',
|
|
121
393
|
'<': 'lt', '>': 'gt', '<=': 'lte', '>=': 'gte'
|
|
122
394
|
};
|
|
123
395
|
return `${left}.${methodMap[op]}(${right})`;
|
|
@@ -127,6 +399,14 @@ function astToBuilder(node, prefixOrOptions = 'g') {
|
|
|
127
399
|
case '~*':
|
|
128
400
|
case '!~':
|
|
129
401
|
case '!~*':
|
|
402
|
+
if (chainable && leftIsChainable) {
|
|
403
|
+
const flags = op.includes('*') ? 'i' : '';
|
|
404
|
+
const negated = op.startsWith('!');
|
|
405
|
+
if (negated) {
|
|
406
|
+
return `${left}.matches(${right}${flags ? `, '${flags}'` : ''}).not()`;
|
|
407
|
+
}
|
|
408
|
+
return `${left}.matches(${right}${flags ? `, '${flags}'` : ''})`;
|
|
409
|
+
}
|
|
130
410
|
return `${prefix}.regex(${left}, '${op}', ${right})`;
|
|
131
411
|
default:
|
|
132
412
|
throw new Error(`Unsupported operator in generated expression: "${op}". Add explicit handling for this operator in astToBuilder.`);
|
|
@@ -138,22 +418,19 @@ function astToBuilder(node, prefixOrOptions = 'g') {
|
|
|
138
418
|
.filter(Boolean);
|
|
139
419
|
if (fields.length === 1) {
|
|
140
420
|
const colName = useCamelCase ? (0, utils_1.toCamelCase)(fields[0]) : fields[0];
|
|
141
|
-
return
|
|
421
|
+
return `${prefix}.${colName}`;
|
|
142
422
|
}
|
|
143
423
|
else if (fields.length === 2) {
|
|
144
424
|
const colName = useCamelCase ? (0, utils_1.toCamelCase)(fields[1]) : fields[1];
|
|
145
|
-
return
|
|
425
|
+
return `${prefix}.${colName}`;
|
|
146
426
|
}
|
|
147
427
|
const colName = useCamelCase ? (0, utils_1.toCamelCase)(fields[fields.length - 1]) : fields[fields.length - 1];
|
|
148
|
-
return
|
|
428
|
+
return `${prefix}.${colName}`;
|
|
149
429
|
}
|
|
150
430
|
if (node.A_Const) {
|
|
151
431
|
const val = node.A_Const;
|
|
152
432
|
if (val.sval !== undefined) {
|
|
153
433
|
const s = val.sval?.sval ?? val.sval;
|
|
154
|
-
if (s === '' || s === ' ') {
|
|
155
|
-
return s === '' ? `${prefix}.asText()` : `${prefix}.asText(' ')`;
|
|
156
|
-
}
|
|
157
434
|
return `'${(0, utils_1.escapeString)(String(s))}'`;
|
|
158
435
|
}
|
|
159
436
|
else if (val.ival !== undefined) {
|
|
@@ -167,9 +444,11 @@ function astToBuilder(node, prefixOrOptions = 'g') {
|
|
|
167
444
|
else if (val.boolval !== undefined) {
|
|
168
445
|
return val.boolval?.boolval ? 'true' : 'false';
|
|
169
446
|
}
|
|
170
|
-
return
|
|
447
|
+
return "''";
|
|
171
448
|
}
|
|
172
449
|
if (node.TypeCast) {
|
|
450
|
+
const argIsChainable = isChainableNode(node.TypeCast.arg);
|
|
451
|
+
const argIsLiteral = node.TypeCast.arg?.A_Const !== undefined;
|
|
173
452
|
const arg = astToBuilder(node.TypeCast.arg, opts);
|
|
174
453
|
const typeName = node.TypeCast.typeName?.names
|
|
175
454
|
?.map((n) => n.String?.sval)
|
|
@@ -179,6 +458,12 @@ function astToBuilder(node, prefixOrOptions = 'g') {
|
|
|
179
458
|
return arg;
|
|
180
459
|
}
|
|
181
460
|
if (typeName === 'text' || typeName === 'pg_catalog.text') {
|
|
461
|
+
if (argIsLiteral) {
|
|
462
|
+
return arg;
|
|
463
|
+
}
|
|
464
|
+
if (chainable && argIsChainable) {
|
|
465
|
+
return `${arg}.asText()`;
|
|
466
|
+
}
|
|
182
467
|
return `${prefix}.asText(${arg})`;
|
|
183
468
|
}
|
|
184
469
|
if (typeName === 'varchar' || typeName === 'pg_catalog.varchar' || typeName.includes('character varying')) {
|
|
@@ -193,11 +478,18 @@ function astToBuilder(node, prefixOrOptions = 'g') {
|
|
|
193
478
|
if (typeName === 'int4' || typeName === 'integer' || typeName === 'pg_catalog.int4') {
|
|
194
479
|
return arg;
|
|
195
480
|
}
|
|
481
|
+
if (chainable && argIsChainable) {
|
|
482
|
+
return `${arg}.cast('${typeName}')`;
|
|
483
|
+
}
|
|
196
484
|
return `${prefix}.cast(${arg}, '${typeName}')`;
|
|
197
485
|
}
|
|
198
486
|
if (node.NullTest) {
|
|
487
|
+
const argIsChainable = isChainableNode(node.NullTest.arg);
|
|
199
488
|
const arg = astToBuilder(node.NullTest.arg, opts);
|
|
200
489
|
const isNull = node.NullTest.nulltesttype === 'IS_NULL';
|
|
490
|
+
if (chainable && argIsChainable) {
|
|
491
|
+
return isNull ? `${arg}.isNull()` : `${arg}.isNotNull()`;
|
|
492
|
+
}
|
|
201
493
|
return isNull ? `${prefix}.isNull(${arg})` : `${prefix}.isNotNull(${arg})`;
|
|
202
494
|
}
|
|
203
495
|
if (node.BoolExpr) {
|
|
@@ -20,6 +20,52 @@ function generateTrackingId(prefix) {
|
|
|
20
20
|
const base = (Date.now().toString(36) + trackingIdCounter.toString(36)).slice(-5);
|
|
21
21
|
return prefix + base.padStart(5, '0');
|
|
22
22
|
}
|
|
23
|
+
function formatGeneratedExpr(expr, indent) {
|
|
24
|
+
if (expr.length <= 100)
|
|
25
|
+
return expr;
|
|
26
|
+
const indentStr = ' '.repeat(indent);
|
|
27
|
+
const breakMethods = ['setWeight', 'toTsvector', 'concat'];
|
|
28
|
+
let result = '';
|
|
29
|
+
let i = 0;
|
|
30
|
+
let depth = 0;
|
|
31
|
+
while (i < expr.length) {
|
|
32
|
+
const char = expr[i];
|
|
33
|
+
if (char === '(')
|
|
34
|
+
depth++;
|
|
35
|
+
else if (char === ')')
|
|
36
|
+
depth--;
|
|
37
|
+
if (char === '.' && depth === 0 && i > 0) {
|
|
38
|
+
for (const method of breakMethods) {
|
|
39
|
+
if (expr.substring(i + 1, i + 1 + method.length + 1).startsWith(method + '(')) {
|
|
40
|
+
let parenDepth = 0;
|
|
41
|
+
let j = i + 1 + method.length;
|
|
42
|
+
while (j < expr.length) {
|
|
43
|
+
if (expr[j] === '(')
|
|
44
|
+
parenDepth++;
|
|
45
|
+
else if (expr[j] === ')') {
|
|
46
|
+
parenDepth--;
|
|
47
|
+
if (parenDepth === 0) {
|
|
48
|
+
result += expr.substring(i, j + 1);
|
|
49
|
+
i = j + 1;
|
|
50
|
+
if (i < expr.length && expr[i] === '.') {
|
|
51
|
+
result += '\n' + indentStr;
|
|
52
|
+
}
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
j++;
|
|
57
|
+
}
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (i < expr.length) {
|
|
63
|
+
result += expr[i];
|
|
64
|
+
i++;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return result || expr;
|
|
68
|
+
}
|
|
23
69
|
function resetTrackingIdCounter() {
|
|
24
70
|
trackingIdCounter = 0;
|
|
25
71
|
}
|
|
@@ -173,10 +219,6 @@ function generateColumnCode(col, useCamelCase, enumNames, domainNames, checkOver
|
|
|
173
219
|
const defaultVal = (0, defaults_1.formatDefaultValue)(col.defaultValue, col.type);
|
|
174
220
|
line += `.default(${defaultVal})`;
|
|
175
221
|
}
|
|
176
|
-
if (col.isGenerated && col.generatedExpression) {
|
|
177
|
-
const escapedExpr = col.generatedExpression.replace(/`/g, '\\`');
|
|
178
|
-
line += `.generatedAlwaysAs(F => F.raw(\`${escapedExpr}\`))`;
|
|
179
|
-
}
|
|
180
222
|
if (!col.isNullable && !col.isPrimaryKey) {
|
|
181
223
|
line += '.notNull()';
|
|
182
224
|
}
|
|
@@ -488,6 +530,38 @@ function generateTableCode(table, useCamelCase, enumNames, domainNames) {
|
|
|
488
530
|
if (checkConstraintsOption) {
|
|
489
531
|
optionParts.push(checkConstraintsOption);
|
|
490
532
|
}
|
|
533
|
+
const generatedCols = table.columns.filter(col => col.isGenerated && col.generatedExpression);
|
|
534
|
+
if (generatedCols.length > 0) {
|
|
535
|
+
const generatedLines = [];
|
|
536
|
+
for (const col of generatedCols) {
|
|
537
|
+
const colName = useCamelCase ? (0, utils_1.toCamelCase)(col.name) : col.name;
|
|
538
|
+
const ast = col.generatedExpressionAst;
|
|
539
|
+
if (ast) {
|
|
540
|
+
try {
|
|
541
|
+
const builderExpr = (0, builder_1.astToBuilder)(ast, {
|
|
542
|
+
prefix: 't',
|
|
543
|
+
useCamelCase,
|
|
544
|
+
useTableRef: true,
|
|
545
|
+
chainable: true,
|
|
546
|
+
});
|
|
547
|
+
const formattedExpr = formatGeneratedExpr(builderExpr, 16);
|
|
548
|
+
generatedLines.push(` As.on(t.${colName}).as(${formattedExpr})`);
|
|
549
|
+
}
|
|
550
|
+
catch (err) {
|
|
551
|
+
throw new Error(`Failed to generate typed expression for generated column "${col.name}": ${err instanceof Error ? err.message : String(err)}\n` +
|
|
552
|
+
`SQL expression: ${col.generatedExpression}\n` +
|
|
553
|
+
`Hint: Add missing function to KNOWN_BUILDER_FUNCTIONS in src/cli/utils/ast/codegen/builder.ts`);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
else {
|
|
557
|
+
throw new Error(`Missing generatedExpressionAst for column "${col.name}". ` +
|
|
558
|
+
`The SQL expression "${col.generatedExpression}" cannot be converted to typed builder.`);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
if (generatedLines.length > 0) {
|
|
562
|
+
optionParts.push(` generatedAs: (t, As) => [\n${generatedLines.join(',\n')},\n ]`);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
491
565
|
if (table.indexes.length > 0) {
|
|
492
566
|
const indexLines = table.indexes.map(idx => generateIndexCode(idx, useCamelCase));
|
|
493
567
|
optionParts.push(` indexes: (table, index) => [\n${indexLines.join(',\n')},\n ]`);
|
|
@@ -304,8 +304,8 @@ function columnToAST(col, schemaKey) {
|
|
|
304
304
|
isUnique: config.$unique || false,
|
|
305
305
|
hasDefault: config.$default !== undefined,
|
|
306
306
|
defaultValue: config.$default?.toString(),
|
|
307
|
-
isGenerated: !!config.$
|
|
308
|
-
generatedExpression: config.$
|
|
307
|
+
isGenerated: !!config.$generated,
|
|
308
|
+
generatedExpression: config.$generated?.expression,
|
|
309
309
|
isArray: config.$isArray || false,
|
|
310
310
|
arrayDimensions: config.$arrayDimensions,
|
|
311
311
|
comment: config.$comment,
|