@dbsp/adapter-pgsql 1.11.1 → 1.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +459 -86
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -94,6 +94,332 @@ var init_naming_plugin = __esm({
|
|
|
94
94
|
}
|
|
95
95
|
});
|
|
96
96
|
|
|
97
|
+
// src/db-type.ts
|
|
98
|
+
function splitDbType(input) {
|
|
99
|
+
const trimmed = input.trim();
|
|
100
|
+
let rest = trimmed;
|
|
101
|
+
let isArray = false;
|
|
102
|
+
if (rest.endsWith("[]")) {
|
|
103
|
+
isArray = true;
|
|
104
|
+
rest = rest.slice(0, -2).trimEnd();
|
|
105
|
+
}
|
|
106
|
+
const lowerRest = rest.toLowerCase();
|
|
107
|
+
for (const suffix of TEMPORAL_TZ_SUFFIXES) {
|
|
108
|
+
if (!lowerRest.endsWith(suffix)) continue;
|
|
109
|
+
const beforeSuffix = rest.slice(0, -suffix.length).trimEnd();
|
|
110
|
+
const temporal = splitTrailingModifier(beforeSuffix);
|
|
111
|
+
const temporalBase = normalizeBase(temporal.base).toLowerCase();
|
|
112
|
+
if (temporalBase === "timestamp" || temporalBase === "time") {
|
|
113
|
+
const base2 = normalizeBase(`${temporal.base}${suffix}`);
|
|
114
|
+
return {
|
|
115
|
+
base: base2,
|
|
116
|
+
modifier: temporal.modifier,
|
|
117
|
+
isArray,
|
|
118
|
+
schemaQualified: isSchemaQualified(base2)
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const split = splitTrailingModifier(rest);
|
|
123
|
+
const base = normalizeBase(split.base);
|
|
124
|
+
return {
|
|
125
|
+
base,
|
|
126
|
+
modifier: split.modifier,
|
|
127
|
+
isArray,
|
|
128
|
+
schemaQualified: isSchemaQualified(base)
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function splitTrailingModifier(input) {
|
|
132
|
+
const match = input.match(/^(.*)\(([^()]*)\)$/);
|
|
133
|
+
if (!match) return { base: input.trim(), modifier: void 0 };
|
|
134
|
+
return {
|
|
135
|
+
base: (match[1] ?? "").trimEnd(),
|
|
136
|
+
modifier: (match[2] ?? "").trim()
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function normalizeBase(base) {
|
|
140
|
+
const trimmed = base.trim();
|
|
141
|
+
return trimmed.includes('"') ? trimmed : trimmed.replace(/\s+/g, " ");
|
|
142
|
+
}
|
|
143
|
+
function isSchemaQualified(base) {
|
|
144
|
+
return QUALIFIED_IDENTIFIER_RE.test(base);
|
|
145
|
+
}
|
|
146
|
+
function canonicalizeDbType(type) {
|
|
147
|
+
const split = splitDbType(type);
|
|
148
|
+
const base = normalizeBase(split.base);
|
|
149
|
+
const canonicalBase = base.includes('"') ? base : TYPE_ALIASES.get(base.toLowerCase()) ?? base.toLowerCase();
|
|
150
|
+
const modifier = split.modifier === void 0 ? "" : `(${split.modifier.replace(/\s*,\s*/g, ",").trim()})`;
|
|
151
|
+
const arraySuffix = split.isArray ? "[]" : "";
|
|
152
|
+
return `${canonicalBase}${modifier}${arraySuffix}`;
|
|
153
|
+
}
|
|
154
|
+
function dbTypeCastTarget(originalDbType) {
|
|
155
|
+
const split = splitDbType(originalDbType);
|
|
156
|
+
const base = normalizeBase(split.base).toLowerCase();
|
|
157
|
+
const hasModifier = split.modifier !== void 0;
|
|
158
|
+
const arraySuffix = split.isArray ? "[]" : "";
|
|
159
|
+
if (base === "varchar" || base === "character varying") {
|
|
160
|
+
return hasModifier ? `varchar${arraySuffix}` : originalDbType;
|
|
161
|
+
}
|
|
162
|
+
if (base === "char" || base === "character" || base === "bpchar") {
|
|
163
|
+
return `text${arraySuffix}`;
|
|
164
|
+
}
|
|
165
|
+
if (base === "bit" || base === "bit varying" || base === "varbit") {
|
|
166
|
+
return hasModifier ? `bit varying${arraySuffix}` : originalDbType;
|
|
167
|
+
}
|
|
168
|
+
if (base === "numeric" || base === "decimal") {
|
|
169
|
+
return hasModifier ? `numeric${arraySuffix}` : originalDbType;
|
|
170
|
+
}
|
|
171
|
+
if (base === "timestamp with time zone" || base === "timestamptz") {
|
|
172
|
+
return hasModifier ? `timestamp with time zone${arraySuffix}` : originalDbType;
|
|
173
|
+
}
|
|
174
|
+
if (base === "timestamp without time zone") {
|
|
175
|
+
return hasModifier ? `timestamp without time zone${arraySuffix}` : originalDbType;
|
|
176
|
+
}
|
|
177
|
+
if (base === "timestamp") {
|
|
178
|
+
return hasModifier ? `timestamp without time zone${arraySuffix}` : originalDbType;
|
|
179
|
+
}
|
|
180
|
+
if (base === "time with time zone" || base === "timetz") {
|
|
181
|
+
return hasModifier ? `time with time zone${arraySuffix}` : originalDbType;
|
|
182
|
+
}
|
|
183
|
+
if (base === "time without time zone") {
|
|
184
|
+
return hasModifier ? `time without time zone${arraySuffix}` : originalDbType;
|
|
185
|
+
}
|
|
186
|
+
if (base === "time") {
|
|
187
|
+
return hasModifier ? `time${arraySuffix}` : originalDbType;
|
|
188
|
+
}
|
|
189
|
+
if (INTERVAL_BASE_RE.test(base)) {
|
|
190
|
+
return hasModifier ? `${base}${arraySuffix}` : originalDbType;
|
|
191
|
+
}
|
|
192
|
+
return originalDbType;
|
|
193
|
+
}
|
|
194
|
+
function dbTypesEqual(a, b) {
|
|
195
|
+
return canonicalizeDbType(a) === canonicalizeDbType(b);
|
|
196
|
+
}
|
|
197
|
+
function isPgBuiltInTypeName(type) {
|
|
198
|
+
const split = splitDbType(type);
|
|
199
|
+
const base = normalizeBase(split.base);
|
|
200
|
+
if (base.includes('"') || split.schemaQualified) return false;
|
|
201
|
+
const baseLower = base.toLowerCase();
|
|
202
|
+
return MULTIWORD_BASE_TYPES.has(baseLower) || INTERVAL_BASE_RE.test(base) || BUILTIN_BASE_TYPES.has(baseLower);
|
|
203
|
+
}
|
|
204
|
+
function quoteTypeIdentifier(rawIdentifier) {
|
|
205
|
+
if (SAFE_LOWERCASE_IDENTIFIER_RE.test(rawIdentifier)) return rawIdentifier;
|
|
206
|
+
return `"${rawIdentifier.replace(/"/g, '""')}"`;
|
|
207
|
+
}
|
|
208
|
+
function unquoteIdentifier(id) {
|
|
209
|
+
const t = id.trim();
|
|
210
|
+
if (t.length >= 2 && t.startsWith('"') && t.endsWith('"')) {
|
|
211
|
+
return t.slice(1, -1).replace(/""/g, '"');
|
|
212
|
+
}
|
|
213
|
+
return t;
|
|
214
|
+
}
|
|
215
|
+
function enumReferenceKind(originalDbType, typname) {
|
|
216
|
+
const split = splitDbType(originalDbType);
|
|
217
|
+
if (split.schemaQualified) return null;
|
|
218
|
+
if (unquoteIdentifier(normalizeBase(split.base)) !== typname) return null;
|
|
219
|
+
return split.isArray ? "array" : "scalar";
|
|
220
|
+
}
|
|
221
|
+
function validateDbType(type) {
|
|
222
|
+
if (typeof type !== "string") {
|
|
223
|
+
throw new Error(
|
|
224
|
+
`Unsafe database type name: expected a string, received ${typeof type}`
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
if (!isStructurallyValidDbType(type)) {
|
|
228
|
+
throw new Error(
|
|
229
|
+
`Unsafe database type name: "${type}". Must be a structurally valid PostgreSQL type name.`
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
return type;
|
|
233
|
+
}
|
|
234
|
+
function isStructurallyValidDbType(type) {
|
|
235
|
+
const trimmed = type.trim();
|
|
236
|
+
if (trimmed.length === 0 || trimmed !== type) return false;
|
|
237
|
+
if (/[;]|--|\/\*|\*\//.test(trimmed)) return false;
|
|
238
|
+
if (trimmed.endsWith("[][]")) return false;
|
|
239
|
+
if (hasForbiddenTypeKeyword(trimmed)) return false;
|
|
240
|
+
const split = splitDbType(trimmed);
|
|
241
|
+
const base = split.base;
|
|
242
|
+
const baseLower = base.toLowerCase();
|
|
243
|
+
if (split.modifier !== void 0 && !isSafeModifier(split.modifier, baseLower)) {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
if (MULTIWORD_BASE_TYPES.has(baseLower)) {
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
if (INTERVAL_BASE_RE.test(base)) {
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
return IDENTIFIER_RE.test(base) || split.schemaQualified;
|
|
253
|
+
}
|
|
254
|
+
function isSafeModifier(modifier, baseLower) {
|
|
255
|
+
const structurallySafe = modifier.length > 0 && !/[();]|--|\/\*|\*\//.test(modifier) && !MODIFIER_OPERATOR_RE.test(modifier) && MODIFIER_CONTENT_RE.test(modifier) && !hasForbiddenTypeKeyword(modifier);
|
|
256
|
+
if (!structurallySafe) return false;
|
|
257
|
+
if (PRECISION_SCALE_BUILTINS.has(baseLower)) {
|
|
258
|
+
return /^\d+(\s*,\s*-?\d+)?$/.test(modifier);
|
|
259
|
+
}
|
|
260
|
+
if (SINGLE_INT_MODIFIER_BUILTINS.has(baseLower) || INTERVAL_BASE_RE.test(baseLower)) {
|
|
261
|
+
return /^\d+$/.test(modifier.trim());
|
|
262
|
+
}
|
|
263
|
+
if (BUILTIN_BASE_TYPES.has(baseLower) || MULTIWORD_BASE_TYPES.has(baseLower)) {
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
function hasForbiddenTypeKeyword(type) {
|
|
269
|
+
const withoutQuotedIdentifiers = type.replace(QUOTED_IDENTIFIER_RE, '""');
|
|
270
|
+
return /\bnot\s+null\b|\b(default|references|check|primary|unique|constraint|select|insert|update|delete|drop|alter|create|truncate|grant|revoke|copy)\b/i.test(
|
|
271
|
+
withoutQuotedIdentifiers
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
var TEMPORAL_TZ_SUFFIXES, SAFE_LOWERCASE_IDENTIFIER_RE, MULTIWORD_BASE_TYPES, TYPE_ALIASES, BUILTIN_BASE_TYPES, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER, IDENTIFIER_RE, QUALIFIED_IDENTIFIER_RE, QUOTED_IDENTIFIER_RE, INTERVAL_FIELD, INTERVAL_BASE_RE, MODIFIER_CONTENT_RE, MODIFIER_OPERATOR_RE, SINGLE_INT_MODIFIER_BUILTINS, PRECISION_SCALE_BUILTINS;
|
|
275
|
+
var init_db_type = __esm({
|
|
276
|
+
"src/db-type.ts"() {
|
|
277
|
+
"use strict";
|
|
278
|
+
TEMPORAL_TZ_SUFFIXES = [" without time zone", " with time zone"];
|
|
279
|
+
SAFE_LOWERCASE_IDENTIFIER_RE = /^[a-z_][a-z0-9_]*$/;
|
|
280
|
+
MULTIWORD_BASE_TYPES = /* @__PURE__ */ new Set([
|
|
281
|
+
"timestamp with time zone",
|
|
282
|
+
"timestamp without time zone",
|
|
283
|
+
"time with time zone",
|
|
284
|
+
"time without time zone",
|
|
285
|
+
"double precision",
|
|
286
|
+
"character varying",
|
|
287
|
+
"bit varying"
|
|
288
|
+
]);
|
|
289
|
+
TYPE_ALIASES = /* @__PURE__ */ new Map([
|
|
290
|
+
["character varying", "varchar"],
|
|
291
|
+
["character", "char"],
|
|
292
|
+
["bpchar", "char"],
|
|
293
|
+
["bit varying", "varbit"],
|
|
294
|
+
["timestamp with time zone", "timestamptz"],
|
|
295
|
+
["timestamp without time zone", "timestamp"],
|
|
296
|
+
["time with time zone", "timetz"],
|
|
297
|
+
["time without time zone", "time"],
|
|
298
|
+
["int", "integer"],
|
|
299
|
+
["int4", "integer"],
|
|
300
|
+
["int8", "bigint"],
|
|
301
|
+
["int2", "smallint"],
|
|
302
|
+
["float", "double precision"],
|
|
303
|
+
["float8", "double precision"],
|
|
304
|
+
["float4", "real"],
|
|
305
|
+
["bool", "boolean"],
|
|
306
|
+
["decimal", "numeric"],
|
|
307
|
+
["serial", "integer"],
|
|
308
|
+
["serial4", "integer"],
|
|
309
|
+
["bigserial", "bigint"],
|
|
310
|
+
["serial8", "bigint"],
|
|
311
|
+
["smallserial", "smallint"],
|
|
312
|
+
["serial2", "smallint"]
|
|
313
|
+
]);
|
|
314
|
+
BUILTIN_BASE_TYPES = /* @__PURE__ */ new Set([
|
|
315
|
+
...TYPE_ALIASES.keys(),
|
|
316
|
+
...TYPE_ALIASES.values(),
|
|
317
|
+
"bigint",
|
|
318
|
+
"bit",
|
|
319
|
+
"boolean",
|
|
320
|
+
"box",
|
|
321
|
+
"bytea",
|
|
322
|
+
"char",
|
|
323
|
+
"cidr",
|
|
324
|
+
"circle",
|
|
325
|
+
"date",
|
|
326
|
+
"float",
|
|
327
|
+
"inet",
|
|
328
|
+
"integer",
|
|
329
|
+
"interval",
|
|
330
|
+
"json",
|
|
331
|
+
"jsonb",
|
|
332
|
+
"line",
|
|
333
|
+
"lseg",
|
|
334
|
+
"macaddr",
|
|
335
|
+
"macaddr8",
|
|
336
|
+
"money",
|
|
337
|
+
"numeric",
|
|
338
|
+
"path",
|
|
339
|
+
"pg_lsn",
|
|
340
|
+
"point",
|
|
341
|
+
"polygon",
|
|
342
|
+
"real",
|
|
343
|
+
"text",
|
|
344
|
+
"time",
|
|
345
|
+
"timestamp",
|
|
346
|
+
"timetz",
|
|
347
|
+
"timestamptz",
|
|
348
|
+
"tsquery",
|
|
349
|
+
"tsvector",
|
|
350
|
+
"txid_snapshot",
|
|
351
|
+
"uuid",
|
|
352
|
+
"varbit",
|
|
353
|
+
"varchar",
|
|
354
|
+
"xml",
|
|
355
|
+
"jsonpath",
|
|
356
|
+
"name",
|
|
357
|
+
"oid",
|
|
358
|
+
"regclass",
|
|
359
|
+
"regtype",
|
|
360
|
+
"regrole",
|
|
361
|
+
"regnamespace",
|
|
362
|
+
"regproc",
|
|
363
|
+
"regprocedure",
|
|
364
|
+
"xid",
|
|
365
|
+
"xid8",
|
|
366
|
+
"cid",
|
|
367
|
+
"tid",
|
|
368
|
+
"daterange",
|
|
369
|
+
"int4range",
|
|
370
|
+
"int8range",
|
|
371
|
+
"numrange",
|
|
372
|
+
"tsrange",
|
|
373
|
+
"tstzrange",
|
|
374
|
+
"datemultirange",
|
|
375
|
+
"int4multirange",
|
|
376
|
+
"int8multirange",
|
|
377
|
+
"nummultirange",
|
|
378
|
+
"tsmultirange",
|
|
379
|
+
"tstzmultirange"
|
|
380
|
+
]);
|
|
381
|
+
UNQUOTED_IDENTIFIER = "[A-Za-z_][A-Za-z0-9_]*";
|
|
382
|
+
QUOTED_IDENTIFIER = '"(?:[^"]|"")+"';
|
|
383
|
+
IDENTIFIER_RE = new RegExp(
|
|
384
|
+
`^(?:${UNQUOTED_IDENTIFIER}|${QUOTED_IDENTIFIER})$`
|
|
385
|
+
);
|
|
386
|
+
QUALIFIED_IDENTIFIER_RE = new RegExp(
|
|
387
|
+
`^(?:${UNQUOTED_IDENTIFIER}|${QUOTED_IDENTIFIER})\\.(?:${UNQUOTED_IDENTIFIER}|${QUOTED_IDENTIFIER})$`
|
|
388
|
+
);
|
|
389
|
+
QUOTED_IDENTIFIER_RE = new RegExp(QUOTED_IDENTIFIER, "g");
|
|
390
|
+
INTERVAL_FIELD = "(?:year|month|day|hour|minute|second)";
|
|
391
|
+
INTERVAL_BASE_RE = new RegExp(
|
|
392
|
+
`^interval(?: ${INTERVAL_FIELD}(?: to ${INTERVAL_FIELD})?)?$`,
|
|
393
|
+
"i"
|
|
394
|
+
);
|
|
395
|
+
MODIFIER_CONTENT_RE = /^[A-Za-z0-9_,.\- ]+$/;
|
|
396
|
+
MODIFIER_OPERATOR_RE = /[=<>+*/%|&!@#^~]/;
|
|
397
|
+
SINGLE_INT_MODIFIER_BUILTINS = /* @__PURE__ */ new Set([
|
|
398
|
+
"varchar",
|
|
399
|
+
"character varying",
|
|
400
|
+
"char",
|
|
401
|
+
"character",
|
|
402
|
+
"bpchar",
|
|
403
|
+
// float(p): PostgreSQL treats float(1..24) as real, float(25..53) as double
|
|
404
|
+
// precision — a single-integer mantissa precision.
|
|
405
|
+
"float",
|
|
406
|
+
"bit",
|
|
407
|
+
"bit varying",
|
|
408
|
+
"varbit",
|
|
409
|
+
"timestamp",
|
|
410
|
+
"timestamptz",
|
|
411
|
+
"timestamp with time zone",
|
|
412
|
+
"timestamp without time zone",
|
|
413
|
+
"time",
|
|
414
|
+
"timetz",
|
|
415
|
+
"time with time zone",
|
|
416
|
+
"time without time zone",
|
|
417
|
+
"interval"
|
|
418
|
+
]);
|
|
419
|
+
PRECISION_SCALE_BUILTINS = /* @__PURE__ */ new Set(["numeric", "decimal"]);
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
|
|
97
423
|
// src/validate.ts
|
|
98
424
|
function assertString(value, context) {
|
|
99
425
|
if (typeof value !== "string") {
|
|
@@ -494,17 +820,13 @@ function isDollarQuoteTagContinuation(ch) {
|
|
|
494
820
|
}
|
|
495
821
|
function validateDbTypeName(type) {
|
|
496
822
|
assertString(type, "Unsafe database type name");
|
|
497
|
-
|
|
498
|
-
throw new Error(
|
|
499
|
-
`Unsafe database type name: "${type}". Must match PostgreSQL type name rules.`
|
|
500
|
-
);
|
|
501
|
-
}
|
|
502
|
-
return type;
|
|
823
|
+
return validateDbType(type);
|
|
503
824
|
}
|
|
504
|
-
var SQL_RESERVED_KEYWORDS, InvalidIdentifierError, SAFE_DECIMAL_LITERAL, SAFE_STORAGE_BOOLEAN_LITERAL, SAFE_SIMPLE_IDENTIFIER_VALUE
|
|
825
|
+
var SQL_RESERVED_KEYWORDS, InvalidIdentifierError, SAFE_DECIMAL_LITERAL, SAFE_STORAGE_BOOLEAN_LITERAL, SAFE_SIMPLE_IDENTIFIER_VALUE;
|
|
505
826
|
var init_validate = __esm({
|
|
506
827
|
"src/validate.ts"() {
|
|
507
828
|
"use strict";
|
|
829
|
+
init_db_type();
|
|
508
830
|
SQL_RESERVED_KEYWORDS = /* @__PURE__ */ new Set([
|
|
509
831
|
"all",
|
|
510
832
|
"analyse",
|
|
@@ -623,7 +945,6 @@ var init_validate = __esm({
|
|
|
623
945
|
SAFE_DECIMAL_LITERAL = /^[+-]?(?:\d+(?:\.\d+)?|\.\d+)$/;
|
|
624
946
|
SAFE_STORAGE_BOOLEAN_LITERAL = /^(?:true|false|on|off)$/i;
|
|
625
947
|
SAFE_SIMPLE_IDENTIFIER_VALUE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
626
|
-
SAFE_TYPE_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_ ]*(\(\d+(,\s*\d+)?\))?(\[\])?$/;
|
|
627
948
|
}
|
|
628
949
|
});
|
|
629
950
|
|
|
@@ -2909,7 +3230,7 @@ var init_raw_expression_parser = __esm({
|
|
|
2909
3230
|
});
|
|
2910
3231
|
|
|
2911
3232
|
// src/compiler-utils.ts
|
|
2912
|
-
import { InvalidOperationError
|
|
3233
|
+
import { InvalidOperationError } from "@dbsp/core";
|
|
2913
3234
|
function inferPgArrayType(columnName, columnTypes, sampleValue) {
|
|
2914
3235
|
if (columnTypes?.[columnName]) {
|
|
2915
3236
|
const pgBase = mapToPgBaseType(columnTypes[columnName]);
|
|
@@ -2927,7 +3248,16 @@ function inferPgArrayType(columnName, columnTypes, sampleValue) {
|
|
|
2927
3248
|
return "text[]";
|
|
2928
3249
|
}
|
|
2929
3250
|
function mapToPgBaseType(pgType) {
|
|
2930
|
-
const
|
|
3251
|
+
const trimmedPgType = pgType.trim();
|
|
3252
|
+
try {
|
|
3253
|
+
validateDbType(trimmedPgType);
|
|
3254
|
+
} catch {
|
|
3255
|
+
throw new Error(
|
|
3256
|
+
`batchValues: invalid type name '${pgType}'. Must be a structurally valid PostgreSQL type name.`
|
|
3257
|
+
);
|
|
3258
|
+
}
|
|
3259
|
+
const elementType = stripArraySuffix(trimmedPgType);
|
|
3260
|
+
const normalized = elementType.toUpperCase().replace(/\(.*\)/, "").trim();
|
|
2931
3261
|
switch (normalized) {
|
|
2932
3262
|
// ColumnType aliases (lowercase ColumnType values from ModelIR)
|
|
2933
3263
|
case "STRING":
|
|
@@ -2957,9 +3287,10 @@ function mapToPgBaseType(pgType) {
|
|
|
2957
3287
|
case "DOUBLE PRECISION":
|
|
2958
3288
|
case "FLOAT8":
|
|
2959
3289
|
case "FLOAT":
|
|
3290
|
+
return "float8";
|
|
2960
3291
|
case "NUMERIC":
|
|
2961
3292
|
case "DECIMAL":
|
|
2962
|
-
return "
|
|
3293
|
+
return "numeric";
|
|
2963
3294
|
case "TEXT":
|
|
2964
3295
|
case "VARCHAR":
|
|
2965
3296
|
case "CHAR":
|
|
@@ -2979,11 +3310,8 @@ function mapToPgBaseType(pgType) {
|
|
|
2979
3310
|
return "timestamptz";
|
|
2980
3311
|
case "DATE":
|
|
2981
3312
|
return "date";
|
|
2982
|
-
default:
|
|
2983
|
-
|
|
2984
|
-
validateTypeName2(customType);
|
|
2985
|
-
return customType;
|
|
2986
|
-
}
|
|
3313
|
+
default:
|
|
3314
|
+
return elementType;
|
|
2987
3315
|
}
|
|
2988
3316
|
}
|
|
2989
3317
|
function stripArraySuffix(pgArrayType) {
|
|
@@ -3032,6 +3360,7 @@ function parseRawExpression(sqlFragment) {
|
|
|
3032
3360
|
var init_compiler_utils = __esm({
|
|
3033
3361
|
"src/compiler-utils.ts"() {
|
|
3034
3362
|
"use strict";
|
|
3363
|
+
init_db_type();
|
|
3035
3364
|
init_raw_expression_parser();
|
|
3036
3365
|
}
|
|
3037
3366
|
});
|
|
@@ -3048,7 +3377,6 @@ var init_param_intent = __esm({
|
|
|
3048
3377
|
});
|
|
3049
3378
|
|
|
3050
3379
|
// src/handlers/where/utils.ts
|
|
3051
|
-
import { validateTypeName as validateTypeName3 } from "@dbsp/core";
|
|
3052
3380
|
import { isFieldRef, isParamIntent as isParamIntent3 } from "@dbsp/types";
|
|
3053
3381
|
function buildColumnRef(column, ctx) {
|
|
3054
3382
|
if (column.includes(".")) {
|
|
@@ -3112,8 +3440,8 @@ function resolveColumnPgType(columnName, ctx) {
|
|
|
3112
3440
|
if (!column) return void 0;
|
|
3113
3441
|
if (column.originalDbType) {
|
|
3114
3442
|
const typeName = column.originalDbType.trim();
|
|
3115
|
-
|
|
3116
|
-
return typeName;
|
|
3443
|
+
validateDbType(typeName);
|
|
3444
|
+
return dbTypeCastTarget(typeName);
|
|
3117
3445
|
}
|
|
3118
3446
|
return void 0;
|
|
3119
3447
|
}
|
|
@@ -3121,6 +3449,7 @@ var init_utils = __esm({
|
|
|
3121
3449
|
"src/handlers/where/utils.ts"() {
|
|
3122
3450
|
"use strict";
|
|
3123
3451
|
init_ast_helpers();
|
|
3452
|
+
init_db_type();
|
|
3124
3453
|
init_param_intent();
|
|
3125
3454
|
init_param_ref();
|
|
3126
3455
|
init_types();
|
|
@@ -11753,16 +12082,37 @@ function generateRlsPhase(ctx) {
|
|
|
11753
12082
|
init_validate();
|
|
11754
12083
|
|
|
11755
12084
|
// src/ddl/type-mapping.ts
|
|
12085
|
+
init_db_type();
|
|
11756
12086
|
init_validate();
|
|
11757
12087
|
function mapColumnType(col) {
|
|
11758
12088
|
if (col.originalDbType) {
|
|
11759
|
-
|
|
12089
|
+
const originalDbType = validateDbTypeName(col.originalDbType);
|
|
12090
|
+
return isPgBuiltInTypeName(originalDbType) ? uppercaseOutsideQuotedIdentifiers(originalDbType) : originalDbType;
|
|
11760
12091
|
}
|
|
11761
12092
|
if (col.autoIncrement) {
|
|
11762
12093
|
return col.type === "bigint" ? "BIGSERIAL" : "SERIAL";
|
|
11763
12094
|
}
|
|
11764
12095
|
return mapBaseType(col.type);
|
|
11765
12096
|
}
|
|
12097
|
+
function uppercaseOutsideQuotedIdentifiers(type) {
|
|
12098
|
+
let result = "";
|
|
12099
|
+
let inQuotedIdentifier = false;
|
|
12100
|
+
for (let i = 0; i < type.length; i++) {
|
|
12101
|
+
const char = type[i];
|
|
12102
|
+
if (char === '"') {
|
|
12103
|
+
result += char;
|
|
12104
|
+
if (inQuotedIdentifier && type[i + 1] === '"') {
|
|
12105
|
+
result += type[i + 1];
|
|
12106
|
+
i++;
|
|
12107
|
+
continue;
|
|
12108
|
+
}
|
|
12109
|
+
inQuotedIdentifier = !inQuotedIdentifier;
|
|
12110
|
+
continue;
|
|
12111
|
+
}
|
|
12112
|
+
result += inQuotedIdentifier ? char : char.toUpperCase();
|
|
12113
|
+
}
|
|
12114
|
+
return result;
|
|
12115
|
+
}
|
|
11766
12116
|
function mapBaseType(type) {
|
|
11767
12117
|
switch (type) {
|
|
11768
12118
|
case "string":
|
|
@@ -12265,9 +12615,12 @@ function upDropEnum(change, schemaName) {
|
|
|
12265
12615
|
if (!enumDef) return void 0;
|
|
12266
12616
|
const enumName = schemaName ? `${quoteIdent2(schemaName, "alias")}.${quoteIdent2(enumDef.name, "alias")}` : quoteIdent2(enumDef.name, "alias");
|
|
12267
12617
|
const refs = change.meta?.referencingColumns;
|
|
12268
|
-
const alterStatements = refs && refs.length > 0 ? refs.map(
|
|
12269
|
-
|
|
12270
|
-
|
|
12618
|
+
const alterStatements = refs && refs.length > 0 ? refs.map((ref) => {
|
|
12619
|
+
const column = quoteIdent2(ref.column, "alias");
|
|
12620
|
+
const targetType = ref.isArray ? "text[]" : "text";
|
|
12621
|
+
const using = ref.isArray ? ` USING ${column}::text[]` : "";
|
|
12622
|
+
return `ALTER TABLE ${qualifyTable(ref.table, schemaName)} ALTER COLUMN ${column} TYPE ${targetType}${using};`;
|
|
12623
|
+
}) : [];
|
|
12271
12624
|
return [...alterStatements, `DROP TYPE IF EXISTS ${enumName} CASCADE;`].join(
|
|
12272
12625
|
"\n"
|
|
12273
12626
|
);
|
|
@@ -13351,6 +13704,7 @@ async function removeMigrationRecord(pool, name) {
|
|
|
13351
13704
|
}
|
|
13352
13705
|
|
|
13353
13706
|
// src/ddl/schema-diff.ts
|
|
13707
|
+
init_db_type();
|
|
13354
13708
|
init_naming_plugin();
|
|
13355
13709
|
function compareSchemata(schema, db, options) {
|
|
13356
13710
|
const changes = [];
|
|
@@ -13538,9 +13892,7 @@ function compareColumns(schema, db, changes) {
|
|
|
13538
13892
|
}
|
|
13539
13893
|
}
|
|
13540
13894
|
function compareColumnDetails(tableName, schema, db, changes) {
|
|
13541
|
-
|
|
13542
|
-
const dbDbType = db.originalDbType?.toLowerCase();
|
|
13543
|
-
if (schemaDbType && dbDbType && schemaDbType !== dbDbType) {
|
|
13895
|
+
if (schema.originalDbType && db.originalDbType && !dbTypesEqual(schema.originalDbType, db.originalDbType)) {
|
|
13544
13896
|
changes.push({
|
|
13545
13897
|
kind: "alter_column_type",
|
|
13546
13898
|
table: tableName,
|
|
@@ -14011,8 +14363,13 @@ function compareEnums(schema, db, changes) {
|
|
|
14011
14363
|
const referencingColumns = [];
|
|
14012
14364
|
for (const [tableName, tableIR] of db.tables) {
|
|
14013
14365
|
for (const col of tableIR.columns) {
|
|
14014
|
-
|
|
14015
|
-
|
|
14366
|
+
const kind = col.originalDbType !== void 0 ? enumReferenceKind(col.originalDbType, name) : null;
|
|
14367
|
+
if (kind !== null) {
|
|
14368
|
+
referencingColumns.push({
|
|
14369
|
+
table: tableName,
|
|
14370
|
+
column: col.name,
|
|
14371
|
+
...kind === "array" ? { isArray: true } : {}
|
|
14372
|
+
});
|
|
14016
14373
|
}
|
|
14017
14374
|
}
|
|
14018
14375
|
}
|
|
@@ -14402,6 +14759,7 @@ function vectorDims(column) {
|
|
|
14402
14759
|
|
|
14403
14760
|
// src/introspection.ts
|
|
14404
14761
|
init_assert_field();
|
|
14762
|
+
init_db_type();
|
|
14405
14763
|
import { ModelIRImpl } from "@dbsp/core";
|
|
14406
14764
|
import { buildRelationKeyFields } from "@dbsp/types";
|
|
14407
14765
|
function parseExpressionsList(raw) {
|
|
@@ -14438,7 +14796,8 @@ async function queryAllCatalogs(pool, schema) {
|
|
|
14438
14796
|
extensionsResult,
|
|
14439
14797
|
sequencesResult,
|
|
14440
14798
|
rlsResult,
|
|
14441
|
-
policiesResult
|
|
14799
|
+
policiesResult,
|
|
14800
|
+
formattedColumnTypesResult
|
|
14442
14801
|
] = await Promise.all([
|
|
14443
14802
|
// 1. Columns (including identity and collation)
|
|
14444
14803
|
pool.query(
|
|
@@ -14672,6 +15031,29 @@ async function queryAllCatalogs(pool, schema) {
|
|
|
14672
15031
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
14673
15032
|
WHERE n.nspname = $1`,
|
|
14674
15033
|
[schema]
|
|
15034
|
+
),
|
|
15035
|
+
// 14. Faithful SQL-facing column types via format_type, for two cases:
|
|
15036
|
+
// (a) typmod-bearing columns (atttypmod <> -1) — varchar(120), numeric(10,2),
|
|
15037
|
+
// timestamptz(3), bit(8), vector(768) — to preserve modifier fidelity (#261);
|
|
15038
|
+
// (b) array columns (typcategory 'A') — so integer[] is stored as `integer[]`
|
|
15039
|
+
// rather than the internal `_int4` udt_name.
|
|
15040
|
+
// Other columns (plain base types, enums/composites/domains) fall back to
|
|
15041
|
+
// quoteTypeIdentifier(udt_name) in buildTableIR, which keeps a bare typname for
|
|
15042
|
+
// lowercase types and quotes a case-sensitive custom type (`"Money"`).
|
|
15043
|
+
pool.query(
|
|
15044
|
+
`SELECT c.relname AS table_name,
|
|
15045
|
+
a.attname AS column_name,
|
|
15046
|
+
format_type(a.atttypid, a.atttypmod) AS db_type
|
|
15047
|
+
FROM pg_catalog.pg_attribute a
|
|
15048
|
+
JOIN pg_catalog.pg_class c ON c.oid = a.attrelid
|
|
15049
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
15050
|
+
JOIN pg_catalog.pg_type t ON t.oid = a.atttypid
|
|
15051
|
+
WHERE n.nspname = $1
|
|
15052
|
+
AND c.relkind IN ('r','p','v','m','f')
|
|
15053
|
+
AND a.attnum > 0
|
|
15054
|
+
AND NOT a.attisdropped
|
|
15055
|
+
AND (a.atttypmod <> -1 OR t.typcategory = 'A')`,
|
|
15056
|
+
[schema]
|
|
14675
15057
|
)
|
|
14676
15058
|
]);
|
|
14677
15059
|
return {
|
|
@@ -14687,7 +15069,8 @@ async function queryAllCatalogs(pool, schema) {
|
|
|
14687
15069
|
extensions: extensionsResult.rows,
|
|
14688
15070
|
sequences: sequencesResult.rows,
|
|
14689
15071
|
rls: rlsResult.rows,
|
|
14690
|
-
policies: policiesResult.rows
|
|
15072
|
+
policies: policiesResult.rows,
|
|
15073
|
+
formattedColumnTypes: formattedColumnTypesResult.rows
|
|
14691
15074
|
};
|
|
14692
15075
|
}
|
|
14693
15076
|
function buildPartitionMap(rows) {
|
|
@@ -14879,6 +15262,16 @@ function buildRLSMaps(rlsRows, policiesRows) {
|
|
|
14879
15262
|
}
|
|
14880
15263
|
return { tableRlsEnabled, tablePolicies };
|
|
14881
15264
|
}
|
|
15265
|
+
function columnTypeMapKey(tableName, columnName) {
|
|
15266
|
+
return `${tableName}\0${columnName}`;
|
|
15267
|
+
}
|
|
15268
|
+
function buildFormattedColumnTypeMap(rows) {
|
|
15269
|
+
const result = /* @__PURE__ */ new Map();
|
|
15270
|
+
for (const row of rows) {
|
|
15271
|
+
result.set(columnTypeMapKey(row.table_name, row.column_name), row.db_type);
|
|
15272
|
+
}
|
|
15273
|
+
return result;
|
|
15274
|
+
}
|
|
14882
15275
|
function buildTableIR(tableName, ctx) {
|
|
14883
15276
|
const rawCols = ctx.tableColumns.get(tableName) ?? [];
|
|
14884
15277
|
const pkCols = ctx.tablePKs.get(tableName);
|
|
@@ -14896,7 +15289,13 @@ function buildTableIR(tableName, ctx) {
|
|
|
14896
15289
|
// it verbatim (e.g. CURRENT_TIMESTAMP, nextval('seq'::regclass)) instead
|
|
14897
15290
|
// of quoting it as a string literal.
|
|
14898
15291
|
...col.column_default != null ? { default: { sql: col.column_default } } : {},
|
|
14899
|
-
|
|
15292
|
+
// format_type output (typmod-bearing + array columns) is already
|
|
15293
|
+
// SQL-facing; the udt_name fallback is a bare catalog typname, so
|
|
15294
|
+
// quote it when case-sensitive (`"Money"`) — a lowercase typname
|
|
15295
|
+
// stays bare, preserving the common enum/UDT identity.
|
|
15296
|
+
originalDbType: ctx.formattedColumnTypes.get(
|
|
15297
|
+
columnTypeMapKey(tableName, col.column_name)
|
|
15298
|
+
) ?? quoteTypeIdentifier(col.udt_name),
|
|
14900
15299
|
...uniqueConstraintName !== void 0 ? { unique: true, uniqueConstraintName } : {},
|
|
14901
15300
|
...collation ? { collation } : {},
|
|
14902
15301
|
...identity ? { identity } : {},
|
|
@@ -14966,6 +15365,9 @@ async function introspect(pool, options) {
|
|
|
14966
15365
|
const tableIndexes = buildIndexMap(raw.indexes);
|
|
14967
15366
|
const uniqueColumns = buildUniqueColumnMap(raw.uniqueColumns);
|
|
14968
15367
|
const tableColumns = buildColumnMap(raw.columns);
|
|
15368
|
+
const formattedColumnTypes = buildFormattedColumnTypeMap(
|
|
15369
|
+
raw.formattedColumnTypes
|
|
15370
|
+
);
|
|
14969
15371
|
const tablePKs = buildPKMap(raw.pks);
|
|
14970
15372
|
const fksByConstraint = buildFKMap(raw.fks);
|
|
14971
15373
|
const enumMap = buildEnumMap(raw.enums);
|
|
@@ -14980,6 +15382,7 @@ async function introspect(pool, options) {
|
|
|
14980
15382
|
for (const tableName of tableNames) {
|
|
14981
15383
|
const table = buildTableIR(tableName, {
|
|
14982
15384
|
tableColumns,
|
|
15385
|
+
formattedColumnTypes,
|
|
14983
15386
|
tablePKs,
|
|
14984
15387
|
fksByConstraint,
|
|
14985
15388
|
tableIndexes,
|
|
@@ -16027,11 +16430,7 @@ init_naming_plugin();
|
|
|
16027
16430
|
init_param_ref();
|
|
16028
16431
|
|
|
16029
16432
|
// src/pgsql-adapter.ts
|
|
16030
|
-
import {
|
|
16031
|
-
POSTGRESQL_CAPABILITIES as POSTGRESQL_CAPABILITIES2,
|
|
16032
|
-
plan as planFn2,
|
|
16033
|
-
validateTypeName as validateTypeName4
|
|
16034
|
-
} from "@dbsp/core";
|
|
16433
|
+
import { POSTGRESQL_CAPABILITIES as POSTGRESQL_CAPABILITIES2, plan as planFn2 } from "@dbsp/core";
|
|
16035
16434
|
import { getNqlBindingRefName as getNqlBindingRefName2, isNqlBindingRef as isNqlBindingRef2 } from "@dbsp/types/internal";
|
|
16036
16435
|
|
|
16037
16436
|
// src/adapter-compiler-includes.ts
|
|
@@ -16251,6 +16650,7 @@ init_compile_where();
|
|
|
16251
16650
|
import { countDistinctRelationPathsByName } from "@dbsp/core";
|
|
16252
16651
|
import { toColumnList as toColumnList10 } from "@dbsp/types";
|
|
16253
16652
|
init_compiler_utils();
|
|
16653
|
+
init_db_type();
|
|
16254
16654
|
init_types();
|
|
16255
16655
|
init_intent_to_decisions();
|
|
16256
16656
|
init_param_ref();
|
|
@@ -17153,16 +17553,6 @@ function buildIncludeTree(allDecisions) {
|
|
|
17153
17553
|
}
|
|
17154
17554
|
|
|
17155
17555
|
// src/adapter-compiler-select.ts
|
|
17156
|
-
var ADAPTER_MULTIWORD_BASE_TYPES = [
|
|
17157
|
-
"timestamp with time zone",
|
|
17158
|
-
"timestamp without time zone",
|
|
17159
|
-
"time with time zone",
|
|
17160
|
-
"time without time zone",
|
|
17161
|
-
"double precision",
|
|
17162
|
-
"character varying",
|
|
17163
|
-
"bit varying"
|
|
17164
|
-
];
|
|
17165
|
-
var ADAPTER_IDENT_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
17166
17556
|
function assertSafeTypeName(typeName, colIndex) {
|
|
17167
17557
|
const raw = typeName.trim();
|
|
17168
17558
|
if (raw.length === 0) {
|
|
@@ -17170,42 +17560,14 @@ function assertSafeTypeName(typeName, colIndex) {
|
|
|
17170
17560
|
`BatchValues compile error: type name at column index ${colIndex} must not be empty.`
|
|
17171
17561
|
);
|
|
17172
17562
|
}
|
|
17173
|
-
|
|
17174
|
-
|
|
17175
|
-
|
|
17176
|
-
|
|
17177
|
-
throw new Error(
|
|
17178
|
-
`BatchValues compile error: unsafe type name '${typeName}' at column index ${colIndex}. At most one array suffix "[]" is allowed as a raw type-name input.`
|
|
17179
|
-
);
|
|
17180
|
-
}
|
|
17181
|
-
}
|
|
17182
|
-
const modifierMatch = rest.match(/\(([^)]*)\)$/);
|
|
17183
|
-
if (modifierMatch) {
|
|
17184
|
-
const inner = modifierMatch[1] ?? "";
|
|
17185
|
-
if (!/^\d+(?:,\d+)?$/.test(inner)) {
|
|
17186
|
-
throw new Error(
|
|
17187
|
-
`BatchValues compile error: unsafe type name '${typeName}' at column index ${colIndex}. Type modifier must be "(N)" or "(N,M)" with digits only; got "(${inner})".`
|
|
17188
|
-
);
|
|
17189
|
-
}
|
|
17190
|
-
rest = rest.slice(0, rest.length - modifierMatch[0].length).trimEnd();
|
|
17191
|
-
}
|
|
17192
|
-
const baseLower = rest.toLowerCase();
|
|
17193
|
-
if (ADAPTER_MULTIWORD_BASE_TYPES.includes(baseLower)) {
|
|
17194
|
-
return;
|
|
17195
|
-
}
|
|
17196
|
-
const parts = rest.split(".");
|
|
17197
|
-
if (parts.length > 2) {
|
|
17563
|
+
try {
|
|
17564
|
+
validateDbType(raw);
|
|
17565
|
+
} catch (error) {
|
|
17566
|
+
const reason = error instanceof Error ? ` ${error.message}` : "";
|
|
17198
17567
|
throw new Error(
|
|
17199
|
-
`BatchValues compile error: unsafe type name '${typeName}' at column index ${colIndex}
|
|
17568
|
+
`BatchValues compile error: unsafe type name '${typeName}' at column index ${colIndex}.${reason}`
|
|
17200
17569
|
);
|
|
17201
17570
|
}
|
|
17202
|
-
for (const part of parts) {
|
|
17203
|
-
if (!ADAPTER_IDENT_RE.test(part)) {
|
|
17204
|
-
throw new Error(
|
|
17205
|
-
`BatchValues compile error: unsafe type name '${typeName}' at column index ${colIndex}. Base type "${part}" is not a valid SQL identifier and is not in the multi-word type allowlist.`
|
|
17206
|
-
);
|
|
17207
|
-
}
|
|
17208
|
-
}
|
|
17209
17571
|
}
|
|
17210
17572
|
function buildBatchValuesRangeFn(bv, startParamIndex, aliasOverride) {
|
|
17211
17573
|
const params = [];
|
|
@@ -17668,6 +18030,7 @@ function compileWithIncludes(plan, options, deps) {
|
|
|
17668
18030
|
init_binding_registry();
|
|
17669
18031
|
init_compile_where();
|
|
17670
18032
|
init_compiler_utils();
|
|
18033
|
+
init_db_type();
|
|
17671
18034
|
init_handlers();
|
|
17672
18035
|
init_cte_compiler();
|
|
17673
18036
|
function whereIntentAsDecision(where) {
|
|
@@ -17780,7 +18143,14 @@ function getColumnTypes(tableName, columns, deps) {
|
|
|
17780
18143
|
const columnIR = table.columns.find((c) => c.name === col);
|
|
17781
18144
|
if (columnIR) {
|
|
17782
18145
|
result ??= {};
|
|
17783
|
-
|
|
18146
|
+
const authored = columnIR.originalDbType?.trim();
|
|
18147
|
+
const castTarget = authored !== void 0 && authored !== "" ? dbTypeCastTarget(validateDbType(authored)) : columnIR.type;
|
|
18148
|
+
if (castTarget.trim().endsWith("[]")) {
|
|
18149
|
+
throw new Error(
|
|
18150
|
+
`Batch mutation of array-typed column '${col}' (${castTarget}) is not supported: unnest flattens multi-dimensional arrays. Use single-row mutations for array columns.`
|
|
18151
|
+
);
|
|
18152
|
+
}
|
|
18153
|
+
result[col] = castTarget;
|
|
17784
18154
|
}
|
|
17785
18155
|
}
|
|
17786
18156
|
return result;
|
|
@@ -18567,6 +18937,7 @@ function buildRecursiveAnchorWhere(where, tableAlias, deps, state) {
|
|
|
18567
18937
|
init_assert_field();
|
|
18568
18938
|
init_ast_helpers();
|
|
18569
18939
|
init_binding_registry();
|
|
18940
|
+
init_db_type();
|
|
18570
18941
|
|
|
18571
18942
|
// src/ddl/index-operations.ts
|
|
18572
18943
|
init_validate();
|
|
@@ -19020,7 +19391,8 @@ function resolveRuntimeBindingColumnType(bindingName, sourceTable, columnName) {
|
|
|
19020
19391
|
`NQL runtime binding '${bindingName}' cannot resolve projected column '${columnName}' on source table '${sourceTable.name}'.`
|
|
19021
19392
|
);
|
|
19022
19393
|
}
|
|
19023
|
-
const
|
|
19394
|
+
const originalDbType = column.originalDbType?.trim();
|
|
19395
|
+
const dbType = originalDbType || mapRuntimeBindingColumnType(column.type);
|
|
19024
19396
|
if (dbType === void 0 || dbType.trim() === "") {
|
|
19025
19397
|
throw new Error(
|
|
19026
19398
|
`NQL runtime binding '${bindingName}' cannot resolve a PostgreSQL type for projected column '${columnName}' on source table '${sourceTable.name}'.`
|
|
@@ -19028,14 +19400,14 @@ function resolveRuntimeBindingColumnType(bindingName, sourceTable, columnName) {
|
|
|
19028
19400
|
}
|
|
19029
19401
|
const typeName = dbType.trim();
|
|
19030
19402
|
try {
|
|
19031
|
-
|
|
19403
|
+
validateDbType(typeName);
|
|
19032
19404
|
} catch (error) {
|
|
19033
19405
|
const reason = error instanceof Error ? error.message : String(error);
|
|
19034
19406
|
throw new Error(
|
|
19035
19407
|
`NQL runtime binding '${bindingName}' cannot use PostgreSQL cast type for projected column '${columnName}': ${reason}`
|
|
19036
19408
|
);
|
|
19037
19409
|
}
|
|
19038
|
-
return typeName;
|
|
19410
|
+
return originalDbType !== void 0 ? dbTypeCastTarget(typeName) : typeName;
|
|
19039
19411
|
}
|
|
19040
19412
|
function resolveRuntimeBindingColumnTypes(name, binding, model, sourceTableName) {
|
|
19041
19413
|
if (model === void 0) {
|
|
@@ -19069,7 +19441,8 @@ function resolvePgTypeForColumnTypeInfo(bindingName, column, info) {
|
|
|
19069
19441
|
`NQL runtime binding '${bindingName}' cannot resolve a PostgreSQL type for projected column '${column}': unsupported aggregate kind '${String(info.fn)}'.`
|
|
19070
19442
|
);
|
|
19071
19443
|
}
|
|
19072
|
-
const
|
|
19444
|
+
const originalDbType = info.kind === "aggregate" ? void 0 : info.originalDbType?.trim();
|
|
19445
|
+
const rawType = info.kind === "aggregate" ? "bigint" : originalDbType || mapRuntimeBindingColumnType(info.type);
|
|
19073
19446
|
if (rawType === void 0 || rawType.trim() === "") {
|
|
19074
19447
|
throw new Error(
|
|
19075
19448
|
`NQL runtime binding '${bindingName}' cannot resolve a PostgreSQL type for projected column '${column}'.`
|
|
@@ -19077,14 +19450,14 @@ function resolvePgTypeForColumnTypeInfo(bindingName, column, info) {
|
|
|
19077
19450
|
}
|
|
19078
19451
|
const typeName = rawType.trim();
|
|
19079
19452
|
try {
|
|
19080
|
-
|
|
19453
|
+
validateDbType(typeName);
|
|
19081
19454
|
} catch (error) {
|
|
19082
19455
|
const reason = error instanceof Error ? error.message : String(error);
|
|
19083
19456
|
throw new Error(
|
|
19084
19457
|
`NQL runtime binding '${bindingName}' cannot use PostgreSQL cast type for projected column '${column}': ${reason}`
|
|
19085
19458
|
);
|
|
19086
19459
|
}
|
|
19087
|
-
return typeName;
|
|
19460
|
+
return originalDbType !== void 0 ? dbTypeCastTarget(typeName) : typeName;
|
|
19088
19461
|
}
|
|
19089
19462
|
function resolveRuntimeBindingCteColumnTypes(name, binding) {
|
|
19090
19463
|
const columnTypes = binding.columnTypes;
|