@vibeorm/sql 2.4.0 → 2.5.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 +5 -2
- package/dist/ast.d.ts.map +1 -1
- package/dist/dialects/external-dependents.d.ts +28 -0
- package/dist/dialects/external-dependents.d.ts.map +1 -0
- package/dist/dialects/external-ownership.d.ts +8 -0
- package/dist/dialects/external-ownership.d.ts.map +1 -0
- package/dist/dialects/migration-inventory.d.ts.map +1 -1
- package/dist/dialects/migration-objects.d.ts.map +1 -1
- package/dist/dialects/migration-shadow.d.ts +5 -0
- package/dist/dialects/migration-shadow.d.ts.map +1 -1
- package/dist/dialects/postgres-index-keys.d.ts +9 -0
- package/dist/dialects/postgres-index-keys.d.ts.map +1 -0
- package/dist/dialects/postgres-physical-catalog.d.ts +11 -0
- package/dist/dialects/postgres-physical-catalog.d.ts.map +1 -0
- package/dist/exclusion.d.ts +2 -0
- package/dist/exclusion.d.ts.map +1 -1
- package/dist/index-columns.d.ts +15 -0
- package/dist/index-columns.d.ts.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +375 -189
- package/dist/index.js.map +18 -12
- package/dist/native-enum-parameter.d.ts +17 -0
- package/dist/native-enum-parameter.d.ts.map +1 -0
- package/dist/params.d.ts.map +1 -1
- package/dist/render.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
// packages/sql/src/native-enum-parameter.ts
|
|
3
|
+
var NATIVE_ENUM_ARRAY_PARAMETER = Symbol("vibeorm.nativeEnumArrayParameter");
|
|
4
|
+
function nativeEnumArrayParameter(params) {
|
|
5
|
+
return { [NATIVE_ENUM_ARRAY_PARAMETER]: true, value: params.value, type: params.type };
|
|
6
|
+
}
|
|
7
|
+
function isNativeEnumArrayParameter(value) {
|
|
8
|
+
return typeof value === "object" && value !== null && NATIVE_ENUM_ARRAY_PARAMETER in value;
|
|
9
|
+
}
|
|
10
|
+
// packages/sql/src/dialects/external-ownership.ts
|
|
11
|
+
import { unsupportedCapability } from "@vibeorm/schema";
|
|
12
|
+
function renderExternalOwnershipCatalog(params) {
|
|
13
|
+
if (params.dialect.name !== "postgres")
|
|
14
|
+
throw unsupportedCapability({ dialect: params.dialect.name, feature: "externalObjects" });
|
|
15
|
+
const scope = "n.nspname <> 'information_schema' AND n.nspname NOT LIKE 'pg\\_%' ESCAPE '\\' AND n.nspname NOT IN ('_vibeorm_shadow', '_vibe_shadow')";
|
|
16
|
+
let text;
|
|
17
|
+
switch (params.operation) {
|
|
18
|
+
case "namespaces":
|
|
19
|
+
text = `SELECT n.nspname::text AS namespace, has_schema_privilege(n.oid, 'USAGE') AS visible FROM pg_catalog.pg_namespace n WHERE ${scope} ORDER BY n.nspname`;
|
|
20
|
+
break;
|
|
21
|
+
case "inheritance":
|
|
22
|
+
text = `SELECT n.nspname::text AS namespace, c.relname::text AS name, pn.nspname::text AS "parentNamespace", p.relname::text AS "parentName" FROM pg_catalog.pg_inherits i JOIN pg_catalog.pg_class c ON c.oid = i.inhrelid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace JOIN pg_catalog.pg_class p ON p.oid = i.inhparent JOIN pg_catalog.pg_namespace pn ON pn.oid = p.relnamespace WHERE ${scope} ORDER BY n.nspname, c.relname, pn.nspname, p.relname`;
|
|
23
|
+
break;
|
|
24
|
+
case "ownedSequences":
|
|
25
|
+
text = `SELECT n.nspname::text AS namespace, s.relname::text AS name, tn.nspname::text AS "tableNamespace", t.relname::text AS "tableName" FROM pg_catalog.pg_depend d JOIN pg_catalog.pg_class s ON s.oid = d.objid AND s.relkind = 'S' JOIN pg_catalog.pg_namespace n ON n.oid = s.relnamespace JOIN pg_catalog.pg_class t ON t.oid = d.refobjid JOIN pg_catalog.pg_namespace tn ON tn.oid = t.relnamespace WHERE d.classid = 'pg_class'::regclass AND d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i') AND d.refobjsubid > 0 AND ${scope} ORDER BY n.nspname, s.relname`;
|
|
26
|
+
break;
|
|
27
|
+
case "foreignKeys":
|
|
28
|
+
text = `SELECT n.nspname::text AS namespace, t.relname::text AS table, rn.nspname::text AS "refNamespace", r.relname::text AS "refTable", c.conname::text AS name FROM pg_catalog.pg_constraint c JOIN pg_catalog.pg_class t ON t.oid = c.conrelid JOIN pg_catalog.pg_namespace n ON n.oid = t.relnamespace JOIN pg_catalog.pg_class r ON r.oid = c.confrelid JOIN pg_catalog.pg_namespace rn ON rn.oid = r.relnamespace WHERE c.contype = 'f' AND ${scope} ORDER BY n.nspname, t.relname, c.conname`;
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
return { text, values: [], returning: "none" };
|
|
32
|
+
}
|
|
33
|
+
// packages/sql/src/dialects/external-dependents.ts
|
|
34
|
+
import { unsupportedCapability as unsupportedCapability3 } from "@vibeorm/schema";
|
|
35
|
+
|
|
2
36
|
// packages/sql/src/params.ts
|
|
37
|
+
import { unsupportedCapability as unsupportedCapability2 } from "@vibeorm/schema";
|
|
3
38
|
class ParamCollector {
|
|
4
39
|
dialect;
|
|
5
40
|
values;
|
|
@@ -8,6 +43,12 @@ class ParamCollector {
|
|
|
8
43
|
this.values = [];
|
|
9
44
|
}
|
|
10
45
|
add(value) {
|
|
46
|
+
if (isNativeEnumArrayParameter(value)) {
|
|
47
|
+
if (!this.dialect.capabilities.scalarArrays)
|
|
48
|
+
throw unsupportedCapability2({ dialect: this.dialect.name, feature: "scalarArrays" });
|
|
49
|
+
this.values.push(value.value);
|
|
50
|
+
return `${this.dialect.placeholder({ index: this.values.length })}::${this.dialect.quoteIdent({ name: value.type.namespace })}.${this.dialect.quoteIdent({ name: value.type.name })}[]`;
|
|
51
|
+
}
|
|
11
52
|
this.values.push(value);
|
|
12
53
|
return this.dialect.placeholder({ index: this.values.length });
|
|
13
54
|
}
|
|
@@ -16,6 +57,121 @@ class ParamCollector {
|
|
|
16
57
|
}
|
|
17
58
|
}
|
|
18
59
|
|
|
60
|
+
// packages/sql/src/dialects/external-dependents.ts
|
|
61
|
+
function renderExternalDependents(params) {
|
|
62
|
+
if (params.dialect.name !== "postgres")
|
|
63
|
+
throw unsupportedCapability3({ dialect: params.dialect.name, feature: "externalObjects" });
|
|
64
|
+
const collector = new ParamCollector(params.dialect);
|
|
65
|
+
const requests = params.targets.map((target, position) => ({ position, kind: target.kind, namespace: target.namespace, name: target.name, column: target.kind === "column" ? target.column : null }));
|
|
66
|
+
const request = collector.add(JSON.stringify(requests));
|
|
67
|
+
const text = `WITH request AS (
|
|
68
|
+
SELECT * FROM jsonb_to_recordset(${request}::text::jsonb) AS request(position integer, kind text, namespace text, name text, "column" text)
|
|
69
|
+
), target AS (
|
|
70
|
+
SELECT request.position, 'pg_type'::regclass AS classid, t.oid AS objid, NULL::integer AS objsubid FROM request JOIN pg_catalog.pg_namespace n ON n.nspname = request.namespace JOIN pg_catalog.pg_type t ON t.typnamespace = n.oid AND t.typname = request.name WHERE request.kind = 'type'
|
|
71
|
+
UNION ALL SELECT request.position, 'pg_class'::regclass, c.oid, a.attnum::integer FROM request JOIN pg_catalog.pg_namespace n ON n.nspname = request.namespace JOIN pg_catalog.pg_class c ON c.relnamespace = n.oid AND c.relname = request.name LEFT JOIN pg_catalog.pg_attribute a ON request.kind = 'column' AND a.attrelid = c.oid AND a.attname = request."column" AND NOT a.attisdropped WHERE request.kind = 'relation' OR request.kind = 'column' AND a.attnum IS NOT NULL
|
|
72
|
+
), owned AS (
|
|
73
|
+
SELECT position, classid, objid, objsubid FROM target
|
|
74
|
+
UNION SELECT target.position, 'pg_type'::regclass, c.reltype, NULL FROM target JOIN pg_catalog.pg_class c ON c.oid = target.objid WHERE target.classid = 'pg_class'::regclass AND target.objsubid IS NULL AND c.reltype <> 0
|
|
75
|
+
UNION SELECT target.position, 'pg_class'::regclass, s.oid, NULL FROM target JOIN pg_catalog.pg_depend sd ON sd.refclassid = target.classid AND sd.refobjid = target.objid AND (target.objsubid IS NULL OR sd.refobjsubid = target.objsubid) AND sd.classid = 'pg_class'::regclass AND sd.deptype IN ('a', 'i') JOIN pg_catalog.pg_class s ON s.oid = sd.objid AND s.relkind = 'S'
|
|
76
|
+
), referenced AS (
|
|
77
|
+
SELECT position, classid, objid, objsubid FROM owned
|
|
78
|
+
UNION SELECT owned.position, 'pg_type'::regclass, t.typarray, NULL FROM owned JOIN pg_catalog.pg_type t ON t.oid = owned.objid WHERE owned.classid = 'pg_type'::regclass AND t.typarray <> 0
|
|
79
|
+
)
|
|
80
|
+
SELECT DISTINCT referenced.position, dependent.type AS "dependentType", dependent.identity AS "dependentIdentity", ref.identity AS referenced, d.classid::regclass::text AS "dependentClass",
|
|
81
|
+
rn.nspname::text AS "relationNamespace", rel.relname::text AS "relationName", rel.relkind::text AS "relationKind", col.attname::text AS "columnName",
|
|
82
|
+
COALESCE(pn.nspname, tn.nspname, dependent.schema)::text AS "objectNamespace", COALESCE(p.proname, ty.typname)::text AS "objectName"
|
|
83
|
+
FROM referenced
|
|
84
|
+
JOIN pg_catalog.pg_depend d ON d.refclassid = referenced.classid AND d.refobjid = referenced.objid AND (referenced.objsubid IS NULL OR d.refobjsubid = referenced.objsubid) AND d.deptype = 'n'
|
|
85
|
+
CROSS JOIN LATERAL pg_catalog.pg_identify_object(d.classid, d.objid, d.objsubid) dependent
|
|
86
|
+
CROSS JOIN LATERAL pg_catalog.pg_identify_object(d.refclassid, d.refobjid, d.refobjsubid) ref
|
|
87
|
+
LEFT JOIN pg_catalog.pg_class self ON d.classid = 'pg_class'::regclass AND self.oid = d.objid
|
|
88
|
+
LEFT JOIN pg_catalog.pg_index ix ON ix.indexrelid = self.oid
|
|
89
|
+
LEFT JOIN pg_catalog.pg_attrdef ad ON d.classid = 'pg_attrdef'::regclass AND ad.oid = d.objid
|
|
90
|
+
LEFT JOIN pg_catalog.pg_rewrite rw ON d.classid = 'pg_rewrite'::regclass AND rw.oid = d.objid
|
|
91
|
+
LEFT JOIN pg_catalog.pg_trigger tg ON d.classid = 'pg_trigger'::regclass AND tg.oid = d.objid
|
|
92
|
+
LEFT JOIN pg_catalog.pg_constraint con ON d.classid = 'pg_constraint'::regclass AND con.oid = d.objid
|
|
93
|
+
LEFT JOIN pg_catalog.pg_policy pol ON d.classid = 'pg_policy'::regclass AND pol.oid = d.objid
|
|
94
|
+
LEFT JOIN pg_catalog.pg_type ty ON d.classid = 'pg_type'::regclass AND ty.oid = d.objid
|
|
95
|
+
LEFT JOIN pg_catalog.pg_namespace tn ON tn.oid = ty.typnamespace
|
|
96
|
+
LEFT JOIN pg_catalog.pg_proc p ON d.classid = 'pg_proc'::regclass AND p.oid = d.objid
|
|
97
|
+
LEFT JOIN pg_catalog.pg_namespace pn ON pn.oid = p.pronamespace
|
|
98
|
+
LEFT JOIN pg_catalog.pg_class rel ON rel.oid = COALESCE(ix.indrelid, self.oid, ad.adrelid, rw.ev_class, tg.tgrelid, NULLIF(con.conrelid, 0), pol.polrelid, NULLIF(ty.typrelid, 0))
|
|
99
|
+
LEFT JOIN pg_catalog.pg_namespace rn ON rn.oid = rel.relnamespace
|
|
100
|
+
LEFT JOIN pg_catalog.pg_attribute col ON col.attrelid = rel.oid AND col.attnum = CASE WHEN self.oid IS NOT NULL AND d.objsubid > 0 THEN d.objsubid WHEN ad.oid IS NOT NULL THEN ad.adnum END
|
|
101
|
+
ORDER BY 1, 2, 3, 4`;
|
|
102
|
+
return { text, values: collector.values, returning: "none" };
|
|
103
|
+
}
|
|
104
|
+
// packages/sql/src/dialects/postgres-physical-catalog.ts
|
|
105
|
+
import { unsupportedCapability as unsupportedCapability4 } from "@vibeorm/schema";
|
|
106
|
+
function renderPostgresPhysicalCatalog(params) {
|
|
107
|
+
const { dialect } = params;
|
|
108
|
+
if (dialect.name !== "postgres")
|
|
109
|
+
throw unsupportedCapability4({ dialect: dialect.name, feature: "postgresPhysicalCatalog" });
|
|
110
|
+
const collector = new ParamCollector(dialect);
|
|
111
|
+
const namespace = collector.add(params.namespace);
|
|
112
|
+
const extensionOwnedFilter = `NOT EXISTS (SELECT 1 FROM pg_catalog.pg_depend d JOIN pg_catalog.pg_class c ON c.oid = d.objid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE d.classid = 'pg_class'::regclass AND d.deptype = 'e' AND n.nspname = ${namespace} AND c.relname = table_name)`;
|
|
113
|
+
let text;
|
|
114
|
+
switch (params.query) {
|
|
115
|
+
case "tables":
|
|
116
|
+
text = `SELECT table_name FROM information_schema.tables WHERE table_schema = ${namespace} AND table_type = 'BASE TABLE' AND table_name <> '_vibe_migrations' AND ${extensionOwnedFilter} ORDER BY table_name`;
|
|
117
|
+
break;
|
|
118
|
+
case "views":
|
|
119
|
+
text = `SELECT table_name FROM information_schema.views WHERE table_schema = ${namespace} AND ${extensionOwnedFilter} ORDER BY table_name`;
|
|
120
|
+
break;
|
|
121
|
+
case "columns":
|
|
122
|
+
text = `SELECT table_name, column_name, data_type, udt_name, udt_schema, is_nullable, is_identity, is_generated, collation_name, column_default, datetime_precision, character_maximum_length, numeric_precision, numeric_scale, ordinal_position, (SELECT format_type(a.atttypid, a.atttypmod) FROM pg_attribute a JOIN pg_class c ON c.oid = a.attrelid JOIN pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = ${namespace} AND c.relname = columns.table_name AND a.attname = columns.column_name) AS full_type FROM information_schema.columns AS columns WHERE table_schema = ${namespace} ORDER BY table_name, ordinal_position`;
|
|
123
|
+
break;
|
|
124
|
+
case "constraints":
|
|
125
|
+
text = `SELECT c.conname AS constraint_name, CASE c.contype WHEN 'p' THEN 'PRIMARY KEY' ELSE 'UNIQUE' END AS constraint_type, cl.relname AS table_name, att.attname AS column_name FROM pg_catalog.pg_constraint c JOIN pg_catalog.pg_class cl ON cl.oid = c.conrelid JOIN pg_catalog.pg_namespace n ON n.oid = cl.relnamespace JOIN unnest(c.conkey) WITH ORDINALITY AS k(attnum, ord) ON true JOIN pg_catalog.pg_attribute att ON att.attrelid = c.conrelid AND att.attnum = k.attnum WHERE c.contype IN ('p', 'u') AND n.nspname = ${namespace} ORDER BY cl.relname, c.conname, k.ord`;
|
|
126
|
+
break;
|
|
127
|
+
case "checks":
|
|
128
|
+
text = `SELECT cl.relname AS table_name, c.conname AS constraint_name, pg_get_constraintdef(c.oid) AS definition FROM pg_catalog.pg_constraint c JOIN pg_catalog.pg_class cl ON cl.oid = c.conrelid JOIN pg_catalog.pg_namespace n ON n.oid = cl.relnamespace WHERE c.contype = 'c' AND n.nspname = ${namespace} ORDER BY cl.relname, c.conname`;
|
|
129
|
+
break;
|
|
130
|
+
case "foreignKeys":
|
|
131
|
+
text = `SELECT c.conname AS constraint_name, cl.relname AS table_name, att.attname AS column_name, fn.nspname AS foreign_namespace, fcl.relname AS foreign_table_name, fatt.attname AS foreign_column_name, c.confdeltype AS on_delete_char, c.confupdtype AS on_update_char, c.convalidated AS validated, c.condeferrable AS deferrable, (SELECT bool_and(t.tgenabled IN ('O', 'A')) FROM pg_catalog.pg_trigger t WHERE t.tgconstraint = c.oid) AS triggers_enabled FROM pg_catalog.pg_constraint c JOIN pg_catalog.pg_class cl ON cl.oid = c.conrelid JOIN pg_catalog.pg_namespace n ON n.oid = cl.relnamespace JOIN pg_catalog.pg_class fcl ON fcl.oid = c.confrelid JOIN pg_catalog.pg_namespace fn ON fn.oid = fcl.relnamespace JOIN unnest(c.conkey) WITH ORDINALITY AS lk(attnum, ord) ON true JOIN unnest(c.confkey) WITH ORDINALITY AS rk(attnum, ord) ON lk.ord = rk.ord JOIN pg_catalog.pg_attribute att ON att.attrelid = c.conrelid AND att.attnum = lk.attnum JOIN pg_catalog.pg_attribute fatt ON fatt.attrelid = c.confrelid AND fatt.attnum = rk.attnum WHERE c.contype = 'f' AND n.nspname = ${namespace} ORDER BY cl.relname, c.conname, lk.ord`;
|
|
132
|
+
break;
|
|
133
|
+
case "enums":
|
|
134
|
+
text = `SELECT t.typname AS type_name, n.nspname AS type_namespace, e.enumlabel AS enum_value, e.enumsortorder AS sort_order FROM pg_type t JOIN pg_enum e ON t.oid = e.enumtypid JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace WHERE n.nspname = ${namespace} ORDER BY t.typname, e.enumsortorder`;
|
|
135
|
+
break;
|
|
136
|
+
case "indexes":
|
|
137
|
+
text = `SELECT tablename AS table_name, indexname AS index_name, indexdef AS index_def, con.conname AS backing_constraint, con.contype AS backing_constraint_type, health.indisvalid AS valid, health.indisready AS ready, health.indimmediate AS immediate, health.indexprs IS NULL AS plain_columns, health.indnkeyatts AS key_count, health.indnatts AS attribute_count FROM pg_indexes ix JOIN pg_catalog.pg_namespace ns ON ns.nspname = ix.schemaname JOIN pg_catalog.pg_class idx ON idx.relnamespace = ns.oid AND idx.relname = ix.indexname JOIN pg_catalog.pg_index health ON health.indexrelid = idx.oid LEFT JOIN pg_catalog.pg_constraint con ON con.conindid = idx.oid AND con.contype IN ('p', 'u', 'x') WHERE schemaname = ${namespace} ORDER BY tablename, indexname`;
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
return { text, values: collector.values, returning: "none" };
|
|
141
|
+
}
|
|
142
|
+
// packages/sql/src/dialects/postgres-index-keys.ts
|
|
143
|
+
import { unsupportedCapability as unsupportedCapability5 } from "@vibeorm/schema";
|
|
144
|
+
function renderPostgresIndexKeys(params) {
|
|
145
|
+
const { dialect } = params;
|
|
146
|
+
if (dialect.name !== "postgres")
|
|
147
|
+
throw unsupportedCapability5({ dialect: dialect.name, feature: "indexOperatorClasses" });
|
|
148
|
+
const collector = new ParamCollector(dialect);
|
|
149
|
+
const scope = params.table === undefined ? "n.nspname <> 'information_schema' AND n.nspname NOT LIKE 'pg\\_%' ESCAPE '\\'" : `n.nspname = ${collector.add(params.table.namespace)} AND c.relname = ${collector.add(params.table.name)}`;
|
|
150
|
+
const defaultResolution = `LEFT JOIN LATERAL (WITH RECURSIVE input_types AS (SELECT t.oid, t.typbasetype, t.typtype, t.typelem, t.typcategory FROM pg_catalog.pg_type t WHERE t.oid = a.atttypid UNION ALL SELECT t.oid, t.typbasetype, t.typtype, t.typelem, t.typcategory FROM pg_catalog.pg_type t JOIN input_types previous ON t.oid = previous.typbasetype WHERE previous.typtype = 'd'), candidates AS (SELECT candidate.oid, CASE WHEN candidate.opcintype = input.oid THEN 0 WHEN class_input.typispreferred AND class_input.typcategory = input.typcategory THEN 1 ELSE 2 END AS priority FROM pg_catalog.pg_opclass candidate JOIN pg_catalog.pg_type class_input ON class_input.oid = candidate.opcintype CROSS JOIN input_types input WHERE input.typtype <> 'd' AND candidate.opcdefault AND candidate.opcmethod = idx.relam AND (candidate.opcintype = input.oid OR EXISTS (SELECT 1 FROM pg_catalog.pg_cast cast_entry WHERE cast_entry.castsource = input.oid AND cast_entry.casttarget = candidate.opcintype AND cast_entry.castmethod = 'b' AND cast_entry.castcontext = 'i') OR input.typtype = 'e' AND candidate.opcintype = 'pg_catalog.anyenum'::regtype OR input.typelem <> 0 AND candidate.opcintype = 'pg_catalog.anyarray'::regtype)) SELECT (array_agg(candidate.oid))[1] AS oid FROM candidates candidate WHERE candidate.priority = (SELECT min(priority) FROM candidates) HAVING count(*) = 1) resolved_default ON true`;
|
|
151
|
+
return {
|
|
152
|
+
text: `SELECT n.nspname AS table_namespace, c.relname AS table_name, idx.relname AS index_name, am.amname AS method, i.indisunique AS unique, pg_catalog.pg_get_expr(i.indpred, i.indrelid, false) AS predicate, i.indnullsnotdistinct AS nulls_not_distinct, k.ordinality AS ordinal, a.attname AS column_name, (i.indoption[k.ordinality - 1] & 1) <> 0 AS descending, opn.nspname AS operator_namespace, op.opcname AS operator_name, COALESCE(op.oid = resolved_default.oid, false) AS exact_default FROM pg_catalog.pg_index i JOIN pg_catalog.pg_class c ON c.oid = i.indrelid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace JOIN pg_catalog.pg_class idx ON idx.oid = i.indexrelid JOIN pg_catalog.pg_am am ON am.oid = idx.relam CROSS JOIN LATERAL unnest(i.indkey) WITH ORDINALITY k(attnum, ordinality) LEFT JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid AND a.attnum = k.attnum JOIN pg_catalog.pg_opclass op ON op.oid = i.indclass[k.ordinality - 1] JOIN pg_catalog.pg_namespace opn ON opn.oid = op.opcnamespace ${defaultResolution} WHERE ${scope} AND k.ordinality <= i.indnkeyatts ORDER BY n.nspname, c.relname, idx.relname, k.ordinality`,
|
|
153
|
+
values: collector.values,
|
|
154
|
+
returning: "none"
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
// packages/sql/src/index-columns.ts
|
|
158
|
+
import { VibeError, isSqlObjectIdentity, unsupportedCapability as unsupportedCapability6 } from "@vibeorm/schema";
|
|
159
|
+
function renderIndexColumns(params) {
|
|
160
|
+
const { dialect, columns, unique } = params;
|
|
161
|
+
const hasOperatorClass = columns.some((column) => column.operatorClass !== undefined);
|
|
162
|
+
if (hasOperatorClass && !dialect.capabilities.indexOperatorClasses)
|
|
163
|
+
throw unsupportedCapability6({ dialect: dialect.name, feature: "indexOperatorClasses" });
|
|
164
|
+
if (hasOperatorClass && unique)
|
|
165
|
+
throw unsupportedCapability6({ dialect: dialect.name, feature: "uniqueIndexOperatorClasses", hint: "custom unique operator classes can change client selector equality" });
|
|
166
|
+
return columns.map((column) => {
|
|
167
|
+
const operatorClass = column.operatorClass;
|
|
168
|
+
if (operatorClass !== undefined && !isSqlObjectIdentity({ kind: "table", name: operatorClass })) {
|
|
169
|
+
throw new VibeError({ code: "VIBE_SCHEMA_INVALID", message: "Index operator class must be a qualified SQL name { namespace, name }", meta: { rule: "index-operator-class-identity", column: column.name } });
|
|
170
|
+
}
|
|
171
|
+
const ops = operatorClass === undefined ? "" : ` ${dialect.quoteIdent({ name: operatorClass.namespace })}.${dialect.quoteIdent({ name: operatorClass.name })}`;
|
|
172
|
+
return `${dialect.quoteIdent({ name: column.name })}${ops}${column.desc ? " DESC" : ""}`;
|
|
173
|
+
});
|
|
174
|
+
}
|
|
19
175
|
// packages/sql/src/dialects/module-dependency.ts
|
|
20
176
|
function renderModuleDependencyQuery(params) {
|
|
21
177
|
const { dialect, operation } = params;
|
|
@@ -50,19 +206,19 @@ function renderReplayCoverageGaps(params) {
|
|
|
50
206
|
const collector = new ParamCollector(dialect);
|
|
51
207
|
const namespace = collector.add(params.namespace);
|
|
52
208
|
if (dialect.name === "postgres")
|
|
53
|
-
return { text: `SELECT 'type' AS kind, t.typname::text AS name FROM pg_catalog.pg_type t JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace WHERE n.nspname = ${namespace} AND (t.typtype IN ('b', 'd', 'r', 'm') AND t.typelem = 0 OR t.typtype = 'c' AND EXISTS (SELECT 1 FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid AND c.relkind = 'c')) AND NOT EXISTS (SELECT 1 FROM pg_catalog.pg_depend d WHERE d.classid = 'pg_type'::regclass AND d.objid = t.oid AND d.deptype = 'e')
|
|
54
|
-
UNION ALL SELECT 'routine', p.proname::text FROM pg_catalog.pg_proc p JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace WHERE n.nspname = ${namespace} AND p.prokind <> 'f' AND NOT EXISTS (SELECT 1 FROM pg_catalog.pg_depend d WHERE d.classid = 'pg_proc'::regclass AND d.objid = p.oid AND d.deptype = 'e')
|
|
55
|
-
UNION ALL SELECT 'relation-layout', c.relname::text FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = ${namespace} AND (c.relkind IN ('p', 'f') OR c.relispartition OR EXISTS (SELECT 1 FROM pg_catalog.pg_inherits i WHERE i.inhrelid = c.oid)) AND NOT EXISTS (SELECT 1 FROM pg_catalog.pg_depend d WHERE d.classid = 'pg_class'::regclass AND d.objid = c.oid AND d.deptype = 'e')
|
|
56
|
-
UNION ALL SELECT 'rule', r.rulename::text FROM pg_catalog.pg_rewrite r JOIN pg_catalog.pg_class c ON c.oid = r.ev_class JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = ${namespace} AND r.rulename <> '_RETURN' AND NOT ${extensionMember("pg_class", "c.oid")}
|
|
57
|
-
UNION ALL SELECT 'namespace', n.nspname::text FROM pg_catalog.pg_namespace n WHERE n.nspname <> ${namespace} AND n.nspname <> 'information_schema' AND n.nspname NOT LIKE 'pg\\_%' ESCAPE '\\' AND NOT (${extensionOwnedNamespace})${params.privateNamespace === undefined ? "" : ` AND n.nspname <> ${collector.add(params.privateNamespace)}`}`, values: collector.values, returning: "none" };
|
|
209
|
+
return { text: `SELECT 'type' AS kind, t.typname::text AS name, n.nspname::text AS namespace, NULL::text AS parent FROM pg_catalog.pg_type t JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace WHERE n.nspname = ${namespace} AND (t.typtype IN ('b', 'd', 'r', 'm') AND t.typelem = 0 OR t.typtype = 'c' AND EXISTS (SELECT 1 FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid AND c.relkind = 'c')) AND NOT EXISTS (SELECT 1 FROM pg_catalog.pg_depend d WHERE d.classid = 'pg_type'::regclass AND d.objid = t.oid AND d.deptype = 'e')
|
|
210
|
+
UNION ALL SELECT 'routine', p.proname::text, n.nspname::text, NULL::text FROM pg_catalog.pg_proc p JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace WHERE n.nspname = ${namespace} AND p.prokind <> 'f' AND NOT EXISTS (SELECT 1 FROM pg_catalog.pg_depend d WHERE d.classid = 'pg_proc'::regclass AND d.objid = p.oid AND d.deptype = 'e')
|
|
211
|
+
UNION ALL SELECT 'relation-layout', c.relname::text, n.nspname::text, NULL::text FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = ${namespace} AND (c.relkind IN ('p', 'f') OR c.relispartition OR EXISTS (SELECT 1 FROM pg_catalog.pg_inherits i WHERE i.inhrelid = c.oid)) AND NOT EXISTS (SELECT 1 FROM pg_catalog.pg_depend d WHERE d.classid = 'pg_class'::regclass AND d.objid = c.oid AND d.deptype = 'e')
|
|
212
|
+
UNION ALL SELECT 'rule', r.rulename::text, n.nspname::text, c.relname::text FROM pg_catalog.pg_rewrite r JOIN pg_catalog.pg_class c ON c.oid = r.ev_class JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = ${namespace} AND r.rulename <> '_RETURN' AND NOT ${extensionMember("pg_class", "c.oid")}
|
|
213
|
+
UNION ALL SELECT 'namespace', n.nspname::text, n.nspname::text, NULL::text FROM pg_catalog.pg_namespace n WHERE n.nspname <> ${namespace} AND n.nspname <> 'information_schema' AND n.nspname NOT LIKE 'pg\\_%' ESCAPE '\\' AND NOT (${extensionOwnedNamespace})${params.privateNamespace === undefined ? "" : ` AND n.nspname <> ${collector.add(params.privateNamespace)}`}`, values: collector.values, returning: "none" };
|
|
58
214
|
if (dialect.name === "mysql")
|
|
59
|
-
return { text: `SELECT 'procedure' AS kind, ROUTINE_NAME AS name FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = ${namespace} AND ROUTINE_TYPE = 'PROCEDURE'
|
|
60
|
-
UNION ALL SELECT 'event', EVENT_NAME FROM information_schema.EVENTS WHERE EVENT_SCHEMA = ${collector.add(params.namespace)}
|
|
61
|
-
UNION ALL SELECT DISTINCT 'partition', TABLE_NAME FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = ${collector.add(params.namespace)} AND PARTITION_NAME IS NOT NULL`, values: collector.values, returning: "none" };
|
|
62
|
-
return { text: `SELECT 'table-options' AS kind, name FROM pragma_table_list WHERE schema = ${namespace} AND name NOT LIKE 'sqlite\\_%' ESCAPE '\\' AND (type = 'virtual' OR wr <> 0 OR strict <> 0)`, values: collector.values, returning: "none" };
|
|
215
|
+
return { text: `SELECT 'procedure' AS kind, ROUTINE_NAME AS name, ROUTINE_SCHEMA AS namespace, NULL AS parent FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = ${namespace} AND ROUTINE_TYPE = 'PROCEDURE'
|
|
216
|
+
UNION ALL SELECT 'event', EVENT_NAME, EVENT_SCHEMA, NULL FROM information_schema.EVENTS WHERE EVENT_SCHEMA = ${collector.add(params.namespace)}
|
|
217
|
+
UNION ALL SELECT DISTINCT 'partition', TABLE_NAME, TABLE_SCHEMA, NULL FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = ${collector.add(params.namespace)} AND PARTITION_NAME IS NOT NULL`, values: collector.values, returning: "none" };
|
|
218
|
+
return { text: `SELECT 'table-options' AS kind, name, schema AS namespace, NULL AS parent FROM pragma_table_list WHERE schema = ${namespace} AND name NOT LIKE 'sqlite\\_%' ESCAPE '\\' AND (type = 'virtual' OR wr <> 0 OR strict <> 0)`, values: collector.values, returning: "none" };
|
|
63
219
|
}
|
|
64
220
|
// packages/sql/src/dialects/migration-shadow.ts
|
|
65
|
-
import { unsupportedCapability } from "@vibeorm/schema";
|
|
221
|
+
import { assertSqlNamespace, unsupportedCapability as unsupportedCapability7 } from "@vibeorm/schema";
|
|
66
222
|
var SHADOW_DATABASE = Object.freeze({ schema: "_vibeorm_shadow", table: "_vibe_shadow", lock: 1447645267, timeoutSeconds: 60 });
|
|
67
223
|
var SHADOW_CAPABILITIES = Object.freeze({
|
|
68
224
|
postgres: Object.freeze({ serverProvisioning: true, dedicated: true }),
|
|
@@ -72,7 +228,7 @@ var SHADOW_CAPABILITIES = Object.freeze({
|
|
|
72
228
|
function renderShadowOperation(params) {
|
|
73
229
|
const { dialect, operation } = params;
|
|
74
230
|
if (!SHADOW_CAPABILITIES[dialect.name].serverProvisioning)
|
|
75
|
-
throw
|
|
231
|
+
throw unsupportedCapability7({ dialect: dialect.name, feature: "shadowDatabaseProvisioning" });
|
|
76
232
|
const pg = dialect.name === "postgres";
|
|
77
233
|
const collector = new ParamCollector(dialect);
|
|
78
234
|
const marker = pg ? `${dialect.quoteIdent({ name: SHADOW_DATABASE.schema })}.${dialect.quoteIdent({ name: SHADOW_DATABASE.table })}` : dialect.quoteIdent({ name: SHADOW_DATABASE.table });
|
|
@@ -97,7 +253,7 @@ function renderShadowOperation(params) {
|
|
|
97
253
|
ORDER BY ordinal_position`);
|
|
98
254
|
case "grants": {
|
|
99
255
|
if (pg)
|
|
100
|
-
throw
|
|
256
|
+
throw unsupportedCapability7({ dialect: dialect.name, feature: "mysqlShadowPrivileges" });
|
|
101
257
|
return result("SHOW GRANTS FOR CURRENT_USER");
|
|
102
258
|
}
|
|
103
259
|
case "markerCreate":
|
|
@@ -125,19 +281,27 @@ UNION ALL SELECT ROUTINE_TYPE, ROUTINE_NAME, ROUTINE_SCHEMA FROM information_sch
|
|
|
125
281
|
UNION ALL SELECT 'EVENT', EVENT_NAME, EVENT_SCHEMA FROM information_schema.EVENTS WHERE EVENT_SCHEMA = DATABASE()
|
|
126
282
|
UNION ALL SELECT 'TRIGGER', TRIGGER_NAME, TRIGGER_SCHEMA FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA = DATABASE()
|
|
127
283
|
UNION ALL SELECT 'EXTERNAL FOREIGN KEY', CONCAT(TABLE_NAME, '.', CONSTRAINT_NAME), CONSTRAINT_SCHEMA FROM information_schema.REFERENTIAL_CONSTRAINTS WHERE UNIQUE_CONSTRAINT_SCHEMA = DATABASE() AND CAST(CONSTRAINT_SCHEMA AS BINARY) <> CAST(DATABASE() AS BINARY)`);
|
|
128
|
-
case "resetPostgres":
|
|
284
|
+
case "resetPostgres":
|
|
285
|
+
case "resetDedicatedPostgres": {
|
|
129
286
|
if (!pg)
|
|
130
|
-
throw
|
|
131
|
-
|
|
287
|
+
throw unsupportedCapability7({ dialect: dialect.name, feature: "postgresShadowReset" });
|
|
288
|
+
const owned = operation.kind === "resetDedicatedPostgres" ? operation.ownedNamespaces : [];
|
|
289
|
+
for (const namespace of owned)
|
|
290
|
+
assertSqlNamespace({ namespace, dialect: "postgres", allowPublic: false });
|
|
291
|
+
return [
|
|
292
|
+
...owned.map((namespace) => ({ text: `DROP SCHEMA IF EXISTS ${dialect.quoteIdent({ name: namespace })} CASCADE`, values: [], returning: "none" })),
|
|
293
|
+
{ text: 'DROP SCHEMA "public" CASCADE', values: [], returning: "none" },
|
|
294
|
+
{ text: 'CREATE SCHEMA "public"', values: [], returning: "none" }
|
|
295
|
+
];
|
|
132
296
|
}
|
|
133
297
|
case "mysqlForeignKeys": {
|
|
134
298
|
if (pg)
|
|
135
|
-
throw
|
|
299
|
+
throw unsupportedCapability7({ dialect: dialect.name, feature: "mysqlShadowReset" });
|
|
136
300
|
return result(`SET FOREIGN_KEY_CHECKS = ${operation.enabled ? "1" : "0"}`);
|
|
137
301
|
}
|
|
138
302
|
case "dropMysqlObject": {
|
|
139
303
|
if (pg)
|
|
140
|
-
throw
|
|
304
|
+
throw unsupportedCapability7({ dialect: dialect.name, feature: "mysqlShadowReset" });
|
|
141
305
|
return result(`DROP ${operation.object} ${dialect.quoteIdent({ name: operation.name })}`);
|
|
142
306
|
}
|
|
143
307
|
}
|
|
@@ -182,10 +346,10 @@ var SQLITE_SESSION_SQL = Object.freeze({
|
|
|
182
346
|
foreignKeysOn: "PRAGMA foreign_keys = ON"
|
|
183
347
|
});
|
|
184
348
|
// packages/sql/src/composable.ts
|
|
185
|
-
import { VibeError } from "@vibeorm/schema";
|
|
349
|
+
import { VibeError as VibeError2 } from "@vibeorm/schema";
|
|
186
350
|
var fragments = new WeakMap;
|
|
187
351
|
function invalid(message) {
|
|
188
|
-
throw new
|
|
352
|
+
throw new VibeError2({ code: "VIBE_VALIDATION", message });
|
|
189
353
|
}
|
|
190
354
|
function construct(parts) {
|
|
191
355
|
const snapshot = Object.freeze([...parts]);
|
|
@@ -310,7 +474,7 @@ function sqlUsesIncoming(params) {
|
|
|
310
474
|
return partsOf(params.fragment).some((part) => typeof part !== "string" && (("row" in part) && part.row === "incoming" || ("greatest" in part) && part.greatest.some((fragment) => sqlUsesIncoming({ fragment }))));
|
|
311
475
|
}
|
|
312
476
|
// packages/sql/src/result-decoder.ts
|
|
313
|
-
import { VibeError as
|
|
477
|
+
import { VibeError as VibeError4 } from "@vibeorm/schema";
|
|
314
478
|
|
|
315
479
|
// packages/sql/src/pg-array.ts
|
|
316
480
|
var PG_ARRAY_QUOTE = /^$|^NULL$|[{},"\\\s]/i;
|
|
@@ -365,7 +529,7 @@ function parsePgArrayLiteral(params) {
|
|
|
365
529
|
}
|
|
366
530
|
|
|
367
531
|
// packages/sql/src/codecs.ts
|
|
368
|
-
import { VibeError as
|
|
532
|
+
import { VibeError as VibeError3, invalidStoredData } from "@vibeorm/schema";
|
|
369
533
|
function enumMembershipCodec(params) {
|
|
370
534
|
const { model, field, enum: enumName } = params;
|
|
371
535
|
const members = new Set(params.members);
|
|
@@ -373,7 +537,7 @@ function enumMembershipCodec(params) {
|
|
|
373
537
|
encode: (value) => {
|
|
374
538
|
if (typeof value === "string" && members.has(value))
|
|
375
539
|
return value;
|
|
376
|
-
throw new
|
|
540
|
+
throw new VibeError3({
|
|
377
541
|
code: "VIBE_VALIDATION",
|
|
378
542
|
message: `Invalid value for enum ${enumName} on ${model}.${field}`,
|
|
379
543
|
meta: { model, field, enum: enumName }
|
|
@@ -413,7 +577,7 @@ var bigIntCodec = {
|
|
|
413
577
|
return BigInt(value.trim());
|
|
414
578
|
if (typeof value === "number" && Number.isSafeInteger(value))
|
|
415
579
|
return BigInt(value);
|
|
416
|
-
throw new
|
|
580
|
+
throw new VibeError3({ code: "VIBE_DATA_INVALID", message: "BigInt requires an integer string or a safe integer", meta: { value } });
|
|
417
581
|
}
|
|
418
582
|
};
|
|
419
583
|
var decimalCodec = {
|
|
@@ -443,7 +607,7 @@ function parseDateTimeText(params) {
|
|
|
443
607
|
var dateNativeCodec = {
|
|
444
608
|
encode: (value) => {
|
|
445
609
|
if (value instanceof Date && !Number.isFinite(value.getTime()) || typeof value === "number" && !Number.isFinite(value) || typeof value === "string" && /^[+-]?infinity$/i.test(value.trim())) {
|
|
446
|
-
throw new
|
|
610
|
+
throw new VibeError3({ code: "VIBE_VALIDATION", message: "DateTime parameters require finite timestamps; use an extended timestamp encoder for infinity" });
|
|
447
611
|
}
|
|
448
612
|
return value;
|
|
449
613
|
},
|
|
@@ -451,7 +615,7 @@ var dateNativeCodec = {
|
|
|
451
615
|
const date = value instanceof Date ? value : typeof value === "string" ? parseDateTimeText({ text: value }) : typeof value === "number" ? new Date(value) : undefined;
|
|
452
616
|
if (date !== undefined && Number.isFinite(date.getTime()))
|
|
453
617
|
return date;
|
|
454
|
-
throw new
|
|
618
|
+
throw new VibeError3({ code: "VIBE_DATA_INVALID", message: "DateTime requires a finite timestamp; use an explicit extended timestamp decoder for infinity" });
|
|
455
619
|
}
|
|
456
620
|
};
|
|
457
621
|
var dateTextCodec = {
|
|
@@ -460,7 +624,7 @@ var dateTextCodec = {
|
|
|
460
624
|
const date = value instanceof Date ? value : typeof value === "string" ? parseDateTimeText({ text: value }) : typeof value === "number" ? new Date(value) : undefined;
|
|
461
625
|
if (date !== undefined && Number.isFinite(date.getTime()))
|
|
462
626
|
return date.toISOString();
|
|
463
|
-
throw new
|
|
627
|
+
throw new VibeError3({ code: "VIBE_VALIDATION", message: "DateTime parameters require a valid finite timestamp" });
|
|
464
628
|
},
|
|
465
629
|
decode: dateNativeCodec.decode
|
|
466
630
|
};
|
|
@@ -497,7 +661,7 @@ var jsonCodec = {
|
|
|
497
661
|
try {
|
|
498
662
|
return JSON.parse(value);
|
|
499
663
|
} catch (cause) {
|
|
500
|
-
throw new
|
|
664
|
+
throw new VibeError3({
|
|
501
665
|
code: "VIBE_INTERNAL",
|
|
502
666
|
message: "a Json column returned text that is not valid JSON",
|
|
503
667
|
meta: { value },
|
|
@@ -547,7 +711,7 @@ var DIALECT_CODECS = {
|
|
|
547
711
|
|
|
548
712
|
// packages/sql/src/result-decoder.ts
|
|
549
713
|
function refuse(encoding, message) {
|
|
550
|
-
throw new
|
|
714
|
+
throw new VibeError4({ code: encoding ? "VIBE_VALIDATION" : "VIBE_DATA_INVALID", message });
|
|
551
715
|
}
|
|
552
716
|
function scalar(type, valid) {
|
|
553
717
|
const convert = (params, encoding) => {
|
|
@@ -593,7 +757,7 @@ var extendedDecoder = Object.freeze({
|
|
|
593
757
|
encode: (params) => {
|
|
594
758
|
if (params.value === "infinity" || params.value === "-infinity") {
|
|
595
759
|
if (params.dialect !== "postgres")
|
|
596
|
-
throw new
|
|
760
|
+
throw new VibeError4({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: "Timestamp infinity parameters require PostgreSQL" });
|
|
597
761
|
return params.value;
|
|
598
762
|
}
|
|
599
763
|
return dateDecoder.encode(params);
|
|
@@ -651,15 +815,15 @@ var decode = Object.freeze({
|
|
|
651
815
|
}
|
|
652
816
|
});
|
|
653
817
|
// packages/sql/src/exclusion.ts
|
|
654
|
-
import { VibeError as
|
|
818
|
+
import { VibeError as VibeError6, fieldTypeIdentity as fieldTypeIdentity2, isEnumType as isEnumType2, unsupportedCapability as unsupportedCapability9 } from "@vibeorm/schema";
|
|
655
819
|
|
|
656
820
|
// packages/sql/src/predicate.ts
|
|
657
|
-
import { VibeError as
|
|
821
|
+
import { VibeError as VibeError5, fieldTypeIdentity, isEnumType, unsupportedCapability as unsupportedCapability8 } from "@vibeorm/schema";
|
|
658
822
|
function renderPredicate(params) {
|
|
659
823
|
if (params.usage === "exclusionPredicate" && !params.dialect.capabilities.exclusionConstraints)
|
|
660
|
-
throw
|
|
824
|
+
throw unsupportedCapability8({ dialect: params.dialect.name, feature: "exclusionConstraints" });
|
|
661
825
|
if (params.usage === "indexPredicate" && !params.dialect.capabilities.partialIndexes) {
|
|
662
|
-
throw
|
|
826
|
+
throw unsupportedCapability8({ dialect: params.dialect.name, feature: "partialIndexes" });
|
|
663
827
|
}
|
|
664
828
|
const context = {
|
|
665
829
|
model: params.model,
|
|
@@ -694,7 +858,7 @@ var INT64_MIN = -(2n ** 63n);
|
|
|
694
858
|
var INT64_MAX = 2n ** 63n - 1n;
|
|
695
859
|
function refuse2(params) {
|
|
696
860
|
const { context, rule, message } = params;
|
|
697
|
-
throw new
|
|
861
|
+
throw new VibeError5({
|
|
698
862
|
code: "VIBE_SCHEMA_INVALID",
|
|
699
863
|
message: `${context.site} on "${context.model.name}": ${message}`,
|
|
700
864
|
meta: { rule, model: context.model.name, site: context.site, ...params.meta ?? {} }
|
|
@@ -787,7 +951,7 @@ function resolveField(params) {
|
|
|
787
951
|
});
|
|
788
952
|
}
|
|
789
953
|
if (context.usage === "check" && context.dialect.name === "mysql" && field.default?.kind === "autoincrement") {
|
|
790
|
-
throw
|
|
954
|
+
throw unsupportedCapability8({
|
|
791
955
|
dialect: "mysql",
|
|
792
956
|
feature: `CHECK constraint referencing auto-increment column "${context.model.name}.${name}"`,
|
|
793
957
|
hint: "mysql refuses this with error 3818 \u2014 enforce the rule in application code or on a non-generated column"
|
|
@@ -958,12 +1122,12 @@ function describe(params) {
|
|
|
958
1122
|
|
|
959
1123
|
// packages/sql/src/exclusion.ts
|
|
960
1124
|
function invalid2(rule) {
|
|
961
|
-
throw new
|
|
1125
|
+
throw new VibeError6({ code: "VIBE_SCHEMA_INVALID", message: `Invalid exclusion constraint: ${rule}`, meta: { rule: `exclusion-${rule}` } });
|
|
962
1126
|
}
|
|
963
1127
|
function compileExclusion(params) {
|
|
964
1128
|
const { exclusion: spec, model, dialect } = params;
|
|
965
1129
|
if (!dialect.capabilities.exclusionConstraints)
|
|
966
|
-
throw
|
|
1130
|
+
throw unsupportedCapability9({ dialect: dialect.name, feature: "exclusionConstraints" });
|
|
967
1131
|
if (!spec.name || spec.name.includes("\x00"))
|
|
968
1132
|
invalid2("name");
|
|
969
1133
|
if (!["int8range", "tsrange", "tstzrange"].includes(spec.range.type))
|
|
@@ -1006,7 +1170,7 @@ function compileExclusion(params) {
|
|
|
1006
1170
|
const column = field(key.field);
|
|
1007
1171
|
if (column.isOptional)
|
|
1008
1172
|
invalid2("nullable-key-requires-expression");
|
|
1009
|
-
if (!["String", "Int", "BigInt", "Float", "Decimal", "Boolean", "DateTime"].includes(fieldTypeIdentity2({ type: column.type })))
|
|
1173
|
+
if (!isEnumType2(column.type) && !["String", "Int", "BigInt", "Float", "Decimal", "Boolean", "DateTime"].includes(fieldTypeIdentity2({ type: column.type })))
|
|
1010
1174
|
invalid2("key-type");
|
|
1011
1175
|
return `${dialect.quoteIdent({ name: column.dbName ?? column.name })} WITH =`;
|
|
1012
1176
|
});
|
|
@@ -1016,13 +1180,13 @@ function compileExclusion(params) {
|
|
|
1016
1180
|
}
|
|
1017
1181
|
function renderExclusionSetup(params) {
|
|
1018
1182
|
if (!params.dialect.capabilities.exclusionConstraints)
|
|
1019
|
-
throw
|
|
1183
|
+
throw unsupportedCapability9({ dialect: params.dialect.name, feature: "exclusionConstraints" });
|
|
1020
1184
|
return params.exclusion.requiredExtensions.map((name) => `CREATE EXTENSION IF NOT EXISTS ${params.dialect.quoteIdent({ name })};`);
|
|
1021
1185
|
}
|
|
1022
1186
|
function renderExclusionDdl(params) {
|
|
1023
1187
|
const { dialect, table, exclusion, operation } = params;
|
|
1024
1188
|
if (!dialect.capabilities.exclusionConstraints)
|
|
1025
|
-
throw
|
|
1189
|
+
throw unsupportedCapability9({ dialect: dialect.name, feature: "exclusionConstraints" });
|
|
1026
1190
|
const target = `ALTER TABLE ${dialect.quoteIdent({ name: table })}`;
|
|
1027
1191
|
if (operation === "drop")
|
|
1028
1192
|
return [`${target} DROP CONSTRAINT ${dialect.quoteIdent({ name: exclusion.name })};`];
|
|
@@ -1031,15 +1195,15 @@ function renderExclusionDdl(params) {
|
|
|
1031
1195
|
function renderExclusionCatalog(params) {
|
|
1032
1196
|
const { dialect, probe } = params;
|
|
1033
1197
|
if (!dialect.capabilities.exclusionConstraints)
|
|
1034
|
-
throw
|
|
1035
|
-
const scope = probe === undefined ?
|
|
1198
|
+
throw unsupportedCapability9({ dialect: dialect.name, feature: "exclusionConstraints" });
|
|
1199
|
+
const scope = probe === undefined ? `n.nspname = ${dialect.quoteStringLiteral({ value: params.namespace ?? "public" })}` : `t.oid = ${dialect.quoteStringLiteral({ value: probe })}::regclass`;
|
|
1036
1200
|
return `SELECT t.relname AS table_name, c.conname AS constraint_name, pg_catalog.pg_get_constraintdef(c.oid, true) AS definition, c.convalidated AS validated, i.indisvalid AS valid, i.indisready AS ready FROM pg_catalog.pg_constraint c JOIN pg_catalog.pg_class t ON t.oid = c.conrelid JOIN pg_catalog.pg_namespace n ON n.oid = t.relnamespace JOIN pg_catalog.pg_index i ON i.indexrelid = c.conindid WHERE c.contype = 'x' AND ${scope} ORDER BY t.relname, c.conname`;
|
|
1037
1201
|
}
|
|
1038
1202
|
function renderExclusionProbe(params) {
|
|
1039
1203
|
const { dialect, table, probe, definition } = params;
|
|
1040
1204
|
if (!dialect.capabilities.exclusionConstraints)
|
|
1041
|
-
throw
|
|
1042
|
-
return [`CREATE TEMP TABLE ${dialect.quoteIdent({ name: probe })} (LIKE ${dialect.quoteIdent({ name: "public" })}.${dialect.quoteIdent({ name: table })})`, `ALTER TABLE ${dialect.quoteIdent({ name: probe })} ADD CONSTRAINT ${dialect.quoteIdent({ name: `${probe}_x` })} ${definition}`];
|
|
1205
|
+
throw unsupportedCapability9({ dialect: dialect.name, feature: "exclusionConstraints" });
|
|
1206
|
+
return [`CREATE TEMP TABLE ${dialect.quoteIdent({ name: probe })} (LIKE ${dialect.quoteIdent({ name: params.namespace ?? "public" })}.${dialect.quoteIdent({ name: table })})`, `ALTER TABLE ${dialect.quoteIdent({ name: probe })} ADD CONSTRAINT ${dialect.quoteIdent({ name: `${probe}_x` })} ${definition}`];
|
|
1043
1207
|
}
|
|
1044
1208
|
// packages/sql/src/ast.ts
|
|
1045
1209
|
var SET_OPERATORS = ["increment", "decrement", "multiply", "divide"];
|
|
@@ -1094,7 +1258,7 @@ function isExcludedRef(value) {
|
|
|
1094
1258
|
}
|
|
1095
1259
|
var ADVISORY_LOCK_RESULT_COLUMN = "acquired";
|
|
1096
1260
|
// packages/sql/src/locks.ts
|
|
1097
|
-
import { internalError, unsupportedCapability as
|
|
1261
|
+
import { internalError, unsupportedCapability as unsupportedCapability10 } from "@vibeorm/schema";
|
|
1098
1262
|
var ROW_LOCK_PROSE = Object.freeze({
|
|
1099
1263
|
strengths: Object.freeze({
|
|
1100
1264
|
update: "FOR UPDATE",
|
|
@@ -1114,7 +1278,7 @@ function renderRowLockClause(params) {
|
|
|
1114
1278
|
if (syntax === null) {
|
|
1115
1279
|
if (lock.strength === "update" && lock.wait === "wait")
|
|
1116
1280
|
return null;
|
|
1117
|
-
throw
|
|
1281
|
+
throw unsupportedCapability10({
|
|
1118
1282
|
dialect: dialect.name,
|
|
1119
1283
|
feature: `a ${describeRowLock({ lock })} locking read`,
|
|
1120
1284
|
hint: `${dialect.name} has no locking-read clause at all`
|
|
@@ -1122,7 +1286,7 @@ function renderRowLockClause(params) {
|
|
|
1122
1286
|
}
|
|
1123
1287
|
const strengthText = syntax.strengths[lock.strength];
|
|
1124
1288
|
if (strengthText === undefined) {
|
|
1125
|
-
throw
|
|
1289
|
+
throw unsupportedCapability10({
|
|
1126
1290
|
dialect: dialect.name,
|
|
1127
1291
|
feature: `the ${describeRowLock({ lock: { ...lock, wait: "wait" } })} row-lock strength`,
|
|
1128
1292
|
hint: `${dialect.name} can express: ${Object.keys(syntax.strengths).join(", ")}`
|
|
@@ -1130,7 +1294,7 @@ function renderRowLockClause(params) {
|
|
|
1130
1294
|
}
|
|
1131
1295
|
const waitText = syntax.wait[lock.wait];
|
|
1132
1296
|
if (waitText === undefined) {
|
|
1133
|
-
throw
|
|
1297
|
+
throw unsupportedCapability10({
|
|
1134
1298
|
dialect: dialect.name,
|
|
1135
1299
|
feature: `the "${lock.wait}" lock wait policy`,
|
|
1136
1300
|
hint: `${dialect.name} can express: ${Object.keys(syntax.wait).join(", ")}`
|
|
@@ -1149,7 +1313,7 @@ function renderAdvisoryLock(params) {
|
|
|
1149
1313
|
const { dialect, statement, collector } = params;
|
|
1150
1314
|
const functions = dialect.advisoryLockFunctions;
|
|
1151
1315
|
if (functions === null) {
|
|
1152
|
-
throw
|
|
1316
|
+
throw unsupportedCapability10({
|
|
1153
1317
|
dialect: dialect.name,
|
|
1154
1318
|
feature: "advisory locks",
|
|
1155
1319
|
hint: dialect.name === "mysql" ? "mysql's GET_LOCK is SESSION-scoped \u2014 it survives a rollback, so it cannot be released with the transaction" : `${dialect.name} has no advisory-lock functions`
|
|
@@ -1191,10 +1355,10 @@ import {
|
|
|
1191
1355
|
} from "@vibeorm/schema";
|
|
1192
1356
|
|
|
1193
1357
|
// packages/sql/src/identifiers.ts
|
|
1194
|
-
import { VibeError as
|
|
1358
|
+
import { VibeError as VibeError7 } from "@vibeorm/schema";
|
|
1195
1359
|
function assertNoNul(params) {
|
|
1196
1360
|
if (params.name.includes("\x00")) {
|
|
1197
|
-
throw new
|
|
1361
|
+
throw new VibeError7({
|
|
1198
1362
|
code: "VIBE_VALIDATION",
|
|
1199
1363
|
message: "an SQL identifier cannot contain a NUL character \u2014 the server would stop reading it there and address a different object",
|
|
1200
1364
|
meta: { name: params.name.replaceAll("\x00", "\\0") }
|
|
@@ -1387,8 +1551,85 @@ var SQL_DIALECTS = {
|
|
|
1387
1551
|
function getSqlDialect(params) {
|
|
1388
1552
|
return SQL_DIALECTS[params.dialect];
|
|
1389
1553
|
}
|
|
1554
|
+
// packages/sql/src/dialects/sqlite-table-definition.ts
|
|
1555
|
+
import { VibeError as VibeError8 } from "@vibeorm/schema";
|
|
1556
|
+
function tableDefinitionParts(params) {
|
|
1557
|
+
const sql = params.sql;
|
|
1558
|
+
if (!/^\s*CREATE\s+(?:TEMP(?:ORARY)?\s+)?TABLE\b/i.test(sql))
|
|
1559
|
+
throw unavailable();
|
|
1560
|
+
const parts = [];
|
|
1561
|
+
let start = -1;
|
|
1562
|
+
let depth = 0;
|
|
1563
|
+
let quote;
|
|
1564
|
+
for (let index = 0;index < sql.length; index++) {
|
|
1565
|
+
const char = sql[index];
|
|
1566
|
+
if (quote !== undefined) {
|
|
1567
|
+
if (char === quote) {
|
|
1568
|
+
if (quote !== "]" && sql[index + 1] === quote)
|
|
1569
|
+
index++;
|
|
1570
|
+
else
|
|
1571
|
+
quote = undefined;
|
|
1572
|
+
}
|
|
1573
|
+
continue;
|
|
1574
|
+
}
|
|
1575
|
+
if (char === "'" || char === '"' || char === "`") {
|
|
1576
|
+
quote = char;
|
|
1577
|
+
continue;
|
|
1578
|
+
}
|
|
1579
|
+
if (char === "[") {
|
|
1580
|
+
quote = "]";
|
|
1581
|
+
continue;
|
|
1582
|
+
}
|
|
1583
|
+
if (char === "-" && sql[index + 1] === "-") {
|
|
1584
|
+
const end = sql.indexOf(`
|
|
1585
|
+
`, index + 2);
|
|
1586
|
+
if (end < 0)
|
|
1587
|
+
break;
|
|
1588
|
+
index = end;
|
|
1589
|
+
continue;
|
|
1590
|
+
}
|
|
1591
|
+
if (char === "/" && sql[index + 1] === "*") {
|
|
1592
|
+
const end = sql.indexOf("*/", index + 2);
|
|
1593
|
+
if (end < 0)
|
|
1594
|
+
break;
|
|
1595
|
+
index = end + 1;
|
|
1596
|
+
continue;
|
|
1597
|
+
}
|
|
1598
|
+
if (char === "(") {
|
|
1599
|
+
if (depth === 0)
|
|
1600
|
+
start = index + 1;
|
|
1601
|
+
depth++;
|
|
1602
|
+
} else if (char === ")") {
|
|
1603
|
+
depth--;
|
|
1604
|
+
if (depth === 0 && start >= 0) {
|
|
1605
|
+
parts.push(sql.slice(start, index).trim());
|
|
1606
|
+
return { clauses: parts, suffix: sql.slice(index + 1) };
|
|
1607
|
+
}
|
|
1608
|
+
} else if (char === "," && depth === 1) {
|
|
1609
|
+
parts.push(sql.slice(start, index).trim());
|
|
1610
|
+
start = index + 1;
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
throw unavailable();
|
|
1614
|
+
}
|
|
1615
|
+
function unavailable() {
|
|
1616
|
+
return new VibeError8({ code: "VIBE_MIGRATION", message: "Cannot preserve table definition", meta: { reason: "table-definition-unavailable" } });
|
|
1617
|
+
}
|
|
1618
|
+
function sqliteColumnClauses(params) {
|
|
1619
|
+
const columns = [];
|
|
1620
|
+
for (const part of tableDefinitionParts(params).clauses) {
|
|
1621
|
+
const token = /^(?:"((?:[^"]|"")+)"|`((?:[^`]|``)+)`|\[([^\]]+)\]|([A-Za-z_][A-Za-z_0-9]*))/.exec(part);
|
|
1622
|
+
if (token === null)
|
|
1623
|
+
throw unavailable();
|
|
1624
|
+
if (token[4] !== undefined && /^(?:CONSTRAINT|PRIMARY|UNIQUE|CHECK|FOREIGN)$/i.test(token[4]))
|
|
1625
|
+
continue;
|
|
1626
|
+
const name = token[1]?.replaceAll('""', '"') ?? token[2]?.replaceAll("``", "`") ?? token[3] ?? token[4];
|
|
1627
|
+
columns.push({ name, sql: part });
|
|
1628
|
+
}
|
|
1629
|
+
return columns;
|
|
1630
|
+
}
|
|
1390
1631
|
// packages/sql/src/dialects/diagnostics.ts
|
|
1391
|
-
import { unsupportedCapability as
|
|
1632
|
+
import { unsupportedCapability as unsupportedCapability11 } from "@vibeorm/schema";
|
|
1392
1633
|
var QUERIES = Object.freeze({
|
|
1393
1634
|
postgresJsonWire: { dialect: "postgres", text: `SELECT '{"__vibeorm":1}'::jsonb AS "probe"` },
|
|
1394
1635
|
sqliteTriggers: { dialect: "sqlite", text: "SELECT name, tbl_name, sql FROM sqlite_master WHERE type = 'trigger'" }
|
|
@@ -1396,7 +1637,7 @@ var QUERIES = Object.freeze({
|
|
|
1396
1637
|
function renderDiagnostic(params) {
|
|
1397
1638
|
const query = QUERIES[params.query];
|
|
1398
1639
|
if (params.dialect.name !== query.dialect) {
|
|
1399
|
-
throw
|
|
1640
|
+
throw unsupportedCapability11({ dialect: params.dialect.name, feature: params.query, hint: `this diagnostic requires ${query.dialect}` });
|
|
1400
1641
|
}
|
|
1401
1642
|
return { text: query.text, values: [], returning: "none" };
|
|
1402
1643
|
}
|
|
@@ -1405,7 +1646,7 @@ function isFixedDiagnostic(params) {
|
|
|
1405
1646
|
}
|
|
1406
1647
|
|
|
1407
1648
|
// packages/sql/src/dialects/postgres-diagnostics.ts
|
|
1408
|
-
import { VibeError as
|
|
1649
|
+
import { VibeError as VibeError9, unsupportedCapability as unsupportedCapability12 } from "@vibeorm/schema";
|
|
1409
1650
|
function renderPostgresExplain(params) {
|
|
1410
1651
|
const { dialect, query, options } = params;
|
|
1411
1652
|
requirePostgres({ dialect, feature: "query plan inspection (EXPLAIN)" });
|
|
@@ -1440,7 +1681,7 @@ var POSTGRES_WORKLOAD_LIMITS = Object.freeze({
|
|
|
1440
1681
|
});
|
|
1441
1682
|
function requirePostgres(params) {
|
|
1442
1683
|
if (params.dialect.name !== "postgres") {
|
|
1443
|
-
throw
|
|
1684
|
+
throw unsupportedCapability12({
|
|
1444
1685
|
dialect: params.dialect.name,
|
|
1445
1686
|
feature: params.feature,
|
|
1446
1687
|
hint: "plan inspection and workload statistics are PostgreSQL-shaped; portable operation tracing works on every dialect"
|
|
@@ -1458,7 +1699,7 @@ function renderPostgresWorkload(params) {
|
|
|
1458
1699
|
if (query === "statementSnapshot") {
|
|
1459
1700
|
const bounded = limit ?? 20;
|
|
1460
1701
|
if (!Number.isInteger(bounded) || bounded < POSTGRES_WORKLOAD_LIMITS.minLimit || bounded > POSTGRES_WORKLOAD_LIMITS.maxLimit) {
|
|
1461
|
-
throw new
|
|
1702
|
+
throw new VibeError9({
|
|
1462
1703
|
code: "VIBE_CONFIG",
|
|
1463
1704
|
message: `workload snapshot limit must be an integer between ${POSTGRES_WORKLOAD_LIMITS.minLimit} and ${POSTGRES_WORKLOAD_LIMITS.maxLimit}, got ${String(limit)}`,
|
|
1464
1705
|
meta: { limit }
|
|
@@ -1477,7 +1718,7 @@ function renderPostgresWorkload(params) {
|
|
|
1477
1718
|
function requireArg(params) {
|
|
1478
1719
|
const { value, name, query } = params;
|
|
1479
1720
|
if (value === undefined || value.length === 0) {
|
|
1480
|
-
throw new
|
|
1721
|
+
throw new VibeError9({
|
|
1481
1722
|
code: "VIBE_CONFIG",
|
|
1482
1723
|
message: `the "${query}" diagnostic read requires a ${name}`,
|
|
1483
1724
|
meta: { query, argument: name }
|
|
@@ -1487,10 +1728,10 @@ function requireArg(params) {
|
|
|
1487
1728
|
}
|
|
1488
1729
|
|
|
1489
1730
|
// packages/sql/src/dialects/postgres-rls-readiness.ts
|
|
1490
|
-
import { unsupportedCapability as
|
|
1731
|
+
import { unsupportedCapability as unsupportedCapability14 } from "@vibeorm/schema";
|
|
1491
1732
|
|
|
1492
1733
|
// packages/sql/src/dialects/postgres-rls.ts
|
|
1493
|
-
import { RlsContextError, VibeError as
|
|
1734
|
+
import { RlsContextError, VibeError as VibeError10, assertValidSchemaIR, unsupportedCapability as unsupportedCapability13, validateRlsContextIR } from "@vibeorm/schema";
|
|
1494
1735
|
var NATIVE_RLS = Object.freeze({ policyName: "vibeorm_managed", tableSchema: "public", settingPrefix: "vibeorm.", parentAlias: "parent" });
|
|
1495
1736
|
var COLUMN_TYPES = {
|
|
1496
1737
|
String: { default: "text", native: { text: "text", varchar: "varchar", charactervarying: "varchar", uuid: "uuid" } },
|
|
@@ -1503,18 +1744,18 @@ var COLUMN_TYPES = {
|
|
|
1503
1744
|
};
|
|
1504
1745
|
function requireRls(params) {
|
|
1505
1746
|
if (!params.dialect.capabilities.nativeRowLevelSecurity) {
|
|
1506
|
-
throw
|
|
1747
|
+
throw unsupportedCapability13({ dialect: params.dialect.name, feature: "nativeRowLevelSecurity" });
|
|
1507
1748
|
}
|
|
1508
1749
|
}
|
|
1509
1750
|
function identifier2(params) {
|
|
1510
1751
|
if (typeof params.name !== "string" || params.name.length === 0 || params.name.includes("\x00") || new TextEncoder().encode(params.name).length > 63) {
|
|
1511
|
-
throw new
|
|
1752
|
+
throw new VibeError10({ code: "VIBE_SCHEMA_INVALID", message: "Native RLS identifiers must be nonempty PostgreSQL identifiers of at most 63 bytes" });
|
|
1512
1753
|
}
|
|
1513
1754
|
return params.dialect.quoteIdent({ name: params.name });
|
|
1514
1755
|
}
|
|
1515
1756
|
function tableRef(params) {
|
|
1516
1757
|
if (params.schema !== undefined && params.schema !== "public" && params.schema !== "pg_temp") {
|
|
1517
|
-
throw
|
|
1758
|
+
throw unsupportedCapability13({ dialect: params.dialect.name, feature: "nativeRowLevelSecurity", hint: "Only public tables and temporary policy probes are supported" });
|
|
1518
1759
|
}
|
|
1519
1760
|
return `${identifier2({ dialect: params.dialect, name: params.schema ?? NATIVE_RLS.tableSchema })}.${identifier2({ dialect: params.dialect, name: params.table })}`;
|
|
1520
1761
|
}
|
|
@@ -1555,14 +1796,14 @@ function renderRlsColumnType(params) {
|
|
|
1555
1796
|
if (native !== undefined)
|
|
1556
1797
|
return native;
|
|
1557
1798
|
}
|
|
1558
|
-
throw
|
|
1799
|
+
throw unsupportedCapability13({ dialect: params.dialect.name, feature: "nativeRowLevelSecurity", hint: `Unsupported physical ownership type on field ${field.name}` });
|
|
1559
1800
|
}
|
|
1560
1801
|
function protectedModel(params) {
|
|
1561
1802
|
requireRls(params);
|
|
1562
1803
|
assertValidSchemaIR({ schema: params.schema });
|
|
1563
1804
|
const model = params.schema.models.find((entry) => entry.name === params.model);
|
|
1564
1805
|
if (model === undefined || model.rls === undefined || model.rls === "unprotected") {
|
|
1565
|
-
throw new
|
|
1806
|
+
throw new VibeError10({ code: "VIBE_SCHEMA_INVALID", message: "Native RLS policy rendering requires a protected model", meta: { model: params.model } });
|
|
1566
1807
|
}
|
|
1567
1808
|
return model;
|
|
1568
1809
|
}
|
|
@@ -1595,7 +1836,7 @@ function predicate(params) {
|
|
|
1595
1836
|
}).join(" AND ");
|
|
1596
1837
|
return `EXISTS (SELECT 1 FROM ${tableRef({ dialect, table: parent.dbName ?? parent.name })} AS ${alias} WHERE ${join})`;
|
|
1597
1838
|
}
|
|
1598
|
-
throw new
|
|
1839
|
+
throw new VibeError10({ code: "VIBE_SCHEMA_INVALID", message: "Native RLS requires a protected policy rule" });
|
|
1599
1840
|
}
|
|
1600
1841
|
function renderRlsPolicy(params) {
|
|
1601
1842
|
const model = protectedModel(params);
|
|
@@ -1629,7 +1870,7 @@ function renderRlsContext(params) {
|
|
|
1629
1870
|
function renderRlsRole(params) {
|
|
1630
1871
|
requireRls(params);
|
|
1631
1872
|
if (typeof params.role !== "string" || params.role.trim().length === 0 || params.role.includes("\x00")) {
|
|
1632
|
-
throw new
|
|
1873
|
+
throw new VibeError10({ code: "VIBE_CONFIG", message: "PGlite native RLS requires a trusted nonempty runtime role name" });
|
|
1633
1874
|
}
|
|
1634
1875
|
const collector = new ParamCollector(params.dialect);
|
|
1635
1876
|
return query({ text: `SELECT set_config('role', ${collector.add(params.role)}, true)`, values: collector.values });
|
|
@@ -1781,7 +2022,7 @@ ORDER BY c.relname, p.polname`,
|
|
|
1781
2022
|
});
|
|
1782
2023
|
function requireRls2(params) {
|
|
1783
2024
|
if (!params.dialect.capabilities.nativeRowLevelSecurity) {
|
|
1784
|
-
throw
|
|
2025
|
+
throw unsupportedCapability14({ dialect: params.dialect.name, feature: "nativeRowLevelSecurity" });
|
|
1785
2026
|
}
|
|
1786
2027
|
}
|
|
1787
2028
|
function renderRlsReadinessQuery(params) {
|
|
@@ -1813,7 +2054,7 @@ function renderRlsPolicyPath(params) {
|
|
|
1813
2054
|
}
|
|
1814
2055
|
|
|
1815
2056
|
// packages/sql/src/render.ts
|
|
1816
|
-
import { internalError as internalError2, unsupportedCapability as
|
|
2057
|
+
import { assertSqlNamespace as assertSqlNamespace2, internalError as internalError2, unsupportedCapability as unsupportedCapability15 } from "@vibeorm/schema";
|
|
1817
2058
|
|
|
1818
2059
|
// packages/sql/src/like.ts
|
|
1819
2060
|
function escapeLikePattern(params) {
|
|
@@ -1919,7 +2160,10 @@ function quoteProjection(dialect, column) {
|
|
|
1919
2160
|
return `encode(${ref}, 'base64') AS ${alias}`;
|
|
1920
2161
|
}
|
|
1921
2162
|
function renderTable(dialect, table) {
|
|
1922
|
-
|
|
2163
|
+
if (table.namespace !== undefined)
|
|
2164
|
+
assertSqlNamespace2({ namespace: table.namespace, dialect: dialect.name });
|
|
2165
|
+
const relation = dialect.quoteIdent({ name: table.name });
|
|
2166
|
+
const name = table.namespace === undefined ? relation : `${dialect.quoteIdent({ name: table.namespace })}.${relation}`;
|
|
1923
2167
|
if (table.alias === undefined)
|
|
1924
2168
|
return name;
|
|
1925
2169
|
return `${name} AS ${dialect.quoteIdent({ name: table.alias })}`;
|
|
@@ -1958,7 +2202,7 @@ function renderAggRef(dialect, agg) {
|
|
|
1958
2202
|
function assertScalarArrays(dialect, feature) {
|
|
1959
2203
|
if (dialect.capabilities.scalarArrays)
|
|
1960
2204
|
return;
|
|
1961
|
-
throw
|
|
2205
|
+
throw unsupportedCapability15({
|
|
1962
2206
|
dialect: dialect.name,
|
|
1963
2207
|
feature,
|
|
1964
2208
|
hint: "only postgres has native array columns \u2014 model the list as a related table instead"
|
|
@@ -1992,7 +2236,7 @@ function renderExpr(params) {
|
|
|
1992
2236
|
}
|
|
1993
2237
|
const column = quoteCol(dialect, expr.column);
|
|
1994
2238
|
if (dialect.inArrayStrategy === "any") {
|
|
1995
|
-
const base = `${column} = ANY(${collector.add([...expr.values])})`;
|
|
2239
|
+
const base = `${column} = ANY(${collector.add(Array.isArray(expr.values) ? [...expr.values] : expr.values)})`;
|
|
1996
2240
|
return expr.negate === true ? `NOT (${base})` : base;
|
|
1997
2241
|
}
|
|
1998
2242
|
const placeholders = collector.addMany(expr.values);
|
|
@@ -2089,11 +2333,11 @@ function renderExpr(params) {
|
|
|
2089
2333
|
}
|
|
2090
2334
|
case "arrayContainsAll": {
|
|
2091
2335
|
assertScalarArrays(dialect, 'the scalar-list filter "hasEvery"');
|
|
2092
|
-
return `${quoteCol(dialect, expr.column)} @> ${collector.add([...expr.values])}`;
|
|
2336
|
+
return `${quoteCol(dialect, expr.column)} @> ${collector.add(Array.isArray(expr.values) ? [...expr.values] : expr.values)}`;
|
|
2093
2337
|
}
|
|
2094
2338
|
case "arrayOverlaps": {
|
|
2095
2339
|
assertScalarArrays(dialect, 'the scalar-list filter "hasSome"');
|
|
2096
|
-
return `${quoteCol(dialect, expr.column)} && ${collector.add([...expr.values])}`;
|
|
2340
|
+
return `${quoteCol(dialect, expr.column)} && ${collector.add(Array.isArray(expr.values) ? [...expr.values] : expr.values)}`;
|
|
2097
2341
|
}
|
|
2098
2342
|
case "arrayIsEmpty": {
|
|
2099
2343
|
assertScalarArrays(dialect, 'the scalar-list filter "isEmpty"');
|
|
@@ -2168,7 +2412,7 @@ function renderJsonLike(params) {
|
|
|
2168
2412
|
function renderJsonFilter(params) {
|
|
2169
2413
|
const { dialect, expr, collector } = params;
|
|
2170
2414
|
if (!dialect.supportedJsonOps.includes(expr.op)) {
|
|
2171
|
-
throw
|
|
2415
|
+
throw unsupportedCapability15({
|
|
2172
2416
|
dialect: dialect.name,
|
|
2173
2417
|
feature: `the json filter "${expr.op}"`,
|
|
2174
2418
|
hint: `this dialect can express: ${dialect.supportedJsonOps.join(", ")}`
|
|
@@ -2232,7 +2476,7 @@ function renderJsonFilter(params) {
|
|
|
2232
2476
|
const elements = Array.isArray(expr.value) ? expr.value : [expr.value];
|
|
2233
2477
|
const tests = elements.map((element) => {
|
|
2234
2478
|
if (element === null || typeof element === "object" && element !== null) {
|
|
2235
|
-
throw
|
|
2479
|
+
throw unsupportedCapability15({
|
|
2236
2480
|
dialect: dialect.name,
|
|
2237
2481
|
feature: "json array_contains with object/array/null elements",
|
|
2238
2482
|
hint: "sqlite expresses scalar-element containment only \u2014 deep structural containment needs postgres or mysql"
|
|
@@ -2383,7 +2627,7 @@ function renderSelect(params) {
|
|
|
2383
2627
|
let distinctPrefix = "";
|
|
2384
2628
|
if (statement.distinctOn !== undefined && statement.distinctOn.length > 0) {
|
|
2385
2629
|
if (!dialect.capabilities.distinctOn) {
|
|
2386
|
-
throw
|
|
2630
|
+
throw unsupportedCapability15({
|
|
2387
2631
|
dialect: dialect.name,
|
|
2388
2632
|
feature: "SELECT DISTINCT ON",
|
|
2389
2633
|
hint: "postgres-only \u2014 the runtime emulates distinct client-side on this dialect"
|
|
@@ -2414,7 +2658,7 @@ function renderSelect(params) {
|
|
|
2414
2658
|
}
|
|
2415
2659
|
if (statement.lateralJoins !== undefined && statement.lateralJoins.length > 0) {
|
|
2416
2660
|
if (!dialect.capabilities.lateralJoin) {
|
|
2417
|
-
throw
|
|
2661
|
+
throw unsupportedCapability15({
|
|
2418
2662
|
dialect: dialect.name,
|
|
2419
2663
|
feature: "LATERAL JOIN relation loading",
|
|
2420
2664
|
hint: 'use the portable "query" relation strategy on this dialect'
|
|
@@ -2499,7 +2743,7 @@ function renderInsert(params) {
|
|
|
2499
2743
|
let target = "";
|
|
2500
2744
|
if (onConflict.constraint !== undefined) {
|
|
2501
2745
|
if (dialect.name !== "postgres") {
|
|
2502
|
-
throw
|
|
2746
|
+
throw unsupportedCapability15({
|
|
2503
2747
|
dialect: dialect.name,
|
|
2504
2748
|
feature: "a named-constraint conflict target (ON CONFLICT ON CONSTRAINT)",
|
|
2505
2749
|
hint: "only postgres names constraints in conflict targets \u2014 use a column-list target"
|
|
@@ -2514,7 +2758,7 @@ function renderInsert(params) {
|
|
|
2514
2758
|
}
|
|
2515
2759
|
text += ` ON CONFLICT${target} DO NOTHING`;
|
|
2516
2760
|
} else if (onConflict.constraint !== undefined || onConflict.conflictWhere !== undefined) {
|
|
2517
|
-
throw
|
|
2761
|
+
throw unsupportedCapability15({
|
|
2518
2762
|
dialect: dialect.name,
|
|
2519
2763
|
feature: "a refined conflict target (constraint / partial-index predicate) on INSERT IGNORE",
|
|
2520
2764
|
hint: "mysql skips on any duplicate key \u2014 drop the refinement or gate the call per dialect"
|
|
@@ -2532,7 +2776,7 @@ function renderInsert(params) {
|
|
|
2532
2776
|
throw internalError2({ message: "lastInsertIdColumn is a mysql (onDuplicateKey) construct" });
|
|
2533
2777
|
}
|
|
2534
2778
|
if (onConflict.constraint !== undefined && dialect.name !== "postgres") {
|
|
2535
|
-
throw
|
|
2779
|
+
throw unsupportedCapability15({
|
|
2536
2780
|
dialect: dialect.name,
|
|
2537
2781
|
feature: "a named-constraint conflict target (ON CONFLICT ON CONSTRAINT)",
|
|
2538
2782
|
hint: "sqlite conflict targets are column lists \u2014 name the indexed columns instead"
|
|
@@ -2548,14 +2792,14 @@ function renderInsert(params) {
|
|
|
2548
2792
|
text += ` ON CONFLICT${target} DO UPDATE SET ${assignments}`;
|
|
2549
2793
|
} else {
|
|
2550
2794
|
if (onConflict.constraint !== undefined) {
|
|
2551
|
-
throw
|
|
2795
|
+
throw unsupportedCapability15({
|
|
2552
2796
|
dialect: dialect.name,
|
|
2553
2797
|
feature: "a named-constraint conflict target on ON DUPLICATE KEY UPDATE",
|
|
2554
2798
|
hint: "mysql's ODKU fires on any duplicate key \u2014 no target can be named"
|
|
2555
2799
|
});
|
|
2556
2800
|
}
|
|
2557
2801
|
if (onConflict.conflictWhere !== undefined) {
|
|
2558
|
-
throw
|
|
2802
|
+
throw unsupportedCapability15({
|
|
2559
2803
|
dialect: dialect.name,
|
|
2560
2804
|
feature: "a partial-index conflict target on ON DUPLICATE KEY UPDATE",
|
|
2561
2805
|
hint: "mysql's ODKU fires on any duplicate key \u2014 a partial arbiter cannot be selected; gate the call per dialect"
|
|
@@ -2637,85 +2881,8 @@ function renderDelete(params) {
|
|
|
2637
2881
|
const returning = applyReturning({ dialect, requested: statement.returning });
|
|
2638
2882
|
return { text: text + returning.suffix, values: collector.values, returning: returning.status };
|
|
2639
2883
|
}
|
|
2640
|
-
// packages/sql/src/dialects/sqlite-table-definition.ts
|
|
2641
|
-
import { VibeError as VibeError9 } from "@vibeorm/schema";
|
|
2642
|
-
function tableDefinitionParts(params) {
|
|
2643
|
-
const sql = params.sql;
|
|
2644
|
-
if (!/^\s*CREATE\s+(?:TEMP(?:ORARY)?\s+)?TABLE\b/i.test(sql))
|
|
2645
|
-
throw unavailable();
|
|
2646
|
-
const parts = [];
|
|
2647
|
-
let start = -1;
|
|
2648
|
-
let depth = 0;
|
|
2649
|
-
let quote;
|
|
2650
|
-
for (let index = 0;index < sql.length; index++) {
|
|
2651
|
-
const char = sql[index];
|
|
2652
|
-
if (quote !== undefined) {
|
|
2653
|
-
if (char === quote) {
|
|
2654
|
-
if (quote !== "]" && sql[index + 1] === quote)
|
|
2655
|
-
index++;
|
|
2656
|
-
else
|
|
2657
|
-
quote = undefined;
|
|
2658
|
-
}
|
|
2659
|
-
continue;
|
|
2660
|
-
}
|
|
2661
|
-
if (char === "'" || char === '"' || char === "`") {
|
|
2662
|
-
quote = char;
|
|
2663
|
-
continue;
|
|
2664
|
-
}
|
|
2665
|
-
if (char === "[") {
|
|
2666
|
-
quote = "]";
|
|
2667
|
-
continue;
|
|
2668
|
-
}
|
|
2669
|
-
if (char === "-" && sql[index + 1] === "-") {
|
|
2670
|
-
const end = sql.indexOf(`
|
|
2671
|
-
`, index + 2);
|
|
2672
|
-
if (end < 0)
|
|
2673
|
-
break;
|
|
2674
|
-
index = end;
|
|
2675
|
-
continue;
|
|
2676
|
-
}
|
|
2677
|
-
if (char === "/" && sql[index + 1] === "*") {
|
|
2678
|
-
const end = sql.indexOf("*/", index + 2);
|
|
2679
|
-
if (end < 0)
|
|
2680
|
-
break;
|
|
2681
|
-
index = end + 1;
|
|
2682
|
-
continue;
|
|
2683
|
-
}
|
|
2684
|
-
if (char === "(") {
|
|
2685
|
-
if (depth === 0)
|
|
2686
|
-
start = index + 1;
|
|
2687
|
-
depth++;
|
|
2688
|
-
} else if (char === ")") {
|
|
2689
|
-
depth--;
|
|
2690
|
-
if (depth === 0 && start >= 0) {
|
|
2691
|
-
parts.push(sql.slice(start, index).trim());
|
|
2692
|
-
return { clauses: parts, suffix: sql.slice(index + 1) };
|
|
2693
|
-
}
|
|
2694
|
-
} else if (char === "," && depth === 1) {
|
|
2695
|
-
parts.push(sql.slice(start, index).trim());
|
|
2696
|
-
start = index + 1;
|
|
2697
|
-
}
|
|
2698
|
-
}
|
|
2699
|
-
throw unavailable();
|
|
2700
|
-
}
|
|
2701
|
-
function unavailable() {
|
|
2702
|
-
return new VibeError9({ code: "VIBE_MIGRATION", message: "Cannot preserve table definition", meta: { reason: "table-definition-unavailable" } });
|
|
2703
|
-
}
|
|
2704
|
-
function sqliteColumnClauses(params) {
|
|
2705
|
-
const columns = [];
|
|
2706
|
-
for (const part of tableDefinitionParts(params).clauses) {
|
|
2707
|
-
const token = /^(?:"((?:[^"]|"")+)"|`((?:[^`]|``)+)`|\[([^\]]+)\]|([A-Za-z_][A-Za-z_0-9]*))/.exec(part);
|
|
2708
|
-
if (token === null)
|
|
2709
|
-
throw unavailable();
|
|
2710
|
-
if (token[4] !== undefined && /^(?:CONSTRAINT|PRIMARY|UNIQUE|CHECK|FOREIGN)$/i.test(token[4]))
|
|
2711
|
-
continue;
|
|
2712
|
-
const name = token[1]?.replaceAll('""', '"') ?? token[2]?.replaceAll("``", "`") ?? token[3] ?? token[4];
|
|
2713
|
-
columns.push({ name, sql: part });
|
|
2714
|
-
}
|
|
2715
|
-
return columns;
|
|
2716
|
-
}
|
|
2717
2884
|
// packages/sql/src/dialects/postgres-type-identity.ts
|
|
2718
|
-
import { unsupportedCapability as
|
|
2885
|
+
import { unsupportedCapability as unsupportedCapability16 } from "@vibeorm/schema";
|
|
2719
2886
|
var IDENTIFIER = '(?:"(?:[^"\\x00]|"")+"|[a-zA-Z_][a-zA-Z_0-9$]*)';
|
|
2720
2887
|
var MODIFIER_VALUE = `(?:[+-]?\\d+|${IDENTIFIER}|'(?:[^'\\x00]|'')*')`;
|
|
2721
2888
|
var TYPE_NAME = new RegExp(`^\\s*(${IDENTIFIER})(?:\\s*\\.\\s*(${IDENTIFIER}))?\\s*(\\(\\s*${MODIFIER_VALUE}(?:\\s*,\\s*${MODIFIER_VALUE})*\\s*\\))?\\s*((?:\\[\\s*\\]\\s*)*)$`);
|
|
@@ -2742,13 +2909,13 @@ function parsePostgresTypeName(params) {
|
|
|
2742
2909
|
}
|
|
2743
2910
|
function renderPostgresTypeName(params) {
|
|
2744
2911
|
if (params.dialect.name !== "postgres")
|
|
2745
|
-
throw
|
|
2912
|
+
throw unsupportedCapability16({ dialect: params.dialect.name, feature: "postgresTypeIdentity" });
|
|
2746
2913
|
const { dialect, type } = params;
|
|
2747
2914
|
return `${type.namespace === undefined ? "" : `${dialect.quoteIdent({ name: type.namespace })}.`}${dialect.quoteIdent({ name: type.name })}${type.modifier}${type.array ? "[]" : ""}`;
|
|
2748
2915
|
}
|
|
2749
2916
|
function renderPostgresTypeIdentity(params) {
|
|
2750
2917
|
if (params.dialect.name !== "postgres")
|
|
2751
|
-
throw
|
|
2918
|
+
throw unsupportedCapability16({ dialect: params.dialect.name, feature: "postgresTypeIdentity" });
|
|
2752
2919
|
const collector = new ParamCollector(params.dialect);
|
|
2753
2920
|
const { source } = params;
|
|
2754
2921
|
let text;
|
|
@@ -2761,11 +2928,11 @@ function renderPostgresTypeIdentity(params) {
|
|
|
2761
2928
|
return { text, values: collector.values, returning: "none" };
|
|
2762
2929
|
}
|
|
2763
2930
|
// packages/sql/src/dialects/postgres-default-identity.ts
|
|
2764
|
-
import { unsupportedCapability as
|
|
2931
|
+
import { unsupportedCapability as unsupportedCapability17 } from "@vibeorm/schema";
|
|
2765
2932
|
function renderPostgresDefaultFunctionIdentity(params) {
|
|
2766
2933
|
const { dialect, table, column } = params;
|
|
2767
2934
|
if (dialect.name !== "postgres")
|
|
2768
|
-
throw
|
|
2935
|
+
throw unsupportedCapability17({ dialect: dialect.name, feature: "defaultFunctionIdentity" });
|
|
2769
2936
|
const collector = new ParamCollector(dialect);
|
|
2770
2937
|
const namespace = collector.add(table.namespace);
|
|
2771
2938
|
const name = collector.add(table.name);
|
|
@@ -2789,28 +2956,28 @@ WHERE n.nspname = ${namespace} AND c.relname = ${name} AND a.attname = ${field}
|
|
|
2789
2956
|
};
|
|
2790
2957
|
}
|
|
2791
2958
|
// packages/sql/src/dialects/constraint-owned-index.ts
|
|
2792
|
-
import { unsupportedCapability as
|
|
2959
|
+
import { unsupportedCapability as unsupportedCapability18 } from "@vibeorm/schema";
|
|
2793
2960
|
function renderConstraintOwnedIndexDrop(params) {
|
|
2794
2961
|
if (params.dialect.name !== "postgres")
|
|
2795
|
-
throw
|
|
2962
|
+
throw unsupportedCapability18({ dialect: params.dialect.name, feature: "constraintOwnedIndexDrop" });
|
|
2796
2963
|
const quote = (name) => params.dialect.quoteIdent({ name });
|
|
2797
2964
|
return { text: `ALTER TABLE ${quote(params.table)} DROP CONSTRAINT ${quote(params.constraint)};`, values: [], returning: "none" };
|
|
2798
2965
|
}
|
|
2799
2966
|
// packages/sql/src/dialects/mysql-check-probe.ts
|
|
2800
|
-
import { unsupportedCapability as
|
|
2967
|
+
import { unsupportedCapability as unsupportedCapability19 } from "@vibeorm/schema";
|
|
2801
2968
|
function renderMysqlCheckProbe(params) {
|
|
2802
2969
|
if (params.dialect.name !== "mysql")
|
|
2803
|
-
throw
|
|
2970
|
+
throw unsupportedCapability19({ dialect: params.dialect.name, feature: "temporaryCheckProbe" });
|
|
2804
2971
|
const q = (name) => params.dialect.quoteIdent({ name });
|
|
2805
2972
|
const probe = q(params.probe);
|
|
2806
2973
|
switch (params.operation) {
|
|
2807
2974
|
case "clone":
|
|
2808
2975
|
if (params.table === undefined)
|
|
2809
|
-
throw
|
|
2976
|
+
throw unsupportedCapability19({ dialect: "mysql", feature: "temporaryCheckProbe", hint: "A source table is required" });
|
|
2810
2977
|
return { text: `CREATE TEMPORARY TABLE ${probe} LIKE ${q(params.table.namespace)}.${q(params.table.name)}`, values: [], returning: "none" };
|
|
2811
2978
|
case "add": {
|
|
2812
2979
|
if (params.expression === undefined || params.definition === undefined)
|
|
2813
|
-
throw
|
|
2980
|
+
throw unsupportedCapability19({ dialect: "mysql", feature: "temporaryCheckProbe", hint: "An authored expression and temporary clone definition are required" });
|
|
2814
2981
|
const parts = tableDefinitionParts({ sql: params.definition });
|
|
2815
2982
|
return { text: `CREATE TEMPORARY TABLE ${probe} (
|
|
2816
2983
|
${[...parts.clauses, `CONSTRAINT ${probe} CHECK (${params.expression})`].join(`,
|
|
@@ -2856,31 +3023,31 @@ function sqliteTableConstraints(params) {
|
|
|
2856
3023
|
return result;
|
|
2857
3024
|
}
|
|
2858
3025
|
// packages/sql/src/dialects/migration-visibility.ts
|
|
2859
|
-
import { unsupportedCapability as
|
|
3026
|
+
import { unsupportedCapability as unsupportedCapability20 } from "@vibeorm/schema";
|
|
2860
3027
|
function renderMigrationVisibility(params) {
|
|
2861
3028
|
if (params.dialect.name !== "mysql")
|
|
2862
|
-
throw
|
|
3029
|
+
throw unsupportedCapability20({ dialect: params.dialect.name, feature: "mysqlCatalogVisibility" });
|
|
2863
3030
|
const collector = new ParamCollector(params.dialect);
|
|
2864
3031
|
const grantee = "CONCAT(QUOTE(SUBSTRING_INDEX(CURRENT_USER(), '@', 1)), '@', QUOTE(SUBSTRING_INDEX(CURRENT_USER(), '@', -1)))";
|
|
2865
3032
|
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`, values: collector.values, returning: "none" };
|
|
2866
3033
|
}
|
|
2867
3034
|
// packages/sql/src/dialects/migration-inventory.ts
|
|
2868
|
-
import { unsupportedCapability as
|
|
3035
|
+
import { unsupportedCapability as unsupportedCapability21 } from "@vibeorm/schema";
|
|
2869
3036
|
function renderSqliteColumnInventory(params) {
|
|
2870
3037
|
if (params.dialect.name !== "sqlite")
|
|
2871
|
-
throw
|
|
3038
|
+
throw unsupportedCapability21({ dialect: params.dialect.name, feature: "sqliteColumnInventory" });
|
|
2872
3039
|
const collector = new ParamCollector(params.dialect);
|
|
2873
3040
|
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" };
|
|
2874
3041
|
}
|
|
2875
3042
|
function renderSqliteForeignKeyInventory(params) {
|
|
2876
3043
|
if (params.dialect.name !== "sqlite")
|
|
2877
|
-
throw
|
|
3044
|
+
throw unsupportedCapability21({ dialect: params.dialect.name, feature: "sqliteForeignKeyInventory" });
|
|
2878
3045
|
const collector = new ParamCollector(params.dialect);
|
|
2879
3046
|
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" };
|
|
2880
3047
|
}
|
|
2881
3048
|
function renderSqliteRebuildObjects(params) {
|
|
2882
3049
|
if (params.dialect.name !== "sqlite")
|
|
2883
|
-
throw
|
|
3050
|
+
throw unsupportedCapability21({ dialect: params.dialect.name, feature: "sqliteRebuildObjects" });
|
|
2884
3051
|
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" };
|
|
2885
3052
|
}
|
|
2886
3053
|
function renderMigrationInventory(params) {
|
|
@@ -2900,6 +3067,8 @@ UNION ALL SELECT 'trigger', t.tgname::text, r.relname::text, NULL, NULL, NULL FR
|
|
|
2900
3067
|
UNION ALL SELECT 'column', a.attname::text, r.relname::text, NULL, NULL, NULL FROM relations r JOIN pg_catalog.pg_attribute a ON a.attrelid = r.oid WHERE a.attnum > 0 AND NOT a.attisdropped AND r.relkind IN ('r','p')
|
|
2901
3068
|
UNION ALL SELECT CASE WHEN a.attgenerated <> '' THEN 'generatedColumn' ELSE 'columnDefault' END, a.attname::text, r.relname::text, NULL, NULL, NULL FROM relations r JOIN pg_catalog.pg_attribute a ON a.attrelid = r.oid JOIN pg_catalog.pg_attrdef d ON d.adrelid = r.oid AND d.adnum = a.attnum WHERE a.attnum > 0 AND NOT a.attisdropped
|
|
2902
3069
|
UNION ALL SELECT 'function', p.proname::text, NULL, NULL, COALESCE((SELECT json_agg(json_build_object('namespace', tn.nspname, 'name', t.typname) ORDER BY a.ord)::text FROM unnest(p.proargtypes) WITH ORDINALITY a(oid, ord) JOIN pg_catalog.pg_type t ON t.oid = a.oid JOIN pg_catalog.pg_namespace tn ON tn.oid = t.typnamespace), '[]'), NULL FROM pg_catalog.pg_proc p JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace WHERE n.nspname = ${namespace} AND p.prokind = 'f' AND NOT EXISTS (SELECT 1 FROM pg_catalog.pg_depend d WHERE d.classid = 'pg_proc'::regclass AND d.objid = p.oid AND d.deptype = 'e')
|
|
3070
|
+
UNION ALL SELECT 'enum', t.typname::text, NULL, NULL, NULL, NULL FROM pg_catalog.pg_type t JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace WHERE n.nspname = ${namespace} AND t.typtype = 'e' AND NOT EXISTS (SELECT 1 FROM pg_catalog.pg_depend d WHERE d.classid = 'pg_type'::regclass AND d.objid = t.oid AND d.deptype = 'e')
|
|
3071
|
+
${params.namespace === "public" ? "" : `UNION ALL SELECT 'namespace', n.nspname::text, NULL, NULL, NULL, NULL FROM pg_catalog.pg_namespace n WHERE n.nspname = ${namespace}`}
|
|
2903
3072
|
ORDER BY kind, parent, name`, values: collector.values, returning: "none" };
|
|
2904
3073
|
}
|
|
2905
3074
|
if (params.dialect.name === "mysql") {
|
|
@@ -2917,12 +3086,17 @@ ORDER BY kind, parent, name`, values: collector.values, returning: "none" };
|
|
|
2917
3086
|
return { text: `SELECT type AS kind, name, tbl_name AS parent, sql AS definition FROM ${schema}.sqlite_schema WHERE name NOT LIKE 'sqlite\\_%' ESCAPE '\\' AND name <> '_vibe_migrations' ORDER BY type, tbl_name, name`, values: [], returning: "none" };
|
|
2918
3087
|
}
|
|
2919
3088
|
// packages/sql/src/dialects/migration-objects.ts
|
|
2920
|
-
import { internalError as internalError3, unsupportedCapability as
|
|
3089
|
+
import { internalError as internalError3, unsupportedCapability as unsupportedCapability22 } from "@vibeorm/schema";
|
|
2921
3090
|
function renderMigrationObjectQuery(params) {
|
|
2922
3091
|
return objectQuery({ ...params, collector: new ParamCollector(params.dialect) });
|
|
2923
3092
|
}
|
|
2924
3093
|
function objectQuery(params) {
|
|
2925
3094
|
const { dialect, identity: object, collector } = params;
|
|
3095
|
+
if (object.kind === "namespace") {
|
|
3096
|
+
if (dialect.name !== "postgres")
|
|
3097
|
+
throw unsupportedCapability22({ dialect: dialect.name, feature: "fixedNamespaces" });
|
|
3098
|
+
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" };
|
|
3099
|
+
}
|
|
2926
3100
|
const physical = "table" in object ? object.table : object.name;
|
|
2927
3101
|
const namespace = collector.add(physical.namespace);
|
|
2928
3102
|
const name = collector.add(physical.name);
|
|
@@ -2984,7 +3158,7 @@ function objectQuery(params) {
|
|
|
2984
3158
|
break;
|
|
2985
3159
|
case "constraint":
|
|
2986
3160
|
if (object.constraintType === "exclusion")
|
|
2987
|
-
throw
|
|
3161
|
+
throw unsupportedCapability22({ dialect: "mysql", feature: "exclusionConstraints" });
|
|
2988
3162
|
text = `SELECT tc.CONSTRAINT_TYPE AS type, tc.ENFORCED AS enforced, cc.CHECK_CLAUSE AS definition, rc.UPDATE_RULE AS onUpdate, rc.DELETE_RULE AS onDelete, rc.MATCH_OPTION AS matchOption FROM information_schema.TABLE_CONSTRAINTS tc LEFT JOIN information_schema.CHECK_CONSTRAINTS cc ON cc.CONSTRAINT_SCHEMA = tc.CONSTRAINT_SCHEMA AND cc.CONSTRAINT_NAME = tc.CONSTRAINT_NAME LEFT JOIN information_schema.REFERENTIAL_CONSTRAINTS rc ON rc.CONSTRAINT_SCHEMA = tc.CONSTRAINT_SCHEMA AND rc.TABLE_NAME = tc.TABLE_NAME AND rc.CONSTRAINT_NAME = tc.CONSTRAINT_NAME WHERE tc.TABLE_SCHEMA = ${namespace} AND tc.TABLE_NAME = ${name} AND tc.CONSTRAINT_NAME = ${collector.add(object.name)}`;
|
|
2989
3163
|
break;
|
|
2990
3164
|
case "index":
|
|
@@ -2994,15 +3168,15 @@ function objectQuery(params) {
|
|
|
2994
3168
|
text = `SELECT TABLE_TYPE AS type, ENGINE AS engine, TABLE_COLLATION AS collation FROM information_schema.TABLES WHERE TABLE_SCHEMA = ${namespace} AND TABLE_NAME = ${name}`;
|
|
2995
3169
|
break;
|
|
2996
3170
|
default:
|
|
2997
|
-
throw
|
|
3171
|
+
throw unsupportedCapability22({ dialect: "mysql", feature: `inspect:${object.kind}` });
|
|
2998
3172
|
}
|
|
2999
3173
|
} else {
|
|
3000
3174
|
if (physical.namespace !== "main" && physical.namespace !== "temp")
|
|
3001
|
-
throw
|
|
3175
|
+
throw unsupportedCapability22({ dialect: "sqlite", feature: "attachedSchemaInspection" });
|
|
3002
3176
|
const catalog = `${dialect.quoteIdent({ name: physical.namespace })}.sqlite_schema`;
|
|
3003
3177
|
const kind = object.kind === "table" || object.kind === "view" ? object.kind : object.kind === "trigger" ? "trigger" : object.kind === "index" ? "index" : "table";
|
|
3004
3178
|
if (["function", "sequence", "postgresExtension", "enum"].includes(object.kind) || object.kind === "constraint" && object.constraintType === "exclusion")
|
|
3005
|
-
throw
|
|
3179
|
+
throw unsupportedCapability22({ dialect: "sqlite", feature: `inspect:${object.kind}` });
|
|
3006
3180
|
const sqliteParams = new ParamCollector(dialect);
|
|
3007
3181
|
if (object.kind === "column" || object.kind === "columnDefault" || object.kind === "generatedColumn") {
|
|
3008
3182
|
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)}`;
|
|
@@ -3032,10 +3206,14 @@ function renderMigrationDependencies(params) {
|
|
|
3032
3206
|
}
|
|
3033
3207
|
function dependencyQuery(params) {
|
|
3034
3208
|
if (params.dialect.name !== "postgres")
|
|
3035
|
-
throw
|
|
3209
|
+
throw unsupportedCapability22({ dialect: params.dialect.name, feature: "catalogDependencies" });
|
|
3036
3210
|
const object = params.identity;
|
|
3037
|
-
const physical = "table" in object ? object.table : object.name;
|
|
3038
3211
|
const collector = params.collector;
|
|
3212
|
+
if (object.kind === "namespace") {
|
|
3213
|
+
const namespace = collector.add(object.name);
|
|
3214
|
+
return { text: `SELECT DISTINCT json_build_array(d.deptype, a.type, a.object_names, a.object_args)::text AS address FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_depend d ON d.classid = 'pg_namespace'::regclass AND d.objid = n.oid AND d.objsubid = 0 CROSS JOIN LATERAL pg_catalog.pg_identify_object_as_address(d.refclassid, d.refobjid, d.refobjsubid) a WHERE n.nspname = ${namespace} ORDER BY address`, values: collector.values, returning: "none" };
|
|
3215
|
+
}
|
|
3216
|
+
const physical = "table" in object ? object.table : object.name;
|
|
3039
3217
|
const namespace = collector.add(physical.namespace);
|
|
3040
3218
|
const name = collector.add(physical.name);
|
|
3041
3219
|
const relation = `SELECT c.oid FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = ${namespace} AND c.relname = ${name}`;
|
|
@@ -3085,7 +3263,7 @@ function inspectionReferences(params) {
|
|
|
3085
3263
|
function renderMigrationObjectBatch(params) {
|
|
3086
3264
|
const { dialect } = params;
|
|
3087
3265
|
if (dialect.name !== "postgres")
|
|
3088
|
-
throw
|
|
3266
|
+
throw unsupportedCapability22({ dialect: dialect.name, feature: "batchedMigrationInspection" });
|
|
3089
3267
|
const groups = new Map;
|
|
3090
3268
|
for (const [position, identity] of params.identities.entries()) {
|
|
3091
3269
|
const kind = identity.kind === "constraint" ? `${identity.kind}:${identity.constraintType}` : identity.kind === "generatedColumn" ? "columnDefault" : identity.kind;
|
|
@@ -3118,16 +3296,16 @@ function renderMigrationNamespace(params) {
|
|
|
3118
3296
|
}
|
|
3119
3297
|
function renderCheckProbe(params) {
|
|
3120
3298
|
if (params.dialect.name !== "postgres")
|
|
3121
|
-
throw
|
|
3299
|
+
throw unsupportedCapability22({ dialect: params.dialect.name, feature: "rollbackCheckProbe" });
|
|
3122
3300
|
const q = (name) => params.dialect.quoteIdent({ name });
|
|
3123
3301
|
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" };
|
|
3124
3302
|
}
|
|
3125
3303
|
// packages/sql/src/dialects/postgres-migration.ts
|
|
3126
|
-
import { VibeError as
|
|
3304
|
+
import { VibeError as VibeError11, unsupportedCapability as unsupportedCapability23 } from "@vibeorm/schema";
|
|
3127
3305
|
var SETTING_VALUE = /^[0-9]+(?:\.[0-9]+)?\s*(?:us|ms|s|min|h|d)?$/;
|
|
3128
3306
|
function requirePostgres2(params) {
|
|
3129
3307
|
if (params.dialect.name !== "postgres") {
|
|
3130
|
-
throw
|
|
3308
|
+
throw unsupportedCapability23({ dialect: params.dialect.name, feature: params.feature });
|
|
3131
3309
|
}
|
|
3132
3310
|
}
|
|
3133
3311
|
function renderMigrationSessionRead(params) {
|
|
@@ -3142,7 +3320,7 @@ function renderMigrationSessionSet(params) {
|
|
|
3142
3320
|
requirePostgres2({ dialect: params.dialect, feature: "migrationSessionSettings" });
|
|
3143
3321
|
const { milliseconds, setting } = params;
|
|
3144
3322
|
if (!Number.isSafeInteger(milliseconds) || milliseconds < 0) {
|
|
3145
|
-
throw new
|
|
3323
|
+
throw new VibeError11({
|
|
3146
3324
|
code: "VIBE_MIGRATION",
|
|
3147
3325
|
message: `${setting} must be a non-negative integer number of milliseconds (got ${String(milliseconds)})`,
|
|
3148
3326
|
meta: { reason: "execution-metadata-invalid", setting, value: milliseconds }
|
|
@@ -3271,12 +3449,14 @@ export {
|
|
|
3271
3449
|
isFixedDiagnostic,
|
|
3272
3450
|
isJsonParamCell,
|
|
3273
3451
|
isListSetOperation,
|
|
3452
|
+
isNativeEnumArrayParameter,
|
|
3274
3453
|
isSetOperation,
|
|
3275
3454
|
isSqlDefaultCell,
|
|
3276
3455
|
isSqlFragment,
|
|
3277
3456
|
jsonParamCell,
|
|
3278
3457
|
mapConflictColumns,
|
|
3279
3458
|
mysqlDialect,
|
|
3459
|
+
nativeEnumArrayParameter,
|
|
3280
3460
|
parseDateTimeText,
|
|
3281
3461
|
parsePgArrayLiteral,
|
|
3282
3462
|
parsePostgresTypeName,
|
|
@@ -3293,7 +3473,10 @@ export {
|
|
|
3293
3473
|
renderExclusionProbe,
|
|
3294
3474
|
renderExclusionSetup,
|
|
3295
3475
|
renderExpr,
|
|
3476
|
+
renderExternalDependents,
|
|
3477
|
+
renderExternalOwnershipCatalog,
|
|
3296
3478
|
renderFragment,
|
|
3479
|
+
renderIndexColumns,
|
|
3297
3480
|
renderIndexStateQuery,
|
|
3298
3481
|
renderMigrationDependencies,
|
|
3299
3482
|
renderMigrationHistoryQuery,
|
|
@@ -3312,6 +3495,8 @@ export {
|
|
|
3312
3495
|
renderMysqlObjectMembers,
|
|
3313
3496
|
renderPostgresDefaultFunctionIdentity,
|
|
3314
3497
|
renderPostgresExplain,
|
|
3498
|
+
renderPostgresIndexKeys,
|
|
3499
|
+
renderPostgresPhysicalCatalog,
|
|
3315
3500
|
renderPostgresTypeIdentity,
|
|
3316
3501
|
renderPostgresTypeName,
|
|
3317
3502
|
renderPostgresWorkload,
|
|
@@ -3345,7 +3530,8 @@ export {
|
|
|
3345
3530
|
sqliteTableConstraints,
|
|
3346
3531
|
startsWithPattern,
|
|
3347
3532
|
strictMatchPattern,
|
|
3533
|
+
tableDefinitionParts,
|
|
3348
3534
|
toPgArrayLiteral
|
|
3349
3535
|
};
|
|
3350
3536
|
|
|
3351
|
-
//# debugId=
|
|
3537
|
+
//# debugId=55E18657169AA23764756E2164756E21
|