@vibeorm/sql 5.0.1 → 5.2.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.
- package/dist/ast.d.ts +59 -5
- package/dist/date-truncation.d.ts +27 -0
- package/dist/dialect.d.ts +10 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +300 -208
- package/dist/index.js.map +9 -8
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2402,6 +2402,12 @@ var sqliteDialect = {
|
|
|
2402
2402
|
quoteStringLiteral({ value }) {
|
|
2403
2403
|
return `'${value.replaceAll("'", "''")}'`;
|
|
2404
2404
|
},
|
|
2405
|
+
renderEnumOrdinal({ column }) {
|
|
2406
|
+
return column;
|
|
2407
|
+
},
|
|
2408
|
+
renderEnumMinMax({ fn, column }) {
|
|
2409
|
+
return `${fn === "min" ? "MIN" : "MAX"}(${column})`;
|
|
2410
|
+
},
|
|
2405
2411
|
placeholder() {
|
|
2406
2412
|
return "?";
|
|
2407
2413
|
},
|
|
@@ -3075,6 +3081,12 @@ var postgresDialect = {
|
|
|
3075
3081
|
quoteStringLiteral({ value }) {
|
|
3076
3082
|
return `'${value.replaceAll("'", "''")}'`;
|
|
3077
3083
|
},
|
|
3084
|
+
renderEnumOrdinal({ column }) {
|
|
3085
|
+
return column;
|
|
3086
|
+
},
|
|
3087
|
+
renderEnumMinMax({ fn, column }) {
|
|
3088
|
+
return `${fn === "min" ? "MIN" : "MAX"}(${column})`;
|
|
3089
|
+
},
|
|
3078
3090
|
placeholder({ index }) {
|
|
3079
3091
|
return `$${index}`;
|
|
3080
3092
|
},
|
|
@@ -3148,6 +3160,15 @@ var mysqlDialect = {
|
|
|
3148
3160
|
quoteStringLiteral({ value }) {
|
|
3149
3161
|
return `'${value.replaceAll("\\", "\\\\").replaceAll("'", "''")}'`;
|
|
3150
3162
|
},
|
|
3163
|
+
renderEnumOrdinal({ column }) {
|
|
3164
|
+
return `${column} + 0`;
|
|
3165
|
+
},
|
|
3166
|
+
renderEnumMinMax({ fn, column, result }) {
|
|
3167
|
+
const aggregate = fn === "min" ? "MIN" : "MAX";
|
|
3168
|
+
if (result === "ordinal")
|
|
3169
|
+
return `${aggregate}(${column} + 0)`;
|
|
3170
|
+
return `SUBSTRING(${aggregate}(CONCAT(LPAD(${column} + 0, 5, '0'), ${column})), 6)`;
|
|
3171
|
+
},
|
|
3151
3172
|
placeholder() {
|
|
3152
3173
|
return "?";
|
|
3153
3174
|
},
|
|
@@ -3281,17 +3302,53 @@ function renderLocalDateCheck({ dialect, table, column }) {
|
|
|
3281
3302
|
expression: `${quoted} IS date(${quoted}) AND (${quoted} IS NULL OR ${quoted} >= ${dialect.quoteStringLiteral({ value: "0001-01-01" })})`
|
|
3282
3303
|
};
|
|
3283
3304
|
}
|
|
3305
|
+
// packages/sql/src/date-truncation.ts
|
|
3306
|
+
import { DATE_TRUNCATION_UNITS, VibeError as VibeError16, internalError as internalError2, unsupportedCapability as unsupportedCapability17 } from "@vibeorm/schema";
|
|
3307
|
+
var TIME_ZONE_NAME = /^[A-Za-z][A-Za-z0-9_+\-/]{0,63}$/;
|
|
3308
|
+
function isTimeZoneName(params) {
|
|
3309
|
+
return typeof params.value === "string" && TIME_ZONE_NAME.test(params.value);
|
|
3310
|
+
}
|
|
3311
|
+
function renderDateTruncation(params) {
|
|
3312
|
+
const { dialect, reference, truncation } = params;
|
|
3313
|
+
if (!dialect.capabilities.dateTruncation) {
|
|
3314
|
+
throw unsupportedCapability17({
|
|
3315
|
+
dialect: dialect.name,
|
|
3316
|
+
feature: "a truncated groupBy key ({ field, truncate, timeZone })",
|
|
3317
|
+
hint: "only PostgreSQL and PGlite truncate a timestamp in a named time zone \u2014 group by the plain field and bucket the rows in code instead"
|
|
3318
|
+
});
|
|
3319
|
+
}
|
|
3320
|
+
if (!DATE_TRUNCATION_UNITS.includes(truncation.unit)) {
|
|
3321
|
+
throw internalError2({ message: `unknown date truncation unit ${JSON.stringify(truncation.unit)}` });
|
|
3322
|
+
}
|
|
3323
|
+
if (!isTimeZoneName({ value: truncation.timeZone })) {
|
|
3324
|
+
throw new VibeError16({
|
|
3325
|
+
code: "VIBE_VALIDATION",
|
|
3326
|
+
message: `time zone ${JSON.stringify(truncation.timeZone)} is not a time-zone name \u2014 use an IANA name such as "Europe/Oslo" or "UTC"`,
|
|
3327
|
+
meta: { timeZone: truncation.timeZone }
|
|
3328
|
+
});
|
|
3329
|
+
}
|
|
3330
|
+
const unit = dialect.quoteStringLiteral({ value: truncation.unit });
|
|
3331
|
+
const zone = dialect.quoteStringLiteral({ value: truncation.timeZone });
|
|
3332
|
+
switch (truncation.storage) {
|
|
3333
|
+
case "timestamptz":
|
|
3334
|
+
return `date_trunc(${unit}, ${reference}, ${zone})`;
|
|
3335
|
+
case "timestamp":
|
|
3336
|
+
return `(date_trunc(${unit}, ${reference} AT TIME ZONE 'UTC', ${zone}) AT TIME ZONE 'UTC')`;
|
|
3337
|
+
default:
|
|
3338
|
+
throw internalError2({ message: `unknown date truncation storage ${JSON.stringify(truncation.storage)}` });
|
|
3339
|
+
}
|
|
3340
|
+
}
|
|
3284
3341
|
// packages/sql/src/generated-columns.ts
|
|
3285
|
-
import { VibeError as
|
|
3342
|
+
import { VibeError as VibeError17, unsupportedCapability as unsupportedCapability19 } from "@vibeorm/schema";
|
|
3286
3343
|
|
|
3287
3344
|
// packages/sql/src/dialects/postgres-generated-columns.ts
|
|
3288
|
-
import { unsupportedCapability as
|
|
3345
|
+
import { unsupportedCapability as unsupportedCapability18 } from "@vibeorm/schema";
|
|
3289
3346
|
function renderPostgresGeneratedColumnClause({ generated }) {
|
|
3290
3347
|
return `GENERATED ALWAYS AS (${generated.expression}) STORED`;
|
|
3291
3348
|
}
|
|
3292
3349
|
function renderPostgresGeneratedColumnProbe({ dialect, probe }) {
|
|
3293
3350
|
if (dialect.name !== "postgres")
|
|
3294
|
-
throw
|
|
3351
|
+
throw unsupportedCapability18({ dialect: dialect.name, feature: "rollbackGeneratedColumnProbe" });
|
|
3295
3352
|
const q = ({ name }) => dialect.quoteIdent({ name });
|
|
3296
3353
|
let text;
|
|
3297
3354
|
switch (probe.operation) {
|
|
@@ -3312,20 +3369,20 @@ function renderPostgresGeneratedColumnProbe({ dialect, probe }) {
|
|
|
3312
3369
|
}
|
|
3313
3370
|
function renderPostgresDropGeneratedExpression({ dialect, table, column }) {
|
|
3314
3371
|
if (dialect.name !== "postgres")
|
|
3315
|
-
throw
|
|
3372
|
+
throw unsupportedCapability18({ dialect: dialect.name, feature: "dropGeneratedExpression" });
|
|
3316
3373
|
return { text: `ALTER TABLE ${dialect.quoteIdent({ name: table.namespace })}.${dialect.quoteIdent({ name: table.name })} ALTER COLUMN ${dialect.quoteIdent({ name: column })} DROP EXPRESSION`, values: [], returning: "none" };
|
|
3317
3374
|
}
|
|
3318
3375
|
|
|
3319
3376
|
// packages/sql/src/generated-columns.ts
|
|
3320
3377
|
function renderGeneratedColumnClause({ dialect, generated }) {
|
|
3321
3378
|
if (!("generatedColumns" in dialect.capabilities) || dialect.capabilities.generatedColumns !== true) {
|
|
3322
|
-
throw
|
|
3379
|
+
throw unsupportedCapability19({ dialect: dialect.name, feature: "generatedColumns" });
|
|
3323
3380
|
}
|
|
3324
3381
|
if (generated.storage !== "stored") {
|
|
3325
|
-
throw
|
|
3382
|
+
throw unsupportedCapability19({ dialect: dialect.name, feature: "virtualGeneratedColumns" });
|
|
3326
3383
|
}
|
|
3327
3384
|
if (typeof generated.expression !== "string" || generated.expression.trim().length === 0 || generated.expression.includes("\x00")) {
|
|
3328
|
-
throw new
|
|
3385
|
+
throw new VibeError17({ code: "VIBE_SCHEMA_INVALID", message: "A generated column requires non-empty, NUL-free SQL", meta: { reason: "generated-expression-invalid" } });
|
|
3329
3386
|
}
|
|
3330
3387
|
switch (dialect.name) {
|
|
3331
3388
|
case "postgres":
|
|
@@ -3337,10 +3394,10 @@ function renderGeneratedColumnClause({ dialect, generated }) {
|
|
|
3337
3394
|
}
|
|
3338
3395
|
}
|
|
3339
3396
|
// packages/sql/src/row-rules.ts
|
|
3340
|
-
import { VibeError as
|
|
3397
|
+
import { VibeError as VibeError21, internalError as internalError3, normalizeRowRules, rowRuleGateField, rowRuleIdentities, rowRuleProtectedFields, rowRuleShapeIssue, rowRuleTriggerName, unsupportedCapability as unsupportedCapability23 } from "@vibeorm/schema";
|
|
3341
3398
|
|
|
3342
3399
|
// packages/sql/src/dialects/postgres-row-rules.ts
|
|
3343
|
-
import { VibeError as
|
|
3400
|
+
import { VibeError as VibeError18, unsupportedCapability as unsupportedCapability20 } from "@vibeorm/schema";
|
|
3344
3401
|
function comparison({ dialect, field }) {
|
|
3345
3402
|
const column = dialect.quoteIdent({ name: field.dbName ?? field.name });
|
|
3346
3403
|
const cast = field.type === "Json" ? `::pg_catalog.jsonb${field.isList ? "[]" : ""}` : "";
|
|
@@ -3348,7 +3405,7 @@ function comparison({ dialect, field }) {
|
|
|
3348
3405
|
}
|
|
3349
3406
|
function renderPostgresRowRule({ dialect, context }) {
|
|
3350
3407
|
if (dialect.name !== "postgres")
|
|
3351
|
-
throw
|
|
3408
|
+
throw unsupportedCapability20({ dialect: dialect.name, feature: "postgresRowRules" });
|
|
3352
3409
|
const { rule, table, functionIdentity, triggerIdentity, protectedFields, gateField } = context;
|
|
3353
3410
|
const qualify = ({ name }) => `${dialect.quoteIdent({ name: name.namespace })}.${dialect.quoteIdent({ name: name.name })}`;
|
|
3354
3411
|
const functionName = qualify({ name: functionIdentity.name });
|
|
@@ -3365,7 +3422,7 @@ END;`;
|
|
|
3365
3422
|
} else {
|
|
3366
3423
|
const terms = protectedFields.map((field) => comparison({ dialect, field }));
|
|
3367
3424
|
if (terms.length === 0) {
|
|
3368
|
-
throw new
|
|
3425
|
+
throw new VibeError18({ code: "VIBE_SCHEMA_INVALID", message: `Row rule ${rule.name} has no protected fields`, meta: { model: context.model, rule: rule.name } });
|
|
3369
3426
|
}
|
|
3370
3427
|
const condition = gateField === undefined ? terms.join(`
|
|
3371
3428
|
OR `) : `OLD.${dialect.quoteIdent({ name: gateField.dbName ?? gateField.name })} IS NOT NULL AND (
|
|
@@ -3400,19 +3457,19 @@ FOR EACH ROW EXECUTE FUNCTION ${functionName}();`;
|
|
|
3400
3457
|
}
|
|
3401
3458
|
|
|
3402
3459
|
// packages/sql/src/dialects/sqlite-row-rules.ts
|
|
3403
|
-
import { SQLITE_ROW_RULE_ERROR_PREFIX, VibeError as
|
|
3460
|
+
import { SQLITE_ROW_RULE_ERROR_PREFIX, VibeError as VibeError19, unsupportedCapability as unsupportedCapability21 } from "@vibeorm/schema";
|
|
3404
3461
|
function renderSqliteRowRule({ dialect, context }) {
|
|
3405
3462
|
if (dialect.name !== "sqlite")
|
|
3406
|
-
throw
|
|
3463
|
+
throw unsupportedCapability21({ dialect: dialect.name, feature: "sqliteRowRules" });
|
|
3407
3464
|
const { rule, table, triggers, protectedFields, gateField } = context;
|
|
3408
3465
|
if (table.namespace !== "main")
|
|
3409
|
-
throw
|
|
3466
|
+
throw unsupportedCapability21({ dialect: dialect.name, feature: "fixedNamespaces" });
|
|
3410
3467
|
const terms = protectedFields.map((field) => {
|
|
3411
3468
|
const column = dialect.quoteIdent({ name: field.dbName ?? field.name });
|
|
3412
3469
|
return `OLD.${column} IS NOT NEW.${column}`;
|
|
3413
3470
|
});
|
|
3414
3471
|
if (rule.kind !== "appendOnly" && terms.length === 0)
|
|
3415
|
-
throw new
|
|
3472
|
+
throw new VibeError19({ code: "VIBE_SCHEMA_INVALID", message: `Row rule ${rule.name} has no protected fields`, meta: { model: context.model, rule: rule.name } });
|
|
3416
3473
|
const condition = rule.kind === "appendOnly" ? "" : gateField === undefined ? `WHEN ${terms.join(`
|
|
3417
3474
|
OR `)}
|
|
3418
3475
|
` : `WHEN OLD.${dialect.quoteIdent({ name: gateField.dbName ?? gateField.name })} IS NOT NULL AND (
|
|
@@ -3437,11 +3494,11 @@ END;`,
|
|
|
3437
3494
|
}
|
|
3438
3495
|
|
|
3439
3496
|
// packages/sql/src/dialects/mysql-row-rules.ts
|
|
3440
|
-
import { MYSQL_ROW_RULE_MESSAGE_MAX_BYTES, VibeError as
|
|
3497
|
+
import { MYSQL_ROW_RULE_MESSAGE_MAX_BYTES, VibeError as VibeError20, mysqlRowRuleMessageByteLength, unsupportedCapability as unsupportedCapability22 } from "@vibeorm/schema";
|
|
3441
3498
|
function diagnosticLiteral({ name, context, dialect }) {
|
|
3442
3499
|
const message = `Check constraint '${name}' is violated.`;
|
|
3443
3500
|
if (mysqlRowRuleMessageByteLength({ triggerName: name }) > MYSQL_ROW_RULE_MESSAGE_MAX_BYTES)
|
|
3444
|
-
throw new
|
|
3501
|
+
throw new VibeError20({ code: "VIBE_SCHEMA_INVALID", message: `Row rule ${context.rule.name} exceeds MySQL's ${MYSQL_ROW_RULE_MESSAGE_MAX_BYTES}-byte diagnostic limit; supply a shorter name stem`, meta: { model: context.model, rule: context.rule.name } });
|
|
3445
3502
|
if (message.includes("\\")) {
|
|
3446
3503
|
const hex = Array.from(new TextEncoder().encode(message), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
3447
3504
|
return `_utf8mb4 X'${hex}'`;
|
|
@@ -3450,11 +3507,11 @@ function diagnosticLiteral({ name, context, dialect }) {
|
|
|
3450
3507
|
}
|
|
3451
3508
|
function renderMysqlRowRule({ dialect, context }) {
|
|
3452
3509
|
if (dialect.name !== "mysql")
|
|
3453
|
-
throw
|
|
3510
|
+
throw unsupportedCapability22({ dialect: dialect.name, feature: "mysqlRowRules" });
|
|
3454
3511
|
const { rule, table, triggers, protectedFields, gateField, placement } = context;
|
|
3455
3512
|
for (const name of Object.keys(placement ?? {}))
|
|
3456
3513
|
if (!triggers.some(({ identity }) => identity.name === name))
|
|
3457
|
-
throw new
|
|
3514
|
+
throw new VibeError20({ code: "VIBE_INTERNAL", message: "A MySQL trigger placement names a trigger this rule does not own", meta: { model: context.model, rule: rule.name, trigger: name } });
|
|
3458
3515
|
const position = ({ name }) => {
|
|
3459
3516
|
const entry = placement?.[name];
|
|
3460
3517
|
if (entry === undefined)
|
|
@@ -3467,7 +3524,7 @@ function renderMysqlRowRule({ dialect, context }) {
|
|
|
3467
3524
|
return `NOT (OLD.${column} <=> NEW.${column})`;
|
|
3468
3525
|
});
|
|
3469
3526
|
if (rule.kind !== "appendOnly" && terms.length === 0)
|
|
3470
|
-
throw new
|
|
3527
|
+
throw new VibeError20({ code: "VIBE_SCHEMA_INVALID", message: `Row rule ${rule.name} has no protected fields`, meta: { model: context.model, rule: rule.name } });
|
|
3471
3528
|
const condition = gateField === undefined ? terms.join(`
|
|
3472
3529
|
OR `) : `OLD.${dialect.quoteIdent({ name: gateField.dbName ?? gateField.name })} IS NOT NULL AND (
|
|
3473
3530
|
${terms.join(`
|
|
@@ -3496,10 +3553,10 @@ END;`, values: [] };
|
|
|
3496
3553
|
function renderRowRule({ schema, model, rule, dialect, placement }) {
|
|
3497
3554
|
const issue = rowRuleShapeIssue({ value: rule });
|
|
3498
3555
|
if (issue !== undefined) {
|
|
3499
|
-
throw new
|
|
3556
|
+
throw new VibeError21({ code: "VIBE_SCHEMA_INVALID", message: issue, meta: { model: model.name } });
|
|
3500
3557
|
}
|
|
3501
3558
|
if (placement !== undefined && Object.keys(placement).length > 0 && dialect.name !== "mysql")
|
|
3502
|
-
throw
|
|
3559
|
+
throw unsupportedCapability23({ dialect: dialect.name, feature: "rowRuleTriggerPlacement" });
|
|
3503
3560
|
const normalized = normalizeRowRules({ schema, model, rules: [rule], dialect: dialect.name })[0];
|
|
3504
3561
|
switch (dialect.name) {
|
|
3505
3562
|
case "postgres": {
|
|
@@ -3507,7 +3564,7 @@ function renderRowRule({ schema, model, rule, dialect, placement }) {
|
|
|
3507
3564
|
const functionIdentity = objects.find((object) => object.role === "function")?.identity;
|
|
3508
3565
|
const triggerIdentity = objects.find((object) => object.role === "trigger")?.identity;
|
|
3509
3566
|
if (functionIdentity?.kind !== "function" || triggerIdentity?.kind !== "trigger")
|
|
3510
|
-
throw
|
|
3567
|
+
throw internalError3({ message: "PostgreSQL row rules own one function and one trigger", meta: { model: model.name, rule: normalized.name } });
|
|
3511
3568
|
const gate = rowRuleGateField({ rule: normalized });
|
|
3512
3569
|
const gateField = gate === undefined ? undefined : model.fields.find((field) => field.name === gate);
|
|
3513
3570
|
return renderPostgresRowRule({
|
|
@@ -3528,15 +3585,15 @@ function renderRowRule({ schema, model, rule, dialect, placement }) {
|
|
|
3528
3585
|
const objects = rowRuleIdentities({ schema, model, rule: normalized, dialect: dialect.name });
|
|
3529
3586
|
const triggers = objects.map(({ role, identity }) => {
|
|
3530
3587
|
if (role !== "trigger" || identity.kind !== "trigger")
|
|
3531
|
-
throw
|
|
3588
|
+
throw internalError3({ message: "Event row rules own only triggers", meta: { model: model.name, rule: normalized.name } });
|
|
3532
3589
|
const event = ["update", "delete"].find((event) => identity.name === rowRuleTriggerName({ rule: normalized, event }));
|
|
3533
3590
|
if (event === undefined)
|
|
3534
|
-
throw
|
|
3591
|
+
throw internalError3({ message: "Row-rule identity has no declared event", meta: { model: model.name, rule: normalized.name, trigger: identity.name } });
|
|
3535
3592
|
return { event, identity: { kind: "trigger", table: identity.table, name: identity.name } };
|
|
3536
3593
|
});
|
|
3537
3594
|
const table = triggers[0]?.identity.table;
|
|
3538
3595
|
if (table === undefined)
|
|
3539
|
-
throw
|
|
3596
|
+
throw internalError3({ message: "Event row rules require at least one trigger", meta: { model: model.name, rule: normalized.name } });
|
|
3540
3597
|
const gate = rowRuleGateField({ rule: normalized });
|
|
3541
3598
|
const gateField = gate === undefined ? undefined : model.fields.find((field) => field.name === gate);
|
|
3542
3599
|
const context = {
|
|
@@ -3567,7 +3624,7 @@ function renderSqliteJsonEquality(params) {
|
|
|
3567
3624
|
}
|
|
3568
3625
|
|
|
3569
3626
|
// packages/sql/src/dialects/diagnostics.ts
|
|
3570
|
-
import { unsupportedCapability as
|
|
3627
|
+
import { unsupportedCapability as unsupportedCapability24 } from "@vibeorm/schema";
|
|
3571
3628
|
var QUERIES = Object.freeze({
|
|
3572
3629
|
postgresJsonWire: { dialect: "postgres", text: `SELECT '{"__vibeorm":1}'::jsonb AS "probe"` },
|
|
3573
3630
|
sqliteTriggers: { dialect: "sqlite", text: "SELECT name, tbl_name, sql FROM sqlite_master WHERE type = 'trigger'" }
|
|
@@ -3575,7 +3632,7 @@ var QUERIES = Object.freeze({
|
|
|
3575
3632
|
function renderDiagnostic(params) {
|
|
3576
3633
|
const query = QUERIES[params.query];
|
|
3577
3634
|
if (params.dialect.name !== query.dialect) {
|
|
3578
|
-
throw
|
|
3635
|
+
throw unsupportedCapability24({ dialect: params.dialect.name, feature: params.query, hint: `this diagnostic requires ${query.dialect}` });
|
|
3579
3636
|
}
|
|
3580
3637
|
return { text: query.text, values: [], returning: "none" };
|
|
3581
3638
|
}
|
|
@@ -3584,7 +3641,7 @@ function isFixedDiagnostic(params) {
|
|
|
3584
3641
|
}
|
|
3585
3642
|
|
|
3586
3643
|
// packages/sql/src/dialects/postgres-diagnostics.ts
|
|
3587
|
-
import { VibeError as
|
|
3644
|
+
import { VibeError as VibeError22, unsupportedCapability as unsupportedCapability25 } from "@vibeorm/schema";
|
|
3588
3645
|
function renderPostgresExplain(params) {
|
|
3589
3646
|
const { dialect, query, options } = params;
|
|
3590
3647
|
requirePostgres({ dialect, feature: "query plan inspection (EXPLAIN)" });
|
|
@@ -3619,7 +3676,7 @@ var POSTGRES_WORKLOAD_LIMITS = Object.freeze({
|
|
|
3619
3676
|
});
|
|
3620
3677
|
function requirePostgres(params) {
|
|
3621
3678
|
if (params.dialect.name !== "postgres") {
|
|
3622
|
-
throw
|
|
3679
|
+
throw unsupportedCapability25({
|
|
3623
3680
|
dialect: params.dialect.name,
|
|
3624
3681
|
feature: params.feature,
|
|
3625
3682
|
hint: "plan inspection and workload statistics are PostgreSQL-shaped; portable operation tracing works on every dialect"
|
|
@@ -3637,7 +3694,7 @@ function renderPostgresWorkload(params) {
|
|
|
3637
3694
|
if (query === "statementSnapshot") {
|
|
3638
3695
|
const bounded = limit ?? 20;
|
|
3639
3696
|
if (!Number.isInteger(bounded) || bounded < POSTGRES_WORKLOAD_LIMITS.minLimit || bounded > POSTGRES_WORKLOAD_LIMITS.maxLimit) {
|
|
3640
|
-
throw new
|
|
3697
|
+
throw new VibeError22({
|
|
3641
3698
|
code: "VIBE_CONFIG",
|
|
3642
3699
|
message: `workload snapshot limit must be an integer between ${POSTGRES_WORKLOAD_LIMITS.minLimit} and ${POSTGRES_WORKLOAD_LIMITS.maxLimit}, got ${String(limit)}`,
|
|
3643
3700
|
meta: { limit }
|
|
@@ -3656,7 +3713,7 @@ function renderPostgresWorkload(params) {
|
|
|
3656
3713
|
function requireArg(params) {
|
|
3657
3714
|
const { value, name, query } = params;
|
|
3658
3715
|
if (value === undefined || value.length === 0) {
|
|
3659
|
-
throw new
|
|
3716
|
+
throw new VibeError22({
|
|
3660
3717
|
code: "VIBE_CONFIG",
|
|
3661
3718
|
message: `the "${query}" diagnostic read requires a ${name}`,
|
|
3662
3719
|
meta: { query, argument: name }
|
|
@@ -3666,10 +3723,10 @@ function requireArg(params) {
|
|
|
3666
3723
|
}
|
|
3667
3724
|
|
|
3668
3725
|
// packages/sql/src/dialects/postgres-rls-readiness.ts
|
|
3669
|
-
import { unsupportedCapability as
|
|
3726
|
+
import { unsupportedCapability as unsupportedCapability27 } from "@vibeorm/schema";
|
|
3670
3727
|
|
|
3671
3728
|
// packages/sql/src/dialects/postgres-rls.ts
|
|
3672
|
-
import { RlsContextError, VibeError as
|
|
3729
|
+
import { RlsContextError, VibeError as VibeError23, assertNativeRlsAdmission, assertValidSchemaIR, unsupportedCapability as unsupportedCapability26, validateRlsContextIR } from "@vibeorm/schema";
|
|
3673
3730
|
var NATIVE_RLS = Object.freeze({ policyName: "vibeorm_managed", tableSchema: "public", settingPrefix: "vibeorm.", parentAlias: "parent" });
|
|
3674
3731
|
var COLUMN_TYPES = {
|
|
3675
3732
|
String: { default: "text", native: { text: "text", varchar: "varchar", charactervarying: "varchar", uuid: "uuid" } },
|
|
@@ -3682,18 +3739,18 @@ var COLUMN_TYPES = {
|
|
|
3682
3739
|
};
|
|
3683
3740
|
function requireRls(params) {
|
|
3684
3741
|
if (!params.dialect.capabilities.nativeRowLevelSecurity) {
|
|
3685
|
-
throw
|
|
3742
|
+
throw unsupportedCapability26({ dialect: params.dialect.name, feature: "nativeRowLevelSecurity" });
|
|
3686
3743
|
}
|
|
3687
3744
|
}
|
|
3688
3745
|
function identifier2(params) {
|
|
3689
3746
|
if (typeof params.name !== "string" || params.name.length === 0 || params.name.includes("\x00") || new TextEncoder().encode(params.name).length > 63) {
|
|
3690
|
-
throw new
|
|
3747
|
+
throw new VibeError23({ code: "VIBE_SCHEMA_INVALID", message: "Native RLS identifiers must be nonempty PostgreSQL identifiers of at most 63 bytes" });
|
|
3691
3748
|
}
|
|
3692
3749
|
return params.dialect.quoteIdent({ name: params.name });
|
|
3693
3750
|
}
|
|
3694
3751
|
function tableRef(params) {
|
|
3695
3752
|
if (params.schema !== undefined && params.schema !== "public" && params.schema !== "pg_temp") {
|
|
3696
|
-
throw
|
|
3753
|
+
throw unsupportedCapability26({ dialect: params.dialect.name, feature: "nativeRowLevelSecurity", hint: "Only public tables and temporary policy probes are supported" });
|
|
3697
3754
|
}
|
|
3698
3755
|
return `${identifier2({ dialect: params.dialect, name: params.schema ?? NATIVE_RLS.tableSchema })}.${identifier2({ dialect: params.dialect, name: params.table })}`;
|
|
3699
3756
|
}
|
|
@@ -3734,7 +3791,7 @@ function renderRlsColumnType(params) {
|
|
|
3734
3791
|
if (native !== undefined)
|
|
3735
3792
|
return native;
|
|
3736
3793
|
}
|
|
3737
|
-
throw
|
|
3794
|
+
throw unsupportedCapability26({ dialect: params.dialect.name, feature: "nativeRowLevelSecurity", hint: `Unsupported physical ownership type on field ${field.name}` });
|
|
3738
3795
|
}
|
|
3739
3796
|
function protectedModel(params) {
|
|
3740
3797
|
requireRls(params);
|
|
@@ -3742,7 +3799,7 @@ function protectedModel(params) {
|
|
|
3742
3799
|
assertValidSchemaIR({ schema: params.schema });
|
|
3743
3800
|
const model = params.schema.models.find((entry) => entry.name === params.model);
|
|
3744
3801
|
if (model === undefined || model.rls === undefined || model.rls === "unprotected") {
|
|
3745
|
-
throw new
|
|
3802
|
+
throw new VibeError23({ code: "VIBE_SCHEMA_INVALID", message: "Native RLS policy rendering requires a protected model", meta: { model: params.model } });
|
|
3746
3803
|
}
|
|
3747
3804
|
return model;
|
|
3748
3805
|
}
|
|
@@ -3775,7 +3832,7 @@ function predicate(params) {
|
|
|
3775
3832
|
}).join(" AND ");
|
|
3776
3833
|
return `EXISTS (SELECT 1 FROM ${tableRef({ dialect, table: parent.dbName ?? parent.name })} AS ${alias} WHERE ${join})`;
|
|
3777
3834
|
}
|
|
3778
|
-
throw new
|
|
3835
|
+
throw new VibeError23({ code: "VIBE_SCHEMA_INVALID", message: "Native RLS requires a protected policy rule" });
|
|
3779
3836
|
}
|
|
3780
3837
|
function renderRlsPolicy(params) {
|
|
3781
3838
|
const model = protectedModel(params);
|
|
@@ -3816,7 +3873,7 @@ function renderRlsContext(params) {
|
|
|
3816
3873
|
}
|
|
3817
3874
|
function runtimeRoleOf(params) {
|
|
3818
3875
|
if (typeof params.role !== "string" || params.role.trim().length === 0 || params.role.includes("\x00")) {
|
|
3819
|
-
throw new
|
|
3876
|
+
throw new VibeError23({ code: "VIBE_CONFIG", message: "PGlite native RLS requires a trusted nonempty runtime role name" });
|
|
3820
3877
|
}
|
|
3821
3878
|
return params.role;
|
|
3822
3879
|
}
|
|
@@ -3973,7 +4030,7 @@ ORDER BY c.relname, p.polname`,
|
|
|
3973
4030
|
});
|
|
3974
4031
|
function requireRls2(params) {
|
|
3975
4032
|
if (!params.dialect.capabilities.nativeRowLevelSecurity) {
|
|
3976
|
-
throw
|
|
4033
|
+
throw unsupportedCapability27({ dialect: params.dialect.name, feature: "nativeRowLevelSecurity" });
|
|
3977
4034
|
}
|
|
3978
4035
|
}
|
|
3979
4036
|
function renderRlsReadinessQuery(params) {
|
|
@@ -4005,7 +4062,7 @@ function renderRlsPolicyPath(params) {
|
|
|
4005
4062
|
}
|
|
4006
4063
|
|
|
4007
4064
|
// packages/sql/src/render.ts
|
|
4008
|
-
import { assertSqlNamespace as assertSqlNamespace2, internalError as
|
|
4065
|
+
import { assertSqlNamespace as assertSqlNamespace2, internalError as internalError4, unsupportedCapability as unsupportedCapability28 } from "@vibeorm/schema";
|
|
4009
4066
|
|
|
4010
4067
|
// packages/sql/src/like.ts
|
|
4011
4068
|
function escapeLikePattern(params) {
|
|
@@ -4091,15 +4148,19 @@ function renderStatement(params) {
|
|
|
4091
4148
|
function quoteCol(dialect, column) {
|
|
4092
4149
|
const name = dialect.quoteIdent({ name: column.name });
|
|
4093
4150
|
const ref = column.table === undefined ? name : `${dialect.quoteIdent({ name: column.table })}.${name}`;
|
|
4151
|
+
if (column.truncate !== undefined)
|
|
4152
|
+
return renderDateTruncation({ dialect, reference: ref, truncation: column.truncate });
|
|
4153
|
+
if (column.enumOrdinal === true)
|
|
4154
|
+
return dialect.renderEnumOrdinal({ column: ref });
|
|
4094
4155
|
if (column.castReal === true) {
|
|
4095
4156
|
if (dialect.name !== "sqlite") {
|
|
4096
|
-
throw
|
|
4157
|
+
throw internalError4({ message: "ColRef.castReal is a sqlite Decimal construct" });
|
|
4097
4158
|
}
|
|
4098
4159
|
return `CAST(${ref} AS REAL)`;
|
|
4099
4160
|
}
|
|
4100
4161
|
if (column.castJsonb !== undefined) {
|
|
4101
4162
|
if (dialect.name !== "postgres") {
|
|
4102
|
-
throw
|
|
4163
|
+
throw internalError4({ message: "ColRef.castJsonb is a postgres json construct" });
|
|
4103
4164
|
}
|
|
4104
4165
|
return `${ref}::${column.castJsonb}`;
|
|
4105
4166
|
}
|
|
@@ -4107,7 +4168,7 @@ function quoteCol(dialect, column) {
|
|
|
4107
4168
|
}
|
|
4108
4169
|
function typedOrderRef(params) {
|
|
4109
4170
|
const { statement, column } = params;
|
|
4110
|
-
if (column.table !== undefined || column.castReal === true || column.castJsonb !== undefined)
|
|
4171
|
+
if (column.table !== undefined || column.castReal === true || column.castJsonb !== undefined || column.truncate !== undefined)
|
|
4111
4172
|
return column;
|
|
4112
4173
|
const renamed = statement.columns.some((projected) => (projected.alias ?? projected.name) === column.name && (projected.transform !== undefined || projected.alias !== undefined));
|
|
4113
4174
|
return renamed ? { ...column, table: statement.table.alias ?? statement.table.name } : column;
|
|
@@ -4116,16 +4177,17 @@ function jsonCellCast(dialect, cell) {
|
|
|
4116
4177
|
if (cell.storage !== "json" || dialect.jsonParamCast === "")
|
|
4117
4178
|
return dialect.jsonParamCast;
|
|
4118
4179
|
if (dialect.name !== "postgres") {
|
|
4119
|
-
throw
|
|
4180
|
+
throw internalError4({ message: "JsonParamCell storage json is a postgres construct" });
|
|
4120
4181
|
}
|
|
4121
4182
|
return "::text::json";
|
|
4122
4183
|
}
|
|
4123
4184
|
function quoteProjection(dialect, column) {
|
|
4124
4185
|
if (column.transform === undefined) {
|
|
4125
4186
|
const base = quoteCol(dialect, column);
|
|
4126
|
-
|
|
4187
|
+
const alias = column.alias ?? (column.truncate === undefined ? undefined : column.name);
|
|
4188
|
+
if (alias === undefined)
|
|
4127
4189
|
return base;
|
|
4128
|
-
return `${base} AS ${dialect.quoteIdent({ name:
|
|
4190
|
+
return `${base} AS ${dialect.quoteIdent({ name: alias })}`;
|
|
4129
4191
|
}
|
|
4130
4192
|
if (column.transform === "jsonText") {
|
|
4131
4193
|
const ref = quoteCol(dialect, column);
|
|
@@ -4139,7 +4201,7 @@ function quoteProjection(dialect, column) {
|
|
|
4139
4201
|
if (column.transform === "encodeBase64" && dialect.name === "mysql")
|
|
4140
4202
|
return `TO_BASE64(${ref}) AS ${alias}`;
|
|
4141
4203
|
if (dialect.name !== "postgres") {
|
|
4142
|
-
throw
|
|
4204
|
+
throw internalError4({ message: `${column.transform} is a postgres construct` });
|
|
4143
4205
|
}
|
|
4144
4206
|
if (column.transform === "encodeArrayBase64")
|
|
4145
4207
|
return `encode(array_send(${ref}), 'base64') AS ${alias}`;
|
|
@@ -4163,7 +4225,7 @@ function renderTable(dialect, table) {
|
|
|
4163
4225
|
}
|
|
4164
4226
|
function assertCount(value, what) {
|
|
4165
4227
|
if (!Number.isSafeInteger(value) || value < 0) {
|
|
4166
|
-
throw
|
|
4228
|
+
throw internalError4({ message: `${what} must be a non-negative integer, got ${value}` });
|
|
4167
4229
|
}
|
|
4168
4230
|
}
|
|
4169
4231
|
var COMPARISON_SQL2 = {
|
|
@@ -4190,12 +4252,16 @@ var AGG_FN_SQL = {
|
|
|
4190
4252
|
function renderAggRef(dialect, agg) {
|
|
4191
4253
|
if (agg.fn === "countAll")
|
|
4192
4254
|
return "COUNT(*)";
|
|
4193
|
-
|
|
4255
|
+
const column = quoteCol(dialect, agg.column);
|
|
4256
|
+
if ((agg.fn === "min" || agg.fn === "max") && agg.enumOrder !== undefined) {
|
|
4257
|
+
return dialect.renderEnumMinMax({ fn: agg.fn, column, result: agg.enumOrder });
|
|
4258
|
+
}
|
|
4259
|
+
return `${AGG_FN_SQL[agg.fn]}(${column})`;
|
|
4194
4260
|
}
|
|
4195
4261
|
function assertScalarArrays(dialect, feature) {
|
|
4196
4262
|
if (dialect.capabilities.scalarArrays)
|
|
4197
4263
|
return;
|
|
4198
|
-
throw
|
|
4264
|
+
throw unsupportedCapability28({
|
|
4199
4265
|
dialect: dialect.name,
|
|
4200
4266
|
feature,
|
|
4201
4267
|
hint: "only postgres has native array columns \u2014 model the list as a related table instead"
|
|
@@ -4207,7 +4273,7 @@ function renderExpr(params) {
|
|
|
4207
4273
|
case "cmp": {
|
|
4208
4274
|
const op = COMPARISON_SQL2[expr.op];
|
|
4209
4275
|
if (op === undefined) {
|
|
4210
|
-
throw
|
|
4276
|
+
throw internalError4({ message: `unknown comparison operator "${expr.op}"` });
|
|
4211
4277
|
}
|
|
4212
4278
|
if (isDbNowMarker(expr.value)) {
|
|
4213
4279
|
return `${quoteCol(dialect, expr.column)} ${op} ${dialect.renderDbNow({ offsetSeconds: expr.value.offsetSeconds, collector })}`;
|
|
@@ -4218,7 +4284,7 @@ function renderExpr(params) {
|
|
|
4218
4284
|
case "cmpCol": {
|
|
4219
4285
|
const op = COMPARISON_SQL2[expr.op];
|
|
4220
4286
|
if (op === undefined) {
|
|
4221
|
-
throw
|
|
4287
|
+
throw internalError4({ message: `unknown comparison operator "${expr.op}"` });
|
|
4222
4288
|
}
|
|
4223
4289
|
return `${quoteCol(dialect, expr.left)} ${op} ${quoteCol(dialect, expr.right)}`;
|
|
4224
4290
|
}
|
|
@@ -4242,11 +4308,11 @@ function renderExpr(params) {
|
|
|
4242
4308
|
}
|
|
4243
4309
|
case "tupleIn": {
|
|
4244
4310
|
if (expr.columns.length === 0) {
|
|
4245
|
-
throw
|
|
4311
|
+
throw internalError4({ message: "tupleIn needs at least one column" });
|
|
4246
4312
|
}
|
|
4247
4313
|
for (const row of expr.rows) {
|
|
4248
4314
|
if (row.length !== expr.columns.length) {
|
|
4249
|
-
throw
|
|
4315
|
+
throw internalError4({
|
|
4250
4316
|
message: `tupleIn row has ${row.length} values for ${expr.columns.length} columns`
|
|
4251
4317
|
});
|
|
4252
4318
|
}
|
|
@@ -4272,7 +4338,7 @@ function renderExpr(params) {
|
|
|
4272
4338
|
case "rowCompare": {
|
|
4273
4339
|
const op = COMPARISON_SQL2[expr.op];
|
|
4274
4340
|
if (op === undefined || expr.columns.length === 0 || expr.values.length !== expr.columns.length) {
|
|
4275
|
-
throw
|
|
4341
|
+
throw internalError4({ message: `rowCompare needs a range operator and one value per column (${expr.columns.length} columns, ${expr.values.length} values)` });
|
|
4276
4342
|
}
|
|
4277
4343
|
const columns = expr.columns.map((column) => quoteCol(dialect, column));
|
|
4278
4344
|
const placeholders = expr.values.map((value) => collector.add(value));
|
|
@@ -4280,9 +4346,9 @@ function renderExpr(params) {
|
|
|
4280
4346
|
}
|
|
4281
4347
|
case "inSelect": {
|
|
4282
4348
|
if (expr.columns.length === 0)
|
|
4283
|
-
throw
|
|
4349
|
+
throw internalError4({ message: "inSelect needs at least one column" });
|
|
4284
4350
|
if (dialect.name === "mysql" && (expr.select.limit !== undefined || expr.select.offset !== undefined)) {
|
|
4285
|
-
throw
|
|
4351
|
+
throw unsupportedCapability28({
|
|
4286
4352
|
dialect: dialect.name,
|
|
4287
4353
|
feature: "LIMIT inside an IN subquery",
|
|
4288
4354
|
hint: "mysql refuses LIMIT directly inside an IN subquery (error 1235); wrap the limited select in a derived table"
|
|
@@ -4353,7 +4419,7 @@ function renderExpr(params) {
|
|
|
4353
4419
|
case "aggCmp": {
|
|
4354
4420
|
const op = COMPARISON_SQL2[expr.op];
|
|
4355
4421
|
if (op === undefined) {
|
|
4356
|
-
throw
|
|
4422
|
+
throw internalError4({ message: `unknown comparison operator "${expr.op}"` });
|
|
4357
4423
|
}
|
|
4358
4424
|
return `${renderAggRef(dialect, expr.agg)} ${op} ${collector.add(expr.value)}`;
|
|
4359
4425
|
}
|
|
@@ -4435,13 +4501,13 @@ function renderKeyList(params) {
|
|
|
4435
4501
|
const { dialect, expr, collector } = params;
|
|
4436
4502
|
const arity = expr.columns.length;
|
|
4437
4503
|
if (arity === 0)
|
|
4438
|
-
throw
|
|
4504
|
+
throw internalError4({ message: "keyList needs at least one column" });
|
|
4439
4505
|
if (expr.members.length !== arity) {
|
|
4440
|
-
throw
|
|
4506
|
+
throw internalError4({ message: `keyList has ${expr.members.length} members for ${arity} columns` });
|
|
4441
4507
|
}
|
|
4442
4508
|
for (const row of expr.rows) {
|
|
4443
4509
|
if (row.length !== arity)
|
|
4444
|
-
throw
|
|
4510
|
+
throw internalError4({ message: `keyList row has ${row.length} values for ${arity} columns` });
|
|
4445
4511
|
}
|
|
4446
4512
|
if (expr.rows.length === 0)
|
|
4447
4513
|
return "1 = 0";
|
|
@@ -4473,25 +4539,25 @@ function renderKeyPage(params) {
|
|
|
4473
4539
|
const { select } = page;
|
|
4474
4540
|
const arity = page.keyColumns.length;
|
|
4475
4541
|
if (arity === 0 || page.members.length !== arity) {
|
|
4476
|
-
throw
|
|
4542
|
+
throw internalError4({ message: `keyPage has ${page.members.length} members for ${arity} key columns` });
|
|
4477
4543
|
}
|
|
4478
4544
|
if (page.rows.length === 0)
|
|
4479
|
-
throw
|
|
4545
|
+
throw internalError4({ message: "keyPage needs at least one key" });
|
|
4480
4546
|
for (const row of page.rows) {
|
|
4481
4547
|
if (row.length !== arity)
|
|
4482
|
-
throw
|
|
4548
|
+
throw internalError4({ message: `keyPage row has ${row.length} values for ${arity} key columns` });
|
|
4483
4549
|
}
|
|
4484
4550
|
if (page.identity.length === 0)
|
|
4485
|
-
throw
|
|
4551
|
+
throw internalError4({ message: "keyPage needs the child's identity columns" });
|
|
4486
4552
|
const order = select.orderBy ?? [];
|
|
4487
4553
|
if (order.length === 0 || order.some((term) => !("column" in term))) {
|
|
4488
|
-
throw
|
|
4554
|
+
throw internalError4({ message: "keyPage needs a non-empty order of plain column terms" });
|
|
4489
4555
|
}
|
|
4490
4556
|
if (select.table.alias !== undefined || Object.keys(select).some((member) => !KEY_PAGE_SELECT_MEMBERS.has(member))) {
|
|
4491
|
-
throw
|
|
4557
|
+
throw internalError4({ message: "keyPage select carries a member the per-key page cannot render" });
|
|
4492
4558
|
}
|
|
4493
4559
|
if (dialect.keyPageStrategy === "window") {
|
|
4494
|
-
throw
|
|
4560
|
+
throw unsupportedCapability28({
|
|
4495
4561
|
dialect: dialect.name,
|
|
4496
4562
|
feature: "a per-key page (keyPage)",
|
|
4497
4563
|
hint: "the runtime keeps the ROW_NUMBER window on this dialect"
|
|
@@ -4519,7 +4585,7 @@ function renderKeyPage(params) {
|
|
|
4519
4585
|
const keys = dialect.quoteIdent({ name: keyAlias });
|
|
4520
4586
|
if (dialect.keyPageStrategy === "lateral") {
|
|
4521
4587
|
if (keyListBindsUntypedRows({ members: page.members })) {
|
|
4522
|
-
throw
|
|
4588
|
+
throw unsupportedCapability28({
|
|
4523
4589
|
dialect: dialect.name,
|
|
4524
4590
|
feature: "a per-key page over a DateTime key without a declared native type",
|
|
4525
4591
|
hint: "the runtime keeps the ROW_NUMBER window for such keys"
|
|
@@ -4547,22 +4613,22 @@ function renderKeyPage(params) {
|
|
|
4547
4613
|
function renderKeyRows(params) {
|
|
4548
4614
|
const { dialect, statement, keys, collector } = params;
|
|
4549
4615
|
if (statement.fromSelect !== undefined || statement.keyPage !== undefined || statement.fromUnion !== undefined || statement.table.alias !== undefined) {
|
|
4550
|
-
throw
|
|
4616
|
+
throw internalError4({ message: "fromKeys uses table.name as the derived-table alias \u2014 fromSelect, keyPage, fromUnion and table.alias must be unset" });
|
|
4551
4617
|
}
|
|
4552
4618
|
if (statement.rowLock !== undefined)
|
|
4553
|
-
throw
|
|
4619
|
+
throw internalError4({ message: "a locking read cannot read from key rows" });
|
|
4554
4620
|
const arity = keys.columns.length;
|
|
4555
4621
|
if (arity === 0 || keys.members.length !== arity) {
|
|
4556
|
-
throw
|
|
4622
|
+
throw internalError4({ message: `fromKeys has ${keys.members.length} members for ${arity} columns` });
|
|
4557
4623
|
}
|
|
4558
4624
|
if (keys.rows.length === 0)
|
|
4559
|
-
throw
|
|
4625
|
+
throw internalError4({ message: "fromKeys needs at least one key row" });
|
|
4560
4626
|
for (const row of keys.rows) {
|
|
4561
4627
|
if (row.length !== arity)
|
|
4562
|
-
throw
|
|
4628
|
+
throw internalError4({ message: `fromKeys row has ${row.length} values for ${arity} columns` });
|
|
4563
4629
|
}
|
|
4564
4630
|
if (dialect.keyListStrategy !== "unnest" || keyListBindsUntypedRows({ members: keys.members })) {
|
|
4565
|
-
throw
|
|
4631
|
+
throw unsupportedCapability28({
|
|
4566
4632
|
dialect: dialect.name,
|
|
4567
4633
|
feature: dialect.keyListStrategy !== "unnest" ? "a key-rows FROM (fromKeys)" : "a key-rows FROM over a DateTime key without a declared native type",
|
|
4568
4634
|
hint: "the runtime keeps the per-relation loads for this write"
|
|
@@ -4578,20 +4644,20 @@ function renderUnionPage(params) {
|
|
|
4578
4644
|
const { dialect, statement, collector } = params;
|
|
4579
4645
|
const branches = statement.fromUnion ?? [];
|
|
4580
4646
|
if (branches.length < 2)
|
|
4581
|
-
throw
|
|
4647
|
+
throw internalError4({ message: "fromUnion needs at least two branches" });
|
|
4582
4648
|
if (statement.fromSelect !== undefined || statement.keyPage !== undefined || statement.table.alias !== undefined) {
|
|
4583
|
-
throw
|
|
4649
|
+
throw internalError4({ message: "fromUnion uses table.name as the derived-table alias \u2014 fromSelect, keyPage and table.alias must be unset" });
|
|
4584
4650
|
}
|
|
4585
4651
|
if (statement.rowLock !== undefined)
|
|
4586
|
-
throw
|
|
4652
|
+
throw internalError4({ message: "a locking read cannot read from a union page" });
|
|
4587
4653
|
const outputNames = (branch) => branch.columns.map((column) => column.alias ?? column.name).join("\x00");
|
|
4588
4654
|
const names = outputNames(branches[0]);
|
|
4589
4655
|
return branches.map((branch, index) => {
|
|
4590
4656
|
if (branch.columns.length === 0 || Object.keys(branch).some((member) => !UNION_BRANCH_MEMBERS.has(member))) {
|
|
4591
|
-
throw
|
|
4657
|
+
throw internalError4({ message: "a fromUnion branch must be a plain SELECT <columns> FROM <table> [WHERE] [ORDER BY] [LIMIT]" });
|
|
4592
4658
|
}
|
|
4593
4659
|
if (outputNames(branch) !== names)
|
|
4594
|
-
throw
|
|
4660
|
+
throw internalError4({ message: "fromUnion branches must project the same output names in the same order" });
|
|
4595
4661
|
const inner = renderSelect({ dialect, statement: branch, collector });
|
|
4596
4662
|
return `SELECT * FROM (${inner.text}) AS ${dialect.quoteIdent({ name: `__vibe_u${index}` })}`;
|
|
4597
4663
|
}).join(" UNION ALL ");
|
|
@@ -4599,7 +4665,7 @@ function renderUnionPage(params) {
|
|
|
4599
4665
|
function jsonStringPattern(params) {
|
|
4600
4666
|
const { expr } = params;
|
|
4601
4667
|
if (typeof expr.value !== "string") {
|
|
4602
|
-
throw
|
|
4668
|
+
throw internalError4({ message: `json ${expr.op} expects a string operand` });
|
|
4603
4669
|
}
|
|
4604
4670
|
if (expr.op === "string_contains")
|
|
4605
4671
|
return containsPattern({ raw: expr.value });
|
|
@@ -4623,7 +4689,7 @@ function renderJsonLike(params) {
|
|
|
4623
4689
|
function renderJsonFilter(params) {
|
|
4624
4690
|
const { dialect, expr, collector } = params;
|
|
4625
4691
|
if (!dialect.supportedJsonOps.includes(expr.op)) {
|
|
4626
|
-
throw
|
|
4692
|
+
throw unsupportedCapability28({
|
|
4627
4693
|
dialect: dialect.name,
|
|
4628
4694
|
feature: `the json filter "${expr.op}"`,
|
|
4629
4695
|
hint: `this dialect can express: ${dialect.supportedJsonOps.join(", ")}`
|
|
@@ -4690,7 +4756,7 @@ function renderJsonFilter(params) {
|
|
|
4690
4756
|
const elements = Array.isArray(expr.value) ? expr.value : [expr.value];
|
|
4691
4757
|
const tests = elements.map((element) => {
|
|
4692
4758
|
if (element === null || typeof element === "object" && element !== null) {
|
|
4693
|
-
throw
|
|
4759
|
+
throw unsupportedCapability28({
|
|
4694
4760
|
dialect: dialect.name,
|
|
4695
4761
|
feature: "json array_contains with object/array/null elements",
|
|
4696
4762
|
hint: "sqlite expresses scalar-element containment only \u2014 deep structural containment needs postgres or mysql"
|
|
@@ -4704,7 +4770,7 @@ function renderJsonFilter(params) {
|
|
|
4704
4770
|
return tests.length === 0 ? guard : `(${[guard, ...tests].join(" AND ")})`;
|
|
4705
4771
|
}
|
|
4706
4772
|
default:
|
|
4707
|
-
throw
|
|
4773
|
+
throw internalError4({ message: `json op "${expr.op}" leaked past supportedJsonOps on sqlite` });
|
|
4708
4774
|
}
|
|
4709
4775
|
}
|
|
4710
4776
|
const column = quoteCol(dialect, expr.column);
|
|
@@ -4731,23 +4797,20 @@ function renderOrderTerm(params) {
|
|
|
4731
4797
|
if ("agg" in term) {
|
|
4732
4798
|
return `${renderAggRef(dialect, term.agg)} ${term.direction === "asc" ? "ASC" : "DESC"}`;
|
|
4733
4799
|
}
|
|
4734
|
-
|
|
4735
|
-
const sub = renderSelect({ dialect, statement: term.select, collector });
|
|
4736
|
-
return `(${sub.text}) ${term.direction === "asc" ? "ASC" : "DESC"}`;
|
|
4737
|
-
}
|
|
4738
|
-
const column = quoteCol(dialect, term.column);
|
|
4800
|
+
const expression = "select" in term ? () => renderScalarSubquery({ dialect, subquery: term, collector }) : () => quoteCol(dialect, term.column);
|
|
4739
4801
|
const direction = term.direction === "asc" ? "ASC" : "DESC";
|
|
4740
4802
|
if (term.nulls === undefined) {
|
|
4741
|
-
return `${
|
|
4803
|
+
return `${expression()} ${direction}`;
|
|
4742
4804
|
}
|
|
4743
4805
|
if (dialect.orderByNullsMode === "native") {
|
|
4744
|
-
return `${
|
|
4806
|
+
return `${expression()} ${direction} NULLS ${term.nulls === "first" ? "FIRST" : "LAST"}`;
|
|
4745
4807
|
}
|
|
4746
4808
|
if (term.nulls === "first" === (term.direction === "asc")) {
|
|
4747
|
-
return `${
|
|
4809
|
+
return `${expression()} ${direction}`;
|
|
4748
4810
|
}
|
|
4749
|
-
const
|
|
4750
|
-
|
|
4811
|
+
const tested = expression();
|
|
4812
|
+
const nullsTerm = term.nulls === "first" ? `${tested} IS NULL DESC` : `${tested} IS NULL`;
|
|
4813
|
+
return `${nullsTerm}, ${expression()} ${direction}`;
|
|
4751
4814
|
}
|
|
4752
4815
|
function renderSelectExpr(params) {
|
|
4753
4816
|
const { dialect, expr } = params;
|
|
@@ -4762,11 +4825,11 @@ function renderPositionalRow(params) {
|
|
|
4762
4825
|
const position = join.select.rowNumber;
|
|
4763
4826
|
const positioned = position !== undefined && json.order === "positionSlot" && join.agg === "jsonArray" && position.partitionBy.length === 0 && position.orderBy.length > 0;
|
|
4764
4827
|
if (join.select.columns.length === 0 || join.select.selectExpr !== undefined || (join.select.aggregates?.length ?? 0) > 0 || position !== undefined && !positioned) {
|
|
4765
|
-
throw
|
|
4828
|
+
throw internalError4({ message: "positional lateral rows require an explicit column-only projection" });
|
|
4766
4829
|
}
|
|
4767
4830
|
const names = [...join.select.columns.map((column) => projectionOutputName({ column })), ...positioned ? [position.alias] : []];
|
|
4768
4831
|
if (new Set(names).size !== names.length) {
|
|
4769
|
-
throw
|
|
4832
|
+
throw internalError4({ message: "positional lateral projection has duplicate output names" });
|
|
4770
4833
|
}
|
|
4771
4834
|
const values = names.map((name) => `${subAlias}.${dialect.quoteIdent({ name })}`);
|
|
4772
4835
|
const chunks = [];
|
|
@@ -4774,14 +4837,14 @@ function renderPositionalRow(params) {
|
|
|
4774
4837
|
chunks.push(`${json.rowArray}(${values.slice(index, index + JSON_TRANSPORT.chunkSize).join(", ")})`);
|
|
4775
4838
|
}
|
|
4776
4839
|
if (chunks.length > JSON_TRANSPORT.chunkSize) {
|
|
4777
|
-
throw
|
|
4840
|
+
throw internalError4({ message: "positional lateral projection exceeds the transport width limit" });
|
|
4778
4841
|
}
|
|
4779
4842
|
return chunks.length === 1 ? chunks[0] : `${json.rowArray}(${chunks.join(", ")})`;
|
|
4780
4843
|
}
|
|
4781
4844
|
function lateralJsonOf(params) {
|
|
4782
4845
|
const json = params.dialect.lateralJson;
|
|
4783
4846
|
if (json === null)
|
|
4784
|
-
throw
|
|
4847
|
+
throw internalError4({ message: "lateral JSON rendering on a dialect without LATERAL" });
|
|
4785
4848
|
return json;
|
|
4786
4849
|
}
|
|
4787
4850
|
function renderLateralJoin(params) {
|
|
@@ -4789,7 +4852,7 @@ function renderLateralJoin(params) {
|
|
|
4789
4852
|
const inner = renderSelect({ dialect, statement: join.select, collector });
|
|
4790
4853
|
if (join.agg === "count") {
|
|
4791
4854
|
if (join.rowFormat === "positional" || join.select.columns.length !== 0 || join.select.selectExpr?.kind !== "countAll" || join.select.selectExpr.alias !== join.columnAlias || join.select.groupBy !== undefined || join.select.having !== undefined || join.select.limit !== undefined || join.select.offset !== undefined || join.select.distinctOn !== undefined || join.select.distinct !== undefined) {
|
|
4792
|
-
throw
|
|
4855
|
+
throw internalError4({ message: "count lateral must return one ungrouped COUNT(*) under its column alias" });
|
|
4793
4856
|
}
|
|
4794
4857
|
return `LEFT JOIN LATERAL (${inner.text}) AS ${dialect.quoteIdent({ name: join.alias })} ON true`;
|
|
4795
4858
|
}
|
|
@@ -4798,7 +4861,7 @@ function renderLateralJoin(params) {
|
|
|
4798
4861
|
const json = lateralJsonOf({ dialect });
|
|
4799
4862
|
let aggOrder = "";
|
|
4800
4863
|
if (json.order === "inAggregate" && join.agg === "jsonArray" && join.select.orderBy !== undefined && join.select.orderBy.length > 0) {
|
|
4801
|
-
const projected = new Set(join.select.columns.filter((column) => column.transform === undefined && column.castReal !== true).map((column) => column.name));
|
|
4864
|
+
const projected = new Set(join.select.columns.filter((column) => column.transform === undefined && column.castReal !== true).map((column) => column.name).concat((join.select.scalarSubqueries ?? []).map((subquery) => subquery.alias)));
|
|
4802
4865
|
const terms = join.select.orderBy;
|
|
4803
4866
|
const columnTerms = terms.filter((term) => ("column" in term));
|
|
4804
4867
|
if (columnTerms.length === terms.length && columnTerms.every((term) => projected.has(term.column.name))) {
|
|
@@ -4814,7 +4877,7 @@ function renderLateralJoin(params) {
|
|
|
4814
4877
|
}
|
|
4815
4878
|
}
|
|
4816
4879
|
if (join.rowFormat !== "positional" && json.order !== "inAggregate") {
|
|
4817
|
-
throw
|
|
4880
|
+
throw unsupportedCapability28({ dialect: dialect.name, feature: "object-format lateral rows", hint: 'lateral relation rows render positional (rowFormat "positional") on this dialect' });
|
|
4818
4881
|
}
|
|
4819
4882
|
const rowJson = join.rowFormat === "positional" ? renderPositionalRow({ dialect, join, subAlias }) : `to_json(${subAlias}.*)`;
|
|
4820
4883
|
const projection = join.agg === "jsonArray" ? `COALESCE(${json.arrayAgg}(${rowJson}${aggOrder}), ${json.emptyArray}) AS ${columnAlias}` : `${rowJson} AS ${columnAlias}`;
|
|
@@ -4824,12 +4887,17 @@ function renderLateralJoin(params) {
|
|
|
4824
4887
|
function renderCountSubquery(params) {
|
|
4825
4888
|
const { dialect, subquery, collector } = params;
|
|
4826
4889
|
const select = subquery.select;
|
|
4827
|
-
if (select.columns.length !== 0 || select.selectExpr?.kind !== "countAll" || (select.aggregates?.length ?? 0) > 0 || select.rowNumber !== undefined || select.groupBy !== undefined || select.having !== undefined || select.limit !== undefined || select.offset !== undefined || select.distinctOn !== undefined || select.distinct !== undefined || select.rowLock !== undefined || select.countSubqueries !== undefined) {
|
|
4828
|
-
throw
|
|
4890
|
+
if (select.columns.length !== 0 || select.selectExpr?.kind !== "countAll" || (select.aggregates?.length ?? 0) > 0 || select.rowNumber !== undefined || select.groupBy !== undefined || select.having !== undefined || select.limit !== undefined || select.offset !== undefined || select.distinctOn !== undefined || select.distinct !== undefined || select.rowLock !== undefined || select.countSubqueries !== undefined || select.scalarSubqueries !== undefined) {
|
|
4891
|
+
throw internalError4({ message: "count subquery must be one ungrouped COUNT(*)" });
|
|
4829
4892
|
}
|
|
4830
4893
|
const inner = renderSelect({ dialect, statement: select, collector });
|
|
4831
4894
|
return `(${inner.text}) AS ${dialect.quoteIdent({ name: subquery.alias })}`;
|
|
4832
4895
|
}
|
|
4896
|
+
function renderScalarSubquery(params) {
|
|
4897
|
+
const { dialect, subquery, collector } = params;
|
|
4898
|
+
const value = `(${renderSelect({ dialect, statement: subquery.select, collector }).text})`;
|
|
4899
|
+
return subquery.coalesce === 0 ? `COALESCE(${value}, 0)` : value;
|
|
4900
|
+
}
|
|
4833
4901
|
function applyReturning(params) {
|
|
4834
4902
|
const { dialect, requested } = params;
|
|
4835
4903
|
if (requested === undefined || requested.length === 0) {
|
|
@@ -4855,27 +4923,27 @@ function renderKeyTableJoin(params) {
|
|
|
4855
4923
|
const postgresMember = (member) => member.kind === "citext" || member.kind === "text" || member.kind === "integer";
|
|
4856
4924
|
const admitted = dialect.name === "mysql" ? join.members.every((member) => member.kind !== "citext" && member.kind !== "text") : dialect.name === "postgres" && join.members.every(postgresMember);
|
|
4857
4925
|
if (!admitted) {
|
|
4858
|
-
throw
|
|
4926
|
+
throw unsupportedCapability28({
|
|
4859
4927
|
dialect: dialect.name,
|
|
4860
4928
|
feature: "relation key table",
|
|
4861
4929
|
hint: "the key-table join is mysql's relation association \u2014 this dialect compares relation keys by value"
|
|
4862
4930
|
});
|
|
4863
4931
|
}
|
|
4864
4932
|
if (join.columns.length === 0 || join.columns.length !== join.members.length) {
|
|
4865
|
-
throw
|
|
4933
|
+
throw internalError4({ message: `key table needs one member per column, got ${join.members.length} for ${join.columns.length}` });
|
|
4866
4934
|
}
|
|
4867
4935
|
if (join.rows.length === 0)
|
|
4868
|
-
throw
|
|
4936
|
+
throw internalError4({ message: "key table needs at least one key row" });
|
|
4869
4937
|
for (const member of join.members) {
|
|
4870
4938
|
if (member.kind === "decimal" && !(Number.isInteger(member.scale) && member.scale >= 0 && member.scale <= 30)) {
|
|
4871
|
-
throw
|
|
4939
|
+
throw internalError4({ message: `key table decimal scale must be an integer 0-30, got ${String(member.scale)}` });
|
|
4872
4940
|
}
|
|
4873
4941
|
}
|
|
4874
4942
|
const alias = dialect.quoteIdent({ name: join.alias });
|
|
4875
4943
|
const memberNames = join.members.map((_, index) => dialect.quoteIdent({ name: `__vibe_k${index}` }));
|
|
4876
4944
|
const rows = join.rows.map((row, ordinal) => {
|
|
4877
4945
|
if (row.length !== join.members.length) {
|
|
4878
|
-
throw
|
|
4946
|
+
throw internalError4({ message: `key table row has ${row.length} values for ${join.members.length} members` });
|
|
4879
4947
|
}
|
|
4880
4948
|
const cells = row.map((value, index) => {
|
|
4881
4949
|
const placeholder = collector.add(value);
|
|
@@ -4905,10 +4973,10 @@ function renderKeyTableJoin(params) {
|
|
|
4905
4973
|
function renderLeftJoin(params) {
|
|
4906
4974
|
const { dialect, join, collector } = params;
|
|
4907
4975
|
if (join.on.length === 0) {
|
|
4908
|
-
throw
|
|
4976
|
+
throw internalError4({ message: "left join needs at least one ON pair" });
|
|
4909
4977
|
}
|
|
4910
4978
|
if (join.select.columns.length === 0 || join.select.columns.some((column) => column.alias === undefined)) {
|
|
4911
|
-
throw
|
|
4979
|
+
throw internalError4({ message: "a left join's derived select must alias every projected column" });
|
|
4912
4980
|
}
|
|
4913
4981
|
const inner = renderSelect({ dialect, statement: join.select, collector });
|
|
4914
4982
|
const on = join.on.map((pair) => `${quoteCol(dialect, pair.left)} = ${quoteCol(dialect, pair.right)}`).join(" AND ");
|
|
@@ -4917,10 +4985,10 @@ function renderLeftJoin(params) {
|
|
|
4917
4985
|
function renderSelect(params) {
|
|
4918
4986
|
const { dialect, statement, collector } = params;
|
|
4919
4987
|
if (statement.selectExpr !== undefined && statement.columns.length > 0 && statement.selectExpr.kind !== "countAll") {
|
|
4920
|
-
throw
|
|
4988
|
+
throw internalError4({ message: "only countAll can combine with a column list" });
|
|
4921
4989
|
}
|
|
4922
4990
|
if (statement.selectExpr !== undefined && statement.aggregates !== undefined && statement.aggregates.length > 0) {
|
|
4923
|
-
throw
|
|
4991
|
+
throw internalError4({ message: "selectExpr and aggregates cannot combine" });
|
|
4924
4992
|
}
|
|
4925
4993
|
const columnList = statement.columns.map((column) => quoteProjection(dialect, column));
|
|
4926
4994
|
if (statement.selectExpr !== undefined) {
|
|
@@ -4938,10 +5006,15 @@ function renderSelect(params) {
|
|
|
4938
5006
|
columnList.push(renderCountSubquery({ dialect, subquery, collector }));
|
|
4939
5007
|
}
|
|
4940
5008
|
}
|
|
5009
|
+
if (statement.scalarSubqueries !== undefined) {
|
|
5010
|
+
for (const subquery of statement.scalarSubqueries) {
|
|
5011
|
+
columnList.push(`${renderScalarSubquery({ dialect, subquery, collector })} AS ${dialect.quoteIdent({ name: subquery.alias })}`);
|
|
5012
|
+
}
|
|
5013
|
+
}
|
|
4941
5014
|
if (statement.rowNumber !== undefined) {
|
|
4942
5015
|
const rowNumber = statement.rowNumber;
|
|
4943
5016
|
if (rowNumber.partitionBy.length === 0 && rowNumber.orderBy.length === 0) {
|
|
4944
|
-
throw
|
|
5017
|
+
throw internalError4({ message: "rowNumber needs a partition column or an order" });
|
|
4945
5018
|
}
|
|
4946
5019
|
const partition = rowNumber.partitionBy.length === 0 ? "" : `PARTITION BY ${rowNumber.partitionBy.map((column) => quoteCol(dialect, column)).join(", ")}`;
|
|
4947
5020
|
const order = rowNumber.orderBy.length === 0 ? "" : `${partition === "" ? "" : " "}ORDER BY ${rowNumber.orderBy.map((term) => renderOrderTerm({ dialect, term, collector })).join(", ")}`;
|
|
@@ -4949,11 +5022,11 @@ function renderSelect(params) {
|
|
|
4949
5022
|
}
|
|
4950
5023
|
let distinctPrefix = statement.distinct === true ? "DISTINCT " : "";
|
|
4951
5024
|
if (statement.distinct === true && statement.distinctOn !== undefined) {
|
|
4952
|
-
throw
|
|
5025
|
+
throw internalError4({ message: "distinct and distinctOn cannot combine" });
|
|
4953
5026
|
}
|
|
4954
5027
|
if (statement.distinctOn !== undefined && statement.distinctOn.length > 0) {
|
|
4955
5028
|
if (!dialect.capabilities.distinctOn) {
|
|
4956
|
-
throw
|
|
5029
|
+
throw unsupportedCapability28({
|
|
4957
5030
|
dialect: dialect.name,
|
|
4958
5031
|
feature: "SELECT DISTINCT ON",
|
|
4959
5032
|
hint: "postgres-only \u2014 the runtime emulates distinct client-side on this dialect"
|
|
@@ -4969,12 +5042,12 @@ function renderSelect(params) {
|
|
|
4969
5042
|
from = `(${renderUnionPage({ dialect, statement, collector })}) AS ${dialect.quoteIdent({ name: statement.table.name })}`;
|
|
4970
5043
|
} else if (statement.keyPage !== undefined) {
|
|
4971
5044
|
if (statement.fromSelect !== undefined || statement.table.alias !== undefined) {
|
|
4972
|
-
throw
|
|
5045
|
+
throw internalError4({ message: "keyPage uses table.name as the derived-table alias \u2014 fromSelect and table.alias must be unset" });
|
|
4973
5046
|
}
|
|
4974
5047
|
from = `(${renderKeyPage({ dialect, page: statement.keyPage, collector })}) AS ${dialect.quoteIdent({ name: statement.table.name })}`;
|
|
4975
5048
|
} else if (statement.fromSelect !== undefined) {
|
|
4976
5049
|
if (statement.table.alias !== undefined) {
|
|
4977
|
-
throw
|
|
5050
|
+
throw internalError4({ message: "fromSelect uses table.name as the subquery alias \u2014 table.alias must be unset" });
|
|
4978
5051
|
}
|
|
4979
5052
|
const inner = renderSelect({ dialect, statement: statement.fromSelect, collector });
|
|
4980
5053
|
from = `(${inner.text}) AS ${dialect.quoteIdent({ name: statement.table.name })}`;
|
|
@@ -4985,7 +5058,7 @@ function renderSelect(params) {
|
|
|
4985
5058
|
if (statement.innerJoins !== undefined && statement.innerJoins.length > 0) {
|
|
4986
5059
|
for (const join of statement.innerJoins) {
|
|
4987
5060
|
if (join.on.length === 0) {
|
|
4988
|
-
throw
|
|
5061
|
+
throw internalError4({ message: "inner join needs at least one ON pair" });
|
|
4989
5062
|
}
|
|
4990
5063
|
const on = join.on.map((pair) => `${quoteCol(dialect, pair.left)} = ${quoteCol(dialect, pair.right)}`).join(" AND ");
|
|
4991
5064
|
text += ` INNER JOIN ${renderTable(dialect, join.table)} ON ${on}`;
|
|
@@ -4996,7 +5069,7 @@ function renderSelect(params) {
|
|
|
4996
5069
|
}
|
|
4997
5070
|
if (statement.leftJoins !== undefined && statement.leftJoins.length > 0) {
|
|
4998
5071
|
if (statement.rowLock !== undefined) {
|
|
4999
|
-
throw
|
|
5072
|
+
throw internalError4({ message: "a locking read cannot carry a left join \u2014 postgres refuses FOR UPDATE on the nullable side of an outer join" });
|
|
5000
5073
|
}
|
|
5001
5074
|
for (const join of statement.leftJoins) {
|
|
5002
5075
|
text += ` ${renderLeftJoin({ dialect, join, collector })}`;
|
|
@@ -5004,7 +5077,7 @@ function renderSelect(params) {
|
|
|
5004
5077
|
}
|
|
5005
5078
|
if (statement.lateralJoins !== undefined && statement.lateralJoins.length > 0) {
|
|
5006
5079
|
if (!dialect.capabilities.lateralJoin || dialect.lateralJson === null) {
|
|
5007
|
-
throw
|
|
5080
|
+
throw unsupportedCapability28({
|
|
5008
5081
|
dialect: dialect.name,
|
|
5009
5082
|
feature: "LATERAL JOIN relation loading",
|
|
5010
5083
|
hint: 'use the portable "query" relation strategy on this dialect'
|
|
@@ -5053,7 +5126,7 @@ function unnestElement(params) {
|
|
|
5053
5126
|
return null;
|
|
5054
5127
|
if (isJsonParamCell(value)) {
|
|
5055
5128
|
if (jsonStorage === undefined || (value.storage ?? "jsonb") !== jsonStorage) {
|
|
5056
|
-
throw
|
|
5129
|
+
throw internalError4({ message: `unnest insert column "${column}" got a Json cell its declared type does not take` });
|
|
5057
5130
|
}
|
|
5058
5131
|
return value.text;
|
|
5059
5132
|
}
|
|
@@ -5069,24 +5142,24 @@ function unnestElement(params) {
|
|
|
5069
5142
|
return value;
|
|
5070
5143
|
}
|
|
5071
5144
|
}
|
|
5072
|
-
throw
|
|
5145
|
+
throw internalError4({ message: `unnest insert column "${column}" got a cell that is not a plain value (DEFAULT, the database clock, a document) \u2014 such rows keep VALUES` });
|
|
5073
5146
|
}
|
|
5074
5147
|
function renderUnnestRows(params) {
|
|
5075
5148
|
const { dialect, statement, members, collector } = params;
|
|
5076
5149
|
if (dialect.bulkInsertForm !== "unnest") {
|
|
5077
|
-
throw
|
|
5150
|
+
throw unsupportedCapability28({
|
|
5078
5151
|
dialect: dialect.name,
|
|
5079
5152
|
feature: "a bulk insert bound as typed arrays (INSERT \u2026 SELECT FROM unnest)",
|
|
5080
5153
|
hint: "this dialect binds createMany rows as VALUES"
|
|
5081
5154
|
});
|
|
5082
5155
|
}
|
|
5083
5156
|
if (statement.columns.length === 0)
|
|
5084
|
-
throw
|
|
5157
|
+
throw internalError4({ message: "an unnest insert needs at least one column" });
|
|
5085
5158
|
if (members.length !== statement.columns.length) {
|
|
5086
|
-
throw
|
|
5159
|
+
throw internalError4({ message: `unnest insert has ${members.length} column types for ${statement.columns.length} columns` });
|
|
5087
5160
|
}
|
|
5088
5161
|
if (statement.onConflict !== undefined && !("doNothing" in statement.onConflict)) {
|
|
5089
|
-
throw
|
|
5162
|
+
throw internalError4({ message: "an unnest insert takes no DO UPDATE arm \u2014 upserts bind VALUES" });
|
|
5090
5163
|
}
|
|
5091
5164
|
const aliases = statement.columns.map((_column, index) => dialect.quoteIdent({ name: `c${index + 1}` }));
|
|
5092
5165
|
const arrays = members.map((member, index) => {
|
|
@@ -5102,14 +5175,14 @@ function renderUnnestRows(params) {
|
|
|
5102
5175
|
function renderInsert(params) {
|
|
5103
5176
|
const { dialect, statement, collector } = params;
|
|
5104
5177
|
if (statement.rows.length === 0) {
|
|
5105
|
-
throw
|
|
5178
|
+
throw internalError4({ message: "insert requires at least one row" });
|
|
5106
5179
|
}
|
|
5107
5180
|
const defaultValues = statement.columns.length === 0 && dialect.emptyInsert.form === "defaultValues";
|
|
5108
5181
|
if (defaultValues && statement.rows.length !== 1) {
|
|
5109
|
-
throw
|
|
5182
|
+
throw internalError4({ message: `${dialect.name} inserts an all-default row as DEFAULT VALUES, one row per statement` });
|
|
5110
5183
|
}
|
|
5111
5184
|
if (defaultValues && statement.onConflict !== undefined && !(dialect.emptyInsert.form === "defaultValues" && dialect.emptyInsert.conflictClause)) {
|
|
5112
|
-
throw
|
|
5185
|
+
throw unsupportedCapability28({
|
|
5113
5186
|
dialect: dialect.name,
|
|
5114
5187
|
feature: "a conflict clause on an all-default row (DEFAULT VALUES)",
|
|
5115
5188
|
hint: "supply at least one column value, or drop the conflict clause"
|
|
@@ -5117,7 +5190,7 @@ function renderInsert(params) {
|
|
|
5117
5190
|
}
|
|
5118
5191
|
for (const row of statement.rows) {
|
|
5119
5192
|
if (row.length !== statement.columns.length) {
|
|
5120
|
-
throw
|
|
5193
|
+
throw internalError4({
|
|
5121
5194
|
message: `insert row has ${row.length} values but ${statement.columns.length} columns`
|
|
5122
5195
|
});
|
|
5123
5196
|
}
|
|
@@ -5135,7 +5208,7 @@ function renderInsert(params) {
|
|
|
5135
5208
|
if (!isSqlDefaultCell(value))
|
|
5136
5209
|
return collector.add(value);
|
|
5137
5210
|
if (!dialect.rowDefaultKeyword) {
|
|
5138
|
-
throw
|
|
5211
|
+
throw internalError4({
|
|
5139
5212
|
message: `${dialect.name} cannot render a per-row DEFAULT cell \u2014 rows must be grouped by column set`
|
|
5140
5213
|
});
|
|
5141
5214
|
}
|
|
@@ -5151,7 +5224,7 @@ function renderInsert(params) {
|
|
|
5151
5224
|
let target = "";
|
|
5152
5225
|
if (onConflict.constraint !== undefined) {
|
|
5153
5226
|
if (dialect.name !== "postgres") {
|
|
5154
|
-
throw
|
|
5227
|
+
throw unsupportedCapability28({
|
|
5155
5228
|
dialect: dialect.name,
|
|
5156
5229
|
feature: "a named-constraint conflict target (ON CONFLICT ON CONSTRAINT)",
|
|
5157
5230
|
hint: "only postgres names constraints in conflict targets \u2014 use a column-list target"
|
|
@@ -5167,7 +5240,7 @@ function renderInsert(params) {
|
|
|
5167
5240
|
text += ` ON CONFLICT${target} DO NOTHING`;
|
|
5168
5241
|
} else {
|
|
5169
5242
|
if (onConflict.constraint !== undefined || onConflict.conflictWhere !== undefined) {
|
|
5170
|
-
throw
|
|
5243
|
+
throw unsupportedCapability28({
|
|
5171
5244
|
dialect: dialect.name,
|
|
5172
5245
|
feature: "a refined conflict target (constraint / partial-index predicate) on ON DUPLICATE KEY UPDATE",
|
|
5173
5246
|
hint: "mysql skips on any duplicate key \u2014 drop the refinement or gate the call per dialect"
|
|
@@ -5175,52 +5248,69 @@ function renderInsert(params) {
|
|
|
5175
5248
|
}
|
|
5176
5249
|
const keepName = onConflict.keepColumn ?? statement.columns[0];
|
|
5177
5250
|
if (keepName === undefined) {
|
|
5178
|
-
throw
|
|
5251
|
+
throw internalError4({ message: "a skip-duplicates insert of an all-default row must name its keepColumn" });
|
|
5179
5252
|
}
|
|
5180
5253
|
const keep = dialect.quoteIdent({ name: keepName });
|
|
5181
5254
|
const current = `${dialect.quoteIdent({ name: statement.table.name })}.${keep}`;
|
|
5182
5255
|
const flag = onConflict.duplicateFlag;
|
|
5183
5256
|
if (flag !== undefined && !/^\d{1,20}$/.test(flag)) {
|
|
5184
|
-
throw
|
|
5257
|
+
throw internalError4({ message: `duplicateFlag must be a decimal literal, got ${JSON.stringify(flag)}` });
|
|
5185
5258
|
}
|
|
5186
5259
|
text += flag === undefined ? ` ON DUPLICATE KEY UPDATE ${keep} = ${current}` : ` ON DUPLICATE KEY UPDATE ${keep} = IF(LAST_INSERT_ID(${flag}), ${current}, ${current})`;
|
|
5187
5260
|
}
|
|
5188
5261
|
} else {
|
|
5189
5262
|
const updates = Object.entries(onConflict.update);
|
|
5190
5263
|
if (updates.length === 0) {
|
|
5191
|
-
throw
|
|
5264
|
+
throw internalError4({ message: "upsert update must set at least one column" });
|
|
5192
5265
|
}
|
|
5193
5266
|
const selfRef = dialect.quoteIdent({ name: statement.table.name });
|
|
5194
5267
|
const assignments = renderAssignments({ dialect, entries: updates, collector, selfRef, allowExcluded: true, tableName: statement.table.name });
|
|
5195
5268
|
if (dialect.upsertForm === "onConflict") {
|
|
5196
5269
|
if (onConflict.lastInsertIdColumn !== undefined) {
|
|
5197
|
-
throw
|
|
5270
|
+
throw internalError4({ message: "lastInsertIdColumn is a mysql (onDuplicateKey) construct" });
|
|
5198
5271
|
}
|
|
5199
5272
|
if (onConflict.constraint !== undefined && dialect.name !== "postgres") {
|
|
5200
|
-
throw
|
|
5273
|
+
throw unsupportedCapability28({
|
|
5201
5274
|
dialect: dialect.name,
|
|
5202
5275
|
feature: "a named-constraint conflict target (ON CONFLICT ON CONSTRAINT)",
|
|
5203
5276
|
hint: "sqlite conflict targets are column lists \u2014 name the indexed columns instead"
|
|
5204
5277
|
});
|
|
5205
5278
|
}
|
|
5206
5279
|
if (onConflict.constraint !== undefined && onConflict.conflictWhere !== undefined) {
|
|
5207
|
-
throw
|
|
5280
|
+
throw internalError4({
|
|
5208
5281
|
message: "a named-constraint conflict target already identifies the index \u2014 it cannot carry a partial predicate too"
|
|
5209
5282
|
});
|
|
5210
5283
|
}
|
|
5211
5284
|
const partial = onConflict.conflictWhere === undefined ? "" : ` WHERE ${onConflict.conflictWhere}`;
|
|
5212
5285
|
const target = onConflict.constraint !== undefined ? ` ON CONSTRAINT ${dialect.quoteIdent({ name: onConflict.constraint })}` : ` (${onConflict.columns.map((name) => dialect.quoteIdent({ name })).join(", ")})${partial}`;
|
|
5213
5286
|
text += ` ON CONFLICT${target} DO UPDATE SET ${assignments}`;
|
|
5287
|
+
if (onConflict.updateWhere !== undefined) {
|
|
5288
|
+
if (!dialect.capabilities.conflictUpdateWhere) {
|
|
5289
|
+
throw unsupportedCapability28({
|
|
5290
|
+
dialect: dialect.name,
|
|
5291
|
+
feature: "a guarded conflict update (ON CONFLICT \u2026 DO UPDATE \u2026 WHERE)",
|
|
5292
|
+
hint: "run the guarded upsert as a find-then-write in a transaction instead"
|
|
5293
|
+
});
|
|
5294
|
+
}
|
|
5295
|
+
text += ` WHERE ${renderExpr({ dialect, expr: onConflict.updateWhere, collector })}`;
|
|
5296
|
+
}
|
|
5214
5297
|
} else {
|
|
5298
|
+
if (onConflict.updateWhere !== undefined) {
|
|
5299
|
+
throw unsupportedCapability28({
|
|
5300
|
+
dialect: dialect.name,
|
|
5301
|
+
feature: "a guarded conflict update (ON DUPLICATE KEY UPDATE has no WHERE)",
|
|
5302
|
+
hint: "run the guarded upsert as a find-then-write in a transaction instead \u2014 the runtime does this when the dialect lacks conflictUpdateWhere"
|
|
5303
|
+
});
|
|
5304
|
+
}
|
|
5215
5305
|
if (onConflict.constraint !== undefined) {
|
|
5216
|
-
throw
|
|
5306
|
+
throw unsupportedCapability28({
|
|
5217
5307
|
dialect: dialect.name,
|
|
5218
5308
|
feature: "a named-constraint conflict target on ON DUPLICATE KEY UPDATE",
|
|
5219
5309
|
hint: "mysql's ODKU fires on any duplicate key \u2014 no target can be named"
|
|
5220
5310
|
});
|
|
5221
5311
|
}
|
|
5222
5312
|
if (onConflict.conflictWhere !== undefined) {
|
|
5223
|
-
throw
|
|
5313
|
+
throw unsupportedCapability28({
|
|
5224
5314
|
dialect: dialect.name,
|
|
5225
5315
|
feature: "a partial-index conflict target on ON DUPLICATE KEY UPDATE",
|
|
5226
5316
|
hint: "mysql's ODKU fires on any duplicate key \u2014 a partial arbiter cannot be selected; gate the call per dialect"
|
|
@@ -5238,7 +5328,7 @@ function renderUpdate(params) {
|
|
|
5238
5328
|
const { dialect, statement, collector } = params;
|
|
5239
5329
|
const assignments = Object.entries(statement.set);
|
|
5240
5330
|
if (assignments.length === 0) {
|
|
5241
|
-
throw
|
|
5331
|
+
throw internalError4({ message: "update must set at least one column" });
|
|
5242
5332
|
}
|
|
5243
5333
|
const setSql = renderAssignments({ dialect, entries: assignments, collector, ...params.earlier === undefined ? {} : { steps: params.earlier } });
|
|
5244
5334
|
let text = `UPDATE ${renderTable(dialect, statement.table)} SET ${setSql}`;
|
|
@@ -5261,18 +5351,18 @@ function renderAssignments(params) {
|
|
|
5261
5351
|
const read = selfRef === undefined ? column : `${selfRef}.${column}`;
|
|
5262
5352
|
if (isStepColumnRef(value)) {
|
|
5263
5353
|
if (params.steps === undefined || !params.steps.has(value.step)) {
|
|
5264
|
-
throw
|
|
5354
|
+
throw internalError4({ message: `an UPDATE set value reads step "${value.step}", which is not an earlier chain step` });
|
|
5265
5355
|
}
|
|
5266
5356
|
return `${column} = (SELECT ${dialect.quoteIdent({ name: value.column })} FROM ${dialect.quoteIdent({ name: value.step })})`;
|
|
5267
5357
|
}
|
|
5268
5358
|
if (isSqlFragment(value)) {
|
|
5269
5359
|
if (params.allowExcluded !== true || selfRef === undefined)
|
|
5270
|
-
throw
|
|
5360
|
+
throw internalError4({ message: "SQL assignment fragments require a conflict update" });
|
|
5271
5361
|
return `${column} = ${renderSqlFragment({ dialect, fragment: value, collector, conflict: { table: params.tableName } })}`;
|
|
5272
5362
|
}
|
|
5273
5363
|
if (isExcludedRef(value)) {
|
|
5274
5364
|
if (params.allowExcluded !== true) {
|
|
5275
|
-
throw
|
|
5365
|
+
throw internalError4({
|
|
5276
5366
|
message: `an incoming-row reference (${value.column}) is only meaningful inside an upsert's update arm`
|
|
5277
5367
|
});
|
|
5278
5368
|
}
|
|
@@ -5280,7 +5370,7 @@ function renderAssignments(params) {
|
|
|
5280
5370
|
}
|
|
5281
5371
|
if (isSqlKeepCell(value)) {
|
|
5282
5372
|
if (params.allowExcluded !== true || selfRef === undefined)
|
|
5283
|
-
throw
|
|
5373
|
+
throw internalError4({ message: "a keep-column cell is only meaningful inside an upsert's update arm" });
|
|
5284
5374
|
return `${column} = ${read}`;
|
|
5285
5375
|
}
|
|
5286
5376
|
if (isJsonParamCell(value)) {
|
|
@@ -5318,19 +5408,19 @@ var CHAIN_ONE_ALIAS = "__vibe_one";
|
|
|
5318
5408
|
function renderChain(params) {
|
|
5319
5409
|
const { dialect, statement, collector } = params;
|
|
5320
5410
|
if (dialect.statementChain === null) {
|
|
5321
|
-
throw
|
|
5411
|
+
throw unsupportedCapability28({
|
|
5322
5412
|
dialect: dialect.name,
|
|
5323
5413
|
feature: "a statement chain (data-modifying WITH steps)",
|
|
5324
5414
|
hint: "this dialect accepts only SELECT inside WITH \u2014 gate on SqlDialect.statementChain and keep the multi-statement path"
|
|
5325
5415
|
});
|
|
5326
5416
|
}
|
|
5327
5417
|
if (statement.steps.length === 0)
|
|
5328
|
-
throw
|
|
5418
|
+
throw internalError4({ message: "a statement chain needs at least one step" });
|
|
5329
5419
|
const defined = new Set;
|
|
5330
5420
|
const steps = [];
|
|
5331
5421
|
for (const step of statement.steps) {
|
|
5332
5422
|
if (step.name === CHAIN_ROWS_ALIAS || step.name === CHAIN_ONE_ALIAS || defined.has(step.name)) {
|
|
5333
|
-
throw
|
|
5423
|
+
throw internalError4({ message: `chain step name "${step.name}" is reserved or repeated` });
|
|
5334
5424
|
}
|
|
5335
5425
|
const body = renderChainStep({ dialect, statement: step.statement, collector, earlier: defined });
|
|
5336
5426
|
steps.push(`${dialect.quoteIdent({ name: step.name })} AS (${body})`);
|
|
@@ -5338,11 +5428,11 @@ function renderChain(params) {
|
|
|
5338
5428
|
}
|
|
5339
5429
|
const result = statement.result;
|
|
5340
5430
|
if (result.rowsFrom.length === 0 || result.columns.length === 0) {
|
|
5341
|
-
throw
|
|
5431
|
+
throw internalError4({ message: "a chain result needs at least one source step and one column" });
|
|
5342
5432
|
}
|
|
5343
5433
|
for (const name of result.rowsFrom) {
|
|
5344
5434
|
if (!defined.has(name))
|
|
5345
|
-
throw
|
|
5435
|
+
throw internalError4({ message: `chain result reads undefined step "${name}"` });
|
|
5346
5436
|
}
|
|
5347
5437
|
const columnList = result.columns.map((name) => dialect.quoteIdent({ name })).join(", ");
|
|
5348
5438
|
const union = result.rowsFrom.map((name) => `SELECT ${columnList} FROM ${dialect.quoteIdent({ name })}`).join(" UNION ALL ");
|
|
@@ -5351,7 +5441,7 @@ function renderChain(params) {
|
|
|
5351
5441
|
const extra = [];
|
|
5352
5442
|
for (const alias of [result.verdict?.alias, result.tally?.alias]) {
|
|
5353
5443
|
if (alias !== undefined && result.columns.includes(alias)) {
|
|
5354
|
-
throw
|
|
5444
|
+
throw internalError4({ message: `chain result alias "${alias}" collides with a result column` });
|
|
5355
5445
|
}
|
|
5356
5446
|
}
|
|
5357
5447
|
const rows = dialect.quoteIdent({ name: CHAIN_ROWS_ALIAS });
|
|
@@ -5388,21 +5478,21 @@ function renderSelectCell(params) {
|
|
|
5388
5478
|
if (isDbNowMarker(value))
|
|
5389
5479
|
return dialect.renderDbNow({ offsetSeconds: value.offsetSeconds, collector });
|
|
5390
5480
|
if (isSqlDefaultCell(value)) {
|
|
5391
|
-
throw
|
|
5481
|
+
throw internalError4({ message: "DEFAULT is not allowed in an INSERT \u2026 SELECT list \u2014 omit the column instead" });
|
|
5392
5482
|
}
|
|
5393
5483
|
return collector.add(value);
|
|
5394
5484
|
}
|
|
5395
5485
|
function renderRowSource(params) {
|
|
5396
5486
|
const { dialect, source, collector } = params;
|
|
5397
5487
|
if (source.columns.length === 0 || source.rows.length === 0) {
|
|
5398
|
-
throw
|
|
5488
|
+
throw internalError4({ message: "a row source needs at least one column and one row" });
|
|
5399
5489
|
}
|
|
5400
5490
|
const typedBy = renderTable(dialect, source.typedBy);
|
|
5401
5491
|
const columns = source.columns.map((name) => dialect.quoteIdent({ name }));
|
|
5402
5492
|
const rows = [`(${columns.map((column) => `(SELECT ${column} FROM ${typedBy} WHERE FALSE)`).join(", ")})`];
|
|
5403
5493
|
for (const row of source.rows) {
|
|
5404
5494
|
if (row.length !== source.columns.length) {
|
|
5405
|
-
throw
|
|
5495
|
+
throw internalError4({ message: `row source row has ${row.length} values but ${source.columns.length} columns` });
|
|
5406
5496
|
}
|
|
5407
5497
|
rows.push(`(${row.map((value) => renderSelectCell({ dialect, value, collector })).join(", ")})`);
|
|
5408
5498
|
}
|
|
@@ -5414,12 +5504,12 @@ function renderTallyColumn(params) {
|
|
|
5414
5504
|
const { dialect, result, defined, collector } = params;
|
|
5415
5505
|
const tally = result.tally;
|
|
5416
5506
|
if (tally === undefined)
|
|
5417
|
-
throw
|
|
5507
|
+
throw internalError4({ message: "a chain veto needs a tally column to guard" });
|
|
5418
5508
|
if (tally.steps.length === 0)
|
|
5419
|
-
throw
|
|
5509
|
+
throw internalError4({ message: "a chain tally needs at least one step" });
|
|
5420
5510
|
const step = (name) => {
|
|
5421
5511
|
if (!defined.has(name))
|
|
5422
|
-
throw
|
|
5512
|
+
throw internalError4({ message: `chain tally or veto reads undefined step "${name}"` });
|
|
5423
5513
|
return dialect.quoteIdent({ name });
|
|
5424
5514
|
};
|
|
5425
5515
|
const count = (name) => `(SELECT count(*) FROM ${step(name)})`;
|
|
@@ -5429,12 +5519,12 @@ function renderTallyColumn(params) {
|
|
|
5429
5519
|
return `${sum} AS ${dialect.quoteIdent({ name: tally.alias })}`;
|
|
5430
5520
|
const arms = vetoes.map((veto) => {
|
|
5431
5521
|
if (!CHAIN_VETO_TOKEN_PATTERN.test(veto.token))
|
|
5432
|
-
throw
|
|
5522
|
+
throw internalError4({ message: `chain veto token "${veto.token}" is not a lower-case word` });
|
|
5433
5523
|
if (typeof veto.nonce !== "string" || veto.nonce === "")
|
|
5434
|
-
throw
|
|
5524
|
+
throw internalError4({ message: `chain veto "${veto.token}" needs a non-empty nonce` });
|
|
5435
5525
|
const minRows = veto.minRows ?? 1;
|
|
5436
5526
|
if (!Number.isSafeInteger(minRows) || minRows < 1)
|
|
5437
|
-
throw
|
|
5527
|
+
throw internalError4({ message: `chain veto "${veto.token}" needs a positive integer minRows` });
|
|
5438
5528
|
const when = minRows === 1 ? `WHEN NOT EXISTS (SELECT 1 FROM ${step(veto.step)})` : `WHEN ${count(veto.step)} < ${minRows}`;
|
|
5439
5529
|
return `${when} THEN CAST('${CHAIN_VETO_PREFIX}${veto.token}:' || ${collector.add(veto.nonce)} || ':' || ${count(veto.step)} AS integer)`;
|
|
5440
5530
|
});
|
|
@@ -5443,25 +5533,25 @@ function renderTallyColumn(params) {
|
|
|
5443
5533
|
function renderInsertSelect(params) {
|
|
5444
5534
|
const { dialect, statement, collector } = params;
|
|
5445
5535
|
if (statement.columns.length === 0)
|
|
5446
|
-
throw
|
|
5536
|
+
throw internalError4({ message: "insert requires at least one column" });
|
|
5447
5537
|
if (statement.cells.length !== statement.columns.length) {
|
|
5448
|
-
throw
|
|
5538
|
+
throw internalError4({
|
|
5449
5539
|
message: `insert row has ${statement.cells.length} values but ${statement.columns.length} columns`
|
|
5450
5540
|
});
|
|
5451
5541
|
}
|
|
5452
5542
|
const from = statement.from ?? [];
|
|
5453
5543
|
for (const name of from) {
|
|
5454
5544
|
if (!params.earlier.has(name))
|
|
5455
|
-
throw
|
|
5545
|
+
throw internalError4({ message: `INSERT \u2026 SELECT reads step "${name}" before it is defined` });
|
|
5456
5546
|
}
|
|
5457
5547
|
const source = statement.source;
|
|
5458
5548
|
if (source !== undefined && (params.earlier.has(source.alias) || from.includes(source.alias))) {
|
|
5459
|
-
throw
|
|
5549
|
+
throw internalError4({ message: `row source alias "${source.alias}" collides with a chain step` });
|
|
5460
5550
|
}
|
|
5461
5551
|
const cells = statement.cells.map((value) => {
|
|
5462
5552
|
if (isStepColumnRef(value)) {
|
|
5463
5553
|
if (!from.includes(value.step) && value.step !== source?.alias) {
|
|
5464
|
-
throw
|
|
5554
|
+
throw internalError4({ message: `cell reads step "${value.step}", which the INSERT \u2026 SELECT does not name in FROM` });
|
|
5465
5555
|
}
|
|
5466
5556
|
return `${dialect.quoteIdent({ name: value.step })}.${dialect.quoteIdent({ name: value.column })}`;
|
|
5467
5557
|
}
|
|
@@ -5480,9 +5570,9 @@ function renderInsertSelect(params) {
|
|
|
5480
5570
|
const conflict = statement.conflictDoNothing;
|
|
5481
5571
|
if (conflict !== undefined) {
|
|
5482
5572
|
if (conflict.columns.length === 0)
|
|
5483
|
-
throw
|
|
5573
|
+
throw internalError4({ message: "an INSERT \u2026 SELECT conflict clause needs at least one column" });
|
|
5484
5574
|
if (dialect.doNothingForm !== "onConflictDoNothing") {
|
|
5485
|
-
throw
|
|
5575
|
+
throw unsupportedCapability28({
|
|
5486
5576
|
dialect: dialect.name,
|
|
5487
5577
|
feature: "ON CONFLICT DO NOTHING on an INSERT \u2026 SELECT chain step",
|
|
5488
5578
|
hint: "gate on SqlDialect.statementChain and keep the multi-statement path"
|
|
@@ -5493,7 +5583,7 @@ function renderInsertSelect(params) {
|
|
|
5493
5583
|
return text + applyReturning({ dialect, requested: statement.returning }).suffix;
|
|
5494
5584
|
}
|
|
5495
5585
|
// packages/sql/src/dialects/postgres-type-identity.ts
|
|
5496
|
-
import { unsupportedCapability as
|
|
5586
|
+
import { unsupportedCapability as unsupportedCapability29 } from "@vibeorm/schema";
|
|
5497
5587
|
var IDENTIFIER = '(?:"(?:[^"\\x00]|"")+"|[a-zA-Z_][a-zA-Z_0-9$]*)';
|
|
5498
5588
|
var MODIFIER_VALUE = `(?:[+-]?\\d+|${IDENTIFIER}|'(?:[^'\\x00]|'')*')`;
|
|
5499
5589
|
var TYPE_NAME = new RegExp(`^\\s*(${IDENTIFIER})(?:\\s*\\.\\s*(${IDENTIFIER}))?\\s*(\\(\\s*${MODIFIER_VALUE}(?:\\s*,\\s*${MODIFIER_VALUE})*\\s*\\))?\\s*((?:\\[\\s*\\]\\s*)*)$`);
|
|
@@ -5520,13 +5610,13 @@ function parsePostgresTypeName(params) {
|
|
|
5520
5610
|
}
|
|
5521
5611
|
function renderPostgresTypeName(params) {
|
|
5522
5612
|
if (params.dialect.name !== "postgres")
|
|
5523
|
-
throw
|
|
5613
|
+
throw unsupportedCapability29({ dialect: params.dialect.name, feature: "postgresTypeIdentity" });
|
|
5524
5614
|
const { dialect, type } = params;
|
|
5525
5615
|
return `${type.namespace === undefined ? "" : `${dialect.quoteIdent({ name: type.namespace })}.`}${dialect.quoteIdent({ name: type.name })}${type.modifier}${type.array ? "[]" : ""}`;
|
|
5526
5616
|
}
|
|
5527
5617
|
function renderPostgresTypeIdentity(params) {
|
|
5528
5618
|
if (params.dialect.name !== "postgres")
|
|
5529
|
-
throw
|
|
5619
|
+
throw unsupportedCapability29({ dialect: params.dialect.name, feature: "postgresTypeIdentity" });
|
|
5530
5620
|
const collector = new ParamCollector(params.dialect);
|
|
5531
5621
|
const { source } = params;
|
|
5532
5622
|
let text;
|
|
@@ -5539,11 +5629,11 @@ function renderPostgresTypeIdentity(params) {
|
|
|
5539
5629
|
return { text, values: collector.values, returning: "none" };
|
|
5540
5630
|
}
|
|
5541
5631
|
// packages/sql/src/dialects/postgres-default-identity.ts
|
|
5542
|
-
import { unsupportedCapability as
|
|
5632
|
+
import { unsupportedCapability as unsupportedCapability30 } from "@vibeorm/schema";
|
|
5543
5633
|
function renderPostgresDefaultFunctionIdentity(params) {
|
|
5544
5634
|
const { dialect, table, column } = params;
|
|
5545
5635
|
if (dialect.name !== "postgres")
|
|
5546
|
-
throw
|
|
5636
|
+
throw unsupportedCapability30({ dialect: dialect.name, feature: "defaultFunctionIdentity" });
|
|
5547
5637
|
const collector = new ParamCollector(dialect);
|
|
5548
5638
|
const namespace = collector.add(table.namespace);
|
|
5549
5639
|
const name = collector.add(table.name);
|
|
@@ -5567,28 +5657,28 @@ WHERE n.nspname = ${namespace} AND c.relname = ${name} AND a.attname = ${field}
|
|
|
5567
5657
|
};
|
|
5568
5658
|
}
|
|
5569
5659
|
// packages/sql/src/dialects/constraint-owned-index.ts
|
|
5570
|
-
import { unsupportedCapability as
|
|
5660
|
+
import { unsupportedCapability as unsupportedCapability31 } from "@vibeorm/schema";
|
|
5571
5661
|
function renderConstraintOwnedIndexDrop(params) {
|
|
5572
5662
|
if (params.dialect.name !== "postgres")
|
|
5573
|
-
throw
|
|
5663
|
+
throw unsupportedCapability31({ dialect: params.dialect.name, feature: "constraintOwnedIndexDrop" });
|
|
5574
5664
|
const quote = (name) => params.dialect.quoteIdent({ name });
|
|
5575
5665
|
return { text: `ALTER TABLE ${quote(params.table)} DROP CONSTRAINT ${quote(params.constraint)};`, values: [], returning: "none" };
|
|
5576
5666
|
}
|
|
5577
5667
|
// packages/sql/src/dialects/mysql-check-probe.ts
|
|
5578
|
-
import { unsupportedCapability as
|
|
5668
|
+
import { unsupportedCapability as unsupportedCapability32 } from "@vibeorm/schema";
|
|
5579
5669
|
function renderMysqlCheckProbe(params) {
|
|
5580
5670
|
if (params.dialect.name !== "mysql")
|
|
5581
|
-
throw
|
|
5671
|
+
throw unsupportedCapability32({ dialect: params.dialect.name, feature: "temporaryCheckProbe" });
|
|
5582
5672
|
const q = (name) => params.dialect.quoteIdent({ name });
|
|
5583
5673
|
const probe = q(params.probe);
|
|
5584
5674
|
switch (params.operation) {
|
|
5585
5675
|
case "clone":
|
|
5586
5676
|
if (params.table === undefined)
|
|
5587
|
-
throw
|
|
5677
|
+
throw unsupportedCapability32({ dialect: "mysql", feature: "temporaryCheckProbe", hint: "A source table is required" });
|
|
5588
5678
|
return { text: `CREATE TEMPORARY TABLE ${probe} LIKE ${q(params.table.namespace)}.${q(params.table.name)}`, values: [], returning: "none" };
|
|
5589
5679
|
case "add": {
|
|
5590
5680
|
if (params.expression === undefined || params.definition === undefined)
|
|
5591
|
-
throw
|
|
5681
|
+
throw unsupportedCapability32({ dialect: "mysql", feature: "temporaryCheckProbe", hint: "An authored expression and temporary clone definition are required" });
|
|
5592
5682
|
const parts = tableDefinitionParts({ sql: params.definition, backslashEscapes: true });
|
|
5593
5683
|
return { text: `CREATE TEMPORARY TABLE ${probe} (
|
|
5594
5684
|
${[...parts.clauses, `CONSTRAINT ${probe} CHECK (${params.expression})`].join(`,
|
|
@@ -5634,33 +5724,33 @@ function sqliteTableConstraints(params) {
|
|
|
5634
5724
|
return result;
|
|
5635
5725
|
}
|
|
5636
5726
|
// packages/sql/src/dialects/migration-visibility.ts
|
|
5637
|
-
import { unsupportedCapability as
|
|
5727
|
+
import { unsupportedCapability as unsupportedCapability34 } from "@vibeorm/schema";
|
|
5638
5728
|
|
|
5639
5729
|
// packages/sql/src/dialects/migration-inventory.ts
|
|
5640
|
-
import { unsupportedCapability as
|
|
5730
|
+
import { unsupportedCapability as unsupportedCapability33 } from "@vibeorm/schema";
|
|
5641
5731
|
var MYSQL_NO_ROW_LIMIT = " LIMIT 18446744073709551615";
|
|
5642
5732
|
function renderSqliteColumnInventory(params) {
|
|
5643
5733
|
if (params.dialect.name !== "sqlite")
|
|
5644
|
-
throw
|
|
5734
|
+
throw unsupportedCapability33({ dialect: params.dialect.name, feature: "sqliteColumnInventory" });
|
|
5645
5735
|
const collector = new ParamCollector(params.dialect);
|
|
5646
5736
|
return { text: `SELECT name, hidden, pk, dflt_value AS definition FROM pragma_table_xinfo(${collector.add(params.table)}, ${collector.add(params.namespace)}) ORDER BY cid`, values: collector.values, returning: "none" };
|
|
5647
5737
|
}
|
|
5648
5738
|
function renderSqliteForeignKeyInventory(params) {
|
|
5649
5739
|
if (params.dialect.name !== "sqlite")
|
|
5650
|
-
throw
|
|
5740
|
+
throw unsupportedCapability33({ dialect: params.dialect.name, feature: "sqliteForeignKeyInventory" });
|
|
5651
5741
|
const collector = new ParamCollector(params.dialect);
|
|
5652
5742
|
return { text: `SELECT id, seq, "from", "to", "table", on_update, on_delete, match FROM pragma_foreign_key_list(${collector.add(params.table)}, ${collector.add(params.namespace)}) ORDER BY id, seq`, values: collector.values, returning: "none" };
|
|
5653
5743
|
}
|
|
5654
5744
|
function renderSqliteColumnInventoryBatch(params) {
|
|
5655
5745
|
if (params.dialect.name !== "sqlite")
|
|
5656
|
-
throw
|
|
5746
|
+
throw unsupportedCapability33({ dialect: params.dialect.name, feature: "sqliteColumnInventory" });
|
|
5657
5747
|
const collector = new ParamCollector(params.dialect);
|
|
5658
5748
|
const request = params.dialect.quoteIdent({ name: "vibe_request" });
|
|
5659
5749
|
return { text: `SELECT j.key AS ${request}, x.name AS name, x.hidden AS hidden, x.pk AS pk, x.dflt_value AS definition FROM json_each(${collector.add(JSON.stringify(params.tables))}) j LEFT JOIN pragma_table_xinfo(j.value, ${collector.add(params.namespace)}) x ORDER BY j.key, x.cid`, values: collector.values, returning: "none" };
|
|
5660
5750
|
}
|
|
5661
5751
|
function renderSqliteForeignKeyInventoryBatch(params) {
|
|
5662
5752
|
if (params.dialect.name !== "sqlite")
|
|
5663
|
-
throw
|
|
5753
|
+
throw unsupportedCapability33({ dialect: params.dialect.name, feature: "sqliteForeignKeyInventory" });
|
|
5664
5754
|
const collector = new ParamCollector(params.dialect);
|
|
5665
5755
|
const request = params.dialect.quoteIdent({ name: "vibe_request" });
|
|
5666
5756
|
return { text: `SELECT j.key AS ${request}, f.id AS id, f.seq AS seq, f."from" AS "from", f."to" AS "to", f."table" AS "table", f.on_update AS on_update, f.on_delete AS on_delete, f.match AS match FROM json_each(${collector.add(JSON.stringify(params.tables))}) j LEFT JOIN pragma_foreign_key_list(j.value, ${collector.add(params.namespace)}) f ORDER BY j.key, f.id, f.seq`, values: collector.values, returning: "none" };
|
|
@@ -5673,15 +5763,15 @@ var SQLITE_INTROSPECTION_PRAGMA_ORDER = Object.freeze({
|
|
|
5673
5763
|
});
|
|
5674
5764
|
function renderSqliteIntrospectionPragmaBatch(params) {
|
|
5675
5765
|
if (params.dialect.name !== "sqlite")
|
|
5676
|
-
throw
|
|
5766
|
+
throw unsupportedCapability33({ dialect: params.dialect.name, feature: "sqliteIntrospectionPragmaBatch" });
|
|
5677
5767
|
const order = SQLITE_INTROSPECTION_PRAGMA_ORDER[params.pragma];
|
|
5678
5768
|
if (order === undefined)
|
|
5679
|
-
throw
|
|
5769
|
+
throw unsupportedCapability33({ dialect: "sqlite", feature: `introspectionPragma:${String(params.pragma)}` });
|
|
5680
5770
|
return { text: `SELECT j.key AS ${params.dialect.quoteIdent({ name: "vibe_request" })}, p.* FROM json_each(${params.dialect.quoteStringLiteral({ value: JSON.stringify(params.names) })}) j LEFT JOIN pragma_${params.pragma}(j.value) p ORDER BY j.key, ${order}`, values: [], returning: "none" };
|
|
5681
5771
|
}
|
|
5682
5772
|
function renderSqliteRebuildObjects(params) {
|
|
5683
5773
|
if (params.dialect.name !== "sqlite")
|
|
5684
|
-
throw
|
|
5774
|
+
throw unsupportedCapability33({ dialect: params.dialect.name, feature: "sqliteRebuildObjects" });
|
|
5685
5775
|
return { text: "SELECT name, tbl_name, type, sql FROM main.sqlite_schema WHERE type IN ('index', 'trigger') AND sql IS NOT NULL ORDER BY type, name", values: [], returning: "none" };
|
|
5686
5776
|
}
|
|
5687
5777
|
function renderMigrationInventory(params) {
|
|
@@ -5723,13 +5813,13 @@ ORDER BY kind, parent, name${MYSQL_NO_ROW_LIMIT}`, values: collector.values, ret
|
|
|
5723
5813
|
// packages/sql/src/dialects/migration-visibility.ts
|
|
5724
5814
|
function renderMigrationVisibility(params) {
|
|
5725
5815
|
if (params.dialect.name !== "mysql")
|
|
5726
|
-
throw
|
|
5816
|
+
throw unsupportedCapability34({ dialect: params.dialect.name, feature: "mysqlCatalogVisibility" });
|
|
5727
5817
|
const collector = new ParamCollector(params.dialect);
|
|
5728
5818
|
const grantee = "CONCAT(QUOTE(SUBSTRING_INDEX(CURRENT_USER(), '@', 1)), '@', QUOTE(SUBSTRING_INDEX(CURRENT_USER(), '@', -1)))";
|
|
5729
5819
|
return { text: `SELECT PRIVILEGE_TYPE AS privilege FROM information_schema.USER_PRIVILEGES WHERE GRANTEE = ${grantee} UNION SELECT PRIVILEGE_TYPE AS privilege FROM information_schema.SCHEMA_PRIVILEGES WHERE GRANTEE = ${grantee} AND ${collector.add(params.namespace)} LIKE TABLE_SCHEMA${MYSQL_NO_ROW_LIMIT}`, values: collector.values, returning: "none" };
|
|
5730
5820
|
}
|
|
5731
5821
|
// packages/sql/src/dialects/migration-objects.ts
|
|
5732
|
-
import { internalError as
|
|
5822
|
+
import { internalError as internalError5, unsupportedCapability as unsupportedCapability35 } from "@vibeorm/schema";
|
|
5733
5823
|
function renderMigrationObjectQuery(params) {
|
|
5734
5824
|
return objectQuery({ ...params, collector: new ParamCollector(params.dialect) });
|
|
5735
5825
|
}
|
|
@@ -5737,7 +5827,7 @@ function objectQuery(params) {
|
|
|
5737
5827
|
const { dialect, identity: object, collector } = params;
|
|
5738
5828
|
if (object.kind === "namespace") {
|
|
5739
5829
|
if (dialect.name !== "postgres")
|
|
5740
|
-
throw
|
|
5830
|
+
throw unsupportedCapability35({ dialect: dialect.name, feature: "fixedNamespaces" });
|
|
5741
5831
|
return { text: `SELECT n.nspname::text AS "name" FROM pg_catalog.pg_namespace n WHERE n.nspname = ${collector.add(object.name)}`, values: collector.values, returning: "none" };
|
|
5742
5832
|
}
|
|
5743
5833
|
const physical = "table" in object ? object.table : object.name;
|
|
@@ -5785,18 +5875,18 @@ function objectQuery(params) {
|
|
|
5785
5875
|
}
|
|
5786
5876
|
} else if (dialect.name === "mysql") {
|
|
5787
5877
|
if (object.kind === "constraint" && object.constraintType === "exclusion")
|
|
5788
|
-
throw
|
|
5878
|
+
throw unsupportedCapability35({ dialect: "mysql", feature: "exclusionConstraints" });
|
|
5789
5879
|
const mysql = mysqlFactsText({ dialect, identity: object, namespace, name, collector });
|
|
5790
5880
|
if (mysql === undefined)
|
|
5791
|
-
throw
|
|
5881
|
+
throw unsupportedCapability35({ dialect: "mysql", feature: `inspect:${object.kind}` });
|
|
5792
5882
|
text = mysql;
|
|
5793
5883
|
} else {
|
|
5794
5884
|
if (physical.namespace !== "main" && physical.namespace !== "temp")
|
|
5795
|
-
throw
|
|
5885
|
+
throw unsupportedCapability35({ dialect: "sqlite", feature: "attachedSchemaInspection" });
|
|
5796
5886
|
const catalog = `${dialect.quoteIdent({ name: physical.namespace })}.sqlite_schema`;
|
|
5797
5887
|
const kind = object.kind === "table" || object.kind === "view" ? object.kind : object.kind === "trigger" ? "trigger" : object.kind === "index" ? "index" : "table";
|
|
5798
5888
|
if (["function", "sequence", "postgresExtension", "enum"].includes(object.kind) || object.kind === "constraint" && object.constraintType === "exclusion")
|
|
5799
|
-
throw
|
|
5889
|
+
throw unsupportedCapability35({ dialect: "sqlite", feature: `inspect:${object.kind}` });
|
|
5800
5890
|
const sqliteParams = new ParamCollector(dialect);
|
|
5801
5891
|
if (object.kind === "column" || object.kind === "columnDefault" || object.kind === "generatedColumn") {
|
|
5802
5892
|
text = `SELECT x.type AS type, x."notnull" AS "notNull", x.pk AS primaryKeyPosition, x.hidden AS generated, x.dflt_value AS definition, (SELECT sql FROM ${catalog} WHERE name = ${sqliteParams.add(physical.name)} AND type = 'table') AS tableDefinition FROM pragma_table_xinfo(${sqliteParams.add(physical.name)}, ${sqliteParams.add(physical.namespace)}) x WHERE x.name = ${sqliteParams.add(object.column)}`;
|
|
@@ -5871,7 +5961,7 @@ function mysqlBatches(params) {
|
|
|
5871
5961
|
function renderMysqlObjectBatch(params) {
|
|
5872
5962
|
const { dialect } = params;
|
|
5873
5963
|
if (dialect.name !== "mysql")
|
|
5874
|
-
throw
|
|
5964
|
+
throw unsupportedCapability35({ dialect: dialect.name, feature: "batchedMigrationInspection" });
|
|
5875
5965
|
const position = dialect.quoteIdent({ name: "vibe_position" });
|
|
5876
5966
|
const groups = new Map;
|
|
5877
5967
|
for (const [index, identity] of params.identities.entries()) {
|
|
@@ -5891,7 +5981,7 @@ function renderMysqlObjectBatch(params) {
|
|
|
5891
5981
|
function renderMysqlObjectMembersBatch(params) {
|
|
5892
5982
|
const { dialect } = params;
|
|
5893
5983
|
if (dialect.name !== "mysql")
|
|
5894
|
-
throw
|
|
5984
|
+
throw unsupportedCapability35({ dialect: dialect.name, feature: "batchedMigrationInspection" });
|
|
5895
5985
|
const position = dialect.quoteIdent({ name: "vibe_position" });
|
|
5896
5986
|
const ordinal = dialect.quoteIdent({ name: "vibe_ordinal" });
|
|
5897
5987
|
const groups = new Map;
|
|
@@ -5911,7 +6001,7 @@ function renderMigrationDependencies(params) {
|
|
|
5911
6001
|
}
|
|
5912
6002
|
function dependencyQuery(params) {
|
|
5913
6003
|
if (params.dialect.name !== "postgres")
|
|
5914
|
-
throw
|
|
6004
|
+
throw unsupportedCapability35({ dialect: params.dialect.name, feature: "catalogDependencies" });
|
|
5915
6005
|
const object = params.identity;
|
|
5916
6006
|
const collector = params.collector;
|
|
5917
6007
|
if (object.kind === "namespace") {
|
|
@@ -5968,7 +6058,7 @@ function inspectionReferences(params) {
|
|
|
5968
6058
|
function renderMigrationObjectBatch(params) {
|
|
5969
6059
|
const { dialect } = params;
|
|
5970
6060
|
if (dialect.name !== "postgres")
|
|
5971
|
-
throw
|
|
6061
|
+
throw unsupportedCapability35({ dialect: dialect.name, feature: "batchedMigrationInspection" });
|
|
5972
6062
|
const groups = new Map;
|
|
5973
6063
|
for (const [position, identity] of params.identities.entries()) {
|
|
5974
6064
|
const kind = identity.kind === "constraint" ? `${identity.kind}:${identity.constraintType}` : identity.kind === "generatedColumn" ? "columnDefault" : identity.kind;
|
|
@@ -5981,7 +6071,7 @@ function renderMigrationObjectBatch(params) {
|
|
|
5981
6071
|
const facts = objectQuery({ dialect, identity, collector: inspectionReferences({ dialect }) });
|
|
5982
6072
|
const dependencies = dependencyQuery({ dialect, identity, collector: inspectionReferences({ dialect }) });
|
|
5983
6073
|
if (JSON.stringify(dependencies.values) !== JSON.stringify(facts.values))
|
|
5984
|
-
throw
|
|
6074
|
+
throw internalError5({ message: "Batched catalog queries bind their identity in different orders", meta: { kind: identity.kind } });
|
|
5985
6075
|
const columns = facts.values.map((value, index) => `${dialect.quoteIdent({ name: `p${index + 1}` })} ${Array.isArray(value) ? "text[]" : "text"}`);
|
|
5986
6076
|
const requests = group.map(({ identity, position }) => ({ position, ...Object.fromEntries(renderMigrationObjectQuery({ dialect, identity }).values.map((value, index) => [`p${index + 1}`, value])) }));
|
|
5987
6077
|
const collector = new ParamCollector(dialect);
|
|
@@ -6001,16 +6091,16 @@ function renderMigrationNamespace(params) {
|
|
|
6001
6091
|
}
|
|
6002
6092
|
function renderCheckProbe(params) {
|
|
6003
6093
|
if (params.dialect.name !== "postgres")
|
|
6004
|
-
throw
|
|
6094
|
+
throw unsupportedCapability35({ dialect: params.dialect.name, feature: "rollbackCheckProbe" });
|
|
6005
6095
|
const q = (name) => params.dialect.quoteIdent({ name });
|
|
6006
6096
|
return { text: `ALTER TABLE ${q(params.table.namespace)}.${q(params.table.name)} ADD CONSTRAINT ${q(params.name)} CHECK (${params.expression}) NOT VALID`, values: [], returning: "none" };
|
|
6007
6097
|
}
|
|
6008
6098
|
// packages/sql/src/dialects/postgres-migration.ts
|
|
6009
|
-
import { VibeError as
|
|
6099
|
+
import { VibeError as VibeError24, unsupportedCapability as unsupportedCapability36 } from "@vibeorm/schema";
|
|
6010
6100
|
var SETTING_VALUE = /^[0-9]+(?:\.[0-9]+)?\s*(?:us|ms|s|min|h|d)?$/;
|
|
6011
6101
|
function requirePostgres2(params) {
|
|
6012
6102
|
if (params.dialect.name !== "postgres") {
|
|
6013
|
-
throw
|
|
6103
|
+
throw unsupportedCapability36({ dialect: params.dialect.name, feature: params.feature });
|
|
6014
6104
|
}
|
|
6015
6105
|
}
|
|
6016
6106
|
function renderMigrationSessionRead(params) {
|
|
@@ -6025,7 +6115,7 @@ function renderMigrationSessionSet(params) {
|
|
|
6025
6115
|
requirePostgres2({ dialect: params.dialect, feature: "migrationSessionSettings" });
|
|
6026
6116
|
const { milliseconds, setting } = params;
|
|
6027
6117
|
if (!Number.isSafeInteger(milliseconds) || milliseconds < 0) {
|
|
6028
|
-
throw new
|
|
6118
|
+
throw new VibeError24({
|
|
6029
6119
|
code: "VIBE_MIGRATION",
|
|
6030
6120
|
message: `${setting} must be a non-negative integer number of milliseconds (got ${String(milliseconds)})`,
|
|
6031
6121
|
meta: { reason: "execution-metadata-invalid", setting, value: milliseconds }
|
|
@@ -6196,6 +6286,7 @@ export {
|
|
|
6196
6286
|
isSqlParam,
|
|
6197
6287
|
isSqlQuery,
|
|
6198
6288
|
isStepColumnRef,
|
|
6289
|
+
isTimeZoneName,
|
|
6199
6290
|
jsonListParameter,
|
|
6200
6291
|
jsonParamCell,
|
|
6201
6292
|
keyListBindsUntypedRows,
|
|
@@ -6222,6 +6313,7 @@ export {
|
|
|
6222
6313
|
renderColumnStateQuery,
|
|
6223
6314
|
renderConstraintOwnedIndexDrop,
|
|
6224
6315
|
renderConstraintStateQuery,
|
|
6316
|
+
renderDateTruncation,
|
|
6225
6317
|
renderDiagnostic,
|
|
6226
6318
|
renderExclusionCatalog,
|
|
6227
6319
|
renderExclusionDdl,
|
|
@@ -6322,4 +6414,4 @@ export {
|
|
|
6322
6414
|
toPgArrayLiteral
|
|
6323
6415
|
};
|
|
6324
6416
|
|
|
6325
|
-
//# debugId=
|
|
6417
|
+
//# debugId=7A09C0BE2E07A46664756E2164756E21
|