@vibeorm/sql 2.1.1 → 2.3.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 +4 -2
- package/dist/ast.d.ts.map +1 -1
- package/dist/codecs.d.ts.map +1 -1
- package/dist/dialects/migration-objects.d.ts +9 -0
- package/dist/dialects/migration-objects.d.ts.map +1 -1
- package/dist/dialects/migration-replay-coverage.d.ts +9 -0
- package/dist/dialects/migration-replay-coverage.d.ts.map +1 -0
- package/dist/dialects/migration-shadow.d.ts +44 -0
- package/dist/dialects/migration-shadow.d.ts.map +1 -0
- package/dist/dialects/module-dependency.d.ts +16 -0
- package/dist/dialects/module-dependency.d.ts.map +1 -0
- package/dist/dialects/postgres-default-identity.d.ts +10 -0
- package/dist/dialects/postgres-default-identity.d.ts.map +1 -0
- package/dist/dialects/postgres-type-identity.d.ts +32 -0
- package/dist/dialects/postgres-type-identity.d.ts.map +1 -0
- package/dist/dialects/sqlite-session.d.ts +12 -0
- package/dist/dialects/sqlite-session.d.ts.map +1 -0
- package/dist/index.d.ts +12 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +532 -218
- package/dist/index.js.map +16 -9
- package/dist/module-journal.d.ts +25 -0
- package/dist/module-journal.d.ts.map +1 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
// packages/sql/src/composable.ts
|
|
3
|
-
import { VibeError } from "@vibeorm/schema";
|
|
4
|
-
|
|
5
2
|
// packages/sql/src/params.ts
|
|
6
3
|
class ParamCollector {
|
|
7
4
|
dialect;
|
|
@@ -19,7 +16,171 @@ class ParamCollector {
|
|
|
19
16
|
}
|
|
20
17
|
}
|
|
21
18
|
|
|
19
|
+
// packages/sql/src/dialects/module-dependency.ts
|
|
20
|
+
function renderModuleDependencyQuery(params) {
|
|
21
|
+
const { dialect, operation } = params;
|
|
22
|
+
if (operation.kind === "visibility")
|
|
23
|
+
return dialect.name === "mysql" ? { text: "SHOW GRANTS FOR CURRENT_USER", values: [], returning: "none" } : undefined;
|
|
24
|
+
if (dialect.name === "sqlite" || operation.tables.length === 0)
|
|
25
|
+
return;
|
|
26
|
+
const collector = new ParamCollector(dialect);
|
|
27
|
+
const owned = operation.tables.map((table, index) => `SELECT ${collector.add(operation.namespace)}${index === 0 ? " AS namespace" : ""}, ${collector.add(table)}${index === 0 ? " AS table_name" : ""}`).join(" UNION ALL ");
|
|
28
|
+
const pg = dialect.name === "postgres";
|
|
29
|
+
const nameKey = ({ column }) => pg ? column : `CAST(IF(@@lower_case_table_names = 0, ${column}, LOWER(${column})) AS BINARY)`;
|
|
30
|
+
const isOwned = ({ namespace, table }) => `EXISTS (SELECT 1 FROM owned_tables o WHERE ${nameKey({ column: namespace })} = ${nameKey({ column: "o.namespace" })} AND ${nameKey({ column: table })} = ${nameKey({ column: "o.table_name" })})`;
|
|
31
|
+
const sourceNamespace = pg ? "sn.nspname" : "fk.CONSTRAINT_SCHEMA";
|
|
32
|
+
const sourceTable = pg ? "s.relname" : "fk.TABLE_NAME";
|
|
33
|
+
const targetNamespace = pg ? "tn.nspname" : "fk.UNIQUE_CONSTRAINT_SCHEMA";
|
|
34
|
+
const targetTable = pg ? "t.relname" : "fk.REFERENCED_TABLE_NAME";
|
|
35
|
+
const from = pg ? "pg_catalog.pg_constraint fk JOIN pg_catalog.pg_class s ON s.oid = fk.conrelid JOIN pg_catalog.pg_namespace sn ON sn.oid = s.relnamespace JOIN pg_catalog.pg_class t ON t.oid = fk.confrelid JOIN pg_catalog.pg_namespace tn ON tn.oid = t.relnamespace WHERE fk.contype = 'f'" : "information_schema.REFERENTIAL_CONSTRAINTS fk";
|
|
36
|
+
return {
|
|
37
|
+
text: `WITH owned_tables AS (${owned})
|
|
38
|
+
SELECT * FROM (SELECT ${pg ? "fk.conname" : "fk.CONSTRAINT_NAME"} AS constraint_name, ${sourceNamespace} AS source_namespace, ${sourceTable} AS source_table, ${targetNamespace} AS target_namespace, ${targetTable} AS target_table, ${isOwned({ namespace: sourceNamespace, table: sourceTable })} AS source_owned, ${isOwned({ namespace: targetNamespace, table: targetTable })} AS target_owned FROM ${from}) dependencies
|
|
39
|
+
WHERE source_owned OR target_owned
|
|
40
|
+
ORDER BY source_namespace, source_table, constraint_name`,
|
|
41
|
+
values: collector.values,
|
|
42
|
+
returning: "none"
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
// packages/sql/src/dialects/migration-replay-coverage.ts
|
|
46
|
+
function renderReplayCoverageGaps(params) {
|
|
47
|
+
const { dialect } = params;
|
|
48
|
+
const collector = new ParamCollector(dialect);
|
|
49
|
+
const namespace = collector.add(params.namespace);
|
|
50
|
+
if (dialect.name === "postgres")
|
|
51
|
+
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')
|
|
52
|
+
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')
|
|
53
|
+
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')
|
|
54
|
+
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'
|
|
55
|
+
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 '\\'${params.privateNamespace === undefined ? "" : ` AND n.nspname <> ${collector.add(params.privateNamespace)}`}`, values: collector.values, returning: "none" };
|
|
56
|
+
if (dialect.name === "mysql")
|
|
57
|
+
return { text: `SELECT 'procedure' AS kind, ROUTINE_NAME AS name FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = ${namespace} AND ROUTINE_TYPE = 'PROCEDURE'
|
|
58
|
+
UNION ALL SELECT 'event', EVENT_NAME FROM information_schema.EVENTS WHERE EVENT_SCHEMA = ${collector.add(params.namespace)}
|
|
59
|
+
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" };
|
|
60
|
+
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" };
|
|
61
|
+
}
|
|
62
|
+
// packages/sql/src/dialects/migration-shadow.ts
|
|
63
|
+
import { unsupportedCapability } from "@vibeorm/schema";
|
|
64
|
+
var SHADOW_DATABASE = Object.freeze({ schema: "_vibeorm_shadow", table: "_vibe_shadow", lock: 1447645267, timeoutSeconds: 60 });
|
|
65
|
+
var SHADOW_CAPABILITIES = Object.freeze({
|
|
66
|
+
postgres: Object.freeze({ serverProvisioning: true, dedicated: true }),
|
|
67
|
+
mysql: Object.freeze({ serverProvisioning: true, dedicated: true }),
|
|
68
|
+
sqlite: Object.freeze({ serverProvisioning: false, dedicated: false })
|
|
69
|
+
});
|
|
70
|
+
function renderShadowOperation(params) {
|
|
71
|
+
const { dialect, operation } = params;
|
|
72
|
+
if (!SHADOW_CAPABILITIES[dialect.name].serverProvisioning)
|
|
73
|
+
throw unsupportedCapability({ dialect: dialect.name, feature: "shadowDatabaseProvisioning" });
|
|
74
|
+
const pg = dialect.name === "postgres";
|
|
75
|
+
const collector = new ParamCollector(dialect);
|
|
76
|
+
const marker = pg ? `${dialect.quoteIdent({ name: SHADOW_DATABASE.schema })}.${dialect.quoteIdent({ name: SHADOW_DATABASE.table })}` : dialect.quoteIdent({ name: SHADOW_DATABASE.table });
|
|
77
|
+
const result = (text) => [{ text, values: collector.values, returning: "none" }];
|
|
78
|
+
switch (operation.kind) {
|
|
79
|
+
case "createDatabase":
|
|
80
|
+
return result(`CREATE DATABASE ${dialect.quoteIdent({ name: operation.name })}`);
|
|
81
|
+
case "dropDatabase":
|
|
82
|
+
return result(`DROP DATABASE ${dialect.quoteIdent({ name: operation.name })}`);
|
|
83
|
+
case "identity":
|
|
84
|
+
return result(pg ? `SELECT current_database()::text AS database, (SELECT oid::text FROM pg_catalog.pg_database WHERE datname = current_database()) AS database_id, current_schema()::text AS namespace` : `SELECT DATABASE() AS \`database\`, @@lower_case_table_names AS name_folding, @@server_uuid AS server_id`);
|
|
85
|
+
case "lock":
|
|
86
|
+
return result(pg ? `SELECT pg_catalog.pg_advisory_lock(${collector.add(SHADOW_DATABASE.lock)})` : `SELECT GET_LOCK(${collector.add(`vibeorm_shadow:${operation.database}`)}, ${collector.add(SHADOW_DATABASE.timeoutSeconds)}) AS acquired`);
|
|
87
|
+
case "unlock":
|
|
88
|
+
return result(pg ? `SELECT pg_catalog.pg_advisory_unlock(${collector.add(SHADOW_DATABASE.lock)}) AS released` : `SELECT RELEASE_LOCK(${collector.add(`vibeorm_shadow:${operation.database}`)}) AS released`);
|
|
89
|
+
case "markerExists":
|
|
90
|
+
return result(pg ? `SELECT c.relname AS name FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = ${collector.add(SHADOW_DATABASE.schema)} AND c.relname = ${collector.add(SHADOW_DATABASE.table)}` : `SELECT TABLE_NAME AS name FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ${collector.add(SHADOW_DATABASE.table)}`);
|
|
91
|
+
case "markerRead":
|
|
92
|
+
return result(`SELECT payload FROM ${marker}`);
|
|
93
|
+
case "markerColumns":
|
|
94
|
+
return result(`SELECT column_name AS name, data_type AS type, is_nullable AS nullable FROM information_schema.columns AS marker_column WHERE table_schema = ${pg ? collector.add(SHADOW_DATABASE.schema) : "DATABASE()"} AND table_name = ${collector.add(SHADOW_DATABASE.table)} AND ${pg ? `EXISTS (SELECT 1 FROM pg_catalog.pg_class r JOIN pg_catalog.pg_namespace n ON n.oid = r.relnamespace WHERE n.nspname = marker_column.table_schema AND r.relname = marker_column.table_name AND r.relkind = 'r' AND r.relpersistence = 'p' AND NOT r.relrowsecurity AND NOT r.relforcerowsecurity AND NOT r.relhasrules AND NOT r.relhastriggers AND NOT r.relispartition AND NOT EXISTS (SELECT 1 FROM pg_catalog.pg_attrdef a WHERE a.adrelid = r.oid) AND NOT EXISTS (SELECT 1 FROM pg_catalog.pg_constraint c WHERE c.conrelid = r.oid AND c.contype <> 'n') AND NOT EXISTS (SELECT 1 FROM pg_catalog.pg_index i WHERE i.indrelid = r.oid) AND NOT EXISTS (SELECT 1 FROM pg_catalog.pg_inherits i WHERE i.inhrelid = r.oid OR i.inhparent = r.oid) AND NOT EXISTS (SELECT 1 FROM pg_catalog.pg_attribute a WHERE a.attrelid = r.oid AND (a.attisdropped OR a.attidentity <> '' OR a.attgenerated <> '')))` : `EXISTS (SELECT 1 FROM information_schema.TABLES t WHERE t.TABLE_SCHEMA = marker_column.table_schema AND t.TABLE_NAME = marker_column.table_name AND t.TABLE_TYPE = 'BASE TABLE' AND t.ENGINE = 'InnoDB') AND NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS c WHERE c.TABLE_SCHEMA = marker_column.table_schema AND c.TABLE_NAME = marker_column.table_name AND (c.COLUMN_DEFAULT IS NOT NULL OR c.EXTRA <> '')) AND NOT EXISTS (SELECT 1 FROM information_schema.TRIGGERS t WHERE t.EVENT_OBJECT_SCHEMA = DATABASE() AND t.EVENT_OBJECT_TABLE = ${collector.add(SHADOW_DATABASE.table)}) AND NOT EXISTS (SELECT 1 FROM information_schema.TABLE_CONSTRAINTS c WHERE c.TABLE_SCHEMA = DATABASE() AND c.TABLE_NAME = ${collector.add(SHADOW_DATABASE.table)})`}
|
|
95
|
+
ORDER BY ordinal_position`);
|
|
96
|
+
case "grants": {
|
|
97
|
+
if (pg)
|
|
98
|
+
throw unsupportedCapability({ dialect: dialect.name, feature: "mysqlShadowPrivileges" });
|
|
99
|
+
return result("SHOW GRANTS FOR CURRENT_USER");
|
|
100
|
+
}
|
|
101
|
+
case "markerCreate":
|
|
102
|
+
return pg ? [{ text: `CREATE SCHEMA ${dialect.quoteIdent({ name: SHADOW_DATABASE.schema })}`, values: [], returning: "none" }, { text: `CREATE TABLE ${marker} (payload text NOT NULL)`, values: [], returning: "none" }] : result(`CREATE TABLE ${marker} (payload LONGTEXT NOT NULL) ENGINE=InnoDB`);
|
|
103
|
+
case "markerWrite":
|
|
104
|
+
return result(operation.insert ? `INSERT INTO ${marker} (payload) VALUES (${collector.add(operation.value)})` : `UPDATE ${marker} SET payload = ${collector.add(operation.value)}`);
|
|
105
|
+
case "journal":
|
|
106
|
+
return result(`SELECT name, checksum, statement_index, error FROM ${dialect.quoteIdent({ name: "_vibe_migrations" })} ORDER BY name`);
|
|
107
|
+
case "inventory":
|
|
108
|
+
return result(pg ? `SELECT 'namespace' AS kind, nspname::text AS name, nspname::text AS namespace FROM pg_catalog.pg_namespace WHERE nspname NOT IN ('public', 'information_schema') AND nspname NOT LIKE 'pg\\_%' ESCAPE '\\'
|
|
109
|
+
UNION ALL SELECT 'relation', c.relname::text, n.nspname::text FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname <> 'information_schema' AND n.nspname NOT LIKE 'pg\\_%' ESCAPE '\\'
|
|
110
|
+
UNION ALL SELECT 'routine', p.proname::text, n.nspname::text FROM pg_catalog.pg_proc p JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace WHERE n.nspname <> 'information_schema' AND n.nspname NOT LIKE 'pg\\_%' ESCAPE '\\'
|
|
111
|
+
UNION ALL SELECT 'type', t.typname::text, n.nspname::text FROM pg_catalog.pg_type t JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace WHERE n.nspname <> 'information_schema' AND n.nspname NOT LIKE 'pg\\_%' ESCAPE '\\' AND t.typrelid = 0 AND t.typelem = 0
|
|
112
|
+
UNION ALL SELECT 'extension', e.extname::text, n.nspname::text FROM pg_catalog.pg_extension e JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace WHERE e.extname <> 'plpgsql'
|
|
113
|
+
UNION ALL SELECT 'marker-dependency', d.objid::text, '${SHADOW_DATABASE.schema}' FROM pg_catalog.pg_depend d JOIN pg_catalog.pg_class c ON d.classid = 'pg_class'::regclass AND d.objid = c.oid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = '${SHADOW_DATABASE.schema}' AND d.deptype NOT IN ('i', 'a') AND d.refclassid <> 'pg_namespace'::regclass
|
|
114
|
+
UNION ALL SELECT 'marker-trigger', t.tgname::text, n.nspname::text FROM pg_catalog.pg_trigger t JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = '${SHADOW_DATABASE.schema}'
|
|
115
|
+
UNION ALL SELECT 'namespace-object', o.name::text, n.nspname::text FROM pg_catalog.pg_depend d JOIN pg_catalog.pg_namespace n ON d.refclassid = 'pg_namespace'::regclass AND d.refobjid = n.oid CROSS JOIN LATERAL pg_catalog.pg_identify_object(d.classid, d.objid, d.objsubid) o WHERE n.nspname <> 'information_schema' AND n.nspname NOT LIKE 'pg\\_%' ESCAPE '\\' AND d.classid NOT IN ('pg_class'::regclass, 'pg_proc'::regclass, 'pg_type'::regclass, 'pg_extension'::regclass)
|
|
116
|
+
UNION ALL SELECT 'database-object', evtname::text, '' FROM pg_catalog.pg_event_trigger
|
|
117
|
+
UNION ALL SELECT 'database-object', pubname::text, '' FROM pg_catalog.pg_publication
|
|
118
|
+
UNION ALL SELECT 'database-object', subname::text, '' FROM pg_catalog.pg_subscription WHERE subdbid = (SELECT oid FROM pg_catalog.pg_database WHERE datname = current_database())
|
|
119
|
+
UNION ALL SELECT 'database-object', srvname::text, '' FROM pg_catalog.pg_foreign_server
|
|
120
|
+
UNION ALL SELECT 'database-object', fdwname::text, '' FROM pg_catalog.pg_foreign_data_wrapper
|
|
121
|
+
UNION ALL SELECT 'database-object', c.oid::text, '' FROM pg_catalog.pg_cast c JOIN pg_catalog.pg_type s ON s.oid = c.castsource JOIN pg_catalog.pg_type t ON t.oid = c.casttarget LEFT JOIN pg_catalog.pg_proc p ON p.oid = c.castfunc WHERE s.typnamespace <> 'pg_catalog'::regnamespace OR t.typnamespace <> 'pg_catalog'::regnamespace OR p.pronamespace <> 'pg_catalog'::regnamespace` : `SELECT TABLE_TYPE AS kind, TABLE_NAME AS name, TABLE_SCHEMA AS namespace FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE()
|
|
122
|
+
UNION ALL SELECT ROUTINE_TYPE, ROUTINE_NAME, ROUTINE_SCHEMA FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = DATABASE()
|
|
123
|
+
UNION ALL SELECT 'EVENT', EVENT_NAME, EVENT_SCHEMA FROM information_schema.EVENTS WHERE EVENT_SCHEMA = DATABASE()
|
|
124
|
+
UNION ALL SELECT 'TRIGGER', TRIGGER_NAME, TRIGGER_SCHEMA FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA = DATABASE()
|
|
125
|
+
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)`);
|
|
126
|
+
case "resetPostgres": {
|
|
127
|
+
if (!pg)
|
|
128
|
+
throw unsupportedCapability({ dialect: dialect.name, feature: "postgresShadowReset" });
|
|
129
|
+
return [{ text: 'DROP SCHEMA "public" CASCADE', values: [], returning: "none" }, { text: 'CREATE SCHEMA "public"', values: [], returning: "none" }];
|
|
130
|
+
}
|
|
131
|
+
case "mysqlForeignKeys": {
|
|
132
|
+
if (pg)
|
|
133
|
+
throw unsupportedCapability({ dialect: dialect.name, feature: "mysqlShadowReset" });
|
|
134
|
+
return result(`SET FOREIGN_KEY_CHECKS = ${operation.enabled ? "1" : "0"}`);
|
|
135
|
+
}
|
|
136
|
+
case "dropMysqlObject": {
|
|
137
|
+
if (pg)
|
|
138
|
+
throw unsupportedCapability({ dialect: dialect.name, feature: "mysqlShadowReset" });
|
|
139
|
+
return result(`DROP ${operation.object} ${dialect.quoteIdent({ name: operation.name })}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// packages/sql/src/module-journal.ts
|
|
144
|
+
var MODULE_JOURNAL_COLUMN = "module_origin";
|
|
145
|
+
function renderModuleJournal(params) {
|
|
146
|
+
const { dialect, operation } = params;
|
|
147
|
+
const q = (name) => dialect.quoteIdent({ name });
|
|
148
|
+
const table = q(params.table);
|
|
149
|
+
const column = q(MODULE_JOURNAL_COLUMN);
|
|
150
|
+
const collector = new ParamCollector(dialect);
|
|
151
|
+
let text;
|
|
152
|
+
switch (operation.kind) {
|
|
153
|
+
case "columns":
|
|
154
|
+
text = dialect.name === "sqlite" ? `PRAGMA table_info(${table})` : `SELECT column_name AS name FROM information_schema.columns WHERE table_schema = ${dialect.name === "postgres" ? "current_schema()" : "DATABASE()"} AND table_name = ${collector.add(params.table)}`;
|
|
155
|
+
break;
|
|
156
|
+
case "addColumn":
|
|
157
|
+
text = `ALTER TABLE ${table} ADD COLUMN ${column} ${dialect.name === "mysql" ? "LONGTEXT" : "TEXT"}`;
|
|
158
|
+
break;
|
|
159
|
+
case "read":
|
|
160
|
+
text = `SELECT * FROM ${table} ORDER BY ${q("id")}`;
|
|
161
|
+
break;
|
|
162
|
+
case "insert":
|
|
163
|
+
text = `INSERT INTO ${table} (${["name", "checksum", "statement_index", MODULE_JOURNAL_COLUMN].map(q).join(", ")}) VALUES (${collector.addMany([operation.name, operation.checksum, operation.index, operation.entry]).join(", ")})`;
|
|
164
|
+
break;
|
|
165
|
+
case "complete":
|
|
166
|
+
text = `UPDATE ${table} SET ${column} = ${collector.add(operation.entry)} WHERE ${q("name")} = ${collector.add(operation.name)}`;
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
return { text, values: collector.values };
|
|
170
|
+
}
|
|
171
|
+
// packages/sql/src/dialects/sqlite-session.ts
|
|
172
|
+
var SQLITE_SESSION_SQL = Object.freeze({
|
|
173
|
+
lockingMode: "PRAGMA main.locking_mode",
|
|
174
|
+
exclusive: "PRAGMA main.locking_mode = EXCLUSIVE",
|
|
175
|
+
normal: "PRAGMA main.locking_mode = NORMAL",
|
|
176
|
+
acquire: "BEGIN EXCLUSIVE",
|
|
177
|
+
commit: "COMMIT",
|
|
178
|
+
rollback: "ROLLBACK",
|
|
179
|
+
touch: "SELECT name FROM main.sqlite_schema LIMIT 1",
|
|
180
|
+
foreignKeysOn: "PRAGMA foreign_keys = ON"
|
|
181
|
+
});
|
|
22
182
|
// packages/sql/src/composable.ts
|
|
183
|
+
import { VibeError } from "@vibeorm/schema";
|
|
23
184
|
var fragments = new WeakMap;
|
|
24
185
|
function invalid(message) {
|
|
25
186
|
throw new VibeError({ code: "VIBE_VALIDATION", message });
|
|
@@ -246,9 +407,11 @@ var bigIntCodec = {
|
|
|
246
407
|
decode: (value) => {
|
|
247
408
|
if (typeof value === "bigint")
|
|
248
409
|
return value;
|
|
249
|
-
if (typeof value === "string"
|
|
410
|
+
if (typeof value === "string" && /^[+-]?\d+$/.test(value.trim()))
|
|
411
|
+
return BigInt(value.trim());
|
|
412
|
+
if (typeof value === "number" && Number.isSafeInteger(value))
|
|
250
413
|
return BigInt(value);
|
|
251
|
-
|
|
414
|
+
throw new VibeError2({ code: "VIBE_DATA_INVALID", message: "BigInt requires an integer string or a safe integer", meta: { value } });
|
|
252
415
|
}
|
|
253
416
|
};
|
|
254
417
|
var decimalCodec = {
|
|
@@ -292,7 +455,10 @@ var dateNativeCodec = {
|
|
|
292
455
|
var dateTextCodec = {
|
|
293
456
|
encode: (value) => {
|
|
294
457
|
dateNativeCodec.encode(value);
|
|
295
|
-
|
|
458
|
+
const date = value instanceof Date ? value : typeof value === "string" ? parseDateTimeText({ text: value }) : typeof value === "number" ? new Date(value) : undefined;
|
|
459
|
+
if (date !== undefined && Number.isFinite(date.getTime()))
|
|
460
|
+
return date.toISOString();
|
|
461
|
+
throw new VibeError2({ code: "VIBE_VALIDATION", message: "DateTime parameters require a valid finite timestamp" });
|
|
296
462
|
},
|
|
297
463
|
decode: dateNativeCodec.decode
|
|
298
464
|
};
|
|
@@ -483,15 +649,15 @@ var decode = Object.freeze({
|
|
|
483
649
|
}
|
|
484
650
|
});
|
|
485
651
|
// packages/sql/src/exclusion.ts
|
|
486
|
-
import { VibeError as VibeError5, fieldTypeIdentity as fieldTypeIdentity2, unsupportedCapability as
|
|
652
|
+
import { VibeError as VibeError5, fieldTypeIdentity as fieldTypeIdentity2, unsupportedCapability as unsupportedCapability3 } from "@vibeorm/schema";
|
|
487
653
|
|
|
488
654
|
// packages/sql/src/predicate.ts
|
|
489
|
-
import { VibeError as VibeError4, fieldTypeIdentity, isEnumType, unsupportedCapability } from "@vibeorm/schema";
|
|
655
|
+
import { VibeError as VibeError4, fieldTypeIdentity, isEnumType, unsupportedCapability as unsupportedCapability2 } from "@vibeorm/schema";
|
|
490
656
|
function renderPredicate(params) {
|
|
491
657
|
if (params.usage === "exclusionPredicate" && !params.dialect.capabilities.exclusionConstraints)
|
|
492
|
-
throw
|
|
658
|
+
throw unsupportedCapability2({ dialect: params.dialect.name, feature: "exclusionConstraints" });
|
|
493
659
|
if (params.usage === "indexPredicate" && !params.dialect.capabilities.partialIndexes) {
|
|
494
|
-
throw
|
|
660
|
+
throw unsupportedCapability2({ dialect: params.dialect.name, feature: "partialIndexes" });
|
|
495
661
|
}
|
|
496
662
|
const context = {
|
|
497
663
|
model: params.model,
|
|
@@ -619,7 +785,7 @@ function resolveField(params) {
|
|
|
619
785
|
});
|
|
620
786
|
}
|
|
621
787
|
if (context.usage === "check" && context.dialect.name === "mysql" && field.default?.kind === "autoincrement") {
|
|
622
|
-
throw
|
|
788
|
+
throw unsupportedCapability2({
|
|
623
789
|
dialect: "mysql",
|
|
624
790
|
feature: `CHECK constraint referencing auto-increment column "${context.model.name}.${name}"`,
|
|
625
791
|
hint: "mysql refuses this with error 3818 \u2014 enforce the rule in application code or on a non-generated column"
|
|
@@ -795,7 +961,7 @@ function invalid2(rule) {
|
|
|
795
961
|
function compileExclusion(params) {
|
|
796
962
|
const { exclusion: spec, model, dialect } = params;
|
|
797
963
|
if (!dialect.capabilities.exclusionConstraints)
|
|
798
|
-
throw
|
|
964
|
+
throw unsupportedCapability3({ dialect: dialect.name, feature: "exclusionConstraints" });
|
|
799
965
|
if (!spec.name || spec.name.includes("\x00"))
|
|
800
966
|
invalid2("name");
|
|
801
967
|
if (!["int8range", "tsrange", "tstzrange"].includes(spec.range.type))
|
|
@@ -825,8 +991,8 @@ function compileExclusion(params) {
|
|
|
825
991
|
if (timezone !== (spec.range.type === "tstzrange"))
|
|
826
992
|
invalid2("range-timezone");
|
|
827
993
|
}
|
|
828
|
-
const
|
|
829
|
-
return literal === undefined ?
|
|
994
|
+
const sql = dialect.quoteIdent({ name: column.dbName ?? column.name });
|
|
995
|
+
return literal === undefined ? sql : `COALESCE(${sql}, ${literal})`;
|
|
830
996
|
};
|
|
831
997
|
const keys = spec.keys.map((key) => {
|
|
832
998
|
if ("expression" in key) {
|
|
@@ -848,13 +1014,13 @@ function compileExclusion(params) {
|
|
|
848
1014
|
}
|
|
849
1015
|
function renderExclusionSetup(params) {
|
|
850
1016
|
if (!params.dialect.capabilities.exclusionConstraints)
|
|
851
|
-
throw
|
|
1017
|
+
throw unsupportedCapability3({ dialect: params.dialect.name, feature: "exclusionConstraints" });
|
|
852
1018
|
return params.exclusion.requiredExtensions.map((name) => `CREATE EXTENSION IF NOT EXISTS ${params.dialect.quoteIdent({ name })};`);
|
|
853
1019
|
}
|
|
854
1020
|
function renderExclusionDdl(params) {
|
|
855
1021
|
const { dialect, table, exclusion, operation } = params;
|
|
856
1022
|
if (!dialect.capabilities.exclusionConstraints)
|
|
857
|
-
throw
|
|
1023
|
+
throw unsupportedCapability3({ dialect: dialect.name, feature: "exclusionConstraints" });
|
|
858
1024
|
const target = `ALTER TABLE ${dialect.quoteIdent({ name: table })}`;
|
|
859
1025
|
if (operation === "drop")
|
|
860
1026
|
return [`${target} DROP CONSTRAINT ${dialect.quoteIdent({ name: exclusion.name })};`];
|
|
@@ -863,14 +1029,14 @@ function renderExclusionDdl(params) {
|
|
|
863
1029
|
function renderExclusionCatalog(params) {
|
|
864
1030
|
const { dialect, probe } = params;
|
|
865
1031
|
if (!dialect.capabilities.exclusionConstraints)
|
|
866
|
-
throw
|
|
1032
|
+
throw unsupportedCapability3({ dialect: dialect.name, feature: "exclusionConstraints" });
|
|
867
1033
|
const scope = probe === undefined ? "n.nspname = 'public'" : `t.oid = ${dialect.quoteStringLiteral({ value: probe })}::regclass`;
|
|
868
1034
|
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`;
|
|
869
1035
|
}
|
|
870
1036
|
function renderExclusionProbe(params) {
|
|
871
1037
|
const { dialect, table, probe, definition } = params;
|
|
872
1038
|
if (!dialect.capabilities.exclusionConstraints)
|
|
873
|
-
throw
|
|
1039
|
+
throw unsupportedCapability3({ dialect: dialect.name, feature: "exclusionConstraints" });
|
|
874
1040
|
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}`];
|
|
875
1041
|
}
|
|
876
1042
|
// packages/sql/src/ast.ts
|
|
@@ -879,10 +1045,12 @@ function isSetOperation(value) {
|
|
|
879
1045
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
880
1046
|
return false;
|
|
881
1047
|
const keys = Object.keys(value);
|
|
882
|
-
if (
|
|
1048
|
+
if (!keys.includes("__op") || !keys.includes("value"))
|
|
883
1049
|
return false;
|
|
884
1050
|
const candidate = value;
|
|
885
|
-
|
|
1051
|
+
if (keys.length !== 2 && !(keys.length === 3 && keys.includes("numericType") && candidate.numericType === "Decimal"))
|
|
1052
|
+
return false;
|
|
1053
|
+
return typeof candidate.__op === "string" && SET_OPERATORS.includes(candidate.__op) && (typeof candidate.value === "number" && Number.isFinite(candidate.value) || typeof candidate.value === "string" || typeof candidate.value === "bigint");
|
|
886
1054
|
}
|
|
887
1055
|
var LIST_SET_OPERATORS = ["append", "concat"];
|
|
888
1056
|
function isListSetOperation(value) {
|
|
@@ -924,7 +1092,7 @@ function isExcludedRef(value) {
|
|
|
924
1092
|
}
|
|
925
1093
|
var ADVISORY_LOCK_RESULT_COLUMN = "acquired";
|
|
926
1094
|
// packages/sql/src/locks.ts
|
|
927
|
-
import { internalError, unsupportedCapability as
|
|
1095
|
+
import { internalError, unsupportedCapability as unsupportedCapability4 } from "@vibeorm/schema";
|
|
928
1096
|
var ROW_LOCK_PROSE = Object.freeze({
|
|
929
1097
|
strengths: Object.freeze({
|
|
930
1098
|
update: "FOR UPDATE",
|
|
@@ -944,7 +1112,7 @@ function renderRowLockClause(params) {
|
|
|
944
1112
|
if (syntax === null) {
|
|
945
1113
|
if (lock.strength === "update" && lock.wait === "wait")
|
|
946
1114
|
return null;
|
|
947
|
-
throw
|
|
1115
|
+
throw unsupportedCapability4({
|
|
948
1116
|
dialect: dialect.name,
|
|
949
1117
|
feature: `a ${describeRowLock({ lock })} locking read`,
|
|
950
1118
|
hint: `${dialect.name} has no locking-read clause at all`
|
|
@@ -952,7 +1120,7 @@ function renderRowLockClause(params) {
|
|
|
952
1120
|
}
|
|
953
1121
|
const strengthText = syntax.strengths[lock.strength];
|
|
954
1122
|
if (strengthText === undefined) {
|
|
955
|
-
throw
|
|
1123
|
+
throw unsupportedCapability4({
|
|
956
1124
|
dialect: dialect.name,
|
|
957
1125
|
feature: `the ${describeRowLock({ lock: { ...lock, wait: "wait" } })} row-lock strength`,
|
|
958
1126
|
hint: `${dialect.name} can express: ${Object.keys(syntax.strengths).join(", ")}`
|
|
@@ -960,7 +1128,7 @@ function renderRowLockClause(params) {
|
|
|
960
1128
|
}
|
|
961
1129
|
const waitText = syntax.wait[lock.wait];
|
|
962
1130
|
if (waitText === undefined) {
|
|
963
|
-
throw
|
|
1131
|
+
throw unsupportedCapability4({
|
|
964
1132
|
dialect: dialect.name,
|
|
965
1133
|
feature: `the "${lock.wait}" lock wait policy`,
|
|
966
1134
|
hint: `${dialect.name} can express: ${Object.keys(syntax.wait).join(", ")}`
|
|
@@ -979,7 +1147,7 @@ function renderAdvisoryLock(params) {
|
|
|
979
1147
|
const { dialect, statement, collector } = params;
|
|
980
1148
|
const functions = dialect.advisoryLockFunctions;
|
|
981
1149
|
if (functions === null) {
|
|
982
|
-
throw
|
|
1150
|
+
throw unsupportedCapability4({
|
|
983
1151
|
dialect: dialect.name,
|
|
984
1152
|
feature: "advisory locks",
|
|
985
1153
|
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`
|
|
@@ -1205,7 +1373,7 @@ function getSqlDialect(params) {
|
|
|
1205
1373
|
return SQL_DIALECTS[params.dialect];
|
|
1206
1374
|
}
|
|
1207
1375
|
// packages/sql/src/dialects/diagnostics.ts
|
|
1208
|
-
import { unsupportedCapability as
|
|
1376
|
+
import { unsupportedCapability as unsupportedCapability5 } from "@vibeorm/schema";
|
|
1209
1377
|
var QUERIES = Object.freeze({
|
|
1210
1378
|
postgresJsonWire: { dialect: "postgres", text: `SELECT '{"__vibeorm":1}'::jsonb AS "probe"` },
|
|
1211
1379
|
sqliteTriggers: { dialect: "sqlite", text: "SELECT name, tbl_name, sql FROM sqlite_master WHERE type = 'trigger'" }
|
|
@@ -1213,7 +1381,7 @@ var QUERIES = Object.freeze({
|
|
|
1213
1381
|
function renderDiagnostic(params) {
|
|
1214
1382
|
const query = QUERIES[params.query];
|
|
1215
1383
|
if (params.dialect.name !== query.dialect) {
|
|
1216
|
-
throw
|
|
1384
|
+
throw unsupportedCapability5({ dialect: params.dialect.name, feature: params.query, hint: `this diagnostic requires ${query.dialect}` });
|
|
1217
1385
|
}
|
|
1218
1386
|
return { text: query.text, values: [], returning: "none" };
|
|
1219
1387
|
}
|
|
@@ -1222,7 +1390,7 @@ function isFixedDiagnostic(params) {
|
|
|
1222
1390
|
}
|
|
1223
1391
|
|
|
1224
1392
|
// packages/sql/src/dialects/postgres-diagnostics.ts
|
|
1225
|
-
import { VibeError as VibeError6, unsupportedCapability as
|
|
1393
|
+
import { VibeError as VibeError6, unsupportedCapability as unsupportedCapability6 } from "@vibeorm/schema";
|
|
1226
1394
|
function renderPostgresExplain(params) {
|
|
1227
1395
|
const { dialect, query, options } = params;
|
|
1228
1396
|
requirePostgres({ dialect, feature: "query plan inspection (EXPLAIN)" });
|
|
@@ -1257,7 +1425,7 @@ var POSTGRES_WORKLOAD_LIMITS = Object.freeze({
|
|
|
1257
1425
|
});
|
|
1258
1426
|
function requirePostgres(params) {
|
|
1259
1427
|
if (params.dialect.name !== "postgres") {
|
|
1260
|
-
throw
|
|
1428
|
+
throw unsupportedCapability6({
|
|
1261
1429
|
dialect: params.dialect.name,
|
|
1262
1430
|
feature: params.feature,
|
|
1263
1431
|
hint: "plan inspection and workload statistics are PostgreSQL-shaped; portable operation tracing works on every dialect"
|
|
@@ -1304,10 +1472,10 @@ function requireArg(params) {
|
|
|
1304
1472
|
}
|
|
1305
1473
|
|
|
1306
1474
|
// packages/sql/src/dialects/postgres-rls-readiness.ts
|
|
1307
|
-
import { unsupportedCapability as
|
|
1475
|
+
import { unsupportedCapability as unsupportedCapability8 } from "@vibeorm/schema";
|
|
1308
1476
|
|
|
1309
1477
|
// packages/sql/src/dialects/postgres-rls.ts
|
|
1310
|
-
import { RlsContextError, VibeError as VibeError7, assertValidSchemaIR, unsupportedCapability as
|
|
1478
|
+
import { RlsContextError, VibeError as VibeError7, assertValidSchemaIR, unsupportedCapability as unsupportedCapability7, validateRlsContextIR } from "@vibeorm/schema";
|
|
1311
1479
|
var NATIVE_RLS = Object.freeze({ policyName: "vibeorm_managed", tableSchema: "public", settingPrefix: "vibeorm.", parentAlias: "parent" });
|
|
1312
1480
|
var COLUMN_TYPES = {
|
|
1313
1481
|
String: { default: "text", native: { text: "text", varchar: "varchar", charactervarying: "varchar", uuid: "uuid" } },
|
|
@@ -1320,7 +1488,7 @@ var COLUMN_TYPES = {
|
|
|
1320
1488
|
};
|
|
1321
1489
|
function requireRls(params) {
|
|
1322
1490
|
if (!params.dialect.capabilities.nativeRowLevelSecurity) {
|
|
1323
|
-
throw
|
|
1491
|
+
throw unsupportedCapability7({ dialect: params.dialect.name, feature: "nativeRowLevelSecurity" });
|
|
1324
1492
|
}
|
|
1325
1493
|
}
|
|
1326
1494
|
function identifier2(params) {
|
|
@@ -1331,7 +1499,7 @@ function identifier2(params) {
|
|
|
1331
1499
|
}
|
|
1332
1500
|
function tableRef(params) {
|
|
1333
1501
|
if (params.schema !== undefined && params.schema !== "public" && params.schema !== "pg_temp") {
|
|
1334
|
-
throw
|
|
1502
|
+
throw unsupportedCapability7({ dialect: params.dialect.name, feature: "nativeRowLevelSecurity", hint: "Only public tables and temporary policy probes are supported" });
|
|
1335
1503
|
}
|
|
1336
1504
|
return `${identifier2({ dialect: params.dialect, name: params.schema ?? NATIVE_RLS.tableSchema })}.${identifier2({ dialect: params.dialect, name: params.table })}`;
|
|
1337
1505
|
}
|
|
@@ -1372,7 +1540,7 @@ function renderRlsColumnType(params) {
|
|
|
1372
1540
|
if (native !== undefined)
|
|
1373
1541
|
return native;
|
|
1374
1542
|
}
|
|
1375
|
-
throw
|
|
1543
|
+
throw unsupportedCapability7({ dialect: params.dialect.name, feature: "nativeRowLevelSecurity", hint: `Unsupported physical ownership type on field ${field.name}` });
|
|
1376
1544
|
}
|
|
1377
1545
|
function protectedModel(params) {
|
|
1378
1546
|
requireRls(params);
|
|
@@ -1598,7 +1766,7 @@ ORDER BY c.relname, p.polname`,
|
|
|
1598
1766
|
});
|
|
1599
1767
|
function requireRls2(params) {
|
|
1600
1768
|
if (!params.dialect.capabilities.nativeRowLevelSecurity) {
|
|
1601
|
-
throw
|
|
1769
|
+
throw unsupportedCapability8({ dialect: params.dialect.name, feature: "nativeRowLevelSecurity" });
|
|
1602
1770
|
}
|
|
1603
1771
|
}
|
|
1604
1772
|
function renderRlsReadinessQuery(params) {
|
|
@@ -1630,7 +1798,7 @@ function renderRlsPolicyPath(params) {
|
|
|
1630
1798
|
}
|
|
1631
1799
|
|
|
1632
1800
|
// packages/sql/src/render.ts
|
|
1633
|
-
import { internalError as internalError2, unsupportedCapability as
|
|
1801
|
+
import { internalError as internalError2, unsupportedCapability as unsupportedCapability9 } from "@vibeorm/schema";
|
|
1634
1802
|
|
|
1635
1803
|
// packages/sql/src/like.ts
|
|
1636
1804
|
function escapeLikePattern(params) {
|
|
@@ -1775,7 +1943,7 @@ function renderAggRef(dialect, agg) {
|
|
|
1775
1943
|
function assertScalarArrays(dialect, feature) {
|
|
1776
1944
|
if (dialect.capabilities.scalarArrays)
|
|
1777
1945
|
return;
|
|
1778
|
-
throw
|
|
1946
|
+
throw unsupportedCapability9({
|
|
1779
1947
|
dialect: dialect.name,
|
|
1780
1948
|
feature,
|
|
1781
1949
|
hint: "only postgres has native array columns \u2014 model the list as a related table instead"
|
|
@@ -1832,8 +2000,8 @@ function renderExpr(params) {
|
|
|
1832
2000
|
const columns = expr.columns.map((column) => quoteCol(dialect, column));
|
|
1833
2001
|
if (dialect.tupleInStrategy === "rowValue") {
|
|
1834
2002
|
const tuples = expr.rows.map((row) => `(${collector.addMany(row).join(", ")})`);
|
|
1835
|
-
const
|
|
1836
|
-
return expr.negate === true ? `NOT (${
|
|
2003
|
+
const base = `(${columns.join(", ")}) IN (${tuples.join(", ")})`;
|
|
2004
|
+
return expr.negate === true ? `NOT (${base})` : base;
|
|
1837
2005
|
}
|
|
1838
2006
|
const conjunctions = expr.rows.map((row) => {
|
|
1839
2007
|
const terms = row.map((value, index) => `${columns[index]} = ${collector.add(value)}`);
|
|
@@ -1985,7 +2153,7 @@ function renderJsonLike(params) {
|
|
|
1985
2153
|
function renderJsonFilter(params) {
|
|
1986
2154
|
const { dialect, expr, collector } = params;
|
|
1987
2155
|
if (!dialect.supportedJsonOps.includes(expr.op)) {
|
|
1988
|
-
throw
|
|
2156
|
+
throw unsupportedCapability9({
|
|
1989
2157
|
dialect: dialect.name,
|
|
1990
2158
|
feature: `the json filter "${expr.op}"`,
|
|
1991
2159
|
hint: `this dialect can express: ${dialect.supportedJsonOps.join(", ")}`
|
|
@@ -1993,61 +2161,72 @@ function renderJsonFilter(params) {
|
|
|
1993
2161
|
}
|
|
1994
2162
|
const cmp = expr.negate === true ? "<>" : "=";
|
|
1995
2163
|
if (dialect.jsonPathMode === "operators") {
|
|
1996
|
-
const
|
|
2164
|
+
const column = quoteCol(dialect, expr.column);
|
|
1997
2165
|
const pathParam = `${collector.add(expr.path.map(String))}::text[]`;
|
|
1998
2166
|
switch (expr.op) {
|
|
1999
2167
|
case "equals":
|
|
2000
|
-
return `(${
|
|
2168
|
+
return `(${column} #> ${pathParam}) ${cmp} ${collector.add(JSON.stringify(expr.value))}${dialect.jsonParamCast}`;
|
|
2001
2169
|
case "string_contains":
|
|
2002
2170
|
case "string_starts_with":
|
|
2003
2171
|
case "string_ends_with":
|
|
2004
|
-
return renderJsonLike({ dialect, target: `(${
|
|
2172
|
+
return renderJsonLike({ dialect, target: `(${column} #>> ${pathParam})`, expr, collector });
|
|
2005
2173
|
case "array_contains":
|
|
2006
|
-
return `(${
|
|
2174
|
+
return `(${column} #> ${pathParam}) @> ${collector.add(JSON.stringify(expr.value))}${dialect.jsonParamCast}`;
|
|
2007
2175
|
case "array_starts_with":
|
|
2008
|
-
return `(${
|
|
2176
|
+
return `(${column} #> ${pathParam}) -> 0 = ${collector.add(JSON.stringify(expr.value))}${dialect.jsonParamCast}`;
|
|
2009
2177
|
case "array_ends_with":
|
|
2010
|
-
return `(${
|
|
2178
|
+
return `(${column} #> ${pathParam}) -> -1 = ${collector.add(JSON.stringify(expr.value))}${dialect.jsonParamCast}`;
|
|
2011
2179
|
}
|
|
2012
2180
|
}
|
|
2013
2181
|
if (dialect.jsonPathMode === "sqliteExtract") {
|
|
2014
|
-
const
|
|
2015
|
-
const
|
|
2016
|
-
if (typeof value === "
|
|
2017
|
-
return `${
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2182
|
+
const column = quoteCol(dialect, expr.column);
|
|
2183
|
+
const typeMatches = (type, value) => {
|
|
2184
|
+
if (typeof value === "number")
|
|
2185
|
+
return `${type} IN ('integer', 'real')`;
|
|
2186
|
+
const tag = typeof value === "boolean" ? String(value) : value === null ? "null" : Array.isArray(value) ? "array" : typeof value === "object" ? "object" : "text";
|
|
2187
|
+
return `${type} = '${tag}'`;
|
|
2188
|
+
};
|
|
2189
|
+
const compareExtracted = (path, value) => {
|
|
2190
|
+
const type = `json_type(${column}, ${collector.add(path)})`;
|
|
2191
|
+
const guard = typeMatches(type, value);
|
|
2192
|
+
let base = guard;
|
|
2193
|
+
if (value !== null) {
|
|
2194
|
+
const target = `json_extract(${column}, ${collector.add(path)})`;
|
|
2195
|
+
const bound = typeof value === "boolean" ? value ? 1 : 0 : value;
|
|
2196
|
+
const operand = typeof value === "object" ? `json(${collector.add(JSON.stringify(value))})` : collector.add(bound);
|
|
2197
|
+
base = `(${guard} AND ${target} = ${operand})`;
|
|
2021
2198
|
}
|
|
2022
|
-
return
|
|
2199
|
+
return expr.negate === true ? `NOT (${base})` : base;
|
|
2023
2200
|
};
|
|
2024
2201
|
switch (expr.op) {
|
|
2025
2202
|
case "equals":
|
|
2026
|
-
return compareExtracted(
|
|
2203
|
+
return compareExtracted(jsonPathString(expr.path), expr.value);
|
|
2027
2204
|
case "string_contains":
|
|
2028
2205
|
case "string_starts_with":
|
|
2029
2206
|
case "string_ends_with": {
|
|
2030
|
-
const target = `json_extract(${
|
|
2207
|
+
const target = `json_extract(${column}, ${collector.add(jsonPathString(expr.path))})`;
|
|
2031
2208
|
return renderJsonLike({ dialect, target, expr, collector });
|
|
2032
2209
|
}
|
|
2033
2210
|
case "array_starts_with":
|
|
2034
2211
|
case "array_ends_with": {
|
|
2035
2212
|
const edge = expr.op === "array_starts_with" ? "[0]" : "[#-1]";
|
|
2036
|
-
return compareExtracted(
|
|
2213
|
+
return compareExtracted(`${jsonPathString(expr.path)}${edge}`, expr.value);
|
|
2037
2214
|
}
|
|
2038
2215
|
case "array_contains": {
|
|
2039
|
-
const guard = `json_type(${
|
|
2216
|
+
const guard = `json_type(${column}, ${collector.add(jsonPathString(expr.path))}) = 'array'`;
|
|
2040
2217
|
const elements = Array.isArray(expr.value) ? expr.value : [expr.value];
|
|
2041
2218
|
const tests = elements.map((element) => {
|
|
2042
2219
|
if (element === null || typeof element === "object" && element !== null) {
|
|
2043
|
-
throw
|
|
2220
|
+
throw unsupportedCapability9({
|
|
2044
2221
|
dialect: dialect.name,
|
|
2045
2222
|
feature: "json array_contains with object/array/null elements",
|
|
2046
2223
|
hint: "sqlite expresses scalar-element containment only \u2014 deep structural containment needs postgres or mysql"
|
|
2047
2224
|
});
|
|
2048
2225
|
}
|
|
2049
2226
|
const bound = typeof element === "boolean" ? element ? 1 : 0 : element;
|
|
2050
|
-
|
|
2227
|
+
const path = collector.add(jsonPathString(expr.path));
|
|
2228
|
+
const type = `${dialect.quoteIdent({ name: "json_each" })}.${dialect.quoteIdent({ name: "type" })}`;
|
|
2229
|
+
return `EXISTS (SELECT 1 FROM json_each(${column}, ${path}) WHERE ${typeMatches(type, element)} AND ${dialect.quoteIdent({ name: "json_each" })}.${dialect.quoteIdent({ name: "value" })} = ${collector.add(bound)})`;
|
|
2051
2230
|
});
|
|
2052
2231
|
return tests.length === 0 ? guard : `(${[guard, ...tests].join(" AND ")})`;
|
|
2053
2232
|
}
|
|
@@ -2189,7 +2368,7 @@ function renderSelect(params) {
|
|
|
2189
2368
|
let distinctPrefix = "";
|
|
2190
2369
|
if (statement.distinctOn !== undefined && statement.distinctOn.length > 0) {
|
|
2191
2370
|
if (!dialect.capabilities.distinctOn) {
|
|
2192
|
-
throw
|
|
2371
|
+
throw unsupportedCapability9({
|
|
2193
2372
|
dialect: dialect.name,
|
|
2194
2373
|
feature: "SELECT DISTINCT ON",
|
|
2195
2374
|
hint: "postgres-only \u2014 the runtime emulates distinct client-side on this dialect"
|
|
@@ -2220,7 +2399,7 @@ function renderSelect(params) {
|
|
|
2220
2399
|
}
|
|
2221
2400
|
if (statement.lateralJoins !== undefined && statement.lateralJoins.length > 0) {
|
|
2222
2401
|
if (!dialect.capabilities.lateralJoin) {
|
|
2223
|
-
throw
|
|
2402
|
+
throw unsupportedCapability9({
|
|
2224
2403
|
dialect: dialect.name,
|
|
2225
2404
|
feature: "LATERAL JOIN relation loading",
|
|
2226
2405
|
hint: 'use the portable "query" relation strategy on this dialect'
|
|
@@ -2305,7 +2484,7 @@ function renderInsert(params) {
|
|
|
2305
2484
|
let target = "";
|
|
2306
2485
|
if (onConflict.constraint !== undefined) {
|
|
2307
2486
|
if (dialect.name !== "postgres") {
|
|
2308
|
-
throw
|
|
2487
|
+
throw unsupportedCapability9({
|
|
2309
2488
|
dialect: dialect.name,
|
|
2310
2489
|
feature: "a named-constraint conflict target (ON CONFLICT ON CONSTRAINT)",
|
|
2311
2490
|
hint: "only postgres names constraints in conflict targets \u2014 use a column-list target"
|
|
@@ -2320,7 +2499,7 @@ function renderInsert(params) {
|
|
|
2320
2499
|
}
|
|
2321
2500
|
text += ` ON CONFLICT${target} DO NOTHING`;
|
|
2322
2501
|
} else if (onConflict.constraint !== undefined || onConflict.conflictWhere !== undefined) {
|
|
2323
|
-
throw
|
|
2502
|
+
throw unsupportedCapability9({
|
|
2324
2503
|
dialect: dialect.name,
|
|
2325
2504
|
feature: "a refined conflict target (constraint / partial-index predicate) on INSERT IGNORE",
|
|
2326
2505
|
hint: "mysql skips on any duplicate key \u2014 drop the refinement or gate the call per dialect"
|
|
@@ -2338,7 +2517,7 @@ function renderInsert(params) {
|
|
|
2338
2517
|
throw internalError2({ message: "lastInsertIdColumn is a mysql (onDuplicateKey) construct" });
|
|
2339
2518
|
}
|
|
2340
2519
|
if (onConflict.constraint !== undefined && dialect.name !== "postgres") {
|
|
2341
|
-
throw
|
|
2520
|
+
throw unsupportedCapability9({
|
|
2342
2521
|
dialect: dialect.name,
|
|
2343
2522
|
feature: "a named-constraint conflict target (ON CONFLICT ON CONSTRAINT)",
|
|
2344
2523
|
hint: "sqlite conflict targets are column lists \u2014 name the indexed columns instead"
|
|
@@ -2354,14 +2533,14 @@ function renderInsert(params) {
|
|
|
2354
2533
|
text += ` ON CONFLICT${target} DO UPDATE SET ${assignments}`;
|
|
2355
2534
|
} else {
|
|
2356
2535
|
if (onConflict.constraint !== undefined) {
|
|
2357
|
-
throw
|
|
2536
|
+
throw unsupportedCapability9({
|
|
2358
2537
|
dialect: dialect.name,
|
|
2359
2538
|
feature: "a named-constraint conflict target on ON DUPLICATE KEY UPDATE",
|
|
2360
2539
|
hint: "mysql's ODKU fires on any duplicate key \u2014 no target can be named"
|
|
2361
2540
|
});
|
|
2362
2541
|
}
|
|
2363
2542
|
if (onConflict.conflictWhere !== undefined) {
|
|
2364
|
-
throw
|
|
2543
|
+
throw unsupportedCapability9({
|
|
2365
2544
|
dialect: dialect.name,
|
|
2366
2545
|
feature: "a partial-index conflict target on ON DUPLICATE KEY UPDATE",
|
|
2367
2546
|
hint: "mysql's ODKU fires on any duplicate key \u2014 a partial arbiter cannot be selected; gate the call per dialect"
|
|
@@ -2417,7 +2596,9 @@ function renderAssignments(params) {
|
|
|
2417
2596
|
return `${column} = ${collector.add(value.text)}${dialect.jsonParamCast}`;
|
|
2418
2597
|
}
|
|
2419
2598
|
if (isSetOperation(value)) {
|
|
2420
|
-
|
|
2599
|
+
const operand = collector.add(value.value);
|
|
2600
|
+
const numeric = dialect.name === "sqlite" && value.numericType === "Decimal" ? `CAST(${operand} AS REAL)` : operand;
|
|
2601
|
+
return `${column} = ${read} ${SET_OPERATION_SQL[value.__op]} ${numeric}`;
|
|
2421
2602
|
}
|
|
2422
2603
|
if (isDbNowMarker(value)) {
|
|
2423
2604
|
return `${column} = ${dialect.renderDbNow({ offsetSeconds: value.offsetSeconds, collector })}`;
|
|
@@ -2444,18 +2625,18 @@ function renderDelete(params) {
|
|
|
2444
2625
|
// packages/sql/src/dialects/sqlite-table-definition.ts
|
|
2445
2626
|
import { VibeError as VibeError8 } from "@vibeorm/schema";
|
|
2446
2627
|
function tableDefinitionParts(params) {
|
|
2447
|
-
const
|
|
2448
|
-
if (!/^\s*CREATE\s+(?:TEMP(?:ORARY)?\s+)?TABLE\b/i.test(
|
|
2628
|
+
const sql = params.sql;
|
|
2629
|
+
if (!/^\s*CREATE\s+(?:TEMP(?:ORARY)?\s+)?TABLE\b/i.test(sql))
|
|
2449
2630
|
throw unavailable();
|
|
2450
2631
|
const parts = [];
|
|
2451
2632
|
let start = -1;
|
|
2452
2633
|
let depth = 0;
|
|
2453
2634
|
let quote;
|
|
2454
|
-
for (let index = 0;index <
|
|
2455
|
-
const char =
|
|
2635
|
+
for (let index = 0;index < sql.length; index++) {
|
|
2636
|
+
const char = sql[index];
|
|
2456
2637
|
if (quote !== undefined) {
|
|
2457
2638
|
if (char === quote) {
|
|
2458
|
-
if (quote !== "]" &&
|
|
2639
|
+
if (quote !== "]" && sql[index + 1] === quote)
|
|
2459
2640
|
index++;
|
|
2460
2641
|
else
|
|
2461
2642
|
quote = undefined;
|
|
@@ -2470,16 +2651,16 @@ function tableDefinitionParts(params) {
|
|
|
2470
2651
|
quote = "]";
|
|
2471
2652
|
continue;
|
|
2472
2653
|
}
|
|
2473
|
-
if (char === "-" &&
|
|
2474
|
-
const end =
|
|
2654
|
+
if (char === "-" && sql[index + 1] === "-") {
|
|
2655
|
+
const end = sql.indexOf(`
|
|
2475
2656
|
`, index + 2);
|
|
2476
2657
|
if (end < 0)
|
|
2477
2658
|
break;
|
|
2478
2659
|
index = end;
|
|
2479
2660
|
continue;
|
|
2480
2661
|
}
|
|
2481
|
-
if (char === "/" &&
|
|
2482
|
-
const end =
|
|
2662
|
+
if (char === "/" && sql[index + 1] === "*") {
|
|
2663
|
+
const end = sql.indexOf("*/", index + 2);
|
|
2483
2664
|
if (end < 0)
|
|
2484
2665
|
break;
|
|
2485
2666
|
index = end + 1;
|
|
@@ -2492,11 +2673,11 @@ function tableDefinitionParts(params) {
|
|
|
2492
2673
|
} else if (char === ")") {
|
|
2493
2674
|
depth--;
|
|
2494
2675
|
if (depth === 0 && start >= 0) {
|
|
2495
|
-
parts.push(
|
|
2496
|
-
return { clauses: parts, suffix:
|
|
2676
|
+
parts.push(sql.slice(start, index).trim());
|
|
2677
|
+
return { clauses: parts, suffix: sql.slice(index + 1) };
|
|
2497
2678
|
}
|
|
2498
2679
|
} else if (char === "," && depth === 1) {
|
|
2499
|
-
parts.push(
|
|
2680
|
+
parts.push(sql.slice(start, index).trim());
|
|
2500
2681
|
start = index + 1;
|
|
2501
2682
|
}
|
|
2502
2683
|
}
|
|
@@ -2518,29 +2699,103 @@ function sqliteColumnClauses(params) {
|
|
|
2518
2699
|
}
|
|
2519
2700
|
return columns;
|
|
2520
2701
|
}
|
|
2702
|
+
// packages/sql/src/dialects/postgres-type-identity.ts
|
|
2703
|
+
import { unsupportedCapability as unsupportedCapability10 } from "@vibeorm/schema";
|
|
2704
|
+
var IDENTIFIER = '(?:"(?:[^"\\x00]|"")+"|[a-zA-Z_][a-zA-Z_0-9$]*)';
|
|
2705
|
+
var MODIFIER_VALUE = `(?:[+-]?\\d+|${IDENTIFIER}|'(?:[^'\\x00]|'')*')`;
|
|
2706
|
+
var TYPE_NAME = new RegExp(`^\\s*(${IDENTIFIER})(?:\\s*\\.\\s*(${IDENTIFIER}))?\\s*(\\(\\s*${MODIFIER_VALUE}(?:\\s*,\\s*${MODIFIER_VALUE})*\\s*\\))?\\s*((?:\\[\\s*\\]\\s*)*)$`);
|
|
2707
|
+
var MODIFIER_TOKEN = new RegExp(MODIFIER_VALUE, "g");
|
|
2708
|
+
function modifier(params) {
|
|
2709
|
+
if (params.raw === undefined)
|
|
2710
|
+
return "";
|
|
2711
|
+
const tokens = params.raw.slice(1, -1).match(MODIFIER_TOKEN) ?? [];
|
|
2712
|
+
return `(${tokens.map((token) => /^[+-]?\d+$/.test(token) ? BigInt(token).toString() : token.startsWith("'") || token.startsWith('"') ? token : token.toLowerCase()).join(",")})`;
|
|
2713
|
+
}
|
|
2714
|
+
function identifier3(params) {
|
|
2715
|
+
return params.value.startsWith('"') ? params.value.slice(1, -1).replaceAll('""', '"') : params.value.toLowerCase();
|
|
2716
|
+
}
|
|
2717
|
+
function parsePostgresTypeName(params) {
|
|
2718
|
+
const match = TYPE_NAME.exec(params.raw);
|
|
2719
|
+
if (match === null)
|
|
2720
|
+
return;
|
|
2721
|
+
return {
|
|
2722
|
+
...match[2] === undefined ? {} : { namespace: identifier3({ value: match[1] }) },
|
|
2723
|
+
name: identifier3({ value: match[2] ?? match[1] }),
|
|
2724
|
+
modifier: modifier({ ...match[3] === undefined ? {} : { raw: match[3] } }),
|
|
2725
|
+
array: (match[4]?.length ?? 0) > 0
|
|
2726
|
+
};
|
|
2727
|
+
}
|
|
2728
|
+
function renderPostgresTypeName(params) {
|
|
2729
|
+
if (params.dialect.name !== "postgres")
|
|
2730
|
+
throw unsupportedCapability10({ dialect: params.dialect.name, feature: "postgresTypeIdentity" });
|
|
2731
|
+
const { dialect, type } = params;
|
|
2732
|
+
return `${type.namespace === undefined ? "" : `${dialect.quoteIdent({ name: type.namespace })}.`}${dialect.quoteIdent({ name: type.name })}${type.modifier}${type.array ? "[]" : ""}`;
|
|
2733
|
+
}
|
|
2734
|
+
function renderPostgresTypeIdentity(params) {
|
|
2735
|
+
if (params.dialect.name !== "postgres")
|
|
2736
|
+
throw unsupportedCapability10({ dialect: params.dialect.name, feature: "postgresTypeIdentity" });
|
|
2737
|
+
const collector = new ParamCollector(params.dialect);
|
|
2738
|
+
const { source } = params;
|
|
2739
|
+
let text;
|
|
2740
|
+
if ("table" in source) {
|
|
2741
|
+
text = `SELECT tn.nspname::text AS "namespace", base.typname::text AS "name" FROM pg_catalog.pg_attribute a JOIN pg_catalog.pg_class c ON c.oid = a.attrelid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace JOIN pg_catalog.pg_type t ON t.oid = a.atttypid JOIN pg_catalog.pg_type base ON base.oid = CASE WHEN t.typelem <> 0 AND t.typlen = -1 THEN t.typelem ELSE t.oid END JOIN pg_catalog.pg_namespace tn ON tn.oid = base.typnamespace WHERE n.nspname = ${collector.add(source.table.namespace)} AND c.relname = ${collector.add(source.table.name)} AND a.attname = ${collector.add(source.column)} AND a.attnum > 0 AND NOT a.attisdropped`;
|
|
2742
|
+
} else {
|
|
2743
|
+
const name = renderPostgresTypeName({ dialect: params.dialect, type: { ...source.type, modifier: "", array: false } });
|
|
2744
|
+
text = `SELECT n.nspname::text AS "namespace", t.typname::text AS "name" FROM pg_catalog.pg_type t JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace WHERE t.oid = pg_catalog.to_regtype(${collector.add(name)})`;
|
|
2745
|
+
}
|
|
2746
|
+
return { text, values: collector.values, returning: "none" };
|
|
2747
|
+
}
|
|
2748
|
+
// packages/sql/src/dialects/postgres-default-identity.ts
|
|
2749
|
+
import { unsupportedCapability as unsupportedCapability11 } from "@vibeorm/schema";
|
|
2750
|
+
function renderPostgresDefaultFunctionIdentity(params) {
|
|
2751
|
+
const { dialect, table, column } = params;
|
|
2752
|
+
if (dialect.name !== "postgres")
|
|
2753
|
+
throw unsupportedCapability11({ dialect: dialect.name, feature: "defaultFunctionIdentity" });
|
|
2754
|
+
const collector = new ParamCollector(dialect);
|
|
2755
|
+
const namespace = collector.add(table.namespace);
|
|
2756
|
+
const name = collector.add(table.name);
|
|
2757
|
+
const field = collector.add(column);
|
|
2758
|
+
return {
|
|
2759
|
+
text: `SELECT pg_catalog.pg_get_expr(ad.adbin, ad.adrelid, false) AS "expression",
|
|
2760
|
+
pn.nspname::text AS "functionNamespace", p.proname::text AS "functionName",
|
|
2761
|
+
(p.pronargs = 0 AND p.provariadic = 0 AND p.prokind = 'f' AND NOT p.proretset) AS "zeroArguments",
|
|
2762
|
+
(p.prorettype = a.atttypid AND a.atttypmod = -1) AS "exactResultType"
|
|
2763
|
+
FROM pg_catalog.pg_attrdef ad
|
|
2764
|
+
JOIN pg_catalog.pg_attribute a ON a.attrelid = ad.adrelid AND a.attnum = ad.adnum
|
|
2765
|
+
JOIN pg_catalog.pg_class c ON c.oid = ad.adrelid
|
|
2766
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
2767
|
+
JOIN pg_catalog.pg_depend d ON d.classid = 'pg_catalog.pg_attrdef'::pg_catalog.regclass AND d.objid = ad.oid AND d.refclassid = 'pg_catalog.pg_proc'::pg_catalog.regclass AND d.deptype = 'n'
|
|
2768
|
+
JOIN pg_catalog.pg_proc p ON p.oid = d.refobjid
|
|
2769
|
+
JOIN pg_catalog.pg_namespace pn ON pn.oid = p.pronamespace
|
|
2770
|
+
WHERE n.nspname = ${namespace} AND c.relname = ${name} AND a.attname = ${field}
|
|
2771
|
+
AND a.attnum > 0 AND NOT a.attisdropped AND a.attgenerated = ''`,
|
|
2772
|
+
values: collector.values,
|
|
2773
|
+
returning: "none"
|
|
2774
|
+
};
|
|
2775
|
+
}
|
|
2521
2776
|
// packages/sql/src/dialects/constraint-owned-index.ts
|
|
2522
|
-
import { unsupportedCapability as
|
|
2777
|
+
import { unsupportedCapability as unsupportedCapability12 } from "@vibeorm/schema";
|
|
2523
2778
|
function renderConstraintOwnedIndexDrop(params) {
|
|
2524
2779
|
if (params.dialect.name !== "postgres")
|
|
2525
|
-
throw
|
|
2780
|
+
throw unsupportedCapability12({ dialect: params.dialect.name, feature: "constraintOwnedIndexDrop" });
|
|
2526
2781
|
const quote = (name) => params.dialect.quoteIdent({ name });
|
|
2527
2782
|
return { text: `ALTER TABLE ${quote(params.table)} DROP CONSTRAINT ${quote(params.constraint)};`, values: [], returning: "none" };
|
|
2528
2783
|
}
|
|
2529
2784
|
// packages/sql/src/dialects/mysql-check-probe.ts
|
|
2530
|
-
import { unsupportedCapability as
|
|
2785
|
+
import { unsupportedCapability as unsupportedCapability13 } from "@vibeorm/schema";
|
|
2531
2786
|
function renderMysqlCheckProbe(params) {
|
|
2532
2787
|
if (params.dialect.name !== "mysql")
|
|
2533
|
-
throw
|
|
2788
|
+
throw unsupportedCapability13({ dialect: params.dialect.name, feature: "temporaryCheckProbe" });
|
|
2534
2789
|
const q = (name) => params.dialect.quoteIdent({ name });
|
|
2535
2790
|
const probe = q(params.probe);
|
|
2536
2791
|
switch (params.operation) {
|
|
2537
2792
|
case "clone":
|
|
2538
2793
|
if (params.table === undefined)
|
|
2539
|
-
throw
|
|
2794
|
+
throw unsupportedCapability13({ dialect: "mysql", feature: "temporaryCheckProbe", hint: "A source table is required" });
|
|
2540
2795
|
return { text: `CREATE TEMPORARY TABLE ${probe} LIKE ${q(params.table.namespace)}.${q(params.table.name)}`, values: [], returning: "none" };
|
|
2541
2796
|
case "add": {
|
|
2542
2797
|
if (params.expression === undefined || params.definition === undefined)
|
|
2543
|
-
throw
|
|
2798
|
+
throw unsupportedCapability13({ dialect: "mysql", feature: "temporaryCheckProbe", hint: "An authored expression and temporary clone definition are required" });
|
|
2544
2799
|
const parts = tableDefinitionParts({ sql: params.definition });
|
|
2545
2800
|
return { text: `CREATE TEMPORARY TABLE ${probe} (
|
|
2546
2801
|
${[...parts.clauses, `CONSTRAINT ${probe} CHECK (${params.expression})`].join(`,
|
|
@@ -2559,8 +2814,8 @@ function renderMigrationHistoryQuery(params) {
|
|
|
2559
2814
|
return { text: `SELECT ${q("name")}, ${q("checksum")}, ${q("statement_index")}, ${q("error")} FROM ${q(params.namespace)}.${q("_vibe_migrations")} ORDER BY ${q("id")}`, values: [], returning: "none" };
|
|
2560
2815
|
}
|
|
2561
2816
|
// packages/sql/src/dialects/sqlite-constraints.ts
|
|
2562
|
-
var
|
|
2563
|
-
function
|
|
2817
|
+
var IDENTIFIER2 = '(?:"(?:[^" ]| |"")+"|`(?:[^`]|``)+`|\\[[^\\]]+\\]|[A-Za-z_][A-Za-z_0-9]*)';
|
|
2818
|
+
function identifier4(value) {
|
|
2564
2819
|
const text = value.trim();
|
|
2565
2820
|
if (text.startsWith('"'))
|
|
2566
2821
|
return text.slice(1, -1).replaceAll('""', '"');
|
|
@@ -2573,44 +2828,44 @@ function identifier3(value) {
|
|
|
2573
2828
|
function sqliteTableConstraints(params) {
|
|
2574
2829
|
const result = [];
|
|
2575
2830
|
for (const clause of tableDefinitionParts(params).clauses) {
|
|
2576
|
-
const named = new RegExp(`^CONSTRAINT\\s+(${
|
|
2831
|
+
const named = new RegExp(`^CONSTRAINT\\s+(${IDENTIFIER2})\\s+`, "i").exec(clause);
|
|
2577
2832
|
const body = named === null ? clause : clause.slice(named[0].length);
|
|
2578
2833
|
const kind = /^(CHECK|FOREIGN\s+KEY|UNIQUE|PRIMARY\s+KEY)\s*\(/i.exec(body);
|
|
2579
2834
|
if (kind === null)
|
|
2580
2835
|
continue;
|
|
2581
2836
|
const type = /^CHECK$/i.test(kind[1]) ? "check" : /^FOREIGN/i.test(kind[1]) ? "foreignKey" : /^PRIMARY/i.test(kind[1]) ? "primaryKey" : "unique";
|
|
2582
2837
|
const parts = tableDefinitionParts({ sql: `CREATE TABLE x ${body.slice(kind[0].indexOf("("))}` });
|
|
2583
|
-
const columns = type === "check" ? [] : parts.clauses.map(
|
|
2584
|
-
result.push({ name: named === null ? `@sqlite:${type}:${result.length}` :
|
|
2838
|
+
const columns = type === "check" ? [] : parts.clauses.map(identifier4);
|
|
2839
|
+
result.push({ name: named === null ? `@sqlite:${type}:${result.length}` : identifier4(named[1]), named: named !== null, type, sql: body, columns });
|
|
2585
2840
|
}
|
|
2586
2841
|
return result;
|
|
2587
2842
|
}
|
|
2588
2843
|
// packages/sql/src/dialects/migration-visibility.ts
|
|
2589
|
-
import { unsupportedCapability as
|
|
2844
|
+
import { unsupportedCapability as unsupportedCapability14 } from "@vibeorm/schema";
|
|
2590
2845
|
function renderMigrationVisibility(params) {
|
|
2591
2846
|
if (params.dialect.name !== "mysql")
|
|
2592
|
-
throw
|
|
2847
|
+
throw unsupportedCapability14({ dialect: params.dialect.name, feature: "mysqlCatalogVisibility" });
|
|
2593
2848
|
const collector = new ParamCollector(params.dialect);
|
|
2594
2849
|
const grantee = "CONCAT(QUOTE(SUBSTRING_INDEX(CURRENT_USER(), '@', 1)), '@', QUOTE(SUBSTRING_INDEX(CURRENT_USER(), '@', -1)))";
|
|
2595
2850
|
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" };
|
|
2596
2851
|
}
|
|
2597
2852
|
// packages/sql/src/dialects/migration-inventory.ts
|
|
2598
|
-
import { unsupportedCapability as
|
|
2853
|
+
import { unsupportedCapability as unsupportedCapability15 } from "@vibeorm/schema";
|
|
2599
2854
|
function renderSqliteColumnInventory(params) {
|
|
2600
2855
|
if (params.dialect.name !== "sqlite")
|
|
2601
|
-
throw
|
|
2856
|
+
throw unsupportedCapability15({ dialect: params.dialect.name, feature: "sqliteColumnInventory" });
|
|
2602
2857
|
const collector = new ParamCollector(params.dialect);
|
|
2603
2858
|
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" };
|
|
2604
2859
|
}
|
|
2605
2860
|
function renderSqliteForeignKeyInventory(params) {
|
|
2606
2861
|
if (params.dialect.name !== "sqlite")
|
|
2607
|
-
throw
|
|
2862
|
+
throw unsupportedCapability15({ dialect: params.dialect.name, feature: "sqliteForeignKeyInventory" });
|
|
2608
2863
|
const collector = new ParamCollector(params.dialect);
|
|
2609
2864
|
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" };
|
|
2610
2865
|
}
|
|
2611
2866
|
function renderSqliteRebuildObjects(params) {
|
|
2612
2867
|
if (params.dialect.name !== "sqlite")
|
|
2613
|
-
throw
|
|
2868
|
+
throw unsupportedCapability15({ dialect: params.dialect.name, feature: "sqliteRebuildObjects" });
|
|
2614
2869
|
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" };
|
|
2615
2870
|
}
|
|
2616
2871
|
function renderMigrationInventory(params) {
|
|
@@ -2644,13 +2899,15 @@ UNION ALL SELECT 'function', ROUTINE_NAME, NULL, NULL, '[]', NULL FROM informati
|
|
|
2644
2899
|
ORDER BY kind, parent, name`, values: collector.values, returning: "none" };
|
|
2645
2900
|
}
|
|
2646
2901
|
const schema = params.dialect.quoteIdent({ name: params.namespace });
|
|
2647
|
-
return { text: `SELECT type AS kind, name, tbl_name AS parent, sql AS definition FROM ${schema}.sqlite_schema WHERE name NOT LIKE '
|
|
2902
|
+
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" };
|
|
2648
2903
|
}
|
|
2649
2904
|
// packages/sql/src/dialects/migration-objects.ts
|
|
2650
|
-
import { unsupportedCapability as
|
|
2905
|
+
import { internalError as internalError3, unsupportedCapability as unsupportedCapability16 } from "@vibeorm/schema";
|
|
2651
2906
|
function renderMigrationObjectQuery(params) {
|
|
2652
|
-
|
|
2653
|
-
|
|
2907
|
+
return objectQuery({ ...params, collector: new ParamCollector(params.dialect) });
|
|
2908
|
+
}
|
|
2909
|
+
function objectQuery(params) {
|
|
2910
|
+
const { dialect, identity: object, collector } = params;
|
|
2654
2911
|
const physical = "table" in object ? object.table : object.name;
|
|
2655
2912
|
const namespace = collector.add(physical.namespace);
|
|
2656
2913
|
const name = collector.add(physical.name);
|
|
@@ -2668,7 +2925,7 @@ function renderMigrationObjectQuery(params) {
|
|
|
2668
2925
|
text = `SELECT pg_catalog.pg_get_triggerdef(t.oid, false) AS "definition", t.tgenabled::text AS "enabled", pn.nspname::text AS "functionNamespace", p.proname::text AS "functionName", pg_catalog.pg_get_function_identity_arguments(p.oid) AS "functionArguments" ${relation} JOIN pg_catalog.pg_trigger t ON t.tgrelid = c.oid JOIN pg_catalog.pg_proc p ON p.oid = t.tgfoid JOIN pg_catalog.pg_namespace pn ON pn.oid = p.pronamespace WHERE ${where} AND t.tgname = ${collector.add(object.name)} AND NOT t.tgisinternal`;
|
|
2669
2926
|
break;
|
|
2670
2927
|
case "function":
|
|
2671
|
-
text = `SELECT pg_catalog.pg_get_functiondef(p.oid) AS "definition", p.provolatile::text AS "volatility", p.prosecdef AS "securityDefiner", p.proisstrict AS "strict", p.proconfig::text AS "config", pg_catalog.pg_get_function_result(p.oid) AS "result" FROM pg_catalog.pg_proc p JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace WHERE n.nspname = ${namespace} AND p.proname = ${name} AND p.prokind = 'f' AND ARRAY(SELECT tn.nspname || '.' || t.typname 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 ORDER BY a.ord) = ${collector.add(object.argumentTypes.map((type) => `${type.namespace}.${type.name}`))}::text[]`;
|
|
2928
|
+
text = `SELECT pg_catalog.pg_get_functiondef(p.oid) AS "definition", p.provolatile::text AS "volatility", p.prosecdef AS "securityDefiner", CASE WHEN p.prosecdef THEN pg_catalog.pg_get_userbyid(p.proowner)::text ELSE NULL END AS "definerOwner", p.proisstrict AS "strict", p.proconfig::text AS "config", pg_catalog.pg_get_function_result(p.oid) AS "result" FROM pg_catalog.pg_proc p JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace WHERE n.nspname = ${namespace} AND p.proname = ${name} AND p.prokind = 'f' AND ARRAY(SELECT tn.nspname || '.' || t.typname 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 ORDER BY a.ord) = ${collector.add(object.argumentTypes.map((type) => `${type.namespace}.${type.name}`))}::text[]`;
|
|
2672
2929
|
break;
|
|
2673
2930
|
case "view":
|
|
2674
2931
|
text = `SELECT pg_catalog.pg_get_viewdef(c.oid, false) AS "definition", c.relkind::text AS "type", c.reloptions::text AS "options" ${relation} WHERE ${where} AND c.relkind IN ('v', 'm')`;
|
|
@@ -2679,13 +2936,16 @@ function renderMigrationObjectQuery(params) {
|
|
|
2679
2936
|
case "column":
|
|
2680
2937
|
case "columnDefault":
|
|
2681
2938
|
case "generatedColumn":
|
|
2682
|
-
text = `SELECT pg_catalog.format_type(a.atttypid, a.atttypmod) AS "type", a.attnotnull AS "notNull", a.attgenerated::text AS "generated", a.attidentity::text AS "identity", pg_catalog.pg_get_expr(d.adbin, d.adrelid, false) AS "definition" ${relation} JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid LEFT JOIN pg_catalog.pg_attrdef d ON d.adrelid = c.oid AND d.adnum = a.attnum WHERE ${where} AND a.attname = ${collector.add(object.column)} AND a.attnum > 0 AND NOT a.attisdropped`;
|
|
2939
|
+
text = `SELECT pg_catalog.format_type(a.atttypid, a.atttypmod) AS "type", a.attnotnull AS "notNull", a.attgenerated::text AS "generated", a.attidentity::text AS "identity", cn.nspname::text AS "collationNamespace", coll.collname::text AS "collationName", pg_catalog.pg_get_expr(d.adbin, d.adrelid, false) AS "definition" ${relation} JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid LEFT JOIN pg_catalog.pg_collation coll ON coll.oid = a.attcollation LEFT JOIN pg_catalog.pg_namespace cn ON cn.oid = coll.collnamespace LEFT JOIN pg_catalog.pg_attrdef d ON d.adrelid = c.oid AND d.adnum = a.attnum WHERE ${where} AND a.attname = ${collector.add(object.column)} AND a.attnum > 0 AND NOT a.attisdropped`;
|
|
2683
2940
|
break;
|
|
2684
2941
|
case "index":
|
|
2685
2942
|
text = `SELECT pg_catalog.pg_get_indexdef(i.indexrelid, 0, false) AS "definition", i.indisunique AS "unique", i.indisvalid AS "valid", i.indisready AS "ready", con.conname::text AS "constraint", con.contype::text AS "constraintType" ${relation} JOIN pg_catalog.pg_index i ON i.indrelid = c.oid JOIN pg_catalog.pg_class ix ON ix.oid = i.indexrelid LEFT JOIN pg_catalog.pg_constraint con ON con.conindid = i.indexrelid AND con.contype IN ('p', 'u', 'x') WHERE ${where} AND ix.relname = ${collector.add(object.name)}`;
|
|
2686
2943
|
break;
|
|
2687
2944
|
case "table":
|
|
2688
|
-
text = `SELECT c.relkind::text AS "type", c.relrowsecurity AS "rls", c.relforcerowsecurity AS "forceRls" ${relation} WHERE ${where} AND c.relkind IN ('r', 'p')`;
|
|
2945
|
+
text = `SELECT c.relkind::text AS "type", c.relrowsecurity AS "rls", c.relforcerowsecurity AS "forceRls", c.relpersistence::text AS "persistence", ARRAY(SELECT option FROM unnest(c.reloptions) AS option ORDER BY option COLLATE "C") AS "options" ${relation} WHERE ${where} AND c.relkind IN ('r', 'p')`;
|
|
2946
|
+
break;
|
|
2947
|
+
case "enum":
|
|
2948
|
+
text = `SELECT ARRAY(SELECT e.enumlabel::text FROM pg_catalog.pg_enum e WHERE e.enumtypid = t.oid ORDER BY e.enumsortorder) AS "values" FROM pg_catalog.pg_type t JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace WHERE n.nspname = ${namespace} AND t.typname = ${name} AND t.typtype = 'e'`;
|
|
2689
2949
|
break;
|
|
2690
2950
|
case "postgresExtension":
|
|
2691
2951
|
text = `SELECT e.extversion::text AS "version", e.extrelocatable AS "relocatable" FROM pg_catalog.pg_extension e JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace WHERE n.nspname = ${namespace} AND e.extname = ${name}`;
|
|
@@ -2705,11 +2965,11 @@ function renderMigrationObjectQuery(params) {
|
|
|
2705
2965
|
case "column":
|
|
2706
2966
|
case "columnDefault":
|
|
2707
2967
|
case "generatedColumn":
|
|
2708
|
-
text = `SELECT COLUMN_TYPE AS type, IS_NULLABLE AS nullable, COLUMN_DEFAULT AS definition, GENERATION_EXPRESSION AS generated, EXTRA AS extra, COLLATION_NAME AS collation FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ${namespace} AND TABLE_NAME = ${name} AND COLUMN_NAME = ${collector.add(object.column)}`;
|
|
2968
|
+
text = `SELECT COLUMN_TYPE AS type, IS_NULLABLE AS nullable, COLUMN_DEFAULT AS definition, GENERATION_EXPRESSION AS ${dialect.quoteIdent({ name: "generated" })}, EXTRA AS extra, COLLATION_NAME AS collation FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ${namespace} AND TABLE_NAME = ${name} AND COLUMN_NAME = ${collector.add(object.column)}`;
|
|
2709
2969
|
break;
|
|
2710
2970
|
case "constraint":
|
|
2711
2971
|
if (object.constraintType === "exclusion")
|
|
2712
|
-
throw
|
|
2972
|
+
throw unsupportedCapability16({ dialect: "mysql", feature: "exclusionConstraints" });
|
|
2713
2973
|
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)}`;
|
|
2714
2974
|
break;
|
|
2715
2975
|
case "index":
|
|
@@ -2719,15 +2979,15 @@ function renderMigrationObjectQuery(params) {
|
|
|
2719
2979
|
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}`;
|
|
2720
2980
|
break;
|
|
2721
2981
|
default:
|
|
2722
|
-
throw
|
|
2982
|
+
throw unsupportedCapability16({ dialect: "mysql", feature: `inspect:${object.kind}` });
|
|
2723
2983
|
}
|
|
2724
2984
|
} else {
|
|
2725
2985
|
if (physical.namespace !== "main" && physical.namespace !== "temp")
|
|
2726
|
-
throw
|
|
2986
|
+
throw unsupportedCapability16({ dialect: "sqlite", feature: "attachedSchemaInspection" });
|
|
2727
2987
|
const catalog = `${dialect.quoteIdent({ name: physical.namespace })}.sqlite_schema`;
|
|
2728
2988
|
const kind = object.kind === "table" || object.kind === "view" ? object.kind : object.kind === "trigger" ? "trigger" : object.kind === "index" ? "index" : "table";
|
|
2729
|
-
if (["function", "sequence", "postgresExtension"].includes(object.kind) || object.kind === "constraint" && object.constraintType === "exclusion")
|
|
2730
|
-
throw
|
|
2989
|
+
if (["function", "sequence", "postgresExtension", "enum"].includes(object.kind) || object.kind === "constraint" && object.constraintType === "exclusion")
|
|
2990
|
+
throw unsupportedCapability16({ dialect: "sqlite", feature: `inspect:${object.kind}` });
|
|
2731
2991
|
const sqliteParams = new ParamCollector(dialect);
|
|
2732
2992
|
if (object.kind === "column" || object.kind === "columnDefault" || object.kind === "generatedColumn") {
|
|
2733
2993
|
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)}`;
|
|
@@ -2753,11 +3013,14 @@ function renderMysqlObjectMembers(params) {
|
|
|
2753
3013
|
return { text, values: collector.values, returning: "none" };
|
|
2754
3014
|
}
|
|
2755
3015
|
function renderMigrationDependencies(params) {
|
|
3016
|
+
return dependencyQuery({ ...params, collector: new ParamCollector(params.dialect) });
|
|
3017
|
+
}
|
|
3018
|
+
function dependencyQuery(params) {
|
|
2756
3019
|
if (params.dialect.name !== "postgres")
|
|
2757
|
-
throw
|
|
3020
|
+
throw unsupportedCapability16({ dialect: params.dialect.name, feature: "catalogDependencies" });
|
|
2758
3021
|
const object = params.identity;
|
|
2759
3022
|
const physical = "table" in object ? object.table : object.name;
|
|
2760
|
-
const collector =
|
|
3023
|
+
const collector = params.collector;
|
|
2761
3024
|
const namespace = collector.add(physical.namespace);
|
|
2762
3025
|
const name = collector.add(physical.name);
|
|
2763
3026
|
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}`;
|
|
@@ -2785,6 +3048,9 @@ function renderMigrationDependencies(params) {
|
|
|
2785
3048
|
case "function":
|
|
2786
3049
|
source = `SELECT 'pg_proc'::regclass AS classid, p.oid AS objid, 0 AS objsubid FROM pg_catalog.pg_proc p JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace WHERE n.nspname = ${namespace} AND p.proname = ${name} AND ARRAY(SELECT tn.nspname || '.' || t.typname 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 ORDER BY a.ord) = ${collector.add(object.argumentTypes.map((type) => `${type.namespace}.${type.name}`))}::text[]`;
|
|
2787
3050
|
break;
|
|
3051
|
+
case "enum":
|
|
3052
|
+
source = `SELECT 'pg_type'::regclass AS classid, t.oid AS objid, 0 AS objsubid FROM pg_catalog.pg_type t JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace WHERE n.nspname = ${namespace} AND t.typname = ${name} AND t.typtype = 'e'`;
|
|
3053
|
+
break;
|
|
2788
3054
|
case "postgresExtension":
|
|
2789
3055
|
source = `SELECT 'pg_extension'::regclass AS classid, e.oid AS objid, 0 AS objsubid FROM pg_catalog.pg_extension e JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace WHERE n.nspname = ${namespace} AND e.extname = ${name}`;
|
|
2790
3056
|
break;
|
|
@@ -2794,6 +3060,41 @@ function renderMigrationDependencies(params) {
|
|
|
2794
3060
|
}
|
|
2795
3061
|
return { text: `SELECT DISTINCT json_build_array(d.deptype, a.type, a.object_names, a.object_args)::text AS address FROM (${source}) s JOIN pg_catalog.pg_depend d ON d.classid = s.classid AND d.objid = s.objid AND d.objsubid = s.objsubid CROSS JOIN LATERAL pg_catalog.pg_identify_object_as_address(d.refclassid, d.refobjid, d.refobjsubid) a ORDER BY address`, values: collector.values, returning: "none" };
|
|
2796
3062
|
}
|
|
3063
|
+
function inspectionReferences(params) {
|
|
3064
|
+
const values = [];
|
|
3065
|
+
return { values, add(value) {
|
|
3066
|
+
values.push(value);
|
|
3067
|
+
return `request.${params.dialect.quoteIdent({ name: `p${values.length}` })}`;
|
|
3068
|
+
} };
|
|
3069
|
+
}
|
|
3070
|
+
function renderMigrationObjectBatch(params) {
|
|
3071
|
+
const { dialect } = params;
|
|
3072
|
+
if (dialect.name !== "postgres")
|
|
3073
|
+
throw unsupportedCapability16({ dialect: dialect.name, feature: "batchedMigrationInspection" });
|
|
3074
|
+
const groups = new Map;
|
|
3075
|
+
for (const [position, identity] of params.identities.entries()) {
|
|
3076
|
+
const kind = identity.kind === "constraint" ? `${identity.kind}:${identity.constraintType}` : identity.kind === "generatedColumn" ? "columnDefault" : identity.kind;
|
|
3077
|
+
const group = groups.get(kind) ?? [];
|
|
3078
|
+
group.push({ identity, position });
|
|
3079
|
+
groups.set(kind, group);
|
|
3080
|
+
}
|
|
3081
|
+
return [...groups.values()].map((group) => {
|
|
3082
|
+
const identity = group[0].identity;
|
|
3083
|
+
const facts = objectQuery({ dialect, identity, collector: inspectionReferences({ dialect }) });
|
|
3084
|
+
const dependencies = dependencyQuery({ dialect, identity, collector: inspectionReferences({ dialect }) });
|
|
3085
|
+
if (JSON.stringify(dependencies.values) !== JSON.stringify(facts.values))
|
|
3086
|
+
throw internalError3({ message: "Batched catalog queries bind their identity in different orders", meta: { kind: identity.kind } });
|
|
3087
|
+
const columns = facts.values.map((value, index) => `${dialect.quoteIdent({ name: `p${index + 1}` })} ${Array.isArray(value) ? "text[]" : "text"}`);
|
|
3088
|
+
const requests = group.map(({ identity, position }) => ({ position, ...Object.fromEntries(renderMigrationObjectQuery({ dialect, identity }).values.map((value, index) => [`p${index + 1}`, value])) }));
|
|
3089
|
+
const collector = new ParamCollector(dialect);
|
|
3090
|
+
return {
|
|
3091
|
+
text: `SELECT request.position, to_jsonb(facts) AS facts, ARRAY(SELECT address FROM (${dependencies.text}) dependency ORDER BY address) AS "dependencyAddresses" FROM jsonb_to_recordset(${collector.add(JSON.stringify(requests))}::text::jsonb) AS request(position integer, ${columns.join(", ")}) CROSS JOIN LATERAL (${facts.text}) facts`,
|
|
3092
|
+
values: collector.values,
|
|
3093
|
+
returning: "none",
|
|
3094
|
+
positions: group.map(({ position }) => position)
|
|
3095
|
+
};
|
|
3096
|
+
});
|
|
3097
|
+
}
|
|
2797
3098
|
function renderMigrationServerVersion(params) {
|
|
2798
3099
|
return { text: params.dialect.name === "sqlite" ? "SELECT sqlite_version() AS version" : "SELECT version() AS version", values: [], returning: "none" };
|
|
2799
3100
|
}
|
|
@@ -2802,16 +3103,16 @@ function renderMigrationNamespace(params) {
|
|
|
2802
3103
|
}
|
|
2803
3104
|
function renderCheckProbe(params) {
|
|
2804
3105
|
if (params.dialect.name !== "postgres")
|
|
2805
|
-
throw
|
|
3106
|
+
throw unsupportedCapability16({ dialect: params.dialect.name, feature: "rollbackCheckProbe" });
|
|
2806
3107
|
const q = (name) => params.dialect.quoteIdent({ name });
|
|
2807
3108
|
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" };
|
|
2808
3109
|
}
|
|
2809
3110
|
// packages/sql/src/dialects/postgres-migration.ts
|
|
2810
|
-
import { VibeError as VibeError9, unsupportedCapability as
|
|
3111
|
+
import { VibeError as VibeError9, unsupportedCapability as unsupportedCapability17 } from "@vibeorm/schema";
|
|
2811
3112
|
var SETTING_VALUE = /^[0-9]+(?:\.[0-9]+)?\s*(?:us|ms|s|min|h|d)?$/;
|
|
2812
3113
|
function requirePostgres2(params) {
|
|
2813
3114
|
if (params.dialect.name !== "postgres") {
|
|
2814
|
-
throw
|
|
3115
|
+
throw unsupportedCapability17({ dialect: params.dialect.name, feature: params.feature });
|
|
2815
3116
|
}
|
|
2816
3117
|
}
|
|
2817
3118
|
function renderMigrationSessionRead(params) {
|
|
@@ -2914,109 +3215,122 @@ WHERE n.nspname = pg_catalog.current_schema() AND c.relname = ${table} AND a.att
|
|
|
2914
3215
|
};
|
|
2915
3216
|
}
|
|
2916
3217
|
export {
|
|
2917
|
-
|
|
2918
|
-
strictMatchPattern,
|
|
2919
|
-
startsWithPattern,
|
|
2920
|
-
sqliteTableConstraints,
|
|
2921
|
-
sqliteDialect,
|
|
2922
|
-
sqliteColumnClauses,
|
|
2923
|
-
sqlUsesIncoming,
|
|
2924
|
-
sql,
|
|
2925
|
-
renderStatement,
|
|
2926
|
-
renderSqliteRebuildObjects,
|
|
2927
|
-
renderSqliteForeignKeyInventory,
|
|
2928
|
-
renderSqliteColumnInventory,
|
|
2929
|
-
renderSqlFragment,
|
|
2930
|
-
renderRowLockClause,
|
|
2931
|
-
renderRlsRole,
|
|
2932
|
-
renderRlsReadinessQuery,
|
|
2933
|
-
renderRlsProbeTable,
|
|
2934
|
-
renderRlsPredicate,
|
|
2935
|
-
renderRlsPolicyPath,
|
|
2936
|
-
renderRlsPolicy,
|
|
2937
|
-
renderRlsNoForce,
|
|
2938
|
-
renderRlsForce,
|
|
2939
|
-
renderRlsEnable,
|
|
2940
|
-
renderRlsDropPolicy,
|
|
2941
|
-
renderRlsDisable,
|
|
2942
|
-
renderRlsContext,
|
|
2943
|
-
renderRlsColumnType,
|
|
2944
|
-
renderRelationStateQuery,
|
|
2945
|
-
renderPredicate,
|
|
2946
|
-
renderPostgresWorkload,
|
|
2947
|
-
renderPostgresExplain,
|
|
2948
|
-
renderMysqlObjectMembers,
|
|
2949
|
-
renderMysqlCheckProbe,
|
|
2950
|
-
renderMigrationVisibility,
|
|
2951
|
-
renderMigrationSessionSet,
|
|
2952
|
-
renderMigrationSessionRestore,
|
|
2953
|
-
renderMigrationSessionRead,
|
|
2954
|
-
renderMigrationServerVersion,
|
|
2955
|
-
renderMigrationObjectQuery,
|
|
2956
|
-
renderMigrationNamespace,
|
|
2957
|
-
renderMigrationInventory,
|
|
2958
|
-
renderMigrationHistoryQuery,
|
|
2959
|
-
renderMigrationDependencies,
|
|
2960
|
-
renderIndexStateQuery,
|
|
2961
|
-
renderFragment,
|
|
2962
|
-
renderExpr,
|
|
2963
|
-
renderExclusionSetup,
|
|
2964
|
-
renderExclusionProbe,
|
|
2965
|
-
renderExclusionDdl,
|
|
2966
|
-
renderExclusionCatalog,
|
|
2967
|
-
renderDiagnostic,
|
|
2968
|
-
renderConstraintStateQuery,
|
|
2969
|
-
renderConstraintOwnedIndexDrop,
|
|
2970
|
-
renderColumnStateQuery,
|
|
2971
|
-
renderCheckProbe,
|
|
2972
|
-
renderAdvisoryLock,
|
|
2973
|
-
projectionOutputName,
|
|
2974
|
-
postgresDialect,
|
|
2975
|
-
parsePgArrayLiteral,
|
|
2976
|
-
parseDateTimeText,
|
|
2977
|
-
mysqlDialect,
|
|
2978
|
-
mapConflictColumns,
|
|
2979
|
-
jsonParamCell,
|
|
2980
|
-
isSqlFragment,
|
|
2981
|
-
isSqlDefaultCell,
|
|
2982
|
-
isSetOperation,
|
|
2983
|
-
isListSetOperation,
|
|
2984
|
-
isJsonParamCell,
|
|
2985
|
-
isFixedDiagnostic,
|
|
2986
|
-
isExcludedRef,
|
|
2987
|
-
isDbNowMarker,
|
|
2988
|
-
getSqlDialect,
|
|
2989
|
-
excludedRef,
|
|
2990
|
-
escapeLikePattern,
|
|
2991
|
-
escapeGlobPattern,
|
|
2992
|
-
enumMembershipCodec,
|
|
2993
|
-
endsWithPattern,
|
|
2994
|
-
describeRowLock,
|
|
2995
|
-
decodeIsNoop,
|
|
2996
|
-
decode,
|
|
2997
|
-
dbNowMarker,
|
|
2998
|
-
containsPattern,
|
|
2999
|
-
compileSql,
|
|
3000
|
-
compileExclusion,
|
|
3001
|
-
SQL_DIALECTS,
|
|
3002
|
-
SQL_DEFAULT_CELL,
|
|
3003
|
-
SQLITE_CODECS,
|
|
3004
|
-
SQLITE_CAPABILITIES,
|
|
3005
|
-
RLS_READINESS_SQL,
|
|
3006
|
-
ParamCollector,
|
|
3007
|
-
POSTGRES_WORKLOAD_LIMITS,
|
|
3008
|
-
POSTGRES_DIAGNOSTIC_SQL,
|
|
3009
|
-
POSTGRES_CODECS,
|
|
3010
|
-
POSTGRES_CAPABILITIES,
|
|
3011
|
-
NATIVE_RLS_PROBE_POLICY,
|
|
3012
|
-
NATIVE_RLS,
|
|
3013
|
-
MYSQL_CODECS,
|
|
3014
|
-
MYSQL_CAPABILITIES,
|
|
3015
|
-
JSON_TRANSPORT,
|
|
3016
|
-
DIALECT_CODECS,
|
|
3017
|
-
DIALECT_CAPABILITIES,
|
|
3218
|
+
ADVISORY_KEY_BOUNDS,
|
|
3018
3219
|
ADVISORY_LOCK_RESULT_COLUMN,
|
|
3019
|
-
|
|
3220
|
+
DIALECT_CAPABILITIES,
|
|
3221
|
+
DIALECT_CODECS,
|
|
3222
|
+
JSON_TRANSPORT,
|
|
3223
|
+
MODULE_JOURNAL_COLUMN,
|
|
3224
|
+
MYSQL_CAPABILITIES,
|
|
3225
|
+
MYSQL_CODECS,
|
|
3226
|
+
NATIVE_RLS,
|
|
3227
|
+
NATIVE_RLS_PROBE_POLICY,
|
|
3228
|
+
POSTGRES_CAPABILITIES,
|
|
3229
|
+
POSTGRES_CODECS,
|
|
3230
|
+
POSTGRES_DIAGNOSTIC_SQL,
|
|
3231
|
+
POSTGRES_WORKLOAD_LIMITS,
|
|
3232
|
+
ParamCollector,
|
|
3233
|
+
RLS_READINESS_SQL,
|
|
3234
|
+
SHADOW_CAPABILITIES,
|
|
3235
|
+
SHADOW_DATABASE,
|
|
3236
|
+
SQLITE_CAPABILITIES,
|
|
3237
|
+
SQLITE_CODECS,
|
|
3238
|
+
SQLITE_SESSION_SQL,
|
|
3239
|
+
SQL_DEFAULT_CELL,
|
|
3240
|
+
SQL_DIALECTS,
|
|
3241
|
+
compileExclusion,
|
|
3242
|
+
compileSql,
|
|
3243
|
+
containsPattern,
|
|
3244
|
+
dbNowMarker,
|
|
3245
|
+
decode,
|
|
3246
|
+
decodeIsNoop,
|
|
3247
|
+
describeRowLock,
|
|
3248
|
+
endsWithPattern,
|
|
3249
|
+
enumMembershipCodec,
|
|
3250
|
+
escapeGlobPattern,
|
|
3251
|
+
escapeLikePattern,
|
|
3252
|
+
excludedRef,
|
|
3253
|
+
getSqlDialect,
|
|
3254
|
+
isDbNowMarker,
|
|
3255
|
+
isExcludedRef,
|
|
3256
|
+
isFixedDiagnostic,
|
|
3257
|
+
isJsonParamCell,
|
|
3258
|
+
isListSetOperation,
|
|
3259
|
+
isSetOperation,
|
|
3260
|
+
isSqlDefaultCell,
|
|
3261
|
+
isSqlFragment,
|
|
3262
|
+
jsonParamCell,
|
|
3263
|
+
mapConflictColumns,
|
|
3264
|
+
mysqlDialect,
|
|
3265
|
+
parseDateTimeText,
|
|
3266
|
+
parsePgArrayLiteral,
|
|
3267
|
+
parsePostgresTypeName,
|
|
3268
|
+
postgresDialect,
|
|
3269
|
+
projectionOutputName,
|
|
3270
|
+
renderAdvisoryLock,
|
|
3271
|
+
renderCheckProbe,
|
|
3272
|
+
renderColumnStateQuery,
|
|
3273
|
+
renderConstraintOwnedIndexDrop,
|
|
3274
|
+
renderConstraintStateQuery,
|
|
3275
|
+
renderDiagnostic,
|
|
3276
|
+
renderExclusionCatalog,
|
|
3277
|
+
renderExclusionDdl,
|
|
3278
|
+
renderExclusionProbe,
|
|
3279
|
+
renderExclusionSetup,
|
|
3280
|
+
renderExpr,
|
|
3281
|
+
renderFragment,
|
|
3282
|
+
renderIndexStateQuery,
|
|
3283
|
+
renderMigrationDependencies,
|
|
3284
|
+
renderMigrationHistoryQuery,
|
|
3285
|
+
renderMigrationInventory,
|
|
3286
|
+
renderMigrationNamespace,
|
|
3287
|
+
renderMigrationObjectBatch,
|
|
3288
|
+
renderMigrationObjectQuery,
|
|
3289
|
+
renderMigrationServerVersion,
|
|
3290
|
+
renderMigrationSessionRead,
|
|
3291
|
+
renderMigrationSessionRestore,
|
|
3292
|
+
renderMigrationSessionSet,
|
|
3293
|
+
renderMigrationVisibility,
|
|
3294
|
+
renderModuleDependencyQuery,
|
|
3295
|
+
renderModuleJournal,
|
|
3296
|
+
renderMysqlCheckProbe,
|
|
3297
|
+
renderMysqlObjectMembers,
|
|
3298
|
+
renderPostgresDefaultFunctionIdentity,
|
|
3299
|
+
renderPostgresExplain,
|
|
3300
|
+
renderPostgresTypeIdentity,
|
|
3301
|
+
renderPostgresTypeName,
|
|
3302
|
+
renderPostgresWorkload,
|
|
3303
|
+
renderPredicate,
|
|
3304
|
+
renderRelationStateQuery,
|
|
3305
|
+
renderReplayCoverageGaps,
|
|
3306
|
+
renderRlsColumnType,
|
|
3307
|
+
renderRlsContext,
|
|
3308
|
+
renderRlsDisable,
|
|
3309
|
+
renderRlsDropPolicy,
|
|
3310
|
+
renderRlsEnable,
|
|
3311
|
+
renderRlsForce,
|
|
3312
|
+
renderRlsNoForce,
|
|
3313
|
+
renderRlsPolicy,
|
|
3314
|
+
renderRlsPolicyPath,
|
|
3315
|
+
renderRlsPredicate,
|
|
3316
|
+
renderRlsProbeTable,
|
|
3317
|
+
renderRlsReadinessQuery,
|
|
3318
|
+
renderRlsRole,
|
|
3319
|
+
renderRowLockClause,
|
|
3320
|
+
renderShadowOperation,
|
|
3321
|
+
renderSqlFragment,
|
|
3322
|
+
renderSqliteColumnInventory,
|
|
3323
|
+
renderSqliteForeignKeyInventory,
|
|
3324
|
+
renderSqliteRebuildObjects,
|
|
3325
|
+
renderStatement,
|
|
3326
|
+
sql,
|
|
3327
|
+
sqlUsesIncoming,
|
|
3328
|
+
sqliteColumnClauses,
|
|
3329
|
+
sqliteDialect,
|
|
3330
|
+
sqliteTableConstraints,
|
|
3331
|
+
startsWithPattern,
|
|
3332
|
+
strictMatchPattern,
|
|
3333
|
+
toPgArrayLiteral
|
|
3020
3334
|
};
|
|
3021
3335
|
|
|
3022
|
-
//# debugId=
|
|
3336
|
+
//# debugId=E08264A778510D8664756E2164756E21
|