qubu 0.0.0 → 0.3.4
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/canonical-BbnqavJm.mjs +972 -0
- package/dist/codegen.d.mts +107 -0
- package/dist/codegen.mjs +1199 -0
- package/dist/column-CXMxx8Hq.mjs +118 -0
- package/dist/complete-D5Djh-zo.mjs +1788 -0
- package/dist/complete-types-BdFqUfbb.d.mts +371 -0
- package/dist/core.d.mts +33 -0
- package/dist/core.mjs +36 -0
- package/dist/ddl.d.mts +118 -0
- package/dist/ddl.mjs +1120 -0
- package/dist/dialect-b2-Z6uBF.mjs +13 -0
- package/dist/diff.d.mts +2 -0
- package/dist/diff.mjs +883 -0
- package/dist/drizzle-mysql.d.mts +24 -0
- package/dist/drizzle-mysql.mjs +72 -0
- package/dist/drizzle-postgres.d.mts +24 -0
- package/dist/drizzle-postgres.mjs +73 -0
- package/dist/drizzle-sqlite.d.mts +24 -0
- package/dist/drizzle-sqlite.mjs +82 -0
- package/dist/drizzle.d.mts +13 -0
- package/dist/drizzle.mjs +2 -0
- package/dist/errors-BGCoLe_r.mjs +14 -0
- package/dist/errors-Dxv73YJu.mjs +26 -0
- package/dist/explain-CkIK13L_.mjs +98 -0
- package/dist/index-Ds7-mhJi.d.mts +146 -0
- package/dist/index-Dug5HnLB.d.mts +204 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +1276 -0
- package/dist/introspection.d.mts +117 -0
- package/dist/introspection.mjs +4341 -0
- package/dist/json-CUZlv4HT.mjs +169 -0
- package/dist/migration.d.mts +215 -0
- package/dist/migration.mjs +1161 -0
- package/dist/mysql-DqkqXB6A.mjs +355 -0
- package/dist/mysql.d.mts +5 -0
- package/dist/mysql.mjs +50 -0
- package/dist/naming-QVCOnSj2.mjs +20 -0
- package/dist/omit-OxV58AwX.mjs +5 -0
- package/dist/on-conflict-BxnxubMb.mjs +143 -0
- package/dist/postgres-DEBBeh52.mjs +235 -0
- package/dist/postgres.d.mts +123 -0
- package/dist/postgres.mjs +52 -0
- package/dist/registry-BufIskVN.mjs +569 -0
- package/dist/relational-DCZrrNia.mjs +77 -0
- package/dist/runtime-BTr-MTlo.mjs +193 -0
- package/dist/schema.d.mts +2 -0
- package/dist/schema.mjs +5 -0
- package/dist/serialize-PF1cfH2P.mjs +556 -0
- package/dist/snapshot-CWPgzxNx.mjs +392 -0
- package/dist/snapshot.d.mts +4 -0
- package/dist/snapshot.mjs +8 -0
- package/dist/source-DUoJVXmL.mjs +68 -0
- package/dist/sqlite-BU6DBxef.mjs +320 -0
- package/dist/sqlite.d.mts +5 -0
- package/dist/sqlite.mjs +48 -0
- package/dist/standard-BTVYKh_F.mjs +12 -0
- package/dist/table-llv9tsZ8.mjs +384 -0
- package/dist/types-4Q076HKo.d.mts +3636 -0
- package/dist/types-BX0mckiU.d.mts +644 -0
- package/dist/types-Cec0xzo4.mjs +116 -0
- package/dist/types-H4vyCw8_.d.mts +45 -0
- package/dist/value-BvilP0oz.mjs +29 -0
- package/dist/vite/ambient.d.ts +449 -0
- package/dist/vite.d.mts +35 -0
- package/dist/vite.mjs +498 -0
- package/docs/config.json +21 -0
- package/docs/dialects-and-execution.md +427 -0
- package/docs/getting-started.md +96 -0
- package/docs/guides/compose-queries.md +225 -0
- package/docs/guides/drizzle.md +130 -0
- package/docs/guides/extensions/dialects.md +40 -0
- package/docs/guides/extensions/overview.md +36 -0
- package/docs/guides/extensions/sources-and-clauses.md +82 -0
- package/docs/guides/extensions/typed-expressions.md +94 -0
- package/docs/guides/extensions/unsafe-syntax.md +27 -0
- package/docs/guides/json.md +65 -0
- package/docs/guides/mutations.md +138 -0
- package/docs/guides/select/conditions.md +110 -0
- package/docs/guides/select/grouping-and-windows.md +82 -0
- package/docs/guides/select/ordering-and-pagination.md +78 -0
- package/docs/guides/select/overview.md +139 -0
- package/docs/guides/sql-templates.md +157 -0
- package/docs/guides/vite-plugin.md +92 -0
- package/docs/index.md +111 -0
- package/docs/query-model/fragments.md +109 -0
- package/docs/query-model/result-shapes.md +125 -0
- package/docs/query-model/source-scope.md +182 -0
- package/docs/reference/introspection-support.md +196 -0
- package/docs/reference/mysql-snapshot.md +55 -0
- package/docs/reference/postgres-snapshot.md +61 -0
- package/docs/reference/sqlite-snapshot.md +53 -0
- package/docs/reference/supported-surface.md +104 -0
- package/docs/schema/catalog-model.md +58 -0
- package/docs/schema/code-generation.md +139 -0
- package/docs/schema/columns-and-writes.md +130 -0
- package/docs/schema/constraints-and-indexes.md +180 -0
- package/docs/schema/ddl-emission.md +75 -0
- package/docs/schema/diff.md +75 -0
- package/docs/schema/introspection.md +214 -0
- package/docs/schema/migration-plans.md +76 -0
- package/docs/schema/snapshots.md +93 -0
- package/docs/schema/storage-and-schema-sql.md +104 -0
- package/docs/schema/tables-and-names.md +106 -0
- package/docs/sql-semantic-types.md +141 -0
- package/docs/troubleshooting.md +151 -0
- package/package.json +132 -10
- package/skills/qubu/SKILL.md +42 -0
- package/skills/qubu/agents/openai.yaml +6 -0
- package/readme.md +0 -1
|
@@ -0,0 +1,4341 @@
|
|
|
1
|
+
import { a as toSnapshotJsonValue } from "./canonical-BbnqavJm.mjs";
|
|
2
|
+
import { a as hasIntrospectionErrors, i as createIntrospectionDiagnostic, n as introspectedPhysicalIdentityPolicy, r as IntrospectionError, t as mapCatalogToSnapshot } from "./snapshot-CWPgzxNx.mjs";
|
|
3
|
+
import { n as assertCompleteSchemaSnapshot } from "./complete-D5Djh-zo.mjs";
|
|
4
|
+
import "./snapshot.mjs";
|
|
5
|
+
//#region src/introspection/catalog.ts
|
|
6
|
+
/**
|
|
7
|
+
* Materialize every optional object-family collection and deeply freeze the
|
|
8
|
+
* normalized catalog. Catalog text and extension data remain values; this
|
|
9
|
+
* helper never evaluates SQL or assigns persisted logical identities.
|
|
10
|
+
*/
|
|
11
|
+
function createCompleteIntrospectionCatalog(catalog) {
|
|
12
|
+
return deepFreeze({
|
|
13
|
+
dialect: catalog.dialect,
|
|
14
|
+
server: catalog.server,
|
|
15
|
+
capabilities: catalog.capabilities ?? catalog.server.capabilities,
|
|
16
|
+
namespace: catalog.namespace,
|
|
17
|
+
tables: sortTables(catalog.tables),
|
|
18
|
+
views: sortObjects(catalog.views ?? []),
|
|
19
|
+
sequences: sortObjects(catalog.sequences ?? []),
|
|
20
|
+
enums: sortObjects(catalog.enums ?? []),
|
|
21
|
+
domains: sortObjects(catalog.domains ?? []),
|
|
22
|
+
collations: sortObjects(catalog.collations ?? []),
|
|
23
|
+
triggers: sortObjects(catalog.triggers ?? []),
|
|
24
|
+
routines: sortObjects(catalog.routines ?? []),
|
|
25
|
+
partitions: sortObjects(catalog.partitions ?? []),
|
|
26
|
+
policies: sortObjects(catalog.policies ?? []),
|
|
27
|
+
extensionObjects: sortObjects(catalog.extensionObjects ?? []),
|
|
28
|
+
deferredObjects: [...catalog.deferredObjects].sort(compareDeferred),
|
|
29
|
+
opaqueObjects: sortObjects(catalog.opaqueObjects ?? []),
|
|
30
|
+
comments: [...catalog.comments ?? []].sort(compareId$1),
|
|
31
|
+
ownership: [...catalog.ownership ?? []].sort(compareId$1),
|
|
32
|
+
diagnostics: [...catalog.diagnostics]
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/** Alias for callers that already use the normalized-catalog terminology. */
|
|
36
|
+
const freezeIntrospectionCatalog = createCompleteIntrospectionCatalog;
|
|
37
|
+
/** Convert a complete catalog back to the optional reader-facing contract. */
|
|
38
|
+
function toIntrospectionCatalog(catalog) {
|
|
39
|
+
return deepFreeze({
|
|
40
|
+
...catalog,
|
|
41
|
+
capabilities: catalog.capabilities
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function sortTables(tables) {
|
|
45
|
+
return [...tables].map((table) => deepFreeze({
|
|
46
|
+
...table,
|
|
47
|
+
columns: [...table.columns].sort(compareColumn),
|
|
48
|
+
constraints: [...table.constraints].sort(compareId$1),
|
|
49
|
+
indexes: [...table.indexes].sort(compareId$1)
|
|
50
|
+
})).sort(compareId$1);
|
|
51
|
+
}
|
|
52
|
+
function sortObjects(objects) {
|
|
53
|
+
return [...objects].sort(compareId$1);
|
|
54
|
+
}
|
|
55
|
+
function compareId$1(left, right) {
|
|
56
|
+
return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
|
|
57
|
+
}
|
|
58
|
+
function compareDeferred(left, right) {
|
|
59
|
+
const leftId = left.id ?? left.physicalName;
|
|
60
|
+
const rightId = right.id ?? right.physicalName;
|
|
61
|
+
return leftId < rightId ? -1 : leftId > rightId ? 1 : 0;
|
|
62
|
+
}
|
|
63
|
+
function compareColumn(left, right) {
|
|
64
|
+
return left.ordinalPosition - right.ordinalPosition || compareId$1(left, right);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Freeze nested catalog values without imposing JSON semantics on bigint or
|
|
68
|
+
* opaque driver values. The normalized contract is expected to contain plain
|
|
69
|
+
* records, arrays, and scalar values; unsupported prototypes are retained but
|
|
70
|
+
* still frozen so the operation remains non-destructive.
|
|
71
|
+
*/
|
|
72
|
+
function deepFreeze(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
73
|
+
if (value === null || typeof value !== "object") return value;
|
|
74
|
+
if (seen.has(value)) return value;
|
|
75
|
+
seen.add(value);
|
|
76
|
+
if (Array.isArray(value)) for (const item of value) deepFreeze(item, seen);
|
|
77
|
+
else for (const child of Object.values(value)) deepFreeze(child, seen);
|
|
78
|
+
return Object.freeze(value);
|
|
79
|
+
}
|
|
80
|
+
//#endregion
|
|
81
|
+
//#region src/introspection/complete-snapshot.ts
|
|
82
|
+
/**
|
|
83
|
+
* Map a normalized catalog to strict Snapshot v2 data. This is intentionally
|
|
84
|
+
* separate from the Snapshot v1 mapper: complete objects are never fabricated
|
|
85
|
+
* as tables, and catalog references remain evidence rather than logical IDs.
|
|
86
|
+
*/
|
|
87
|
+
function mapCatalogToCompleteSnapshot(input) {
|
|
88
|
+
const catalog = createCompleteIntrospectionCatalog(input);
|
|
89
|
+
const diagnostics = [...catalog.diagnostics];
|
|
90
|
+
const tableByPhysicalName = new Map(catalog.tables.map((table) => [table.physicalName, table]));
|
|
91
|
+
const tables = catalog.tables.map((table) => mapTable(table, catalog.dialect, tableByPhysicalName, diagnostics));
|
|
92
|
+
const views = catalog.views.map((view) => mapView(view, catalog.dialect));
|
|
93
|
+
const sequences = catalog.sequences.map((sequence) => mapSequence(sequence, catalog.dialect));
|
|
94
|
+
const enums = catalog.enums.map((item) => mapEnum(item, catalog.dialect));
|
|
95
|
+
const domains = catalog.domains.map((domain) => mapDomain(domain, catalog.dialect));
|
|
96
|
+
const collations = catalog.collations.map((collation) => ({
|
|
97
|
+
kind: "collation",
|
|
98
|
+
id: collation.id,
|
|
99
|
+
physicalName: collation.physicalName,
|
|
100
|
+
...collation.provider === void 0 ? {} : { provider: collation.provider },
|
|
101
|
+
...collation.locale === void 0 ? {} : { locale: collation.locale },
|
|
102
|
+
...collation.deterministic === void 0 ? {} : { deterministic: collation.deterministic },
|
|
103
|
+
...collation.version === void 0 ? {} : { version: collation.version },
|
|
104
|
+
...mapMetadata(collation.provenance, collation.dialect, catalog.dialect, collation.reference)
|
|
105
|
+
}));
|
|
106
|
+
const triggers = catalog.triggers.map((trigger) => mapTrigger(trigger, catalog.dialect, diagnostics));
|
|
107
|
+
const routines = catalog.routines.map((routine) => mapRoutine(routine, catalog.dialect));
|
|
108
|
+
const partitions = catalog.partitions.map((partition) => mapPartition(partition, catalog.dialect));
|
|
109
|
+
const policies = catalog.policies.map((policy) => mapPolicy(policy, catalog.dialect));
|
|
110
|
+
const extensions = catalog.extensionObjects.map((extension) => mapExtensionObject(extension, catalog.dialect));
|
|
111
|
+
const deferredObjects = catalog.deferredObjects.map((object) => mapDeferredObject(object, catalog.dialect));
|
|
112
|
+
const opaqueObjects = catalog.opaqueObjects.map((object) => mapOpaqueObject(object, catalog.dialect));
|
|
113
|
+
for (const object of catalogObjectsWithUnknownFields(catalog)) for (const field of object.unknownFields ?? []) opaqueObjects.push(mapUnknownField(object, field, catalog.dialect));
|
|
114
|
+
const comments = (catalog.comments ?? []).map((comment) => mapComment(comment, catalog.dialect));
|
|
115
|
+
const ownership = (catalog.ownership ?? []).map((item) => mapOwnership(item, catalog.dialect));
|
|
116
|
+
for (const object of catalogObjectList(catalog)) {
|
|
117
|
+
if (object.comment && !comments.some((item) => item.id === object.comment?.id)) comments.push(mapComment(object.comment, catalog.dialect));
|
|
118
|
+
if (object.ownership && !ownership.some((item) => item.id === object.ownership?.id)) ownership.push(mapOwnership(object.ownership, catalog.dialect));
|
|
119
|
+
}
|
|
120
|
+
const snapshot = {
|
|
121
|
+
format: "qubu-schema",
|
|
122
|
+
version: 2,
|
|
123
|
+
dialect: {
|
|
124
|
+
name: catalog.dialect,
|
|
125
|
+
version: 1
|
|
126
|
+
},
|
|
127
|
+
namingPolicy: {
|
|
128
|
+
name: introspectedPhysicalIdentityPolicy.name,
|
|
129
|
+
version: introspectedPhysicalIdentityPolicy.version
|
|
130
|
+
},
|
|
131
|
+
namespace: {
|
|
132
|
+
kind: catalog.namespace.kind,
|
|
133
|
+
name: catalog.namespace.name,
|
|
134
|
+
...mapMetadata(catalog.namespace.provenance, catalog.namespace.dialect, catalog.dialect, catalog.namespace.reference)
|
|
135
|
+
},
|
|
136
|
+
capabilities: catalog.capabilities,
|
|
137
|
+
tables: tables.sort(compareId),
|
|
138
|
+
views: views.sort(compareId),
|
|
139
|
+
sequences: sequences.sort(compareId),
|
|
140
|
+
enums: enums.sort(compareId),
|
|
141
|
+
domains: domains.sort(compareId),
|
|
142
|
+
collations: collations.sort(compareId),
|
|
143
|
+
triggers: triggers.sort(compareId),
|
|
144
|
+
routines: routines.sort(compareId),
|
|
145
|
+
partitions: partitions.sort(compareId),
|
|
146
|
+
policies: policies.sort(compareId),
|
|
147
|
+
extensions: extensions.sort(compareId),
|
|
148
|
+
deferredObjects: deferredObjects.sort(compareId),
|
|
149
|
+
opaqueObjects: opaqueObjects.sort(compareId),
|
|
150
|
+
comments: comments.sort(compareId),
|
|
151
|
+
ownership: ownership.sort(compareId)
|
|
152
|
+
};
|
|
153
|
+
if (diagnostics.some((diagnostic) => diagnostic.severity === "error")) return Object.freeze({
|
|
154
|
+
ok: false,
|
|
155
|
+
catalog,
|
|
156
|
+
diagnostics: Object.freeze(diagnostics),
|
|
157
|
+
lossy: false
|
|
158
|
+
});
|
|
159
|
+
try {
|
|
160
|
+
const value = assertCompleteSchemaSnapshot(snapshot);
|
|
161
|
+
return Object.freeze({
|
|
162
|
+
ok: true,
|
|
163
|
+
catalog,
|
|
164
|
+
snapshot: value,
|
|
165
|
+
diagnostics: Object.freeze(diagnostics),
|
|
166
|
+
lossy: false
|
|
167
|
+
});
|
|
168
|
+
} catch (error) {
|
|
169
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
170
|
+
severity: "error",
|
|
171
|
+
code: "invalid-catalog-row",
|
|
172
|
+
message: error instanceof Error ? `Catalog facts could not form Snapshot v2: ${error.message}` : "Catalog facts could not form Snapshot v2",
|
|
173
|
+
path: [],
|
|
174
|
+
remediation: "Inspect the catalog diagnostics and complete object mappings."
|
|
175
|
+
}));
|
|
176
|
+
return Object.freeze({
|
|
177
|
+
ok: false,
|
|
178
|
+
catalog,
|
|
179
|
+
diagnostics: Object.freeze(diagnostics),
|
|
180
|
+
lossy: false
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/** Numbered alias for callers that keep both snapshot mappers available. */
|
|
185
|
+
const mapCatalogToSnapshotV2 = mapCatalogToCompleteSnapshot;
|
|
186
|
+
function mapTable(table, dialect, tables, diagnostics) {
|
|
187
|
+
const columns = table.columns.map((column) => mapColumn(column, dialect)).sort(compareId);
|
|
188
|
+
const columnIds = new Map(table.columns.map((column) => [column.physicalName, column.id]));
|
|
189
|
+
const constraints = table.constraints.map((constraint) => mapConstraint(constraint, dialect, columnIds, tables, diagnostics)).filter((value) => value !== void 0).sort(compareId);
|
|
190
|
+
const indexes = table.indexes.map((index) => mapIndex$1(index, dialect, columnIds)).sort(compareId);
|
|
191
|
+
return {
|
|
192
|
+
kind: "table",
|
|
193
|
+
id: table.id,
|
|
194
|
+
physicalName: table.physicalName,
|
|
195
|
+
columns,
|
|
196
|
+
constraints,
|
|
197
|
+
indexes,
|
|
198
|
+
...mapMetadata(table.provenance, table.dialect, dialect, table.reference)
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function mapColumn(column, dialect) {
|
|
202
|
+
const defaultValue = column.default ? mapValueFact(column.default) : void 0;
|
|
203
|
+
const generatedColumn = column.generated ? column.generated.mode === "unknown" ? { kind: "external" } : {
|
|
204
|
+
kind: "expression",
|
|
205
|
+
expression: mapExpression(column.generated.expression),
|
|
206
|
+
mode: column.generated.mode
|
|
207
|
+
} : void 0;
|
|
208
|
+
const identity = column.identity ? mapIdentity(column.identity, dialect) : void 0;
|
|
209
|
+
return {
|
|
210
|
+
kind: "column",
|
|
211
|
+
id: column.id,
|
|
212
|
+
physicalName: column.physicalName,
|
|
213
|
+
ordinalPosition: column.ordinalPosition,
|
|
214
|
+
nullable: column.nullable,
|
|
215
|
+
hasDefault: defaultValue !== void 0 || generatedColumn !== void 0 || identity !== void 0,
|
|
216
|
+
generated: generatedColumn !== void 0,
|
|
217
|
+
storage: mapStorage(column.storage, dialect),
|
|
218
|
+
...defaultValue === void 0 ? {} : { default: defaultValue },
|
|
219
|
+
...generatedColumn === void 0 ? {} : { generatedColumn },
|
|
220
|
+
...identity === void 0 ? {} : { identity },
|
|
221
|
+
...column.onUpdate === void 0 ? {} : { onUpdate: mapExpression(column.onUpdate) },
|
|
222
|
+
...mapMetadata(column.provenance, column.dialect, dialect, column.reference)
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
function mapConstraint(constraint, dialect, columns, tables, diagnostics) {
|
|
226
|
+
const physicalName = constraint.physicalName ?? constraint.id;
|
|
227
|
+
const common = {
|
|
228
|
+
id: constraint.id,
|
|
229
|
+
physicalName,
|
|
230
|
+
...mapMetadata(constraint.provenance, constraint.dialect, dialect, constraint.reference)
|
|
231
|
+
};
|
|
232
|
+
const mappedColumns = constraint.kind === "check" ? void 0 : constraint.columns.map((column) => {
|
|
233
|
+
const id = columns.get(column);
|
|
234
|
+
if (id !== void 0) return id;
|
|
235
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
236
|
+
severity: "error",
|
|
237
|
+
code: "unresolved-reference",
|
|
238
|
+
message: `Constraint column ${column} was not found`,
|
|
239
|
+
path: [constraint.id, "columns"]
|
|
240
|
+
}));
|
|
241
|
+
return column;
|
|
242
|
+
});
|
|
243
|
+
if (constraint.kind === "check") return {
|
|
244
|
+
kind: "check",
|
|
245
|
+
...common,
|
|
246
|
+
expression: mapExpression(constraint.expression),
|
|
247
|
+
...constraint.deferrable === void 0 ? {} : { deferrable: constraint.deferrable },
|
|
248
|
+
...constraint.initially === void 0 ? {} : { initially: constraint.initially },
|
|
249
|
+
...constraint.validated === void 0 ? {} : { validated: constraint.validated }
|
|
250
|
+
};
|
|
251
|
+
if (constraint.kind === "primary-key") return {
|
|
252
|
+
kind: "primary-key",
|
|
253
|
+
...common,
|
|
254
|
+
columns: mappedColumns ?? [],
|
|
255
|
+
...constraint.backingIndex === void 0 ? {} : { backingIndex: mapReference(constraint.backingIndex) },
|
|
256
|
+
...constraint.deferrable === void 0 ? {} : { deferrable: constraint.deferrable },
|
|
257
|
+
...constraint.initially === void 0 ? {} : { initially: constraint.initially },
|
|
258
|
+
...constraint.validated === void 0 ? {} : { validated: constraint.validated }
|
|
259
|
+
};
|
|
260
|
+
if (constraint.kind === "unique") return {
|
|
261
|
+
kind: "unique-constraint",
|
|
262
|
+
...common,
|
|
263
|
+
columns: mappedColumns ?? [],
|
|
264
|
+
nulls: constraint.nulls,
|
|
265
|
+
...constraint.backingIndex === void 0 ? {} : { backingIndex: mapReference(constraint.backingIndex) },
|
|
266
|
+
...constraint.deferrable === void 0 ? {} : { deferrable: constraint.deferrable },
|
|
267
|
+
...constraint.initially === void 0 ? {} : { initially: constraint.initially },
|
|
268
|
+
...constraint.validated === void 0 ? {} : { validated: constraint.validated }
|
|
269
|
+
};
|
|
270
|
+
const targetTable = tables.get(constraint.target.table);
|
|
271
|
+
const targetId = targetTable?.id;
|
|
272
|
+
if (targetId === void 0) diagnostics.push(createIntrospectionDiagnostic({
|
|
273
|
+
severity: "error",
|
|
274
|
+
code: "unresolved-reference",
|
|
275
|
+
message: `Foreign-key target table ${constraint.target.table} was not found`,
|
|
276
|
+
path: [
|
|
277
|
+
constraint.id,
|
|
278
|
+
"target",
|
|
279
|
+
"table"
|
|
280
|
+
]
|
|
281
|
+
}));
|
|
282
|
+
const targetColumns = targetTable ? constraint.target.columns.map((column) => targetTable.columns.find((item) => item.physicalName === column)?.id ?? column) : constraint.target.columns;
|
|
283
|
+
return {
|
|
284
|
+
kind: "foreign-key",
|
|
285
|
+
...common,
|
|
286
|
+
columns: mappedColumns ?? [],
|
|
287
|
+
target: {
|
|
288
|
+
table: {
|
|
289
|
+
kind: "table",
|
|
290
|
+
id: targetId ?? constraint.target.table
|
|
291
|
+
},
|
|
292
|
+
columns: targetColumns
|
|
293
|
+
},
|
|
294
|
+
...constraint.onUpdate === void 0 ? {} : { onUpdate: constraint.onUpdate },
|
|
295
|
+
...constraint.onDelete === void 0 ? {} : { onDelete: constraint.onDelete },
|
|
296
|
+
...constraint.match === void 0 ? {} : { match: constraint.match },
|
|
297
|
+
...constraint.deferrable === void 0 ? {} : { deferrable: constraint.deferrable },
|
|
298
|
+
...constraint.initially === void 0 ? {} : { initially: constraint.initially },
|
|
299
|
+
...constraint.validated === void 0 ? {} : { validated: constraint.validated }
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
function mapIndex$1(index, dialect, columns) {
|
|
303
|
+
return {
|
|
304
|
+
kind: "index",
|
|
305
|
+
id: index.id,
|
|
306
|
+
physicalName: index.physicalName ?? index.id,
|
|
307
|
+
terms: index.terms.map((term) => mapIndexTerm(term, columns)).filter((term) => term !== void 0).sort((left, right) => left.position - right.position),
|
|
308
|
+
unique: index.unique,
|
|
309
|
+
candidateKey: index.unique,
|
|
310
|
+
...index.predicate === void 0 ? {} : { predicate: mapExpression(index.predicate) },
|
|
311
|
+
...index.includedColumns === void 0 ? {} : { includedColumns: index.includedColumns.map((column) => columns.get(column) ?? column) },
|
|
312
|
+
...index.backingConstraint === void 0 ? {} : { backingConstraint: mapReference(index.backingConstraint) },
|
|
313
|
+
...index.method === void 0 ? {} : { method: index.method },
|
|
314
|
+
...mapMetadata(void 0, index.dialect, dialect, index.reference)
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
function mapIndexTerm(term, columns) {
|
|
318
|
+
if (term.kind === "column") return {
|
|
319
|
+
kind: "column",
|
|
320
|
+
column: columns.get(term.column) ?? term.column,
|
|
321
|
+
position: term.position,
|
|
322
|
+
...term.direction === void 0 ? {} : { direction: term.direction },
|
|
323
|
+
...term.nulls === void 0 ? {} : { nulls: term.nulls },
|
|
324
|
+
...term.prefixLength === void 0 ? {} : { prefixLength: mapValueFact(term.prefixLength) },
|
|
325
|
+
...term.operatorClass === void 0 ? {} : { operatorClass: term.operatorClass }
|
|
326
|
+
};
|
|
327
|
+
return {
|
|
328
|
+
kind: "expression",
|
|
329
|
+
expression: mapExpression(term.expression),
|
|
330
|
+
position: term.position,
|
|
331
|
+
...term.direction === void 0 ? {} : { direction: term.direction },
|
|
332
|
+
...term.nulls === void 0 ? {} : { nulls: term.nulls },
|
|
333
|
+
...term.operatorClass === void 0 ? {} : { operatorClass: term.operatorClass }
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
function mapView(view, dialect) {
|
|
337
|
+
return {
|
|
338
|
+
kind: view.kind,
|
|
339
|
+
id: view.id,
|
|
340
|
+
physicalName: view.physicalName,
|
|
341
|
+
columns: view.columns.map((column) => mapColumn(column, dialect)).sort(compareId),
|
|
342
|
+
definition: mapExpression(view.definition),
|
|
343
|
+
...view.dependencies === void 0 ? {} : { dependencies: view.dependencies.map(mapReference) },
|
|
344
|
+
...view.checkOption === void 0 ? {} : { checkOption: view.checkOption },
|
|
345
|
+
...view.securityBarrier === void 0 ? {} : { securityBarrier: view.securityBarrier },
|
|
346
|
+
...view.securityInvoker === void 0 ? {} : { securityInvoker: view.securityInvoker },
|
|
347
|
+
...mapMetadata(view.provenance, view.dialect, dialect, view.reference)
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
function mapSequence(sequence, dialect) {
|
|
351
|
+
return {
|
|
352
|
+
kind: "sequence",
|
|
353
|
+
id: sequence.id,
|
|
354
|
+
physicalName: sequence.physicalName,
|
|
355
|
+
...sequence.storage === void 0 ? {} : { storage: mapStorage(sequence.storage, dialect) },
|
|
356
|
+
...sequence.start === void 0 ? {} : { start: mapValueFact(sequence.start) },
|
|
357
|
+
...sequence.increment === void 0 ? {} : { increment: mapValueFact(sequence.increment) },
|
|
358
|
+
...sequence.minimum === void 0 ? {} : { minimum: mapValueFact(sequence.minimum) },
|
|
359
|
+
...sequence.maximum === void 0 ? {} : { maximum: mapValueFact(sequence.maximum) },
|
|
360
|
+
...sequence.cache === void 0 ? {} : { cache: mapValueFact(sequence.cache) },
|
|
361
|
+
...sequence.cycle === void 0 ? {} : { cycle: sequence.cycle },
|
|
362
|
+
...sequence.ownedBy === void 0 ? {} : { ownedBy: mapReference(sequence.ownedBy) },
|
|
363
|
+
...sequence.identity === void 0 ? {} : { identity: mapIdentity(sequence.identity, dialect) },
|
|
364
|
+
...mapMetadata(sequence.provenance, sequence.dialect, dialect, sequence.reference)
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
function mapEnum(item, dialect) {
|
|
368
|
+
return {
|
|
369
|
+
kind: "enum",
|
|
370
|
+
id: item.id,
|
|
371
|
+
physicalName: item.physicalName,
|
|
372
|
+
values: [...item.values].sort((left, right) => left.ordinalPosition - right.ordinalPosition).map((value) => ({
|
|
373
|
+
value: value.value,
|
|
374
|
+
ordinalPosition: value.ordinalPosition,
|
|
375
|
+
...value.provenance === void 0 ? {} : { provenance: mapProvenance(value.provenance) }
|
|
376
|
+
})),
|
|
377
|
+
...mapMetadata(item.provenance, item.dialect, dialect, item.reference)
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
function mapDomain(domain, dialect) {
|
|
381
|
+
return {
|
|
382
|
+
kind: "domain",
|
|
383
|
+
id: domain.id,
|
|
384
|
+
physicalName: domain.physicalName,
|
|
385
|
+
storage: mapStorage(domain.storage, dialect),
|
|
386
|
+
...domain.nullable === void 0 ? {} : { nullable: domain.nullable },
|
|
387
|
+
...domain.default === void 0 ? {} : { default: mapValueFact(domain.default) },
|
|
388
|
+
...domain.constraints === void 0 ? {} : { constraints: domain.constraints.map((constraint) => mapCheckConstraint(constraint, dialect)).sort(compareId) },
|
|
389
|
+
...mapMetadata(domain.provenance, domain.dialect, dialect, domain.reference)
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
function mapCheckConstraint(constraint, dialect) {
|
|
393
|
+
return {
|
|
394
|
+
kind: "check",
|
|
395
|
+
id: constraint.id,
|
|
396
|
+
physicalName: constraint.physicalName ?? constraint.id,
|
|
397
|
+
expression: mapExpression(constraint.expression),
|
|
398
|
+
...constraint.deferrable === void 0 ? {} : { deferrable: constraint.deferrable },
|
|
399
|
+
...constraint.initially === void 0 ? {} : { initially: constraint.initially },
|
|
400
|
+
...constraint.validated === void 0 ? {} : { validated: constraint.validated },
|
|
401
|
+
...mapMetadata(constraint.provenance, constraint.dialect, dialect, constraint.reference)
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
function mapTrigger(trigger, dialect, _diagnostics) {
|
|
405
|
+
return {
|
|
406
|
+
kind: "trigger",
|
|
407
|
+
id: trigger.id,
|
|
408
|
+
physicalName: trigger.physicalName,
|
|
409
|
+
table: mapReference(trigger.table),
|
|
410
|
+
timing: trigger.timing,
|
|
411
|
+
events: [...trigger.events].sort(),
|
|
412
|
+
...trigger.orientation === void 0 ? {} : { orientation: trigger.orientation },
|
|
413
|
+
...trigger.condition === void 0 ? {} : { condition: mapExpression(trigger.condition) },
|
|
414
|
+
body: mapExpression(trigger.body),
|
|
415
|
+
...trigger.enabled === void 0 ? {} : { enabled: trigger.enabled },
|
|
416
|
+
...mapMetadata(trigger.provenance, trigger.dialect, dialect, trigger.reference)
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
function mapRoutine(routine, dialect) {
|
|
420
|
+
return {
|
|
421
|
+
kind: "routine",
|
|
422
|
+
id: routine.id,
|
|
423
|
+
physicalName: routine.physicalName,
|
|
424
|
+
routineKind: routine.routineKind,
|
|
425
|
+
parameters: [...routine.parameters].sort((left, right) => left.ordinalPosition - right.ordinalPosition).map((parameter) => mapRoutineParameter(parameter, dialect)),
|
|
426
|
+
...routine.returnType === void 0 ? {} : { returnType: mapStorage(routine.returnType, dialect) },
|
|
427
|
+
...routine.language === void 0 ? {} : { language: routine.language },
|
|
428
|
+
...routine.body === void 0 ? {} : { body: mapExpression(routine.body) },
|
|
429
|
+
...routine.volatility === void 0 ? {} : { volatility: routine.volatility },
|
|
430
|
+
...routine.parallel === void 0 ? {} : { parallel: routine.parallel },
|
|
431
|
+
...routine.security === void 0 ? {} : { security: routine.security },
|
|
432
|
+
...routine.dependencies === void 0 ? {} : { dependencies: routine.dependencies.map(mapReference) },
|
|
433
|
+
...mapMetadata(routine.provenance, routine.dialect, dialect, routine.reference)
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
function mapRoutineParameter(parameter, dialect) {
|
|
437
|
+
return {
|
|
438
|
+
...parameter.name === void 0 ? {} : { name: parameter.name },
|
|
439
|
+
...parameter.mode === void 0 ? {} : { mode: parameter.mode },
|
|
440
|
+
storage: mapStorage(parameter.storage, dialect),
|
|
441
|
+
...parameter.default === void 0 ? {} : { default: mapValueFact(parameter.default) },
|
|
442
|
+
ordinalPosition: parameter.ordinalPosition
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
function mapPartition(partition, dialect) {
|
|
446
|
+
return {
|
|
447
|
+
kind: "partition",
|
|
448
|
+
id: partition.id,
|
|
449
|
+
physicalName: partition.physicalName,
|
|
450
|
+
parent: mapReference(partition.parent),
|
|
451
|
+
strategy: partition.strategy,
|
|
452
|
+
...partition.keyColumns === void 0 ? {} : { keyColumns: [...partition.keyColumns] },
|
|
453
|
+
...partition.bound === void 0 ? {} : { bound: mapExpression(partition.bound) },
|
|
454
|
+
...partition.default === void 0 ? {} : { default: partition.default },
|
|
455
|
+
...mapMetadata(partition.provenance, partition.dialect, dialect, partition.reference)
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
function mapPolicy(policy, dialect) {
|
|
459
|
+
return {
|
|
460
|
+
kind: "policy",
|
|
461
|
+
id: policy.id,
|
|
462
|
+
physicalName: policy.physicalName,
|
|
463
|
+
table: mapReference(policy.table),
|
|
464
|
+
command: policy.command,
|
|
465
|
+
...policy.roles === void 0 ? {} : { roles: [...policy.roles].sort() },
|
|
466
|
+
...policy.permissive === void 0 ? {} : { permissive: policy.permissive },
|
|
467
|
+
...policy.using === void 0 ? {} : { using: mapExpression(policy.using) },
|
|
468
|
+
...policy.check === void 0 ? {} : { check: mapExpression(policy.check) },
|
|
469
|
+
...mapMetadata(policy.provenance, policy.dialect, dialect, policy.reference)
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
function mapExtensionObject(extension, dialect) {
|
|
473
|
+
return {
|
|
474
|
+
kind: "extension",
|
|
475
|
+
id: extension.id,
|
|
476
|
+
physicalName: extension.physicalName,
|
|
477
|
+
extensionName: extension.extensionName,
|
|
478
|
+
...extension.extensionVersion === void 0 ? {} : { extensionVersion: extension.extensionVersion },
|
|
479
|
+
...extension.schema === void 0 ? {} : { schema: extension.schema },
|
|
480
|
+
data: toSnapshotJsonValue(extension.data),
|
|
481
|
+
...extension.configuration === void 0 ? {} : { configuration: toSnapshotJsonValue(extension.configuration) },
|
|
482
|
+
...mapMetadata(extension.provenance, extension.dialect, dialect, extension.reference)
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
function mapDeferredObject(object, dialect) {
|
|
486
|
+
const data = object.unknownFields ? Object.fromEntries(object.unknownFields.map((field) => [field.name, toSnapshotJsonValue(isCatalogSqlExpression(field.value) ? field.value.text : field.value)])) : void 0;
|
|
487
|
+
return {
|
|
488
|
+
kind: "deferred-object",
|
|
489
|
+
id: object.id ?? `deferred:${object.objectKind}:${object.physicalName}`,
|
|
490
|
+
objectKind: object.objectKind,
|
|
491
|
+
physicalName: object.physicalName,
|
|
492
|
+
...data === void 0 ? {} : { data: toSnapshotJsonValue(data) },
|
|
493
|
+
...mapMetadata(object.provenance, object.dialect, dialect, object.reference)
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
function mapOpaqueObject(object, dialect) {
|
|
497
|
+
return {
|
|
498
|
+
kind: "opaque-object",
|
|
499
|
+
id: object.id,
|
|
500
|
+
objectKind: object.objectKind,
|
|
501
|
+
physicalName: object.physicalName,
|
|
502
|
+
data: toSnapshotJsonValue(object.data),
|
|
503
|
+
...object.sql === void 0 ? {} : { sql: mapExpression(object.sql) },
|
|
504
|
+
...mapMetadata(object.provenance, object.dialect, dialect, object.reference)
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
function mapComment(comment, dialect) {
|
|
508
|
+
return {
|
|
509
|
+
kind: "comment",
|
|
510
|
+
id: comment.id,
|
|
511
|
+
physicalName: comment.reference?.name ?? comment.id,
|
|
512
|
+
object: mapReference(comment.object),
|
|
513
|
+
text: comment.text,
|
|
514
|
+
...mapMetadata(comment.provenance, comment.dialect, dialect, comment.reference)
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
function mapOwnership(ownership, dialect) {
|
|
518
|
+
return {
|
|
519
|
+
kind: "ownership",
|
|
520
|
+
id: ownership.id,
|
|
521
|
+
physicalName: ownership.reference?.name ?? ownership.id,
|
|
522
|
+
object: mapReference(ownership.object),
|
|
523
|
+
owner: ownership.owner,
|
|
524
|
+
...mapMetadata(ownership.provenance, ownership.dialect, dialect, ownership.reference)
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
function mapStorage(storage, dialect) {
|
|
528
|
+
if (storage.portable !== void 0) return {
|
|
529
|
+
kind: "portable",
|
|
530
|
+
type: storage.portable.type
|
|
531
|
+
};
|
|
532
|
+
return {
|
|
533
|
+
kind: "native",
|
|
534
|
+
dialect,
|
|
535
|
+
type: storage.nativeType
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
function mapValueFact(value) {
|
|
539
|
+
if (value.kind === "literal") return {
|
|
540
|
+
kind: "literal",
|
|
541
|
+
value: mapLiteral(value)
|
|
542
|
+
};
|
|
543
|
+
return {
|
|
544
|
+
kind: "expression",
|
|
545
|
+
expression: mapExpression(value.expression)
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
function mapLiteral(value) {
|
|
549
|
+
if (value.value === null) return { kind: "null" };
|
|
550
|
+
if (typeof value.value === "boolean") return {
|
|
551
|
+
kind: "boolean",
|
|
552
|
+
value: value.value
|
|
553
|
+
};
|
|
554
|
+
if (typeof value.value === "bigint") return {
|
|
555
|
+
kind: "bigint",
|
|
556
|
+
value: value.value.toString()
|
|
557
|
+
};
|
|
558
|
+
if (typeof value.value === "number") return {
|
|
559
|
+
kind: "number",
|
|
560
|
+
value: String(value.value)
|
|
561
|
+
};
|
|
562
|
+
return {
|
|
563
|
+
kind: "string",
|
|
564
|
+
value: value.value
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
function mapIdentity(identity, dialect) {
|
|
568
|
+
return {
|
|
569
|
+
kind: "identity",
|
|
570
|
+
generation: identity.generation,
|
|
571
|
+
options: Object.fromEntries(Object.entries(identity.options).map(([key, value]) => [key, mapValueFact(value)])),
|
|
572
|
+
...mapMetadata(void 0, identity.dialect, dialect)
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
function mapExpression(value) {
|
|
576
|
+
return {
|
|
577
|
+
kind: "expression",
|
|
578
|
+
expressionKind: "unsafe",
|
|
579
|
+
sql: value.text.replace(/\r\n?/g, "\n").trim(),
|
|
580
|
+
dialect: value.dialect
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
function mapMetadata(provenance, extension, dialect, reference) {
|
|
584
|
+
const mappedProvenance = provenance ? mapProvenance(provenance) : void 0;
|
|
585
|
+
const mappedExtension = extension ? {
|
|
586
|
+
dialect: extension.dialect,
|
|
587
|
+
version: extension.version,
|
|
588
|
+
data: toSnapshotJsonValue(extension.data)
|
|
589
|
+
} : void 0;
|
|
590
|
+
const physicalReference = reference ? {
|
|
591
|
+
kind: reference.kind,
|
|
592
|
+
...reference.namespace === void 0 ? {} : { namespace: reference.namespace },
|
|
593
|
+
...reference.table === void 0 ? {} : { table: reference.table },
|
|
594
|
+
name: reference.name
|
|
595
|
+
} : void 0;
|
|
596
|
+
return {
|
|
597
|
+
...mappedProvenance === void 0 ? {} : { provenance: mappedProvenance },
|
|
598
|
+
...physicalReference === void 0 ? {} : { physicalReference },
|
|
599
|
+
...mappedExtension === void 0 ? {} : { dialect: mappedExtension }
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
function mapProvenance(value) {
|
|
603
|
+
return {
|
|
604
|
+
kind: value.kind,
|
|
605
|
+
dialect: value.dialect,
|
|
606
|
+
...value.path === void 0 ? {} : { path: [...value.path] }
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
function mapReference(reference) {
|
|
610
|
+
return {
|
|
611
|
+
kind: reference.kind,
|
|
612
|
+
id: reference.id
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
function catalogObjectList(catalog) {
|
|
616
|
+
const topLevel = [
|
|
617
|
+
catalog.namespace,
|
|
618
|
+
...catalog.tables,
|
|
619
|
+
...catalog.views,
|
|
620
|
+
...catalog.sequences,
|
|
621
|
+
...catalog.enums,
|
|
622
|
+
...catalog.domains,
|
|
623
|
+
...catalog.collations,
|
|
624
|
+
...catalog.triggers,
|
|
625
|
+
...catalog.routines,
|
|
626
|
+
...catalog.partitions,
|
|
627
|
+
...catalog.policies,
|
|
628
|
+
...catalog.extensionObjects,
|
|
629
|
+
...catalog.deferredObjects,
|
|
630
|
+
...catalog.opaqueObjects,
|
|
631
|
+
...catalog.comments,
|
|
632
|
+
...catalog.ownership
|
|
633
|
+
];
|
|
634
|
+
const nested = [
|
|
635
|
+
...catalog.tables.flatMap((table) => [
|
|
636
|
+
...table.columns,
|
|
637
|
+
...table.constraints,
|
|
638
|
+
...table.indexes
|
|
639
|
+
]),
|
|
640
|
+
...catalog.views.flatMap((view) => view.columns),
|
|
641
|
+
...catalog.domains.flatMap((domain) => domain.constraints ?? [])
|
|
642
|
+
];
|
|
643
|
+
return [...topLevel, ...nested];
|
|
644
|
+
}
|
|
645
|
+
function catalogObjectsWithUnknownFields(catalog) {
|
|
646
|
+
return catalogObjectList(catalog);
|
|
647
|
+
}
|
|
648
|
+
function mapUnknownField(object, field, dialect) {
|
|
649
|
+
const sql = isCatalogSqlExpression(field.value) ? mapExpression(field.value) : void 0;
|
|
650
|
+
const value = isCatalogSqlExpression(field.value) ? field.value.text : field.value;
|
|
651
|
+
return {
|
|
652
|
+
kind: "opaque-object",
|
|
653
|
+
id: `unknown:${object.kind}:${object.id ?? object.physicalName ?? "object"}:${field.name}`,
|
|
654
|
+
objectKind: "unknown-field",
|
|
655
|
+
physicalName: object.physicalName ?? object.id ?? field.name,
|
|
656
|
+
data: toSnapshotJsonValue({
|
|
657
|
+
ownerKind: object.kind,
|
|
658
|
+
ownerId: object.id ?? object.physicalName ?? field.name,
|
|
659
|
+
field: field.name,
|
|
660
|
+
value
|
|
661
|
+
}),
|
|
662
|
+
...sql === void 0 ? {} : { sql },
|
|
663
|
+
...mapMetadata(field.provenance, void 0, dialect)
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
function compareId(left, right) {
|
|
667
|
+
return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
|
|
668
|
+
}
|
|
669
|
+
function isCatalogSqlExpression(value) {
|
|
670
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && value.kind === "sql" && typeof value.text === "string";
|
|
671
|
+
}
|
|
672
|
+
//#endregion
|
|
673
|
+
//#region src/introspection/mysql.ts
|
|
674
|
+
const mysqlServerQuery = `SELECT VERSION() AS version, @@version_comment AS version_comment`;
|
|
675
|
+
const mysqlTablesQuery = `
|
|
676
|
+
SELECT TABLE_NAME AS table_name, TABLE_TYPE AS table_type,
|
|
677
|
+
ENGINE AS engine, TABLE_COLLATION AS table_collation,
|
|
678
|
+
CREATE_OPTIONS AS create_options, TABLE_COMMENT AS table_comment
|
|
679
|
+
FROM INFORMATION_SCHEMA.TABLES
|
|
680
|
+
WHERE TABLE_SCHEMA = ?
|
|
681
|
+
ORDER BY TABLE_NAME
|
|
682
|
+
`;
|
|
683
|
+
const mysqlColumnsQuery = `
|
|
684
|
+
SELECT TABLE_NAME AS table_name, COLUMN_NAME AS column_name,
|
|
685
|
+
ORDINAL_POSITION AS ordinal_position, COLUMN_TYPE AS column_type,
|
|
686
|
+
DATA_TYPE AS data_type,
|
|
687
|
+
IS_NULLABLE AS is_nullable, COLUMN_DEFAULT AS column_default,
|
|
688
|
+
EXTRA AS extra, GENERATION_EXPRESSION AS generation_expression,
|
|
689
|
+
CHARACTER_SET_NAME AS character_set_name,
|
|
690
|
+
COLLATION_NAME AS collation_name, COLUMN_COMMENT AS column_comment
|
|
691
|
+
FROM INFORMATION_SCHEMA.COLUMNS
|
|
692
|
+
WHERE TABLE_SCHEMA = ?
|
|
693
|
+
ORDER BY TABLE_NAME, ORDINAL_POSITION
|
|
694
|
+
`;
|
|
695
|
+
const mysqlKeyUsageQuery = `
|
|
696
|
+
SELECT kcu.TABLE_NAME AS table_name, kcu.CONSTRAINT_NAME AS constraint_name,
|
|
697
|
+
tc.CONSTRAINT_TYPE AS constraint_type, tc.ENFORCED AS enforced,
|
|
698
|
+
kcu.COLUMN_NAME AS column_name, kcu.ORDINAL_POSITION AS ordinal_position,
|
|
699
|
+
kcu.REFERENCED_TABLE_NAME AS referenced_table_name,
|
|
700
|
+
kcu.REFERENCED_COLUMN_NAME AS referenced_column_name,
|
|
701
|
+
rc.UPDATE_RULE AS update_rule, rc.DELETE_RULE AS delete_rule,
|
|
702
|
+
rc.MATCH_OPTION AS match_option
|
|
703
|
+
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
|
|
704
|
+
JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
|
|
705
|
+
ON tc.CONSTRAINT_SCHEMA = kcu.CONSTRAINT_SCHEMA
|
|
706
|
+
AND tc.TABLE_NAME = kcu.TABLE_NAME
|
|
707
|
+
AND tc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME
|
|
708
|
+
LEFT JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
|
|
709
|
+
ON rc.CONSTRAINT_SCHEMA = kcu.CONSTRAINT_SCHEMA
|
|
710
|
+
AND rc.TABLE_NAME = kcu.TABLE_NAME
|
|
711
|
+
AND rc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME
|
|
712
|
+
WHERE kcu.CONSTRAINT_SCHEMA = ?
|
|
713
|
+
ORDER BY kcu.TABLE_NAME, kcu.CONSTRAINT_NAME, kcu.ORDINAL_POSITION
|
|
714
|
+
`;
|
|
715
|
+
const mysqlChecksQuery = `
|
|
716
|
+
SELECT tc.TABLE_NAME AS table_name, tc.CONSTRAINT_NAME AS constraint_name,
|
|
717
|
+
tc.ENFORCED AS enforced, cc.CHECK_CLAUSE AS check_clause
|
|
718
|
+
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
|
|
719
|
+
JOIN INFORMATION_SCHEMA.CHECK_CONSTRAINTS cc
|
|
720
|
+
ON cc.CONSTRAINT_SCHEMA = tc.CONSTRAINT_SCHEMA
|
|
721
|
+
AND cc.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
|
|
722
|
+
WHERE tc.CONSTRAINT_SCHEMA = ? AND tc.CONSTRAINT_TYPE = 'CHECK'
|
|
723
|
+
ORDER BY tc.TABLE_NAME, tc.CONSTRAINT_NAME
|
|
724
|
+
`;
|
|
725
|
+
const mysqlStatisticsQuery = `
|
|
726
|
+
SELECT TABLE_NAME AS table_name, INDEX_NAME AS index_name,
|
|
727
|
+
NON_UNIQUE AS non_unique, SEQ_IN_INDEX AS seq_in_index,
|
|
728
|
+
COLUMN_NAME AS column_name, COLLATION AS collation,
|
|
729
|
+
INDEX_TYPE AS index_type, EXPRESSION AS expression,
|
|
730
|
+
SUB_PART AS sub_part, IS_VISIBLE AS is_visible,
|
|
731
|
+
COMMENT AS comment, INDEX_COMMENT AS index_comment
|
|
732
|
+
FROM INFORMATION_SCHEMA.STATISTICS
|
|
733
|
+
WHERE TABLE_SCHEMA = ?
|
|
734
|
+
ORDER BY TABLE_NAME, INDEX_NAME, SEQ_IN_INDEX
|
|
735
|
+
`;
|
|
736
|
+
/** View definitions and execution properties for the selected database. */
|
|
737
|
+
const mysqlViewsQuery = `
|
|
738
|
+
SELECT TABLE_NAME AS table_name, VIEW_DEFINITION AS view_definition,
|
|
739
|
+
CHECK_OPTION AS check_option, IS_UPDATABLE AS is_updatable,
|
|
740
|
+
SECURITY_TYPE AS security_type, DEFINER AS definer
|
|
741
|
+
FROM INFORMATION_SCHEMA.VIEWS
|
|
742
|
+
WHERE TABLE_SCHEMA = ?
|
|
743
|
+
ORDER BY TABLE_NAME
|
|
744
|
+
`;
|
|
745
|
+
/** Stored function and procedure declarations for the selected database. */
|
|
746
|
+
const mysqlRoutinesQuery = `
|
|
747
|
+
SELECT ROUTINE_NAME AS routine_name, ROUTINE_TYPE AS routine_type,
|
|
748
|
+
DATA_TYPE AS data_type, DTD_IDENTIFIER AS dtd_identifier,
|
|
749
|
+
ROUTINE_BODY AS routine_body,
|
|
750
|
+
ROUTINE_DEFINITION AS routine_definition,
|
|
751
|
+
EXTERNAL_LANGUAGE AS external_language,
|
|
752
|
+
SQL_DATA_ACCESS AS sql_data_access,
|
|
753
|
+
IS_DETERMINISTIC AS is_deterministic,
|
|
754
|
+
SECURITY_TYPE AS security_type, SQL_MODE AS sql_mode,
|
|
755
|
+
ROUTINE_COMMENT AS routine_comment
|
|
756
|
+
FROM INFORMATION_SCHEMA.ROUTINES
|
|
757
|
+
WHERE ROUTINE_SCHEMA = ?
|
|
758
|
+
ORDER BY ROUTINE_NAME, ROUTINE_TYPE
|
|
759
|
+
`;
|
|
760
|
+
/** Parameter rows, including the ordinal zero return row for functions. */
|
|
761
|
+
const mysqlRoutineParametersQuery = `
|
|
762
|
+
SELECT SPECIFIC_NAME AS routine_name, ORDINAL_POSITION AS ordinal_position,
|
|
763
|
+
PARAMETER_MODE AS parameter_mode, PARAMETER_NAME AS parameter_name,
|
|
764
|
+
DATA_TYPE AS data_type, DTD_IDENTIFIER AS dtd_identifier
|
|
765
|
+
FROM INFORMATION_SCHEMA.PARAMETERS
|
|
766
|
+
WHERE SPECIFIC_SCHEMA = ?
|
|
767
|
+
ORDER BY SPECIFIC_NAME, ORDINAL_POSITION
|
|
768
|
+
`;
|
|
769
|
+
/** Trigger bodies and their table/event metadata. */
|
|
770
|
+
const mysqlTriggersQuery = `
|
|
771
|
+
SELECT TRIGGER_NAME AS trigger_name, EVENT_MANIPULATION AS event_manipulation,
|
|
772
|
+
EVENT_OBJECT_TABLE AS table_name, ACTION_CONDITION AS action_condition,
|
|
773
|
+
ACTION_STATEMENT AS action_statement,
|
|
774
|
+
ACTION_ORIENTATION AS action_orientation,
|
|
775
|
+
ACTION_TIMING AS action_timing, ACTION_ORDER AS action_order,
|
|
776
|
+
DEFINER AS definer, SQL_MODE AS sql_mode
|
|
777
|
+
FROM INFORMATION_SCHEMA.TRIGGERS
|
|
778
|
+
WHERE TRIGGER_SCHEMA = ?
|
|
779
|
+
ORDER BY TRIGGER_NAME, ACTION_ORDER
|
|
780
|
+
`;
|
|
781
|
+
/** Partition and subpartition declarations for tables in the selected database. */
|
|
782
|
+
const mysqlPartitionsQuery = `
|
|
783
|
+
SELECT TABLE_NAME AS table_name, PARTITION_NAME AS partition_name,
|
|
784
|
+
SUBPARTITION_NAME AS subpartition_name,
|
|
785
|
+
PARTITION_ORDINAL_POSITION AS partition_ordinal_position,
|
|
786
|
+
SUBPARTITION_ORDINAL_POSITION AS subpartition_ordinal_position,
|
|
787
|
+
PARTITION_METHOD AS partition_method,
|
|
788
|
+
SUBPARTITION_METHOD AS subpartition_method,
|
|
789
|
+
PARTITION_EXPRESSION AS partition_expression,
|
|
790
|
+
SUBPARTITION_EXPRESSION AS subpartition_expression,
|
|
791
|
+
PARTITION_DESCRIPTION AS partition_description,
|
|
792
|
+
PARTITION_COMMENT AS partition_comment,
|
|
793
|
+
TABLESPACE_NAME AS tablespace_name
|
|
794
|
+
FROM INFORMATION_SCHEMA.PARTITIONS
|
|
795
|
+
WHERE TABLE_SCHEMA = ? AND PARTITION_NAME IS NOT NULL
|
|
796
|
+
ORDER BY TABLE_NAME, PARTITION_ORDINAL_POSITION, SUBPARTITION_ORDINAL_POSITION
|
|
797
|
+
`;
|
|
798
|
+
/** Collations used by tables or columns in the selected database. */
|
|
799
|
+
const mysqlCollationsQuery = `
|
|
800
|
+
SELECT c.COLLATION_NAME AS collation_name,
|
|
801
|
+
c.CHARACTER_SET_NAME AS character_set_name,
|
|
802
|
+
c.ID AS collation_id, c.IS_DEFAULT AS is_default,
|
|
803
|
+
c.IS_COMPILED AS is_compiled, c.SORTLEN AS sort_length,
|
|
804
|
+
c.PAD_ATTRIBUTE AS pad_attribute
|
|
805
|
+
FROM INFORMATION_SCHEMA.COLLATIONS c
|
|
806
|
+
JOIN (
|
|
807
|
+
SELECT DISTINCT TABLE_COLLATION AS collation_name
|
|
808
|
+
FROM INFORMATION_SCHEMA.TABLES
|
|
809
|
+
WHERE TABLE_SCHEMA = ? AND TABLE_COLLATION IS NOT NULL
|
|
810
|
+
UNION
|
|
811
|
+
SELECT DISTINCT COLLATION_NAME AS collation_name
|
|
812
|
+
FROM INFORMATION_SCHEMA.COLUMNS
|
|
813
|
+
WHERE TABLE_SCHEMA = ? AND COLLATION_NAME IS NOT NULL
|
|
814
|
+
) used ON used.collation_name = c.COLLATION_NAME
|
|
815
|
+
ORDER BY c.COLLATION_NAME
|
|
816
|
+
`;
|
|
817
|
+
/** Scheduled events are retained as opaque MySQL objects, not migration input. */
|
|
818
|
+
const mysqlEventsQuery = `
|
|
819
|
+
SELECT EVENT_NAME AS event_name, EVENT_TYPE AS event_type,
|
|
820
|
+
STATUS AS status, EVENT_DEFINITION AS event_definition,
|
|
821
|
+
EVENT_BODY AS event_body, EXECUTE_AT AS execute_at,
|
|
822
|
+
INTERVAL_VALUE AS interval_value, INTERVAL_FIELD AS interval_field,
|
|
823
|
+
EVENT_COMMENT AS event_comment, DEFINER AS definer
|
|
824
|
+
FROM INFORMATION_SCHEMA.EVENTS
|
|
825
|
+
WHERE EVENT_SCHEMA = ?
|
|
826
|
+
ORDER BY EVENT_NAME
|
|
827
|
+
`;
|
|
828
|
+
/** Read one MySQL database into the normalized catalog contract. */
|
|
829
|
+
async function readMysqlCatalog(connection, options) {
|
|
830
|
+
const diagnostics = [];
|
|
831
|
+
if (connection.dialect !== "mysql") {
|
|
832
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
833
|
+
severity: "error",
|
|
834
|
+
code: "dialect-mismatch",
|
|
835
|
+
message: "MySQL catalog reading requires a MySQL CatalogConnection",
|
|
836
|
+
path: ["connection", "dialect"]
|
|
837
|
+
}));
|
|
838
|
+
return emptyCatalog$2(options.namespace, diagnostics);
|
|
839
|
+
}
|
|
840
|
+
const server = serverInfo$2((await query$2(connection, mysqlServerQuery, [], options, diagnostics, "server"))[0], diagnostics);
|
|
841
|
+
const tableRows = await query$2(connection, mysqlTablesQuery, [options.namespace], options, diagnostics, "tables");
|
|
842
|
+
const tables = tableRows.filter((row) => text$2(row.table_type) === "BASE TABLE").map((row) => table$1(row, options.namespace));
|
|
843
|
+
const deferredObjects = [];
|
|
844
|
+
const opaqueObjects = [];
|
|
845
|
+
const views = [];
|
|
846
|
+
const comments = [];
|
|
847
|
+
const tableByName = new Map(tables.map((item) => [item.physicalName, item]));
|
|
848
|
+
const viewRows = await query$2(connection, mysqlViewsQuery, [options.namespace], options, diagnostics, "views");
|
|
849
|
+
const viewRowsByName = new Map(viewRows.map((row) => [text$2(row.table_name) ?? "", row]));
|
|
850
|
+
for (const row of tableRows.filter((currentRow) => text$2(currentRow.table_type) !== "BASE TABLE")) {
|
|
851
|
+
const kind = text$2(row.table_type)?.toUpperCase();
|
|
852
|
+
if (kind === "VIEW" || kind === "SYSTEM VIEW") {
|
|
853
|
+
const mapped = viewObject$1(row, viewRowsByName.get(text$2(row.table_name) ?? ""), options.namespace, diagnostics);
|
|
854
|
+
if (mapped.kind === "deferred-object") deferredObjects.push(mapped);
|
|
855
|
+
else views.push(mapped);
|
|
856
|
+
} else {
|
|
857
|
+
const mapped = deferred$1(row, options.namespace);
|
|
858
|
+
deferredObjects.push(mapped);
|
|
859
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
860
|
+
severity: "warning",
|
|
861
|
+
code: "unmodeled-object",
|
|
862
|
+
message: `MySQL object ${mapped.physicalName} (${kind ?? "unknown"}) is retained as a deferred record`,
|
|
863
|
+
path: ["deferredObjects", mapped.physicalName],
|
|
864
|
+
physicalReference: mapped.reference,
|
|
865
|
+
remediation: "Inspect the deferred record before using it as migration input."
|
|
866
|
+
}));
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
const relationByName = /* @__PURE__ */ new Map();
|
|
870
|
+
for (const currentTable of tables) relationByName.set(currentTable.physicalName, {
|
|
871
|
+
kind: "table",
|
|
872
|
+
id: currentTable.id
|
|
873
|
+
});
|
|
874
|
+
for (const view of views) relationByName.set(view.physicalName, {
|
|
875
|
+
kind: "view",
|
|
876
|
+
id: view.id
|
|
877
|
+
});
|
|
878
|
+
const columnRows = await query$2(connection, mysqlColumnsQuery, [options.namespace], options, diagnostics, "columns");
|
|
879
|
+
for (const currentTable of tables) currentTable.columns = columnRows.filter((row) => text$2(row.table_name) === currentTable.physicalName).map((row) => column$2(row, currentTable, options.namespace));
|
|
880
|
+
for (const view of views) view.columns = columnRows.filter((row) => text$2(row.table_name) === view.physicalName).map((row) => column$2(row, view, options.namespace));
|
|
881
|
+
const keyRows = await query$2(connection, mysqlKeyUsageQuery, [options.namespace], options, diagnostics, "constraints");
|
|
882
|
+
for (const currentTable of tables) currentTable.constraints = constraints(currentTable, keyRows.filter((row) => text$2(row.table_name) === currentTable.physicalName), tableByName, options.namespace, diagnostics);
|
|
883
|
+
const checkRows = await query$2(connection, mysqlChecksQuery, [options.namespace], options, diagnostics, "checks");
|
|
884
|
+
const constraintsByTable = /* @__PURE__ */ new Map();
|
|
885
|
+
for (const currentTable of tables) constraintsByTable.set(currentTable.physicalName, [...currentTable.constraints]);
|
|
886
|
+
for (const row of checkRows) {
|
|
887
|
+
const currentTable = tableByName.get(text$2(row.table_name) ?? "");
|
|
888
|
+
if (!currentTable) continue;
|
|
889
|
+
const physicalName = text$2(row.constraint_name) ?? `check_${currentTable.physicalName}`;
|
|
890
|
+
const check = {
|
|
891
|
+
kind: "check",
|
|
892
|
+
id: stableId$2(physicalName),
|
|
893
|
+
identitySource: "physical-name",
|
|
894
|
+
physicalName,
|
|
895
|
+
expression: sql$2(text$2(row.check_clause) ?? "true", options.namespace, currentTable, physicalName),
|
|
896
|
+
dialect: text$2(row.enforced)?.toUpperCase() === "NO" ? {
|
|
897
|
+
dialect: "mysql",
|
|
898
|
+
version: 1,
|
|
899
|
+
data: { enforced: false }
|
|
900
|
+
} : void 0
|
|
901
|
+
};
|
|
902
|
+
constraintsByTable.get(currentTable.physicalName)?.push(check);
|
|
903
|
+
}
|
|
904
|
+
for (const currentTable of tables) currentTable.constraints = constraintsByTable.get(currentTable.physicalName) ?? [];
|
|
905
|
+
const statRows = await query$2(connection, mysqlStatisticsQuery, [options.namespace], options, diagnostics, "statistics");
|
|
906
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
907
|
+
for (const row of statRows) {
|
|
908
|
+
const key = `${text$2(row.table_name) ?? ""}\u0000${text$2(row.index_name) ?? ""}`;
|
|
909
|
+
const group = grouped.get(key) ?? [];
|
|
910
|
+
group.push(row);
|
|
911
|
+
grouped.set(key, group);
|
|
912
|
+
}
|
|
913
|
+
for (const rows of grouped.values()) {
|
|
914
|
+
const currentTable = tableByName.get(text$2(rows[0].table_name) ?? "");
|
|
915
|
+
if (!currentTable) continue;
|
|
916
|
+
const mappedIndex = mapIndex(rows, currentTable, options.namespace, diagnostics);
|
|
917
|
+
if (mappedIndex) currentTable.indexes = [...currentTable.indexes, mappedIndex];
|
|
918
|
+
}
|
|
919
|
+
const routineRows = await query$2(connection, mysqlRoutinesQuery, [options.namespace], options, diagnostics, "routines");
|
|
920
|
+
const routineParameterRows = await query$2(connection, mysqlRoutineParametersQuery, [options.namespace], options, diagnostics, "routine-parameters");
|
|
921
|
+
const routineParameters = /* @__PURE__ */ new Map();
|
|
922
|
+
for (const row of routineParameterRows) {
|
|
923
|
+
const name = text$2(row.routine_name) ?? "unknown";
|
|
924
|
+
const group = routineParameters.get(name) ?? [];
|
|
925
|
+
group.push(row);
|
|
926
|
+
routineParameters.set(name, group);
|
|
927
|
+
}
|
|
928
|
+
const routines = routineRows.map((row) => {
|
|
929
|
+
const routine = routineObject(row, routineParameters.get(text$2(row.routine_name) ?? "") ?? [], options.namespace);
|
|
930
|
+
if (routine.comment) comments.push(routine.comment);
|
|
931
|
+
relationByName.set(routine.physicalName, {
|
|
932
|
+
kind: "routine",
|
|
933
|
+
id: routine.id
|
|
934
|
+
});
|
|
935
|
+
return routine;
|
|
936
|
+
});
|
|
937
|
+
const triggerRows = await query$2(connection, mysqlTriggersQuery, [options.namespace], options, diagnostics, "triggers");
|
|
938
|
+
const triggers = [];
|
|
939
|
+
for (const rows of groupRows(triggerRows, (row) => text$2(row.trigger_name) ?? "unknown")) {
|
|
940
|
+
const mapped = triggerObject$1(rows, relationByName, options.namespace, diagnostics);
|
|
941
|
+
if (mapped.kind === "trigger") triggers.push(mapped);
|
|
942
|
+
else deferredObjects.push(mapped);
|
|
943
|
+
}
|
|
944
|
+
const partitionRows = await query$2(connection, mysqlPartitionsQuery, [options.namespace], options, diagnostics, "partitions");
|
|
945
|
+
const partitions = [];
|
|
946
|
+
for (const row of partitionRows) {
|
|
947
|
+
const mapped = partitionObject$1(row, tableByName, options.namespace, diagnostics);
|
|
948
|
+
if (mapped.kind === "partition") {
|
|
949
|
+
partitions.push(mapped);
|
|
950
|
+
if (mapped.comment) comments.push(mapped.comment);
|
|
951
|
+
} else deferredObjects.push(mapped);
|
|
952
|
+
}
|
|
953
|
+
const collationRows = await query$2(connection, mysqlCollationsQuery, [options.namespace, options.namespace], options, diagnostics, "collations");
|
|
954
|
+
const usedCollations = new Set([...tableRows.map((row) => text$2(row.table_collation)), ...columnRows.map((row) => text$2(row.collation_name))].filter((value) => value !== void 0));
|
|
955
|
+
const collations = collationRows.filter((row) => {
|
|
956
|
+
const name = text$2(row.collation_name);
|
|
957
|
+
return name !== void 0 && usedCollations.has(name);
|
|
958
|
+
}).map((row) => collationObject$1(row, options.namespace));
|
|
959
|
+
const eventRows = await query$2(connection, mysqlEventsQuery, [options.namespace], options, diagnostics, "events");
|
|
960
|
+
for (const row of eventRows) {
|
|
961
|
+
const event = opaqueEvent(row, options.namespace);
|
|
962
|
+
opaqueObjects.push(event);
|
|
963
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
964
|
+
severity: "warning",
|
|
965
|
+
code: "unmodeled-object",
|
|
966
|
+
message: `MySQL event ${event.physicalName} is retained as opaque data`,
|
|
967
|
+
path: ["opaqueObjects", event.physicalName],
|
|
968
|
+
physicalReference: event.reference,
|
|
969
|
+
remediation: "Inspect the event definition before treating it as migration input."
|
|
970
|
+
}));
|
|
971
|
+
const eventComment = text$2(row.event_comment);
|
|
972
|
+
if (eventComment !== void 0 && eventComment !== "") comments.push(objectComment({
|
|
973
|
+
kind: "opaque-object",
|
|
974
|
+
id: event.id
|
|
975
|
+
}, eventComment, event.reference, options.namespace));
|
|
976
|
+
}
|
|
977
|
+
for (const currentTable of tables) {
|
|
978
|
+
const tableComment = text$2(tableRows.find((row) => text$2(row.table_name) === currentTable.physicalName)?.table_comment);
|
|
979
|
+
if (tableComment !== void 0 && tableComment !== "") comments.push(objectComment({
|
|
980
|
+
kind: "table",
|
|
981
|
+
id: currentTable.id
|
|
982
|
+
}, tableComment, currentTable.reference, options.namespace));
|
|
983
|
+
for (const currentColumn of currentTable.columns) {
|
|
984
|
+
const columnComment = text$2(columnRows.find((row) => text$2(row.table_name) === currentTable.physicalName && text$2(row.column_name) === currentColumn.physicalName)?.column_comment);
|
|
985
|
+
if (columnComment !== void 0 && columnComment !== "") comments.push(objectComment({
|
|
986
|
+
kind: "column",
|
|
987
|
+
id: currentColumn.id
|
|
988
|
+
}, columnComment, currentColumn.reference, options.namespace));
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
for (const view of views) {
|
|
992
|
+
const viewComment = text$2(tableRows.find((row) => text$2(row.table_name) === view.physicalName)?.table_comment);
|
|
993
|
+
if (viewComment !== void 0 && viewComment !== "") comments.push(objectComment({
|
|
994
|
+
kind: view.kind,
|
|
995
|
+
id: view.id
|
|
996
|
+
}, viewComment, view.reference, options.namespace));
|
|
997
|
+
for (const currentColumn of view.columns) {
|
|
998
|
+
const columnComment = text$2(columnRows.find((row) => text$2(row.table_name) === view.physicalName && text$2(row.column_name) === currentColumn.physicalName)?.column_comment);
|
|
999
|
+
if (columnComment !== void 0 && columnComment !== "") comments.push(objectComment({
|
|
1000
|
+
kind: "column",
|
|
1001
|
+
id: currentColumn.id
|
|
1002
|
+
}, columnComment, currentColumn.reference, options.namespace));
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
const capabilities = {
|
|
1006
|
+
generatedColumns: server.capabilities.generatedColumns,
|
|
1007
|
+
identityMetadata: server.capabilities.identityMetadata,
|
|
1008
|
+
checkConstraints: server.capabilities.checkConstraints,
|
|
1009
|
+
checkConstraintEnforcement: server.capabilities.checkConstraintEnforcement,
|
|
1010
|
+
expressionDecompilation: server.capabilities.expressionDecompilation,
|
|
1011
|
+
indexExpressions: server.capabilities.indexExpressions,
|
|
1012
|
+
indexPredicates: server.capabilities.indexPredicates,
|
|
1013
|
+
indexIncludedColumns: server.capabilities.indexIncludedColumns,
|
|
1014
|
+
namespaces: server.capabilities.namespaces,
|
|
1015
|
+
visibility: server.capabilities.visibility
|
|
1016
|
+
};
|
|
1017
|
+
const serverCapabilities = {
|
|
1018
|
+
...server.capabilities,
|
|
1019
|
+
views: true,
|
|
1020
|
+
materializedViews: false,
|
|
1021
|
+
sequences: false,
|
|
1022
|
+
enums: false,
|
|
1023
|
+
domains: false,
|
|
1024
|
+
collations: true,
|
|
1025
|
+
routines: true,
|
|
1026
|
+
triggers: true,
|
|
1027
|
+
partitions: true,
|
|
1028
|
+
policies: false,
|
|
1029
|
+
extensions: false,
|
|
1030
|
+
comments: true,
|
|
1031
|
+
ownership: false,
|
|
1032
|
+
scheduledEvents: true,
|
|
1033
|
+
tableEngines: true,
|
|
1034
|
+
generatedColumnModes: true,
|
|
1035
|
+
selectedNamespace: options.namespace,
|
|
1036
|
+
productFamily: server.product === "mariadb" ? "mariadb" : "mysql8"
|
|
1037
|
+
};
|
|
1038
|
+
const namespace = {
|
|
1039
|
+
kind: "mysql-database",
|
|
1040
|
+
name: options.namespace,
|
|
1041
|
+
reference: reference$2("namespace", options.namespace, options.namespace, "INFORMATION_SCHEMA.SCHEMATA", "SCHEMA_NAME"),
|
|
1042
|
+
dialect: mysqlExtension({
|
|
1043
|
+
selectedNamespace: options.namespace,
|
|
1044
|
+
views: true,
|
|
1045
|
+
materializedViews: false,
|
|
1046
|
+
sequences: false,
|
|
1047
|
+
routines: true,
|
|
1048
|
+
triggers: true,
|
|
1049
|
+
partitions: true,
|
|
1050
|
+
collations: true,
|
|
1051
|
+
comments: true,
|
|
1052
|
+
ownership: false,
|
|
1053
|
+
policies: false,
|
|
1054
|
+
extensions: false
|
|
1055
|
+
})
|
|
1056
|
+
};
|
|
1057
|
+
return Object.freeze({
|
|
1058
|
+
dialect: "mysql",
|
|
1059
|
+
server: {
|
|
1060
|
+
...server,
|
|
1061
|
+
capabilities: serverCapabilities
|
|
1062
|
+
},
|
|
1063
|
+
namespace,
|
|
1064
|
+
tables: Object.freeze(tables),
|
|
1065
|
+
views: Object.freeze(views),
|
|
1066
|
+
collations: Object.freeze(collations),
|
|
1067
|
+
routines: Object.freeze(routines),
|
|
1068
|
+
triggers: Object.freeze(triggers),
|
|
1069
|
+
partitions: Object.freeze(partitions),
|
|
1070
|
+
deferredObjects: Object.freeze(deferredObjects),
|
|
1071
|
+
opaqueObjects: Object.freeze(opaqueObjects),
|
|
1072
|
+
comments: Object.freeze(comments),
|
|
1073
|
+
ownership: Object.freeze([]),
|
|
1074
|
+
capabilities,
|
|
1075
|
+
diagnostics: Object.freeze(diagnostics)
|
|
1076
|
+
});
|
|
1077
|
+
}
|
|
1078
|
+
async function query$2(connection, textValue, parameters, options, diagnostics, operation) {
|
|
1079
|
+
try {
|
|
1080
|
+
return await connection.query({
|
|
1081
|
+
text: textValue,
|
|
1082
|
+
parameters
|
|
1083
|
+
}, { signal: options.signal });
|
|
1084
|
+
} catch {
|
|
1085
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
1086
|
+
severity: "error",
|
|
1087
|
+
code: "query-failed",
|
|
1088
|
+
message: `MySQL catalog query failed while reading ${operation}`,
|
|
1089
|
+
path: [operation],
|
|
1090
|
+
remediation: "Check Information Schema permissions and the selected database."
|
|
1091
|
+
}));
|
|
1092
|
+
return [];
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
function serverInfo$2(row, diagnostics) {
|
|
1096
|
+
const rawVersion = text$2(row?.version) ?? "unknown";
|
|
1097
|
+
const comment = text$2(row?.version_comment) ?? "";
|
|
1098
|
+
const mariadb = /mariadb/i.test(rawVersion) || /mariadb/i.test(comment);
|
|
1099
|
+
const parts = rawVersion.match(/(\d+)\.(\d+)(?:\.(\d+))?/);
|
|
1100
|
+
const major = parts ? Number(parts[1]) : void 0;
|
|
1101
|
+
const minor = parts ? Number(parts[2]) : void 0;
|
|
1102
|
+
if (mariadb) diagnostics.push(createIntrospectionDiagnostic({
|
|
1103
|
+
severity: "error",
|
|
1104
|
+
code: "unsupported-product",
|
|
1105
|
+
message: "MariaDB requires a dedicated catalog adapter and is not treated as MySQL",
|
|
1106
|
+
path: ["server", "product"]
|
|
1107
|
+
}));
|
|
1108
|
+
const supported = !mariadb && major === 8 && ((minor ?? 0) > 0 || (minor ?? 0) === 0 && Number(parts?.[3] ?? 0) >= 16);
|
|
1109
|
+
if (!supported && !mariadb) diagnostics.push(createIntrospectionDiagnostic({
|
|
1110
|
+
severity: "error",
|
|
1111
|
+
code: "unsupported-server",
|
|
1112
|
+
message: "MySQL introspection requires MySQL 8.0 or newer",
|
|
1113
|
+
path: ["server", "version"]
|
|
1114
|
+
}));
|
|
1115
|
+
return {
|
|
1116
|
+
product: mariadb ? "mariadb" : "mysql",
|
|
1117
|
+
rawVersion,
|
|
1118
|
+
parsedVersion: major === void 0 ? void 0 : {
|
|
1119
|
+
major,
|
|
1120
|
+
minor,
|
|
1121
|
+
patch: parts?.[3] ? Number(parts[3]) : void 0
|
|
1122
|
+
},
|
|
1123
|
+
capabilities: {
|
|
1124
|
+
generatedColumns: supported,
|
|
1125
|
+
identityMetadata: supported,
|
|
1126
|
+
checkConstraints: supported,
|
|
1127
|
+
checkConstraintEnforcement: supported ? "enforced" : "unknown",
|
|
1128
|
+
expressionDecompilation: false,
|
|
1129
|
+
indexExpressions: supported,
|
|
1130
|
+
indexPredicates: false,
|
|
1131
|
+
indexIncludedColumns: false,
|
|
1132
|
+
namespaces: true,
|
|
1133
|
+
visibility: "complete",
|
|
1134
|
+
mysql8: supported
|
|
1135
|
+
}
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1138
|
+
function table$1(row, namespace) {
|
|
1139
|
+
const physicalName = text$2(row.table_name) ?? "unnamed_table";
|
|
1140
|
+
return {
|
|
1141
|
+
kind: "table",
|
|
1142
|
+
id: stableId$2(physicalName),
|
|
1143
|
+
identitySource: "physical-name",
|
|
1144
|
+
physicalName,
|
|
1145
|
+
reference: reference$2("table", physicalName, namespace, "INFORMATION_SCHEMA.TABLES", "TABLE_NAME"),
|
|
1146
|
+
columns: [],
|
|
1147
|
+
constraints: [],
|
|
1148
|
+
indexes: [],
|
|
1149
|
+
dialect: mysqlExtension({
|
|
1150
|
+
...text$2(row.engine) === void 0 ? {} : { engine: text$2(row.engine) },
|
|
1151
|
+
...text$2(row.table_collation) === void 0 ? {} : { collation: text$2(row.table_collation) },
|
|
1152
|
+
...text$2(row.create_options) === void 0 ? {} : { createOptions: text$2(row.create_options) }
|
|
1153
|
+
})
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
function deferred$1(row, namespace) {
|
|
1157
|
+
const physicalName = text$2(row.table_name) ?? "unnamed_object";
|
|
1158
|
+
return {
|
|
1159
|
+
kind: "deferred-object",
|
|
1160
|
+
id: stableId$2(`deferred:${text$2(row.table_type) ?? "other"}:${physicalName}`),
|
|
1161
|
+
identitySource: "physical-name",
|
|
1162
|
+
objectKind: text$2(row.table_type)?.toUpperCase() === "VIEW" || text$2(row.table_type)?.toUpperCase() === "SYSTEM VIEW" ? "view" : "other",
|
|
1163
|
+
physicalName,
|
|
1164
|
+
reference: reference$2("deferred-object", physicalName, namespace, "INFORMATION_SCHEMA.TABLES", "TABLE_NAME"),
|
|
1165
|
+
dialect: mysqlExtension({
|
|
1166
|
+
...text$2(row.table_type) === void 0 ? {} : { tableType: text$2(row.table_type) },
|
|
1167
|
+
...text$2(row.engine) === void 0 ? {} : { engine: text$2(row.engine) }
|
|
1168
|
+
})
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
function column$2(row, table, namespace) {
|
|
1172
|
+
const physicalName = text$2(row.column_name) ?? "unnamed_column";
|
|
1173
|
+
const extra = text$2(row.extra) ?? "";
|
|
1174
|
+
const generationExpression = text$2(row.generation_expression);
|
|
1175
|
+
const generated = generationExpression !== void 0 && (/GENERATED/i.test(extra) || generationExpression !== "") ? {
|
|
1176
|
+
kind: "generated",
|
|
1177
|
+
mode: /VIRTUAL/i.test(extra) ? "virtual" : /STORED/i.test(extra) ? "stored" : "unknown",
|
|
1178
|
+
expression: sql$2(generationExpression, namespace, table, physicalName)
|
|
1179
|
+
} : void 0;
|
|
1180
|
+
const identity = /auto_increment/i.test(extra) ? {
|
|
1181
|
+
kind: "identity",
|
|
1182
|
+
generation: "by-default",
|
|
1183
|
+
options: {},
|
|
1184
|
+
dialect: {
|
|
1185
|
+
dialect: "mysql",
|
|
1186
|
+
version: 1,
|
|
1187
|
+
data: { autoIncrement: true }
|
|
1188
|
+
}
|
|
1189
|
+
} : void 0;
|
|
1190
|
+
const onUpdateMatch = extra.match(/on update\s+(.+)$/i);
|
|
1191
|
+
const defaultText = text$2(row.column_default);
|
|
1192
|
+
const defaultValue = literal(defaultText, text$2(row.data_type));
|
|
1193
|
+
return {
|
|
1194
|
+
kind: "column",
|
|
1195
|
+
id: stableId$2(physicalName),
|
|
1196
|
+
identitySource: "physical-name",
|
|
1197
|
+
physicalName,
|
|
1198
|
+
ordinalPosition: number$2(row.ordinal_position) ?? 0,
|
|
1199
|
+
nullable: text$2(row.is_nullable)?.toUpperCase() !== "NO",
|
|
1200
|
+
storage: { nativeType: text$2(row.column_type) ?? "unknown" },
|
|
1201
|
+
default: defaultValue !== void 0 ? {
|
|
1202
|
+
kind: "literal",
|
|
1203
|
+
value: defaultValue
|
|
1204
|
+
} : defaultText !== void 0 ? {
|
|
1205
|
+
kind: "expression",
|
|
1206
|
+
expression: sql$2(defaultText, namespace, table, physicalName)
|
|
1207
|
+
} : void 0,
|
|
1208
|
+
generated,
|
|
1209
|
+
identity,
|
|
1210
|
+
onUpdate: onUpdateMatch?.[1] ? sql$2(onUpdateMatch[1], namespace, table, physicalName) : void 0,
|
|
1211
|
+
dialect: mysqlExtension({
|
|
1212
|
+
...text$2(row.data_type) === void 0 ? {} : { dataType: text$2(row.data_type) },
|
|
1213
|
+
...text$2(row.character_set_name) === void 0 ? {} : { characterSet: text$2(row.character_set_name) },
|
|
1214
|
+
...text$2(row.collation_name) === void 0 ? {} : { collation: text$2(row.collation_name) },
|
|
1215
|
+
...extra === "" ? {} : { extra }
|
|
1216
|
+
}),
|
|
1217
|
+
reference: reference$2("column", physicalName, namespace, "INFORMATION_SCHEMA.COLUMNS", "COLUMN_NAME")
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
function constraints(table, rows, tableByName, namespace, diagnostics) {
|
|
1221
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
1222
|
+
for (const row of rows) {
|
|
1223
|
+
const key = text$2(row.constraint_name) ?? "unknown";
|
|
1224
|
+
const group = grouped.get(key) ?? [];
|
|
1225
|
+
group.push(row);
|
|
1226
|
+
grouped.set(key, group);
|
|
1227
|
+
}
|
|
1228
|
+
const result = [];
|
|
1229
|
+
for (const [physicalName, group] of grouped) {
|
|
1230
|
+
const first = group[0];
|
|
1231
|
+
const columns = group.sort((left, right) => (number$2(left.ordinal_position) ?? 0) - (number$2(right.ordinal_position) ?? 0)).map((row) => text$2(row.column_name) ?? "unknown");
|
|
1232
|
+
const common = {
|
|
1233
|
+
id: stableId$2(physicalName),
|
|
1234
|
+
identitySource: "physical-name",
|
|
1235
|
+
physicalName,
|
|
1236
|
+
reference: reference$2("constraint", physicalName, namespace, "INFORMATION_SCHEMA.TABLE_CONSTRAINTS", "CONSTRAINT_NAME")
|
|
1237
|
+
};
|
|
1238
|
+
const type = text$2(first.constraint_type);
|
|
1239
|
+
if (type === "PRIMARY KEY") {
|
|
1240
|
+
result.push({
|
|
1241
|
+
kind: "primary-key",
|
|
1242
|
+
...common,
|
|
1243
|
+
columns
|
|
1244
|
+
});
|
|
1245
|
+
continue;
|
|
1246
|
+
}
|
|
1247
|
+
if (type === "UNIQUE") {
|
|
1248
|
+
result.push({
|
|
1249
|
+
kind: "unique",
|
|
1250
|
+
...common,
|
|
1251
|
+
columns,
|
|
1252
|
+
nulls: "distinct"
|
|
1253
|
+
});
|
|
1254
|
+
continue;
|
|
1255
|
+
}
|
|
1256
|
+
if (type !== "FOREIGN KEY") continue;
|
|
1257
|
+
const targetTableName = text$2(first.referenced_table_name) ?? "unknown";
|
|
1258
|
+
if (!tableByName.has(targetTableName)) diagnostics.push(createIntrospectionDiagnostic({
|
|
1259
|
+
severity: "error",
|
|
1260
|
+
code: "unresolved-reference",
|
|
1261
|
+
message: `MySQL foreign key target ${targetTableName} was not found`,
|
|
1262
|
+
path: [
|
|
1263
|
+
table.id,
|
|
1264
|
+
"constraints",
|
|
1265
|
+
physicalName
|
|
1266
|
+
]
|
|
1267
|
+
}));
|
|
1268
|
+
result.push({
|
|
1269
|
+
kind: "foreign-key",
|
|
1270
|
+
...common,
|
|
1271
|
+
columns,
|
|
1272
|
+
target: {
|
|
1273
|
+
table: targetTableName,
|
|
1274
|
+
columns: group.map((row) => text$2(row.referenced_column_name) ?? "unknown")
|
|
1275
|
+
},
|
|
1276
|
+
onUpdate: action$1(first.update_rule),
|
|
1277
|
+
onDelete: action$1(first.delete_rule),
|
|
1278
|
+
match: match$1(first.match_option),
|
|
1279
|
+
dialect: text$2(first.enforced)?.toUpperCase() === "NO" ? {
|
|
1280
|
+
dialect: "mysql",
|
|
1281
|
+
version: 1,
|
|
1282
|
+
data: { enforced: false }
|
|
1283
|
+
} : void 0
|
|
1284
|
+
});
|
|
1285
|
+
}
|
|
1286
|
+
return result;
|
|
1287
|
+
}
|
|
1288
|
+
function mapIndex(rows, table, namespace, diagnostics) {
|
|
1289
|
+
const first = rows[0];
|
|
1290
|
+
const physicalName = text$2(first.index_name);
|
|
1291
|
+
if (!physicalName) return void 0;
|
|
1292
|
+
const terms = [];
|
|
1293
|
+
for (const row of rows) {
|
|
1294
|
+
const expression = text$2(row.expression);
|
|
1295
|
+
const columnName = text$2(row.column_name);
|
|
1296
|
+
if (!expression && !columnName) {
|
|
1297
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
1298
|
+
severity: "error",
|
|
1299
|
+
code: "unsupported-feature",
|
|
1300
|
+
message: `MySQL index ${physicalName} has an unrepresented term`,
|
|
1301
|
+
path: [
|
|
1302
|
+
table.id,
|
|
1303
|
+
"indexes",
|
|
1304
|
+
physicalName
|
|
1305
|
+
]
|
|
1306
|
+
}));
|
|
1307
|
+
continue;
|
|
1308
|
+
}
|
|
1309
|
+
terms.push(expression ? {
|
|
1310
|
+
kind: "expression",
|
|
1311
|
+
expression: sql$2(expression, namespace, table, physicalName),
|
|
1312
|
+
position: number$2(row.seq_in_index) ?? 0
|
|
1313
|
+
} : {
|
|
1314
|
+
kind: "column",
|
|
1315
|
+
column: columnName,
|
|
1316
|
+
position: number$2(row.seq_in_index) ?? 0,
|
|
1317
|
+
direction: text$2(row.collation) === "D" ? "DESC" : "ASC",
|
|
1318
|
+
prefixLength: row.sub_part === null || row.sub_part === void 0 ? void 0 : {
|
|
1319
|
+
kind: "literal",
|
|
1320
|
+
value: number$2(row.sub_part) ?? text$2(row.sub_part) ?? ""
|
|
1321
|
+
}
|
|
1322
|
+
});
|
|
1323
|
+
if (row.sub_part !== null && row.sub_part !== void 0) diagnostics.push(createIntrospectionDiagnostic({
|
|
1324
|
+
severity: "warning",
|
|
1325
|
+
code: "lossy-mapping",
|
|
1326
|
+
message: `MySQL index prefix length for ${physicalName} is retained only in catalog rows`,
|
|
1327
|
+
path: [
|
|
1328
|
+
table.id,
|
|
1329
|
+
"indexes",
|
|
1330
|
+
physicalName
|
|
1331
|
+
]
|
|
1332
|
+
}));
|
|
1333
|
+
}
|
|
1334
|
+
return {
|
|
1335
|
+
kind: "index",
|
|
1336
|
+
id: stableId$2(physicalName),
|
|
1337
|
+
identitySource: "physical-name",
|
|
1338
|
+
physicalName,
|
|
1339
|
+
unique: number$2(first.non_unique) === 0,
|
|
1340
|
+
terms,
|
|
1341
|
+
method: text$2(first.index_type),
|
|
1342
|
+
dialect: mysqlExtension({
|
|
1343
|
+
...text$2(first.index_type) === void 0 ? {} : { indexType: text$2(first.index_type) },
|
|
1344
|
+
...text$2(first.is_visible) === void 0 ? {} : { visible: text$2(first.is_visible).toUpperCase() !== "NO" },
|
|
1345
|
+
...text$2(first.comment) === void 0 ? {} : { comment: text$2(first.comment) },
|
|
1346
|
+
...text$2(first.index_comment) === void 0 ? {} : { indexComment: text$2(first.index_comment) }
|
|
1347
|
+
}),
|
|
1348
|
+
reference: reference$2("index", physicalName, namespace, "INFORMATION_SCHEMA.STATISTICS", "INDEX_NAME")
|
|
1349
|
+
};
|
|
1350
|
+
}
|
|
1351
|
+
function viewObject$1(tableRow, viewRow, namespace, diagnostics) {
|
|
1352
|
+
const physicalName = text$2(tableRow.table_name) ?? "unnamed_view";
|
|
1353
|
+
const physicalReference = reference$2("view", physicalName, namespace, "INFORMATION_SCHEMA.VIEWS", "TABLE_NAME");
|
|
1354
|
+
const definition = text$2(viewRow?.view_definition);
|
|
1355
|
+
if (definition === void 0 || definition.trim() === "") {
|
|
1356
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
1357
|
+
severity: "error",
|
|
1358
|
+
code: "expression-parse-failed",
|
|
1359
|
+
message: `MySQL view ${physicalName} has no recoverable definition`,
|
|
1360
|
+
path: [
|
|
1361
|
+
"views",
|
|
1362
|
+
physicalName,
|
|
1363
|
+
"definition"
|
|
1364
|
+
],
|
|
1365
|
+
physicalReference,
|
|
1366
|
+
remediation: "Grant the metadata privilege needed to read INFORMATION_SCHEMA.VIEWS.VIEW_DEFINITION."
|
|
1367
|
+
}));
|
|
1368
|
+
return {
|
|
1369
|
+
kind: "deferred-object",
|
|
1370
|
+
id: stableId$2(`view:${physicalName}`),
|
|
1371
|
+
identitySource: "physical-name",
|
|
1372
|
+
objectKind: "view",
|
|
1373
|
+
physicalName,
|
|
1374
|
+
reference: physicalReference,
|
|
1375
|
+
dialect: mysqlExtension({
|
|
1376
|
+
reason: "definition-unavailable",
|
|
1377
|
+
...text$2(viewRow?.definer) === void 0 ? {} : { definer: text$2(viewRow?.definer) }
|
|
1378
|
+
})
|
|
1379
|
+
};
|
|
1380
|
+
}
|
|
1381
|
+
const checkOption = normalizeCheckOption(viewRow?.check_option);
|
|
1382
|
+
const securityType = text$2(viewRow?.security_type)?.toUpperCase();
|
|
1383
|
+
return {
|
|
1384
|
+
kind: "view",
|
|
1385
|
+
id: stableId$2(physicalName),
|
|
1386
|
+
identitySource: "physical-name",
|
|
1387
|
+
physicalName,
|
|
1388
|
+
columns: [],
|
|
1389
|
+
definition: sql$2(definition, namespace, {
|
|
1390
|
+
kind: "view",
|
|
1391
|
+
physicalName,
|
|
1392
|
+
reference: physicalReference
|
|
1393
|
+
}, physicalName),
|
|
1394
|
+
...checkOption === void 0 ? {} : { checkOption },
|
|
1395
|
+
...securityType === "INVOKER" ? { securityInvoker: true } : {},
|
|
1396
|
+
reference: physicalReference,
|
|
1397
|
+
provenance: {
|
|
1398
|
+
kind: "catalog",
|
|
1399
|
+
dialect: "mysql",
|
|
1400
|
+
reference: physicalReference
|
|
1401
|
+
},
|
|
1402
|
+
dialect: mysqlExtension({
|
|
1403
|
+
...text$2(viewRow?.is_updatable) === void 0 ? {} : { isUpdatable: text$2(viewRow?.is_updatable) },
|
|
1404
|
+
...securityType === void 0 ? {} : { securityType },
|
|
1405
|
+
...text$2(viewRow?.definer) === void 0 ? {} : { definer: text$2(viewRow?.definer) }
|
|
1406
|
+
})
|
|
1407
|
+
};
|
|
1408
|
+
}
|
|
1409
|
+
function routineObject(row, parameterRows, namespace) {
|
|
1410
|
+
const physicalName = text$2(row.routine_name) ?? "unnamed_routine";
|
|
1411
|
+
const physicalReference = reference$2("routine", physicalName, namespace, "INFORMATION_SCHEMA.ROUTINES", "ROUTINE_NAME");
|
|
1412
|
+
const parameters = parameterRows.filter((row) => (number$2(row.ordinal_position) ?? 0) > 0).sort((left, right) => (number$2(left.ordinal_position) ?? 0) - (number$2(right.ordinal_position) ?? 0)).map(routineParameter);
|
|
1413
|
+
const definition = text$2(row.routine_definition);
|
|
1414
|
+
const returnType = text$2(row.data_type);
|
|
1415
|
+
const routine = {
|
|
1416
|
+
kind: "routine",
|
|
1417
|
+
id: stableId$2(physicalName),
|
|
1418
|
+
identitySource: "physical-name",
|
|
1419
|
+
physicalName,
|
|
1420
|
+
routineKind: text$2(row.routine_type)?.toUpperCase() === "FUNCTION" ? "function" : text$2(row.routine_type)?.toUpperCase() === "PROCEDURE" ? "procedure" : "unknown",
|
|
1421
|
+
parameters,
|
|
1422
|
+
...returnType === void 0 || returnType.toUpperCase() === "VOID" ? {} : { returnType: storage$1(row.data_type, row.dtd_identifier) },
|
|
1423
|
+
...text$2(row.external_language) === void 0 && text$2(row.routine_body) === void 0 ? {} : { language: text$2(row.external_language) ?? text$2(row.routine_body) ?? "unknown" },
|
|
1424
|
+
...definition === void 0 ? {} : { body: sql$2(definition, namespace, {
|
|
1425
|
+
kind: "routine",
|
|
1426
|
+
physicalName,
|
|
1427
|
+
reference: physicalReference
|
|
1428
|
+
}, physicalName) },
|
|
1429
|
+
volatility: "unknown",
|
|
1430
|
+
...text$2(row.security_type) === void 0 ? {} : { security: routineSecurity(row.security_type) },
|
|
1431
|
+
reference: physicalReference,
|
|
1432
|
+
provenance: {
|
|
1433
|
+
kind: "catalog",
|
|
1434
|
+
dialect: "mysql",
|
|
1435
|
+
reference: physicalReference
|
|
1436
|
+
},
|
|
1437
|
+
dialect: mysqlExtension({
|
|
1438
|
+
...text$2(row.is_deterministic) === void 0 ? {} : { deterministic: text$2(row.is_deterministic).toUpperCase() === "YES" },
|
|
1439
|
+
...text$2(row.sql_data_access) === void 0 ? {} : { sqlDataAccess: text$2(row.sql_data_access) },
|
|
1440
|
+
...text$2(row.sql_mode) === void 0 ? {} : { sqlMode: text$2(row.sql_mode) }
|
|
1441
|
+
})
|
|
1442
|
+
};
|
|
1443
|
+
const commentText = text$2(row.routine_comment);
|
|
1444
|
+
if (commentText === void 0 || commentText === "") return routine;
|
|
1445
|
+
return {
|
|
1446
|
+
...routine,
|
|
1447
|
+
comment: objectComment({
|
|
1448
|
+
kind: "routine",
|
|
1449
|
+
id: routine.id
|
|
1450
|
+
}, commentText, physicalReference, namespace)
|
|
1451
|
+
};
|
|
1452
|
+
}
|
|
1453
|
+
function routineParameter(row) {
|
|
1454
|
+
const parameterName = text$2(row.parameter_name);
|
|
1455
|
+
return {
|
|
1456
|
+
...parameterName === void 0 ? {} : { name: parameterName },
|
|
1457
|
+
...routineParameterMode$1(row.parameter_mode) === void 0 ? {} : { mode: routineParameterMode$1(row.parameter_mode) },
|
|
1458
|
+
storage: storage$1(row.data_type, row.dtd_identifier),
|
|
1459
|
+
ordinalPosition: number$2(row.ordinal_position) ?? 0
|
|
1460
|
+
};
|
|
1461
|
+
}
|
|
1462
|
+
function triggerObject$1(rows, relations, namespace, diagnostics) {
|
|
1463
|
+
const first = rows[0];
|
|
1464
|
+
const physicalName = text$2(first.trigger_name) ?? "unnamed_trigger";
|
|
1465
|
+
const physicalReference = reference$2("trigger", physicalName, namespace, "INFORMATION_SCHEMA.TRIGGERS", "TRIGGER_NAME");
|
|
1466
|
+
const tableName = text$2(first.table_name);
|
|
1467
|
+
const target = tableName === void 0 ? void 0 : relations.get(tableName);
|
|
1468
|
+
const body = text$2(first.action_statement);
|
|
1469
|
+
if (target === void 0 || body === void 0 || body.trim() === "") {
|
|
1470
|
+
if (target === void 0) diagnostics.push(createIntrospectionDiagnostic({
|
|
1471
|
+
severity: "error",
|
|
1472
|
+
code: "unresolved-reference",
|
|
1473
|
+
message: `MySQL trigger ${physicalName} target ${tableName ?? "unknown"} was not found`,
|
|
1474
|
+
path: [
|
|
1475
|
+
"triggers",
|
|
1476
|
+
physicalName,
|
|
1477
|
+
"table"
|
|
1478
|
+
],
|
|
1479
|
+
physicalReference
|
|
1480
|
+
}));
|
|
1481
|
+
if (body === void 0 || body.trim() === "") diagnostics.push(createIntrospectionDiagnostic({
|
|
1482
|
+
severity: "error",
|
|
1483
|
+
code: "expression-parse-failed",
|
|
1484
|
+
message: `MySQL trigger ${physicalName} has no recoverable body`,
|
|
1485
|
+
path: [
|
|
1486
|
+
"triggers",
|
|
1487
|
+
physicalName,
|
|
1488
|
+
"body"
|
|
1489
|
+
],
|
|
1490
|
+
physicalReference
|
|
1491
|
+
}));
|
|
1492
|
+
return {
|
|
1493
|
+
kind: "deferred-object",
|
|
1494
|
+
id: stableId$2(`trigger:${physicalName}`),
|
|
1495
|
+
identitySource: "physical-name",
|
|
1496
|
+
objectKind: "trigger",
|
|
1497
|
+
physicalName,
|
|
1498
|
+
reference: physicalReference,
|
|
1499
|
+
dialect: mysqlExtension({
|
|
1500
|
+
...tableName === void 0 ? {} : { tableName },
|
|
1501
|
+
...body === void 0 ? {} : { actionStatement: body }
|
|
1502
|
+
})
|
|
1503
|
+
};
|
|
1504
|
+
}
|
|
1505
|
+
const timing = triggerTiming$1(first.action_timing);
|
|
1506
|
+
const events = [...new Set(rows.map((row) => triggerEvent(row.event_manipulation)).filter((value) => value !== void 0))];
|
|
1507
|
+
return {
|
|
1508
|
+
kind: "trigger",
|
|
1509
|
+
id: stableId$2(physicalName),
|
|
1510
|
+
identitySource: "physical-name",
|
|
1511
|
+
physicalName,
|
|
1512
|
+
table: target,
|
|
1513
|
+
timing,
|
|
1514
|
+
events,
|
|
1515
|
+
orientation: triggerOrientation(first.action_orientation),
|
|
1516
|
+
...text$2(first.action_condition) === void 0 ? {} : { condition: sql$2(text$2(first.action_condition), namespace, {
|
|
1517
|
+
kind: "trigger",
|
|
1518
|
+
physicalName,
|
|
1519
|
+
reference: physicalReference
|
|
1520
|
+
}, physicalName) },
|
|
1521
|
+
body: sql$2(body, namespace, {
|
|
1522
|
+
kind: "trigger",
|
|
1523
|
+
physicalName,
|
|
1524
|
+
reference: physicalReference
|
|
1525
|
+
}, physicalName),
|
|
1526
|
+
reference: physicalReference,
|
|
1527
|
+
provenance: {
|
|
1528
|
+
kind: "catalog",
|
|
1529
|
+
dialect: "mysql",
|
|
1530
|
+
reference: physicalReference
|
|
1531
|
+
},
|
|
1532
|
+
dialect: mysqlExtension({
|
|
1533
|
+
...text$2(first.definer) === void 0 ? {} : { definer: text$2(first.definer) },
|
|
1534
|
+
...text$2(first.sql_mode) === void 0 ? {} : { sqlMode: text$2(first.sql_mode) },
|
|
1535
|
+
...number$2(first.action_order) === void 0 ? {} : { actionOrder: number$2(first.action_order) }
|
|
1536
|
+
})
|
|
1537
|
+
};
|
|
1538
|
+
}
|
|
1539
|
+
function partitionObject$1(row, tables, namespace, diagnostics) {
|
|
1540
|
+
const tableName = text$2(row.table_name) ?? "unknown";
|
|
1541
|
+
const partitionName = text$2(row.partition_name);
|
|
1542
|
+
const subpartitionName = text$2(row.subpartition_name);
|
|
1543
|
+
const physicalName = partitionName === void 0 ? tableName : subpartitionName === void 0 ? partitionName : `${partitionName}/${subpartitionName}`;
|
|
1544
|
+
const physicalReference = reference$2("partition", physicalName, namespace, "INFORMATION_SCHEMA.PARTITIONS", "PARTITION_NAME");
|
|
1545
|
+
const parent = tables.get(tableName);
|
|
1546
|
+
if (parent === void 0) {
|
|
1547
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
1548
|
+
severity: "error",
|
|
1549
|
+
code: "unresolved-reference",
|
|
1550
|
+
message: `MySQL partition ${physicalName} parent table ${tableName} was not found`,
|
|
1551
|
+
path: [
|
|
1552
|
+
"partitions",
|
|
1553
|
+
physicalName,
|
|
1554
|
+
"parent"
|
|
1555
|
+
],
|
|
1556
|
+
physicalReference
|
|
1557
|
+
}));
|
|
1558
|
+
return {
|
|
1559
|
+
kind: "deferred-object",
|
|
1560
|
+
id: stableId$2(`partition:${tableName}:${physicalName}`),
|
|
1561
|
+
identitySource: "physical-name",
|
|
1562
|
+
objectKind: "partition",
|
|
1563
|
+
physicalName,
|
|
1564
|
+
reference: physicalReference,
|
|
1565
|
+
dialect: mysqlExtension({ tableName })
|
|
1566
|
+
};
|
|
1567
|
+
}
|
|
1568
|
+
const method = text$2(row.subpartition_method) ?? text$2(row.partition_method) ?? "UNKNOWN";
|
|
1569
|
+
const strategy = partitionStrategy$1(method);
|
|
1570
|
+
if (strategy === "unknown") diagnostics.push(createIntrospectionDiagnostic({
|
|
1571
|
+
severity: "warning",
|
|
1572
|
+
code: "unsupported-feature",
|
|
1573
|
+
message: `MySQL partition method ${method} is retained with an unknown normalized strategy`,
|
|
1574
|
+
path: [
|
|
1575
|
+
"partitions",
|
|
1576
|
+
physicalName,
|
|
1577
|
+
"strategy"
|
|
1578
|
+
],
|
|
1579
|
+
physicalReference
|
|
1580
|
+
}));
|
|
1581
|
+
const boundText = text$2(row.partition_description) ?? text$2(row.subpartition_expression) ?? text$2(row.partition_expression);
|
|
1582
|
+
const expression = text$2(row.partition_expression);
|
|
1583
|
+
const partition = {
|
|
1584
|
+
kind: "partition",
|
|
1585
|
+
id: stableId$2(`partition:${tableName}:${physicalName}`),
|
|
1586
|
+
identitySource: "physical-name",
|
|
1587
|
+
physicalName,
|
|
1588
|
+
parent: {
|
|
1589
|
+
kind: "table",
|
|
1590
|
+
id: parent.id
|
|
1591
|
+
},
|
|
1592
|
+
strategy,
|
|
1593
|
+
...expression === void 0 ? {} : { keyColumns: partitionKeyColumns$1(expression) },
|
|
1594
|
+
...boundText === void 0 ? {} : { bound: sql$2(boundText, namespace, parent, physicalName) },
|
|
1595
|
+
reference: physicalReference,
|
|
1596
|
+
dialect: mysqlExtension({
|
|
1597
|
+
...text$2(row.partition_method) === void 0 ? {} : { partitionMethod: text$2(row.partition_method) },
|
|
1598
|
+
...text$2(row.subpartition_method) === void 0 ? {} : { subpartitionMethod: text$2(row.subpartition_method) },
|
|
1599
|
+
...text$2(row.subpartition_name) === void 0 ? {} : { subpartitionName: text$2(row.subpartition_name) },
|
|
1600
|
+
...text$2(row.tablespace_name) === void 0 ? {} : { tablespace: text$2(row.tablespace_name) }
|
|
1601
|
+
})
|
|
1602
|
+
};
|
|
1603
|
+
const commentText = text$2(row.partition_comment);
|
|
1604
|
+
if (commentText === void 0 || commentText === "") return partition;
|
|
1605
|
+
return {
|
|
1606
|
+
...partition,
|
|
1607
|
+
comment: objectComment({
|
|
1608
|
+
kind: "partition",
|
|
1609
|
+
id: partition.id
|
|
1610
|
+
}, commentText, physicalReference, namespace)
|
|
1611
|
+
};
|
|
1612
|
+
}
|
|
1613
|
+
function collationObject$1(row, namespace) {
|
|
1614
|
+
const physicalName = text$2(row.collation_name) ?? "unknown_collation";
|
|
1615
|
+
return {
|
|
1616
|
+
kind: "collation",
|
|
1617
|
+
id: stableId$2(physicalName),
|
|
1618
|
+
identitySource: "physical-name",
|
|
1619
|
+
physicalName,
|
|
1620
|
+
reference: reference$2("collation", physicalName, namespace, "INFORMATION_SCHEMA.COLLATIONS", "COLLATION_NAME"),
|
|
1621
|
+
dialect: mysqlExtension({
|
|
1622
|
+
...text$2(row.character_set_name) === void 0 ? {} : { characterSet: text$2(row.character_set_name) },
|
|
1623
|
+
...number$2(row.collation_id) === void 0 ? {} : { id: number$2(row.collation_id) },
|
|
1624
|
+
...text$2(row.is_default) === void 0 ? {} : { isDefault: text$2(row.is_default) === "Yes" },
|
|
1625
|
+
...text$2(row.is_compiled) === void 0 ? {} : { isCompiled: text$2(row.is_compiled) === "Yes" },
|
|
1626
|
+
...number$2(row.sort_length) === void 0 ? {} : { sortLength: number$2(row.sort_length) },
|
|
1627
|
+
...text$2(row.pad_attribute) === void 0 ? {} : { padAttribute: text$2(row.pad_attribute) }
|
|
1628
|
+
})
|
|
1629
|
+
};
|
|
1630
|
+
}
|
|
1631
|
+
function opaqueEvent(row, namespace) {
|
|
1632
|
+
const physicalName = text$2(row.event_name) ?? "unnamed_event";
|
|
1633
|
+
const physicalReference = reference$2("opaque-object", physicalName, namespace, "INFORMATION_SCHEMA.EVENTS", "EVENT_NAME");
|
|
1634
|
+
const definition = text$2(row.event_definition) ?? text$2(row.event_body);
|
|
1635
|
+
return {
|
|
1636
|
+
kind: "opaque-object",
|
|
1637
|
+
id: stableId$2(`event:${physicalName}`),
|
|
1638
|
+
identitySource: "physical-name",
|
|
1639
|
+
objectKind: "event",
|
|
1640
|
+
physicalName,
|
|
1641
|
+
data: {
|
|
1642
|
+
...text$2(row.event_type) === void 0 ? {} : { eventType: text$2(row.event_type) },
|
|
1643
|
+
...text$2(row.status) === void 0 ? {} : { status: text$2(row.status) },
|
|
1644
|
+
...text$2(row.execute_at) === void 0 ? {} : { executeAt: text$2(row.execute_at) },
|
|
1645
|
+
...text$2(row.interval_value) === void 0 ? {} : { intervalValue: text$2(row.interval_value) },
|
|
1646
|
+
...text$2(row.interval_field) === void 0 ? {} : { intervalField: text$2(row.interval_field) },
|
|
1647
|
+
...text$2(row.definer) === void 0 ? {} : { definer: text$2(row.definer) }
|
|
1648
|
+
},
|
|
1649
|
+
...definition === void 0 ? {} : { sql: sql$2(definition, namespace, {
|
|
1650
|
+
kind: "opaque-object",
|
|
1651
|
+
physicalName,
|
|
1652
|
+
reference: physicalReference
|
|
1653
|
+
}, physicalName) },
|
|
1654
|
+
reference: physicalReference,
|
|
1655
|
+
provenance: {
|
|
1656
|
+
kind: "catalog",
|
|
1657
|
+
dialect: "mysql",
|
|
1658
|
+
reference: physicalReference
|
|
1659
|
+
},
|
|
1660
|
+
dialect: mysqlExtension({ objectKind: "event" })
|
|
1661
|
+
};
|
|
1662
|
+
}
|
|
1663
|
+
function objectComment(object, comment, physicalReference, namespace) {
|
|
1664
|
+
return {
|
|
1665
|
+
kind: "comment",
|
|
1666
|
+
id: stableId$2(`${object.kind}_${object.id}_comment`),
|
|
1667
|
+
object,
|
|
1668
|
+
text: comment,
|
|
1669
|
+
reference: physicalReference,
|
|
1670
|
+
provenance: {
|
|
1671
|
+
kind: "catalog",
|
|
1672
|
+
dialect: "mysql",
|
|
1673
|
+
reference: physicalReference,
|
|
1674
|
+
path: ["namespace", namespace]
|
|
1675
|
+
}
|
|
1676
|
+
};
|
|
1677
|
+
}
|
|
1678
|
+
function groupRows(rows, keyOf) {
|
|
1679
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1680
|
+
for (const row of rows) {
|
|
1681
|
+
const key = keyOf(row);
|
|
1682
|
+
const group = groups.get(key) ?? [];
|
|
1683
|
+
group.push(row);
|
|
1684
|
+
groups.set(key, group);
|
|
1685
|
+
}
|
|
1686
|
+
return [...groups.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([, group]) => group);
|
|
1687
|
+
}
|
|
1688
|
+
function mysqlExtension(data) {
|
|
1689
|
+
return {
|
|
1690
|
+
dialect: "mysql",
|
|
1691
|
+
version: 1,
|
|
1692
|
+
data
|
|
1693
|
+
};
|
|
1694
|
+
}
|
|
1695
|
+
function storage$1(dataType, declaration) {
|
|
1696
|
+
return { nativeType: text$2(declaration) ?? text$2(dataType) ?? "unknown" };
|
|
1697
|
+
}
|
|
1698
|
+
function normalizeCheckOption(value) {
|
|
1699
|
+
const normalized = text$2(value)?.toLowerCase();
|
|
1700
|
+
return normalized === "none" || normalized === void 0 ? normalized === void 0 ? void 0 : "none" : normalized === "local" ? "local" : normalized === "cascaded" ? "cascaded" : void 0;
|
|
1701
|
+
}
|
|
1702
|
+
function routineSecurity(value) {
|
|
1703
|
+
return text$2(value)?.toLowerCase() === "invoker" ? "invoker" : text$2(value)?.toLowerCase() === "definer" ? "definer" : "unknown";
|
|
1704
|
+
}
|
|
1705
|
+
function routineParameterMode$1(value) {
|
|
1706
|
+
const normalized = text$2(value)?.toLowerCase();
|
|
1707
|
+
return normalized === "in" ? "in" : normalized === "out" ? "out" : normalized === "inout" ? "inout" : void 0;
|
|
1708
|
+
}
|
|
1709
|
+
function triggerTiming$1(value) {
|
|
1710
|
+
const normalized = text$2(value)?.toLowerCase();
|
|
1711
|
+
return normalized === "before" ? "before" : normalized === "after" ? "after" : "unknown";
|
|
1712
|
+
}
|
|
1713
|
+
function triggerEvent(value) {
|
|
1714
|
+
const normalized = text$2(value)?.toLowerCase();
|
|
1715
|
+
return normalized === "insert" || normalized === "update" || normalized === "delete" ? normalized : void 0;
|
|
1716
|
+
}
|
|
1717
|
+
function triggerOrientation(value) {
|
|
1718
|
+
const normalized = text$2(value)?.toLowerCase();
|
|
1719
|
+
return normalized === "row" ? "row" : normalized === "statement" ? "statement" : void 0;
|
|
1720
|
+
}
|
|
1721
|
+
function partitionStrategy$1(value) {
|
|
1722
|
+
const normalized = value.toLowerCase();
|
|
1723
|
+
return normalized === "range" ? "range" : normalized === "list" ? "list" : normalized === "hash" ? "hash" : "unknown";
|
|
1724
|
+
}
|
|
1725
|
+
function partitionKeyColumns$1(expression) {
|
|
1726
|
+
return expression.split(",").map((value) => value.trim()).filter((value) => /^[A-Za-z_][A-Za-z0-9_$]*$/.test(value));
|
|
1727
|
+
}
|
|
1728
|
+
function sql$2(textValue, namespace, table, name) {
|
|
1729
|
+
return {
|
|
1730
|
+
kind: "sql",
|
|
1731
|
+
dialect: "mysql",
|
|
1732
|
+
text: textValue,
|
|
1733
|
+
provenance: {
|
|
1734
|
+
kind: "catalog",
|
|
1735
|
+
dialect: "mysql",
|
|
1736
|
+
reference: table.reference ?? reference$2(table.kind, name, namespace, "INFORMATION_SCHEMA", "TABLE_NAME", table.physicalName)
|
|
1737
|
+
}
|
|
1738
|
+
};
|
|
1739
|
+
}
|
|
1740
|
+
function reference$2(kind, name, namespace, relation, key, value = name) {
|
|
1741
|
+
return {
|
|
1742
|
+
kind,
|
|
1743
|
+
name,
|
|
1744
|
+
namespace,
|
|
1745
|
+
catalog: {
|
|
1746
|
+
relation,
|
|
1747
|
+
key,
|
|
1748
|
+
value
|
|
1749
|
+
}
|
|
1750
|
+
};
|
|
1751
|
+
}
|
|
1752
|
+
function literal(value, dataType) {
|
|
1753
|
+
if (value === void 0) return void 0;
|
|
1754
|
+
if (value.toUpperCase() === "NULL") return null;
|
|
1755
|
+
if (value.toUpperCase() === "TRUE") return true;
|
|
1756
|
+
if (value.toUpperCase() === "FALSE") return false;
|
|
1757
|
+
if (/^-?(?:\d+\.?\d*|\.\d+)$/.test(value)) return Number(value);
|
|
1758
|
+
if (/^'(?:''|[^'])*'$/.test(value)) return value.slice(1, -1).replace(/''/g, "'");
|
|
1759
|
+
if (value === "" || /^(?:char|varchar|text|tinytext|mediumtext|longtext|enum|set)$/i.test(dataType ?? "")) return value;
|
|
1760
|
+
}
|
|
1761
|
+
function emptyCatalog$2(namespace, diagnostics) {
|
|
1762
|
+
return {
|
|
1763
|
+
dialect: "mysql",
|
|
1764
|
+
server: {
|
|
1765
|
+
product: "mysql",
|
|
1766
|
+
rawVersion: "unknown",
|
|
1767
|
+
capabilities: {
|
|
1768
|
+
generatedColumns: false,
|
|
1769
|
+
identityMetadata: false,
|
|
1770
|
+
checkConstraints: false,
|
|
1771
|
+
checkConstraintEnforcement: "unknown",
|
|
1772
|
+
expressionDecompilation: false,
|
|
1773
|
+
indexExpressions: false,
|
|
1774
|
+
indexPredicates: false,
|
|
1775
|
+
indexIncludedColumns: false,
|
|
1776
|
+
namespaces: true,
|
|
1777
|
+
visibility: "unknown"
|
|
1778
|
+
}
|
|
1779
|
+
},
|
|
1780
|
+
namespace: {
|
|
1781
|
+
kind: "mysql-database",
|
|
1782
|
+
name: namespace
|
|
1783
|
+
},
|
|
1784
|
+
tables: [],
|
|
1785
|
+
deferredObjects: [],
|
|
1786
|
+
diagnostics
|
|
1787
|
+
};
|
|
1788
|
+
}
|
|
1789
|
+
function stableId$2(value) {
|
|
1790
|
+
if (value && !/[.\\\u0000-\u001f\u007f]/.test(value)) return value;
|
|
1791
|
+
let hash = 2166136261;
|
|
1792
|
+
for (const character of value) {
|
|
1793
|
+
hash ^= character.charCodeAt(0);
|
|
1794
|
+
hash = Math.imul(hash, 16777619);
|
|
1795
|
+
}
|
|
1796
|
+
return `introspected_${(hash >>> 0).toString(16)}`;
|
|
1797
|
+
}
|
|
1798
|
+
function text$2(value) {
|
|
1799
|
+
return value === null || value === void 0 ? void 0 : String(value);
|
|
1800
|
+
}
|
|
1801
|
+
function number$2(value) {
|
|
1802
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
1803
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
1804
|
+
const result = Number(value);
|
|
1805
|
+
return Number.isFinite(result) ? result : void 0;
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
function action$1(value) {
|
|
1809
|
+
const normalized = text$2(value)?.toLowerCase();
|
|
1810
|
+
return normalized === "cascade" ? "cascade" : normalized === "restrict" ? "restrict" : normalized === "set null" ? "set-null" : normalized === "set default" ? "set-default" : "no-action";
|
|
1811
|
+
}
|
|
1812
|
+
function match$1(value) {
|
|
1813
|
+
return text$2(value)?.toLowerCase() === "full" ? "full" : "simple";
|
|
1814
|
+
}
|
|
1815
|
+
//#endregion
|
|
1816
|
+
//#region src/introspection/postgres.ts
|
|
1817
|
+
/** Fixed server metadata query used by the PostgreSQL catalog reader. */
|
|
1818
|
+
const postgresServerQuery = `
|
|
1819
|
+
SELECT
|
|
1820
|
+
current_setting('server_version_num') AS server_version_num,
|
|
1821
|
+
current_setting('server_version') AS server_version
|
|
1822
|
+
`;
|
|
1823
|
+
/** Read one PostgreSQL schema into the normalized catalog contract. */
|
|
1824
|
+
async function readPostgresCatalog(connection, options) {
|
|
1825
|
+
const diagnostics = [];
|
|
1826
|
+
if (connection.dialect !== "postgresql") {
|
|
1827
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
1828
|
+
severity: "error",
|
|
1829
|
+
code: "dialect-mismatch",
|
|
1830
|
+
message: `PostgreSQL catalog reader received a ${connection.dialect} connection`,
|
|
1831
|
+
path: ["connection", "dialect"],
|
|
1832
|
+
remediation: "Use a PostgreSQL CatalogConnection with this reader."
|
|
1833
|
+
}));
|
|
1834
|
+
return emptyCatalog$1(options.namespace, diagnostics);
|
|
1835
|
+
}
|
|
1836
|
+
const server = serverInfo$1((await query$1(connection, postgresServerQuery, [], options, diagnostics, "server"))[0], diagnostics);
|
|
1837
|
+
const relationObjects = (await query$1(connection, postgresRelationsQuery, [options.namespace], options, diagnostics, "relations")).filter((row) => {
|
|
1838
|
+
const kind = text$1(row.relkind);
|
|
1839
|
+
return kind !== "i" && kind !== "I";
|
|
1840
|
+
});
|
|
1841
|
+
const tables = relationObjects.filter((row) => row.relkind === "r" || row.relkind === "p").map((row) => relationTable(row));
|
|
1842
|
+
const tableByOid = new Map(tables.map((table) => [table.reference?.catalog?.value, table]));
|
|
1843
|
+
const viewRows = await query$1(connection, postgresViewsQuery, [options.namespace], options, diagnostics, "views");
|
|
1844
|
+
const views = [];
|
|
1845
|
+
for (const row of viewRows) {
|
|
1846
|
+
const view = viewObject(row, options.namespace, diagnostics);
|
|
1847
|
+
if (view.kind === "deferred-object") continue;
|
|
1848
|
+
views.push(view);
|
|
1849
|
+
}
|
|
1850
|
+
const relationReferences = /* @__PURE__ */ new Map();
|
|
1851
|
+
for (const table of tables) relationReferences.set(table.reference?.catalog?.value, {
|
|
1852
|
+
kind: "table",
|
|
1853
|
+
id: table.id
|
|
1854
|
+
});
|
|
1855
|
+
for (const view of views) relationReferences.set(view.reference?.catalog?.value, {
|
|
1856
|
+
kind: view.kind,
|
|
1857
|
+
id: view.id
|
|
1858
|
+
});
|
|
1859
|
+
const columnRows = await query$1(connection, postgresColumnsQuery, [options.namespace], options, diagnostics, "columns");
|
|
1860
|
+
const identityRows = await query$1(connection, postgresIdentitiesQuery, [options.namespace], options, diagnostics, "identities");
|
|
1861
|
+
const identityOptionsByColumn = /* @__PURE__ */ new Map();
|
|
1862
|
+
for (const row of identityRows) identityOptionsByColumn.set(columnKey(row.table_oid, row.ordinal_position), identityOptions(row));
|
|
1863
|
+
const columnsByTable = groupBy(columnRows, (row) => row.table_oid);
|
|
1864
|
+
for (const table of tables) table.columns = (columnsByTable.get(table.reference?.catalog?.value) ?? []).sort(compareOrdinal).map((row) => column$1(row, table, options.namespace, identityOptionsByColumn.get(columnKey(row.table_oid, row.ordinal_position))));
|
|
1865
|
+
for (const view of views) view.columns = (columnsByTable.get(view.reference?.catalog?.value) ?? []).sort(compareOrdinal).map((row) => column$1(row, view, options.namespace));
|
|
1866
|
+
const indexRows = await query$1(connection, postgresIndexesQuery, [options.namespace], options, diagnostics, "indexes");
|
|
1867
|
+
const indexReferences = /* @__PURE__ */ new Map();
|
|
1868
|
+
for (const row of indexRows) {
|
|
1869
|
+
const indexOid = text$1(row.index_oid);
|
|
1870
|
+
const physicalName = text$1(row.physical_name);
|
|
1871
|
+
if (indexOid && physicalName) indexReferences.set(`pg_class:${indexOid}`, {
|
|
1872
|
+
kind: "index",
|
|
1873
|
+
id: stableId$1(physicalName),
|
|
1874
|
+
physicalName,
|
|
1875
|
+
reference: reference$1("index", physicalName, options.namespace, "pg_class", "oid", row.index_oid)
|
|
1876
|
+
});
|
|
1877
|
+
}
|
|
1878
|
+
const constraintsByTable = groupBy(await query$1(connection, postgresConstraintsQuery, [options.namespace], options, diagnostics, "constraints"), (row) => row.table_oid);
|
|
1879
|
+
for (const table of tables) {
|
|
1880
|
+
const rows = constraintsByTable.get(table.reference?.catalog?.value) ?? [];
|
|
1881
|
+
const columnsByNumber = new Map(table.columns.map((column) => [column.ordinalPosition, column.physicalName]));
|
|
1882
|
+
table.constraints = rows.map((row) => constraint(row, table, columnsByNumber, tableByOid, options.namespace, diagnostics, indexReferences)).filter((value) => value !== void 0);
|
|
1883
|
+
}
|
|
1884
|
+
const indexesByTable = groupBy(indexRows, (row) => row.table_oid);
|
|
1885
|
+
for (const table of tables) table.indexes = mapIndexes(indexesByTable.get(table.reference?.catalog?.value) ?? [], table, new Map(table.columns.map((column) => [column.ordinalPosition, column.physicalName])), options.namespace);
|
|
1886
|
+
const sequences = (await query$1(connection, postgresSequencesQuery, [options.namespace], options, diagnostics, "sequences")).map((row) => sequenceObject(row, options.namespace, tableByOid, diagnostics));
|
|
1887
|
+
const enums = mapEnums(await query$1(connection, postgresEnumsQuery, [options.namespace], options, diagnostics, "enums"), options.namespace);
|
|
1888
|
+
const domains = mapDomains(await query$1(connection, postgresDomainsQuery, [options.namespace], options, diagnostics, "domains"), await query$1(connection, postgresDomainConstraintsQuery, [options.namespace], options, diagnostics, "domain-constraints"), options.namespace);
|
|
1889
|
+
const collations = (await query$1(connection, postgresCollationsQuery, [options.namespace], options, diagnostics, "collations")).map((row) => collationObject(row, options.namespace));
|
|
1890
|
+
const triggerRows = await query$1(connection, postgresTriggersQuery, [options.namespace], options, diagnostics, "triggers");
|
|
1891
|
+
const triggers = [];
|
|
1892
|
+
const triggerDeferredObjects = [];
|
|
1893
|
+
for (const row of triggerRows) {
|
|
1894
|
+
const value = triggerObject(row, options.namespace, relationReferences, diagnostics);
|
|
1895
|
+
if (value.kind === "deferred-object") triggerDeferredObjects.push(value);
|
|
1896
|
+
else triggers.push(value);
|
|
1897
|
+
}
|
|
1898
|
+
const routines = mapRoutines(await query$1(connection, postgresRoutinesQuery, [options.namespace], options, diagnostics, "routines"), await query$1(connection, postgresRoutineParametersQuery, [options.namespace], options, diagnostics, "routine-parameters"), options.namespace, diagnostics);
|
|
1899
|
+
const partitions = (await query$1(connection, postgresPartitionsQuery, [options.namespace], options, diagnostics, "partitions")).map((row) => partitionObject(row, options.namespace, tableByOid, diagnostics)).filter((value) => value !== void 0);
|
|
1900
|
+
const policies = (await query$1(connection, postgresPoliciesQuery, [options.namespace], options, diagnostics, "policies")).map((row) => policyObject(row, options.namespace, tableByOid, diagnostics)).filter((value) => value !== void 0);
|
|
1901
|
+
const extensionObjects = (await query$1(connection, postgresExtensionsQuery, [options.namespace], options, diagnostics, "extensions")).map((row) => extensionObject(row, options.namespace));
|
|
1902
|
+
const typedRelationOids = new Set([...views, ...sequences].map((object) => object.reference?.catalog?.value));
|
|
1903
|
+
const deferredObjects = relationObjects.filter((row) => {
|
|
1904
|
+
const relkind = text$1(row.relkind);
|
|
1905
|
+
return relkind === "f" || (relkind === "v" || relkind === "m" || relkind === "S") && !typedRelationOids.has(row.oid === void 0 ? void 0 : text$1(row.oid));
|
|
1906
|
+
}).map((row) => deferredObject(row, text$1(row.relkind) === "f" ? "foreign-table" : text$1(row.relkind) === "v" ? "view" : text$1(row.relkind) === "m" ? "materialized-view" : "sequence"));
|
|
1907
|
+
deferredObjects.push(...triggerDeferredObjects);
|
|
1908
|
+
const opaqueObjects = relationObjects.filter((row) => {
|
|
1909
|
+
const kind = text$1(row.relkind);
|
|
1910
|
+
return kind !== "r" && kind !== "p" && kind !== "v" && kind !== "m" && kind !== "S" && kind !== "f";
|
|
1911
|
+
}).map((row) => opaqueRelationObject(row, options.namespace, diagnostics));
|
|
1912
|
+
const metadata = mapMetadataRows(await query$1(connection, postgresMetadataQuery, [options.namespace], options, diagnostics, "comments-and-ownership"), options.namespace, tables, views, sequences, enums, domains, collations, routines, triggers, policies, extensionObjects, deferredObjects, opaqueObjects, indexReferences, relationReferences, diagnostics);
|
|
1913
|
+
opaqueObjects.push(...metadata.opaqueObjects);
|
|
1914
|
+
return Object.freeze({
|
|
1915
|
+
dialect: "postgresql",
|
|
1916
|
+
server,
|
|
1917
|
+
namespace: {
|
|
1918
|
+
kind: "postgres-schema",
|
|
1919
|
+
name: options.namespace,
|
|
1920
|
+
reference: reference$1("namespace", options.namespace, options.namespace, "pg_namespace", "nspname")
|
|
1921
|
+
},
|
|
1922
|
+
tables: Object.freeze(tables),
|
|
1923
|
+
views: Object.freeze(views),
|
|
1924
|
+
sequences: Object.freeze(sequences),
|
|
1925
|
+
enums: Object.freeze(enums),
|
|
1926
|
+
domains: Object.freeze(domains),
|
|
1927
|
+
collations: Object.freeze(collations),
|
|
1928
|
+
triggers: Object.freeze(triggers),
|
|
1929
|
+
routines: Object.freeze(routines),
|
|
1930
|
+
partitions: Object.freeze(partitions),
|
|
1931
|
+
policies: Object.freeze(policies),
|
|
1932
|
+
extensionObjects: Object.freeze(extensionObjects),
|
|
1933
|
+
deferredObjects: Object.freeze(deferredObjects),
|
|
1934
|
+
opaqueObjects: Object.freeze(opaqueObjects),
|
|
1935
|
+
comments: Object.freeze(metadata.comments),
|
|
1936
|
+
ownership: Object.freeze(metadata.ownership),
|
|
1937
|
+
capabilities: server.capabilities,
|
|
1938
|
+
diagnostics: Object.freeze(diagnostics)
|
|
1939
|
+
});
|
|
1940
|
+
}
|
|
1941
|
+
const postgresRelationsQuery = `
|
|
1942
|
+
SELECT c.oid::text AS oid, n.nspname AS namespace, c.relname,
|
|
1943
|
+
c.relkind, c.relispartition
|
|
1944
|
+
FROM pg_class c
|
|
1945
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
1946
|
+
WHERE n.nspname = $1
|
|
1947
|
+
AND c.relkind NOT IN ('i', 'I')
|
|
1948
|
+
ORDER BY c.relname
|
|
1949
|
+
`;
|
|
1950
|
+
/** Fixed view and materialized-view definitions from PostgreSQL's decompiler. */
|
|
1951
|
+
const postgresViewsQuery = `
|
|
1952
|
+
SELECT c.oid::text AS oid, n.nspname AS namespace, c.relname AS physical_name,
|
|
1953
|
+
c.relkind, pg_get_viewdef(c.oid, true) AS definition,
|
|
1954
|
+
v.check_option, c.reloptions
|
|
1955
|
+
FROM pg_catalog.pg_class c
|
|
1956
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
1957
|
+
LEFT JOIN information_schema.views v
|
|
1958
|
+
ON v.table_schema = n.nspname AND v.table_name = c.relname
|
|
1959
|
+
WHERE n.nspname = $1 AND c.relkind IN ('v', 'm')
|
|
1960
|
+
ORDER BY c.oid
|
|
1961
|
+
`;
|
|
1962
|
+
const postgresColumnsQuery = `
|
|
1963
|
+
SELECT a.attrelid::text AS table_oid, a.attnum::int AS ordinal_position,
|
|
1964
|
+
a.attname AS physical_name, NOT a.attnotnull AS nullable,
|
|
1965
|
+
format_type(a.atttypid, a.atttypmod) AS native_type,
|
|
1966
|
+
a.attidentity, a.attgenerated,
|
|
1967
|
+
pg_get_expr(ad.adbin, ad.adrelid) AS default_expression
|
|
1968
|
+
FROM pg_attribute a
|
|
1969
|
+
JOIN pg_class c ON c.oid = a.attrelid
|
|
1970
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
1971
|
+
LEFT JOIN pg_attrdef ad ON ad.adrelid = a.attrelid AND ad.adnum = a.attnum
|
|
1972
|
+
WHERE n.nspname = $1
|
|
1973
|
+
AND c.relkind IN ('r', 'p', 'v', 'm')
|
|
1974
|
+
AND a.attnum > 0
|
|
1975
|
+
AND NOT a.attisdropped
|
|
1976
|
+
ORDER BY a.attrelid, a.attnum
|
|
1977
|
+
`;
|
|
1978
|
+
const postgresConstraintsQuery = `
|
|
1979
|
+
SELECT con.oid::text AS oid, con.conrelid::text AS table_oid,
|
|
1980
|
+
con.conname AS physical_name, con.contype,
|
|
1981
|
+
con.conkey, con.confrelid::text AS target_table_oid, con.confkey,
|
|
1982
|
+
con.confupdtype, con.confdeltype, con.confmatchtype,
|
|
1983
|
+
con.condeferrable, con.condeferred, con.convalidated,
|
|
1984
|
+
con.conindid::text AS backing_index_oid,
|
|
1985
|
+
i.indnullsnotdistinct,
|
|
1986
|
+
pg_get_constraintdef(con.oid, true) AS definition
|
|
1987
|
+
FROM pg_constraint con
|
|
1988
|
+
JOIN pg_class c ON c.oid = con.conrelid
|
|
1989
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
1990
|
+
LEFT JOIN pg_index i ON i.indexrelid = con.conindid
|
|
1991
|
+
WHERE n.nspname = $1
|
|
1992
|
+
AND con.contype IN ('p', 'u', 'f', 'c', 'x')
|
|
1993
|
+
ORDER BY con.conrelid, con.oid
|
|
1994
|
+
`;
|
|
1995
|
+
const postgresIndexesQuery = `
|
|
1996
|
+
SELECT i.indexrelid::text AS index_oid, i.indrelid::text AS table_oid,
|
|
1997
|
+
c.relname AS physical_name, i.indisunique, i.indnkeyatts::int,
|
|
1998
|
+
i.indnatts::int, am.amname AS method,
|
|
1999
|
+
pg_get_expr(i.indpred, i.indrelid, true) AS predicate,
|
|
2000
|
+
s.position::int,
|
|
2001
|
+
(i.indkey[s.position])::int AS attnum,
|
|
2002
|
+
(i.indoption[s.position])::int AS indoption,
|
|
2003
|
+
opc.opcname AS operator_class,
|
|
2004
|
+
pg_get_indexdef(i.indexrelid, s.position, true) AS term_definition
|
|
2005
|
+
FROM pg_index i
|
|
2006
|
+
JOIN pg_class c ON c.oid = i.indexrelid
|
|
2007
|
+
JOIN pg_class t ON t.oid = i.indrelid
|
|
2008
|
+
JOIN pg_namespace n ON n.oid = t.relnamespace
|
|
2009
|
+
JOIN pg_am am ON am.oid = c.relam
|
|
2010
|
+
CROSS JOIN LATERAL generate_series(1, i.indnatts) AS s(position)
|
|
2011
|
+
LEFT JOIN pg_opclass opc ON opc.oid = i.indclass[s.position]
|
|
2012
|
+
WHERE n.nspname = $1
|
|
2013
|
+
ORDER BY i.indrelid, i.indexrelid, s.position
|
|
2014
|
+
`;
|
|
2015
|
+
/** Identity sequence options joined to each generated identity column. */
|
|
2016
|
+
const postgresIdentitiesQuery = `
|
|
2017
|
+
SELECT a.attrelid::text AS table_oid, a.attnum::int AS ordinal_position,
|
|
2018
|
+
s.seqstart, s.seqincrement, s.seqmin, s.seqmax, s.seqcache,
|
|
2019
|
+
s.seqcycle, format_type(s.seqtypid, -1) AS sequence_type
|
|
2020
|
+
FROM pg_catalog.pg_attribute a
|
|
2021
|
+
JOIN pg_catalog.pg_class c ON c.oid = a.attrelid
|
|
2022
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
2023
|
+
JOIN pg_catalog.pg_depend d
|
|
2024
|
+
ON d.refclassid = 'pg_catalog.pg_class'::regclass
|
|
2025
|
+
AND d.refobjid = a.attrelid AND d.refobjsubid = a.attnum
|
|
2026
|
+
AND d.classid = 'pg_catalog.pg_class'::regclass
|
|
2027
|
+
AND d.deptype = 'i'
|
|
2028
|
+
JOIN pg_catalog.pg_sequence s ON s.seqrelid = d.objid
|
|
2029
|
+
WHERE n.nspname = $1 AND a.attidentity <> ''
|
|
2030
|
+
ORDER BY a.attrelid, a.attnum
|
|
2031
|
+
`;
|
|
2032
|
+
/** Sequence metadata, including serial/identity ownership dependencies. */
|
|
2033
|
+
const postgresSequencesQuery = `
|
|
2034
|
+
SELECT c.oid::text AS oid, n.nspname AS namespace, c.relname AS physical_name,
|
|
2035
|
+
format_type(s.seqtypid, -1) AS native_type,
|
|
2036
|
+
s.seqstart, s.seqincrement, s.seqmin, s.seqmax, s.seqcache,
|
|
2037
|
+
s.seqcycle, dep.refobjid::text AS owned_table_oid,
|
|
2038
|
+
dep.refobjsubid::int AS owned_column_position
|
|
2039
|
+
FROM pg_catalog.pg_sequence s
|
|
2040
|
+
JOIN pg_catalog.pg_class c ON c.oid = s.seqrelid
|
|
2041
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
2042
|
+
LEFT JOIN pg_catalog.pg_depend dep
|
|
2043
|
+
ON dep.classid = 'pg_catalog.pg_class'::regclass
|
|
2044
|
+
AND dep.objid = c.oid AND dep.refclassid = 'pg_catalog.pg_class'::regclass
|
|
2045
|
+
AND dep.deptype IN ('a', 'i')
|
|
2046
|
+
WHERE n.nspname = $1
|
|
2047
|
+
ORDER BY c.oid
|
|
2048
|
+
`;
|
|
2049
|
+
/** PostgreSQL enum labels in their declared order. */
|
|
2050
|
+
const postgresEnumsQuery = `
|
|
2051
|
+
SELECT t.oid::text AS oid, n.nspname AS namespace,
|
|
2052
|
+
t.typname AS physical_name, e.oid::text AS value_oid,
|
|
2053
|
+
e.enumlabel AS value, e.enumsortorder::float8 AS ordinal_position
|
|
2054
|
+
FROM pg_catalog.pg_type t
|
|
2055
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
|
|
2056
|
+
JOIN pg_catalog.pg_enum e ON e.enumtypid = t.oid
|
|
2057
|
+
WHERE n.nspname = $1 AND t.typtype = 'e'
|
|
2058
|
+
ORDER BY t.oid, e.enumsortorder
|
|
2059
|
+
`;
|
|
2060
|
+
/** PostgreSQL domains and their exact base type/default metadata. */
|
|
2061
|
+
const postgresDomainsQuery = `
|
|
2062
|
+
SELECT t.oid::text AS oid, n.nspname AS namespace,
|
|
2063
|
+
t.typname AS physical_name,
|
|
2064
|
+
format_type(t.typbasetype, t.typtypmod) AS native_type,
|
|
2065
|
+
NOT t.typnotnull AS nullable, t.typdefault AS default_expression
|
|
2066
|
+
FROM pg_catalog.pg_type t
|
|
2067
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
|
|
2068
|
+
WHERE n.nspname = $1 AND t.typtype = 'd'
|
|
2069
|
+
ORDER BY t.oid
|
|
2070
|
+
`;
|
|
2071
|
+
/** Domain CHECK constraints, which use pg_constraint.contypid. */
|
|
2072
|
+
const postgresDomainConstraintsQuery = `
|
|
2073
|
+
SELECT con.oid::text AS oid, con.contypid::text AS domain_oid,
|
|
2074
|
+
con.conname AS physical_name, pg_get_constraintdef(con.oid, true) AS definition,
|
|
2075
|
+
con.condeferrable, con.condeferred, con.convalidated
|
|
2076
|
+
FROM pg_catalog.pg_constraint con
|
|
2077
|
+
JOIN pg_catalog.pg_type t ON t.oid = con.contypid
|
|
2078
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
|
|
2079
|
+
WHERE n.nspname = $1 AND con.contype = 'c'
|
|
2080
|
+
ORDER BY con.contypid, con.oid
|
|
2081
|
+
`;
|
|
2082
|
+
/** Collation provider, locale, determinism, and version facts. */
|
|
2083
|
+
const postgresCollationsQuery = `
|
|
2084
|
+
SELECT c.oid::text AS oid, n.nspname AS namespace,
|
|
2085
|
+
c.collname AS physical_name, c.collprovider, c.collcollate,
|
|
2086
|
+
c.collctype, to_jsonb(c)->>'colllocale' AS colliculocale,
|
|
2087
|
+
c.collisdeterministic, c.collversion
|
|
2088
|
+
FROM pg_catalog.pg_collation c
|
|
2089
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.collnamespace
|
|
2090
|
+
WHERE n.nspname = $1
|
|
2091
|
+
ORDER BY c.oid
|
|
2092
|
+
`;
|
|
2093
|
+
/** User-defined triggers with decompiled condition and definition text. */
|
|
2094
|
+
const postgresTriggersQuery = `
|
|
2095
|
+
SELECT t.oid::text AS oid, t.tgrelid::text AS table_oid,
|
|
2096
|
+
n.nspname AS namespace, t.tgname AS physical_name,
|
|
2097
|
+
t.tgtype::int AS trigger_type, t.tgenabled,
|
|
2098
|
+
pg_get_expr(t.tgqual, t.tgrelid, true) AS condition,
|
|
2099
|
+
pg_get_triggerdef(t.oid, true) AS definition
|
|
2100
|
+
FROM pg_catalog.pg_trigger t
|
|
2101
|
+
JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid
|
|
2102
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
2103
|
+
WHERE n.nspname = $1 AND NOT t.tgisinternal
|
|
2104
|
+
ORDER BY t.tgrelid, t.oid
|
|
2105
|
+
`;
|
|
2106
|
+
/** PostgreSQL functions, procedures, aggregates, and window routines. */
|
|
2107
|
+
const postgresRoutinesQuery = `
|
|
2108
|
+
SELECT p.oid::text AS oid, n.nspname AS namespace,
|
|
2109
|
+
p.proname AS physical_name, p.prokind,
|
|
2110
|
+
format_type(p.prorettype, NULL) AS return_type,
|
|
2111
|
+
l.lanname AS language, pg_get_functiondef(p.oid) AS definition,
|
|
2112
|
+
pg_get_function_identity_arguments(p.oid) AS identity_arguments,
|
|
2113
|
+
pg_get_expr(p.proargdefaults, 0, true) AS argument_defaults,
|
|
2114
|
+
p.pronargdefaults, p.provolatile, p.proparallel, p.prosecdef
|
|
2115
|
+
FROM pg_catalog.pg_proc p
|
|
2116
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
|
|
2117
|
+
JOIN pg_catalog.pg_language l ON l.oid = p.prolang
|
|
2118
|
+
WHERE n.nspname = $1 AND p.prokind IN ('f', 'p', 'a', 'w')
|
|
2119
|
+
ORDER BY p.oid
|
|
2120
|
+
`;
|
|
2121
|
+
/** Routine parameter rows using PostgreSQL's complete argument type arrays. */
|
|
2122
|
+
const postgresRoutineParametersQuery = `
|
|
2123
|
+
SELECT p.oid::text AS routine_oid, x.position::int AS ordinal_position,
|
|
2124
|
+
names.name AS parameter_name, modes.mode,
|
|
2125
|
+
format_type(x.type_oid, -1) AS native_type
|
|
2126
|
+
FROM pg_catalog.pg_proc p
|
|
2127
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
|
|
2128
|
+
CROSS JOIN LATERAL unnest(
|
|
2129
|
+
COALESCE(p.proallargtypes, p.proargtypes::oid[])
|
|
2130
|
+
) WITH ORDINALITY AS x(type_oid, position)
|
|
2131
|
+
LEFT JOIN LATERAL unnest(p.proargnames) WITH ORDINALITY
|
|
2132
|
+
AS names(name, position) ON names.position = x.position
|
|
2133
|
+
LEFT JOIN LATERAL unnest(p.proargmodes) WITH ORDINALITY
|
|
2134
|
+
AS modes(mode, position) ON modes.position = x.position
|
|
2135
|
+
WHERE n.nspname = $1 AND p.prokind IN ('f', 'p', 'a', 'w')
|
|
2136
|
+
ORDER BY p.oid, x.position
|
|
2137
|
+
`;
|
|
2138
|
+
/** Partition children, key attributes, strategy, and bound expression. */
|
|
2139
|
+
const postgresPartitionsQuery = `
|
|
2140
|
+
SELECT child.oid::text AS partition_oid, parent.oid::text AS parent_oid,
|
|
2141
|
+
n.nspname AS namespace, child.relname AS physical_name,
|
|
2142
|
+
part.partstrat, part.partattrs::text AS key_attributes,
|
|
2143
|
+
pg_get_expr(child.relpartbound, child.oid, true) AS bound,
|
|
2144
|
+
child.relispartition, child.relkind
|
|
2145
|
+
FROM pg_catalog.pg_inherits inh
|
|
2146
|
+
JOIN pg_catalog.pg_class child ON child.oid = inh.inhrelid
|
|
2147
|
+
JOIN pg_catalog.pg_class parent ON parent.oid = inh.inhparent
|
|
2148
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = child.relnamespace
|
|
2149
|
+
LEFT JOIN pg_catalog.pg_partitioned_table part ON part.partrelid = parent.oid
|
|
2150
|
+
WHERE n.nspname = $1
|
|
2151
|
+
ORDER BY parent.oid, child.oid
|
|
2152
|
+
`;
|
|
2153
|
+
/** Row-level security policies and their role/expression metadata. */
|
|
2154
|
+
const postgresPoliciesQuery = `
|
|
2155
|
+
SELECT p.oid::text AS oid, p.polrelid::text AS table_oid,
|
|
2156
|
+
n.nspname AS namespace, p.polname AS physical_name,
|
|
2157
|
+
p.polcmd, p.polpermissive,
|
|
2158
|
+
ARRAY(SELECT r.rolname FROM pg_catalog.pg_roles r
|
|
2159
|
+
WHERE r.oid = ANY(p.polroles)) AS roles,
|
|
2160
|
+
pg_get_expr(p.polqual, p.polrelid, true) AS using_expression,
|
|
2161
|
+
pg_get_expr(p.polwithcheck, p.polrelid, true) AS check_expression
|
|
2162
|
+
FROM pg_catalog.pg_policy p
|
|
2163
|
+
JOIN pg_catalog.pg_class c ON c.oid = p.polrelid
|
|
2164
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
2165
|
+
WHERE n.nspname = $1
|
|
2166
|
+
ORDER BY p.polrelid, p.oid
|
|
2167
|
+
`;
|
|
2168
|
+
/** Installed PostgreSQL extensions scoped to the selected schema. */
|
|
2169
|
+
const postgresExtensionsQuery = `
|
|
2170
|
+
SELECT e.oid::text AS oid, n.nspname AS namespace,
|
|
2171
|
+
e.extname AS physical_name, e.extversion, e.extrelocatable,
|
|
2172
|
+
e.extconfig::text AS config_relations,
|
|
2173
|
+
e.extcondition::text AS config_conditions
|
|
2174
|
+
FROM pg_catalog.pg_extension e
|
|
2175
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace
|
|
2176
|
+
WHERE n.nspname = $1
|
|
2177
|
+
ORDER BY e.oid
|
|
2178
|
+
`;
|
|
2179
|
+
/** Comments and owners for PostgreSQL objects visible in one schema. */
|
|
2180
|
+
const postgresMetadataQuery = `
|
|
2181
|
+
WITH objects AS (
|
|
2182
|
+
SELECT 'pg_class'::text AS catalog_relation, 'pg_class'::regclass AS catalog_oid,
|
|
2183
|
+
c.oid::text AS object_oid, 0::int AS object_subid,
|
|
2184
|
+
CASE c.relkind WHEN 'r' THEN 'table' WHEN 'p' THEN 'table'
|
|
2185
|
+
WHEN 'v' THEN 'view' WHEN 'm' THEN 'materialized-view'
|
|
2186
|
+
WHEN 'S' THEN 'sequence' WHEN 'i' THEN 'index'
|
|
2187
|
+
WHEN 'I' THEN 'index' WHEN 'f' THEN 'deferred-object'
|
|
2188
|
+
ELSE 'opaque-object' END AS object_kind,
|
|
2189
|
+
c.relname AS object_name, n.nspname AS namespace,
|
|
2190
|
+
c.relowner::oid AS owner_oid, NULL::text AS parent_oid
|
|
2191
|
+
FROM pg_catalog.pg_class c
|
|
2192
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
2193
|
+
WHERE n.nspname = $1
|
|
2194
|
+
UNION ALL
|
|
2195
|
+
SELECT 'pg_class', 'pg_class'::regclass, c.oid::text, a.attnum::int,
|
|
2196
|
+
'column', a.attname, n.nspname, c.relowner::oid, c.oid::text
|
|
2197
|
+
FROM pg_catalog.pg_attribute a
|
|
2198
|
+
JOIN pg_catalog.pg_class c ON c.oid = a.attrelid
|
|
2199
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
2200
|
+
WHERE n.nspname = $1 AND c.relkind IN ('r', 'p', 'v', 'm')
|
|
2201
|
+
AND a.attnum > 0 AND NOT a.attisdropped
|
|
2202
|
+
UNION ALL
|
|
2203
|
+
SELECT 'pg_proc', 'pg_proc'::regclass, p.oid::text, 0,
|
|
2204
|
+
'routine', p.proname, n.nspname, p.proowner::oid, NULL
|
|
2205
|
+
FROM pg_catalog.pg_proc p
|
|
2206
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
|
|
2207
|
+
WHERE n.nspname = $1 AND p.prokind IN ('f', 'p', 'a', 'w')
|
|
2208
|
+
UNION ALL
|
|
2209
|
+
SELECT 'pg_type', 'pg_type'::regclass, t.oid::text, 0,
|
|
2210
|
+
CASE t.typtype WHEN 'e' THEN 'enum' ELSE 'domain' END,
|
|
2211
|
+
t.typname, n.nspname, t.typowner::oid, NULL
|
|
2212
|
+
FROM pg_catalog.pg_type t
|
|
2213
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
|
|
2214
|
+
WHERE n.nspname = $1 AND t.typtype IN ('e', 'd')
|
|
2215
|
+
UNION ALL
|
|
2216
|
+
SELECT 'pg_collation', 'pg_collation'::regclass, c.oid::text, 0,
|
|
2217
|
+
'collation', c.collname, n.nspname, c.collowner::oid, NULL
|
|
2218
|
+
FROM pg_catalog.pg_collation c
|
|
2219
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.collnamespace
|
|
2220
|
+
WHERE n.nspname = $1
|
|
2221
|
+
UNION ALL
|
|
2222
|
+
SELECT 'pg_extension', 'pg_extension'::regclass, e.oid::text, 0,
|
|
2223
|
+
'extension', e.extname, n.nspname, e.extowner::oid, NULL
|
|
2224
|
+
FROM pg_catalog.pg_extension e
|
|
2225
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace
|
|
2226
|
+
WHERE n.nspname = $1
|
|
2227
|
+
UNION ALL
|
|
2228
|
+
SELECT 'pg_constraint', 'pg_constraint'::regclass, con.oid::text, 0,
|
|
2229
|
+
'constraint', con.conname, n.nspname, c.relowner::oid,
|
|
2230
|
+
con.conrelid::text
|
|
2231
|
+
FROM pg_catalog.pg_constraint con
|
|
2232
|
+
JOIN pg_catalog.pg_class c ON c.oid = con.conrelid
|
|
2233
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
2234
|
+
WHERE n.nspname = $1
|
|
2235
|
+
UNION ALL
|
|
2236
|
+
SELECT 'pg_trigger', 'pg_trigger'::regclass, t.oid::text, 0,
|
|
2237
|
+
'trigger', t.tgname, n.nspname, c.relowner::oid,
|
|
2238
|
+
t.tgrelid::text
|
|
2239
|
+
FROM pg_catalog.pg_trigger t
|
|
2240
|
+
JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid
|
|
2241
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
2242
|
+
WHERE n.nspname = $1 AND NOT t.tgisinternal
|
|
2243
|
+
UNION ALL
|
|
2244
|
+
SELECT 'pg_policy', 'pg_policy'::regclass, p.oid::text, 0,
|
|
2245
|
+
'policy', p.polname, n.nspname, c.relowner::oid,
|
|
2246
|
+
p.polrelid::text
|
|
2247
|
+
FROM pg_catalog.pg_policy p
|
|
2248
|
+
JOIN pg_catalog.pg_class c ON c.oid = p.polrelid
|
|
2249
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
2250
|
+
WHERE n.nspname = $1
|
|
2251
|
+
)
|
|
2252
|
+
SELECT o.catalog_relation, o.object_oid, o.object_subid,
|
|
2253
|
+
o.object_kind, o.object_name, o.namespace, o.parent_oid,
|
|
2254
|
+
d.description, pg_get_userbyid(o.owner_oid) AS owner
|
|
2255
|
+
FROM objects o
|
|
2256
|
+
LEFT JOIN pg_catalog.pg_description d
|
|
2257
|
+
ON d.classoid = o.catalog_oid AND d.objoid::text = o.object_oid
|
|
2258
|
+
AND d.objsubid = o.object_subid
|
|
2259
|
+
ORDER BY o.catalog_relation, o.object_oid, o.object_subid
|
|
2260
|
+
`;
|
|
2261
|
+
async function query$1(connection, text, parameters, options, diagnostics, operation) {
|
|
2262
|
+
try {
|
|
2263
|
+
return await connection.query({
|
|
2264
|
+
text,
|
|
2265
|
+
parameters
|
|
2266
|
+
}, { signal: options.signal });
|
|
2267
|
+
} catch {
|
|
2268
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
2269
|
+
severity: "error",
|
|
2270
|
+
code: "query-failed",
|
|
2271
|
+
message: `PostgreSQL catalog query failed while reading ${operation}`,
|
|
2272
|
+
path: [operation],
|
|
2273
|
+
remediation: "Check PostgreSQL permissions and the selected schema."
|
|
2274
|
+
}));
|
|
2275
|
+
return [];
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
function serverInfo$1(row, diagnostics) {
|
|
2279
|
+
const rawVersion = text$1(row?.server_version) ?? "unknown";
|
|
2280
|
+
const numericVersion = number$1(row?.server_version_num);
|
|
2281
|
+
if (!row) diagnostics.push(createIntrospectionDiagnostic({
|
|
2282
|
+
severity: "error",
|
|
2283
|
+
code: "unsupported-server",
|
|
2284
|
+
message: "PostgreSQL server version metadata was unavailable",
|
|
2285
|
+
path: ["server"],
|
|
2286
|
+
remediation: "Provide access to current_setting(server_version_num)."
|
|
2287
|
+
}));
|
|
2288
|
+
const major = numericVersion ? Math.floor(numericVersion / 1e4) : void 0;
|
|
2289
|
+
const supported = major !== void 0 && major >= 12;
|
|
2290
|
+
if (!supported) diagnostics.push(createIntrospectionDiagnostic({
|
|
2291
|
+
severity: "error",
|
|
2292
|
+
code: "unsupported-server",
|
|
2293
|
+
message: "PostgreSQL introspection requires server version 12 or newer",
|
|
2294
|
+
path: ["server", "version"],
|
|
2295
|
+
remediation: "Use PostgreSQL 12+ or an adapter capability extension."
|
|
2296
|
+
}));
|
|
2297
|
+
return {
|
|
2298
|
+
product: "postgresql",
|
|
2299
|
+
rawVersion,
|
|
2300
|
+
parsedVersion: major === void 0 ? void 0 : { major },
|
|
2301
|
+
capabilities: {
|
|
2302
|
+
generatedColumns: supported,
|
|
2303
|
+
identityMetadata: numericVersion !== void 0 && numericVersion >= 1e5,
|
|
2304
|
+
checkConstraints: true,
|
|
2305
|
+
checkConstraintEnforcement: "enforced",
|
|
2306
|
+
expressionDecompilation: true,
|
|
2307
|
+
indexExpressions: true,
|
|
2308
|
+
indexPredicates: true,
|
|
2309
|
+
indexIncludedColumns: true,
|
|
2310
|
+
namespaces: true,
|
|
2311
|
+
visibility: "complete"
|
|
2312
|
+
}
|
|
2313
|
+
};
|
|
2314
|
+
}
|
|
2315
|
+
function emptyCatalog$1(namespace, diagnostics) {
|
|
2316
|
+
return {
|
|
2317
|
+
dialect: "postgresql",
|
|
2318
|
+
server: {
|
|
2319
|
+
product: "postgresql",
|
|
2320
|
+
rawVersion: "unknown",
|
|
2321
|
+
capabilities: {
|
|
2322
|
+
generatedColumns: false,
|
|
2323
|
+
identityMetadata: false,
|
|
2324
|
+
checkConstraints: false,
|
|
2325
|
+
checkConstraintEnforcement: "unknown",
|
|
2326
|
+
expressionDecompilation: false,
|
|
2327
|
+
indexExpressions: false,
|
|
2328
|
+
indexPredicates: false,
|
|
2329
|
+
indexIncludedColumns: false,
|
|
2330
|
+
namespaces: false,
|
|
2331
|
+
visibility: "unknown"
|
|
2332
|
+
}
|
|
2333
|
+
},
|
|
2334
|
+
namespace: {
|
|
2335
|
+
kind: "postgres-schema",
|
|
2336
|
+
name: namespace
|
|
2337
|
+
},
|
|
2338
|
+
tables: [],
|
|
2339
|
+
deferredObjects: [],
|
|
2340
|
+
diagnostics: Object.freeze(diagnostics)
|
|
2341
|
+
};
|
|
2342
|
+
}
|
|
2343
|
+
function viewObject(row, namespace, diagnostics) {
|
|
2344
|
+
const physicalName = text$1(row.physical_name) ?? "unnamed_view";
|
|
2345
|
+
const kind = row.relkind === "m" ? "materialized-view" : "view";
|
|
2346
|
+
const physicalReference = reference$1(kind, physicalName, text$1(row.namespace) ?? namespace, "pg_class", "oid", row.oid);
|
|
2347
|
+
const definition = text$1(row.definition);
|
|
2348
|
+
if (definition === void 0) {
|
|
2349
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
2350
|
+
severity: "warning",
|
|
2351
|
+
code: "unmodeled-object",
|
|
2352
|
+
message: `PostgreSQL ${kind} ${physicalName} has no recoverable definition`,
|
|
2353
|
+
path: [
|
|
2354
|
+
"views",
|
|
2355
|
+
physicalName,
|
|
2356
|
+
"definition"
|
|
2357
|
+
],
|
|
2358
|
+
physicalReference,
|
|
2359
|
+
remediation: "Grant access to pg_get_viewdef before treating this object as migration input."
|
|
2360
|
+
}));
|
|
2361
|
+
return deferredCatalogObject(kind === "view" ? "view" : "materialized-view", physicalName, physicalReference, [{
|
|
2362
|
+
name: "definition",
|
|
2363
|
+
value: expression("/* view definition unavailable */", "decompiler", physicalReference)
|
|
2364
|
+
}]);
|
|
2365
|
+
}
|
|
2366
|
+
const options = stringArray(row.reloptions);
|
|
2367
|
+
const checkOption = (() => {
|
|
2368
|
+
const value = text$1(row.check_option)?.toLowerCase();
|
|
2369
|
+
return value === "none" || value === "local" || value === "cascaded" ? value : void 0;
|
|
2370
|
+
})();
|
|
2371
|
+
return {
|
|
2372
|
+
kind,
|
|
2373
|
+
id: stableId$1(physicalName),
|
|
2374
|
+
identitySource: "physical-name",
|
|
2375
|
+
physicalName,
|
|
2376
|
+
columns: [],
|
|
2377
|
+
definition: expression(definition, "decompiler", physicalReference),
|
|
2378
|
+
...checkOption === "local" || checkOption === "cascaded" ? { checkOption } : checkOption === "none" ? { checkOption: "none" } : {},
|
|
2379
|
+
...booleanOption(options, "security_barrier") === void 0 ? {} : { securityBarrier: booleanOption(options, "security_barrier") },
|
|
2380
|
+
...booleanOption(options, "security_invoker") === void 0 ? {} : { securityInvoker: booleanOption(options, "security_invoker") },
|
|
2381
|
+
reference: physicalReference
|
|
2382
|
+
};
|
|
2383
|
+
}
|
|
2384
|
+
function columnKey(tableOid, ordinalPosition) {
|
|
2385
|
+
return `${text$1(tableOid) ?? "unknown"}:${number$1(ordinalPosition) ?? 0}`;
|
|
2386
|
+
}
|
|
2387
|
+
function compareOrdinal(left, right) {
|
|
2388
|
+
return (number$1(left.ordinal_position) ?? 0) - (number$1(right.ordinal_position) ?? 0);
|
|
2389
|
+
}
|
|
2390
|
+
function identityOptions(row) {
|
|
2391
|
+
const options = {};
|
|
2392
|
+
for (const [key, value] of [
|
|
2393
|
+
["start", row.seqstart],
|
|
2394
|
+
["increment", row.seqincrement],
|
|
2395
|
+
["minimum", row.seqmin],
|
|
2396
|
+
["maximum", row.seqmax],
|
|
2397
|
+
["cache", row.seqcache]
|
|
2398
|
+
]) {
|
|
2399
|
+
const fact = literalFact(value);
|
|
2400
|
+
if (fact !== void 0) options[key] = fact;
|
|
2401
|
+
}
|
|
2402
|
+
if (row.seqcycle !== void 0) options.cycle = {
|
|
2403
|
+
kind: "literal",
|
|
2404
|
+
value: boolean$1(row.seqcycle)
|
|
2405
|
+
};
|
|
2406
|
+
if (text$1(row.sequence_type) !== void 0) options.type = {
|
|
2407
|
+
kind: "literal",
|
|
2408
|
+
value: text$1(row.sequence_type)
|
|
2409
|
+
};
|
|
2410
|
+
return options;
|
|
2411
|
+
}
|
|
2412
|
+
function sequenceObject(row, namespace, tableByOid, diagnostics) {
|
|
2413
|
+
const physicalName = text$1(row.physical_name) ?? `sequence_${text$1(row.oid) ?? "unknown"}`;
|
|
2414
|
+
const physicalReference = reference$1("sequence", physicalName, text$1(row.namespace) ?? namespace, "pg_class", "oid", row.oid);
|
|
2415
|
+
const ownedTable = tableByOid.get(text$1(row.owned_table_oid));
|
|
2416
|
+
const ownedBy = ownedTable ? {
|
|
2417
|
+
kind: "table",
|
|
2418
|
+
id: ownedTable.id
|
|
2419
|
+
} : void 0;
|
|
2420
|
+
const ownedTableOid = text$1(row.owned_table_oid);
|
|
2421
|
+
const ownedColumnPosition = number$1(row.owned_column_position);
|
|
2422
|
+
if (ownedTableOid !== void 0 && ownedBy === void 0) diagnostics.push(createIntrospectionDiagnostic({
|
|
2423
|
+
severity: "warning",
|
|
2424
|
+
code: "unresolved-reference",
|
|
2425
|
+
message: `PostgreSQL sequence ${physicalName} has an ownership target outside the selected schema`,
|
|
2426
|
+
path: [
|
|
2427
|
+
"sequences",
|
|
2428
|
+
physicalName,
|
|
2429
|
+
"ownedBy"
|
|
2430
|
+
],
|
|
2431
|
+
physicalReference,
|
|
2432
|
+
remediation: "Select the owning table schema or inspect the retained ownership catalog reference."
|
|
2433
|
+
}));
|
|
2434
|
+
const data = {};
|
|
2435
|
+
if (ownedTableOid !== void 0) data.ownedTableOid = ownedTableOid;
|
|
2436
|
+
if (ownedColumnPosition !== void 0) data.ownedColumnPosition = ownedColumnPosition;
|
|
2437
|
+
return {
|
|
2438
|
+
kind: "sequence",
|
|
2439
|
+
id: stableId$1(physicalName),
|
|
2440
|
+
identitySource: "physical-name",
|
|
2441
|
+
physicalName,
|
|
2442
|
+
storage: storage(row.native_type),
|
|
2443
|
+
...factIfPresent(row.seqstart) === void 0 ? {} : { start: factIfPresent(row.seqstart) },
|
|
2444
|
+
...factIfPresent(row.seqincrement) === void 0 ? {} : { increment: factIfPresent(row.seqincrement) },
|
|
2445
|
+
...factIfPresent(row.seqmin) === void 0 ? {} : { minimum: factIfPresent(row.seqmin) },
|
|
2446
|
+
...factIfPresent(row.seqmax) === void 0 ? {} : { maximum: factIfPresent(row.seqmax) },
|
|
2447
|
+
...factIfPresent(row.seqcache) === void 0 ? {} : { cache: factIfPresent(row.seqcache) },
|
|
2448
|
+
...row.seqcycle === void 0 || row.seqcycle === null ? {} : { cycle: boolean$1(row.seqcycle) },
|
|
2449
|
+
...ownedBy === void 0 ? {} : { ownedBy },
|
|
2450
|
+
...Object.keys(data).length === 0 ? {} : { dialect: {
|
|
2451
|
+
dialect: "postgresql",
|
|
2452
|
+
version: 1,
|
|
2453
|
+
data
|
|
2454
|
+
} },
|
|
2455
|
+
reference: physicalReference
|
|
2456
|
+
};
|
|
2457
|
+
}
|
|
2458
|
+
function mapEnums(rows, namespace) {
|
|
2459
|
+
const groups = /* @__PURE__ */ new Map();
|
|
2460
|
+
for (const row of rows) {
|
|
2461
|
+
const key = text$1(row.oid) ?? text$1(row.physical_name) ?? "unknown";
|
|
2462
|
+
const values = groups.get(key) ?? [];
|
|
2463
|
+
values.push(row);
|
|
2464
|
+
groups.set(key, values);
|
|
2465
|
+
}
|
|
2466
|
+
return [...groups.values()].map((enumRows) => {
|
|
2467
|
+
const first = enumRows[0];
|
|
2468
|
+
const physicalName = text$1(first.physical_name) ?? `enum_${text$1(first.oid) ?? "unknown"}`;
|
|
2469
|
+
const physicalReference = reference$1("enum", physicalName, text$1(first.namespace) ?? namespace, "pg_type", "oid", first.oid);
|
|
2470
|
+
const values = [...enumRows].sort((left, right) => (number$1(left.ordinal_position) ?? 0) - (number$1(right.ordinal_position) ?? 0)).map((row, index) => ({
|
|
2471
|
+
value: text$1(row.value) ?? "",
|
|
2472
|
+
ordinalPosition: index + 1,
|
|
2473
|
+
provenance: {
|
|
2474
|
+
kind: "catalog",
|
|
2475
|
+
dialect: "postgresql",
|
|
2476
|
+
reference: reference$1("enum", physicalName, text$1(row.namespace) ?? namespace, "pg_enum", "oid", row.value_oid)
|
|
2477
|
+
}
|
|
2478
|
+
}));
|
|
2479
|
+
return {
|
|
2480
|
+
kind: "enum",
|
|
2481
|
+
id: stableId$1(physicalName),
|
|
2482
|
+
identitySource: "physical-name",
|
|
2483
|
+
physicalName,
|
|
2484
|
+
values,
|
|
2485
|
+
reference: physicalReference
|
|
2486
|
+
};
|
|
2487
|
+
});
|
|
2488
|
+
}
|
|
2489
|
+
function mapDomains(rows, constraintRows, namespace) {
|
|
2490
|
+
const constraintsByDomain = groupBy(constraintRows, (row) => text$1(row.domain_oid) ?? "unknown");
|
|
2491
|
+
return rows.map((row) => {
|
|
2492
|
+
const physicalName = text$1(row.physical_name) ?? `domain_${text$1(row.oid) ?? "unknown"}`;
|
|
2493
|
+
const physicalReference = reference$1("domain", physicalName, text$1(row.namespace) ?? namespace, "pg_type", "oid", row.oid);
|
|
2494
|
+
const domainConstraints = (constraintsByDomain.get(text$1(row.oid)) ?? []).map((constraintRow) => {
|
|
2495
|
+
const constraintName = text$1(constraintRow.physical_name) ?? `domain_constraint_${text$1(constraintRow.oid) ?? "unknown"}`;
|
|
2496
|
+
const constraintReference = reference$1("constraint", constraintName, text$1(row.namespace) ?? namespace, "pg_constraint", "oid", constraintRow.oid);
|
|
2497
|
+
return {
|
|
2498
|
+
kind: "check",
|
|
2499
|
+
id: stableId$1(constraintName),
|
|
2500
|
+
identitySource: "physical-name",
|
|
2501
|
+
physicalName: constraintName,
|
|
2502
|
+
expression: expression(text$1(constraintRow.definition) ?? "CHECK (true)", "decompiler", constraintReference),
|
|
2503
|
+
deferrable: constraintRow.condeferrable === void 0 ? void 0 : boolean$1(constraintRow.condeferrable),
|
|
2504
|
+
initially: constraintRow.condeferred === void 0 ? void 0 : boolean$1(constraintRow.condeferred) ? "deferred" : "immediate",
|
|
2505
|
+
validated: constraintRow.convalidated === void 0 ? void 0 : boolean$1(constraintRow.convalidated),
|
|
2506
|
+
reference: constraintReference
|
|
2507
|
+
};
|
|
2508
|
+
});
|
|
2509
|
+
return {
|
|
2510
|
+
kind: "domain",
|
|
2511
|
+
id: stableId$1(physicalName),
|
|
2512
|
+
identitySource: "physical-name",
|
|
2513
|
+
physicalName,
|
|
2514
|
+
storage: storage(row.native_type),
|
|
2515
|
+
...row.nullable === void 0 || row.nullable === null ? {} : { nullable: boolean$1(row.nullable) },
|
|
2516
|
+
...factIfPresent(row.default_expression) === void 0 ? {} : { default: factIfPresent(row.default_expression) },
|
|
2517
|
+
...domainConstraints.length === 0 ? {} : { constraints: domainConstraints },
|
|
2518
|
+
reference: physicalReference
|
|
2519
|
+
};
|
|
2520
|
+
});
|
|
2521
|
+
}
|
|
2522
|
+
function collationObject(row, namespace) {
|
|
2523
|
+
const physicalName = text$1(row.physical_name) ?? `collation_${text$1(row.oid) ?? "unknown"}`;
|
|
2524
|
+
return {
|
|
2525
|
+
kind: "collation",
|
|
2526
|
+
id: stableId$1(physicalName),
|
|
2527
|
+
identitySource: "physical-name",
|
|
2528
|
+
physicalName,
|
|
2529
|
+
...text$1(row.collprovider) === void 0 ? {} : { provider: text$1(row.collprovider) },
|
|
2530
|
+
...(text$1(row.colliculocale) ?? text$1(row.collcollate) ?? text$1(row.collctype)) === void 0 ? {} : { locale: text$1(row.colliculocale) ?? text$1(row.collcollate) ?? text$1(row.collctype) },
|
|
2531
|
+
...row.collisdeterministic === void 0 || row.collisdeterministic === null ? {} : { deterministic: boolean$1(row.collisdeterministic) },
|
|
2532
|
+
...text$1(row.collversion) === void 0 ? {} : { version: text$1(row.collversion) },
|
|
2533
|
+
reference: reference$1("collation", physicalName, text$1(row.namespace) ?? namespace, "pg_collation", "oid", row.oid)
|
|
2534
|
+
};
|
|
2535
|
+
}
|
|
2536
|
+
function triggerObject(row, namespace, relationReferences, diagnostics) {
|
|
2537
|
+
const physicalName = text$1(row.physical_name) ?? `trigger_${text$1(row.oid) ?? "unknown"}`;
|
|
2538
|
+
const physicalReference = reference$1("trigger", physicalName, text$1(row.namespace) ?? namespace, "pg_trigger", "oid", row.oid);
|
|
2539
|
+
const table = relationReferences.get(text$1(row.table_oid));
|
|
2540
|
+
const definition = text$1(row.definition);
|
|
2541
|
+
if (table === void 0 || definition === void 0) {
|
|
2542
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
2543
|
+
severity: "warning",
|
|
2544
|
+
code: table === void 0 ? "unresolved-reference" : "unmodeled-object",
|
|
2545
|
+
message: table === void 0 ? `PostgreSQL trigger ${physicalName} has no selected parent relation` : `PostgreSQL trigger ${physicalName} has no recoverable definition`,
|
|
2546
|
+
path: ["triggers", physicalName],
|
|
2547
|
+
physicalReference,
|
|
2548
|
+
remediation: "Retain the deferred trigger until its parent relation and definition are visible."
|
|
2549
|
+
}));
|
|
2550
|
+
return deferredCatalogObject("trigger", physicalName, physicalReference, [...table === void 0 ? [{
|
|
2551
|
+
name: "tableOid",
|
|
2552
|
+
value: text$1(row.table_oid) ?? "unknown"
|
|
2553
|
+
}] : [], ...definition === void 0 ? [] : [{
|
|
2554
|
+
name: "definition",
|
|
2555
|
+
value: expression(definition, "decompiler", physicalReference)
|
|
2556
|
+
}]]);
|
|
2557
|
+
}
|
|
2558
|
+
const triggerType = number$1(row.trigger_type) ?? 0;
|
|
2559
|
+
const timing = triggerType & 64 ? "instead-of" : triggerType & 2 ? "before" : "after";
|
|
2560
|
+
const events = triggerEvents$1(triggerType);
|
|
2561
|
+
const mode = triggerType & 1 ? "row" : "statement";
|
|
2562
|
+
const enabled = triggerEnabled(row.tgenabled);
|
|
2563
|
+
return {
|
|
2564
|
+
kind: "trigger",
|
|
2565
|
+
id: stableId$1(physicalName),
|
|
2566
|
+
identitySource: "physical-name",
|
|
2567
|
+
physicalName,
|
|
2568
|
+
table,
|
|
2569
|
+
timing,
|
|
2570
|
+
events,
|
|
2571
|
+
orientation: mode,
|
|
2572
|
+
...text$1(row.condition) === void 0 ? {} : { condition: expression(text$1(row.condition), "decompiler", physicalReference) },
|
|
2573
|
+
body: expression(definition, "decompiler", physicalReference),
|
|
2574
|
+
...enabled === void 0 ? {} : { enabled },
|
|
2575
|
+
reference: physicalReference
|
|
2576
|
+
};
|
|
2577
|
+
}
|
|
2578
|
+
function mapRoutines(rows, parameterRows, namespace, diagnostics) {
|
|
2579
|
+
const parametersByRoutine = groupBy(parameterRows, (row) => text$1(row.routine_oid) ?? "unknown");
|
|
2580
|
+
const names = /* @__PURE__ */ new Map();
|
|
2581
|
+
for (const row of rows) {
|
|
2582
|
+
const name = text$1(row.physical_name) ?? `routine_${text$1(row.oid) ?? "unknown"}`;
|
|
2583
|
+
names.set(name, (names.get(name) ?? 0) + 1);
|
|
2584
|
+
}
|
|
2585
|
+
return rows.map((row) => {
|
|
2586
|
+
const physicalName = text$1(row.physical_name) ?? `routine_${text$1(row.oid) ?? "unknown"}`;
|
|
2587
|
+
const physicalReference = reference$1("routine", physicalName, text$1(row.namespace) ?? namespace, "pg_proc", "oid", row.oid);
|
|
2588
|
+
const identityArguments = text$1(row.identity_arguments);
|
|
2589
|
+
const defaultArguments = text$1(row.argument_defaults);
|
|
2590
|
+
if (defaultArguments !== void 0) diagnostics.push(createIntrospectionDiagnostic({
|
|
2591
|
+
severity: "info",
|
|
2592
|
+
code: "unmodeled-object",
|
|
2593
|
+
message: `PostgreSQL routine ${physicalName} retains its argument defaults as opaque catalog text`,
|
|
2594
|
+
path: [
|
|
2595
|
+
"routines",
|
|
2596
|
+
physicalName,
|
|
2597
|
+
"argumentDefaults"
|
|
2598
|
+
],
|
|
2599
|
+
physicalReference,
|
|
2600
|
+
remediation: "Review routine argument defaults before using the complete snapshot for migration planning."
|
|
2601
|
+
}));
|
|
2602
|
+
if (text$1(row.definition) === void 0) diagnostics.push(createIntrospectionDiagnostic({
|
|
2603
|
+
severity: "warning",
|
|
2604
|
+
code: "unmodeled-object",
|
|
2605
|
+
message: `PostgreSQL routine ${physicalName} has no recoverable definition`,
|
|
2606
|
+
path: [
|
|
2607
|
+
"routines",
|
|
2608
|
+
physicalName,
|
|
2609
|
+
"definition"
|
|
2610
|
+
],
|
|
2611
|
+
physicalReference,
|
|
2612
|
+
remediation: "Grant access to pg_get_functiondef before treating this routine as migration input."
|
|
2613
|
+
}));
|
|
2614
|
+
const routineUnknownFields = [...identityArguments === void 0 ? [] : [{
|
|
2615
|
+
name: "identityArguments",
|
|
2616
|
+
value: expression(identityArguments, "decompiler", physicalReference)
|
|
2617
|
+
}], ...defaultArguments === void 0 ? [] : [{
|
|
2618
|
+
name: "argumentDefaults",
|
|
2619
|
+
value: expression(defaultArguments, "decompiler", physicalReference)
|
|
2620
|
+
}]];
|
|
2621
|
+
const parameters = (parametersByRoutine.get(text$1(row.oid)) ?? []).sort((left, right) => (number$1(left.ordinal_position) ?? 0) - (number$1(right.ordinal_position) ?? 0)).map((parameter) => ({
|
|
2622
|
+
...text$1(parameter.parameter_name) === void 0 ? {} : { name: text$1(parameter.parameter_name) },
|
|
2623
|
+
...routineParameterMode(parameter.mode) === void 0 ? {} : { mode: routineParameterMode(parameter.mode) },
|
|
2624
|
+
storage: storage(parameter.native_type),
|
|
2625
|
+
ordinalPosition: number$1(parameter.ordinal_position) ?? 0,
|
|
2626
|
+
provenance: {
|
|
2627
|
+
kind: "catalog",
|
|
2628
|
+
dialect: "postgresql",
|
|
2629
|
+
reference: physicalReference
|
|
2630
|
+
}
|
|
2631
|
+
}));
|
|
2632
|
+
return {
|
|
2633
|
+
kind: "routine",
|
|
2634
|
+
id: stableId$1((names.get(physicalName) ?? 0) < 2 || identityArguments === void 0 ? physicalName : `${physicalName}_${identityArguments.replace(/[^a-zA-Z0-9_]+/g, "_")}`),
|
|
2635
|
+
identitySource: "physical-name",
|
|
2636
|
+
physicalName,
|
|
2637
|
+
routineKind: routineKind(row.prokind),
|
|
2638
|
+
parameters,
|
|
2639
|
+
...text$1(row.return_type) === void 0 ? {} : { returnType: storage(row.return_type) },
|
|
2640
|
+
...text$1(row.language) === void 0 ? {} : { language: text$1(row.language) },
|
|
2641
|
+
...text$1(row.definition) === void 0 ? {} : { body: expression(text$1(row.definition), "decompiler", physicalReference) },
|
|
2642
|
+
...routineVolatility(row.provolatile) === void 0 ? {} : { volatility: routineVolatility(row.provolatile) },
|
|
2643
|
+
...routineParallel(row.proparallel) === void 0 ? {} : { parallel: routineParallel(row.proparallel) },
|
|
2644
|
+
...row.prosecdef === void 0 || row.prosecdef === null ? {} : { security: boolean$1(row.prosecdef) ? "definer" : "invoker" },
|
|
2645
|
+
...routineUnknownFields.length === 0 ? {} : { unknownFields: routineUnknownFields },
|
|
2646
|
+
reference: physicalReference
|
|
2647
|
+
};
|
|
2648
|
+
});
|
|
2649
|
+
}
|
|
2650
|
+
function partitionObject(row, namespace, tableByOid, diagnostics) {
|
|
2651
|
+
const physicalName = text$1(row.physical_name) ?? `partition_${text$1(row.partition_oid) ?? "unknown"}`;
|
|
2652
|
+
const physicalReference = reference$1("partition", physicalName, text$1(row.namespace) ?? namespace, "pg_class", "oid", row.partition_oid);
|
|
2653
|
+
const parent = tableByOid.get(text$1(row.parent_oid));
|
|
2654
|
+
if (parent === void 0) diagnostics.push(createIntrospectionDiagnostic({
|
|
2655
|
+
severity: "error",
|
|
2656
|
+
code: "unresolved-reference",
|
|
2657
|
+
message: `PostgreSQL partition ${physicalName} has no parent table in the selected schema`,
|
|
2658
|
+
path: [
|
|
2659
|
+
"partitions",
|
|
2660
|
+
physicalName,
|
|
2661
|
+
"parent"
|
|
2662
|
+
],
|
|
2663
|
+
physicalReference,
|
|
2664
|
+
remediation: "Select the parent table schema before mapping partitions."
|
|
2665
|
+
}));
|
|
2666
|
+
const parentReference = parent ? {
|
|
2667
|
+
kind: "table",
|
|
2668
|
+
id: parent.id
|
|
2669
|
+
} : {
|
|
2670
|
+
kind: "table",
|
|
2671
|
+
id: stableId$1(`missing_parent_${text$1(row.parent_oid) ?? "unknown"}`)
|
|
2672
|
+
};
|
|
2673
|
+
const keyColumns = partitionKeyColumns(row.key_attributes, parent?.columns ?? []);
|
|
2674
|
+
const bound = text$1(row.bound);
|
|
2675
|
+
return {
|
|
2676
|
+
kind: "partition",
|
|
2677
|
+
id: stableId$1(physicalName),
|
|
2678
|
+
identitySource: "physical-name",
|
|
2679
|
+
physicalName,
|
|
2680
|
+
parent: parentReference,
|
|
2681
|
+
strategy: partitionStrategy(row.partstrat),
|
|
2682
|
+
...keyColumns.length === 0 ? {} : { keyColumns },
|
|
2683
|
+
...bound === void 0 ? {} : { bound: expression(bound, "decompiler", physicalReference) },
|
|
2684
|
+
...bound !== void 0 && /^default$/i.test(bound.trim()) ? { default: true } : {},
|
|
2685
|
+
reference: physicalReference
|
|
2686
|
+
};
|
|
2687
|
+
}
|
|
2688
|
+
function policyObject(row, namespace, tableByOid, diagnostics) {
|
|
2689
|
+
const physicalName = text$1(row.physical_name) ?? `policy_${text$1(row.oid) ?? "unknown"}`;
|
|
2690
|
+
const physicalReference = reference$1("policy", physicalName, text$1(row.namespace) ?? namespace, "pg_policy", "oid", row.oid);
|
|
2691
|
+
const table = tableByOid.get(text$1(row.table_oid));
|
|
2692
|
+
if (table === void 0) diagnostics.push(createIntrospectionDiagnostic({
|
|
2693
|
+
severity: "error",
|
|
2694
|
+
code: "unresolved-reference",
|
|
2695
|
+
message: `PostgreSQL policy ${physicalName} has no selected table`,
|
|
2696
|
+
path: [
|
|
2697
|
+
"policies",
|
|
2698
|
+
physicalName,
|
|
2699
|
+
"table"
|
|
2700
|
+
],
|
|
2701
|
+
physicalReference,
|
|
2702
|
+
remediation: "Select the policy table schema before mapping row-level security."
|
|
2703
|
+
}));
|
|
2704
|
+
return {
|
|
2705
|
+
kind: "policy",
|
|
2706
|
+
id: stableId$1(physicalName),
|
|
2707
|
+
identitySource: "physical-name",
|
|
2708
|
+
physicalName,
|
|
2709
|
+
table: table ? {
|
|
2710
|
+
kind: "table",
|
|
2711
|
+
id: table.id
|
|
2712
|
+
} : {
|
|
2713
|
+
kind: "table",
|
|
2714
|
+
id: stableId$1(`missing_table_${text$1(row.table_oid) ?? "unknown"}`)
|
|
2715
|
+
},
|
|
2716
|
+
command: policyCommand(row.polcmd),
|
|
2717
|
+
...stringArray(row.roles).length === 0 ? {} : { roles: stringArray(row.roles) },
|
|
2718
|
+
...row.polpermissive === void 0 || row.polpermissive === null ? {} : { permissive: boolean$1(row.polpermissive) },
|
|
2719
|
+
...text$1(row.using_expression) === void 0 ? {} : { using: expression(text$1(row.using_expression), "decompiler", physicalReference) },
|
|
2720
|
+
...text$1(row.check_expression) === void 0 ? {} : { check: expression(text$1(row.check_expression), "decompiler", physicalReference) },
|
|
2721
|
+
reference: physicalReference
|
|
2722
|
+
};
|
|
2723
|
+
}
|
|
2724
|
+
function extensionObject(row, namespace) {
|
|
2725
|
+
const physicalName = text$1(row.physical_name) ?? `extension_${text$1(row.oid) ?? "unknown"}`;
|
|
2726
|
+
const physicalReference = reference$1("extension", physicalName, text$1(row.namespace) ?? namespace, "pg_extension", "oid", row.oid);
|
|
2727
|
+
const data = { relocatable: boolean$1(row.extrelocatable) };
|
|
2728
|
+
const configuration = {};
|
|
2729
|
+
if (text$1(row.config_relations) !== void 0) configuration.relations = text$1(row.config_relations);
|
|
2730
|
+
if (text$1(row.config_conditions) !== void 0) configuration.conditions = text$1(row.config_conditions);
|
|
2731
|
+
return {
|
|
2732
|
+
kind: "extension",
|
|
2733
|
+
id: stableId$1(physicalName),
|
|
2734
|
+
identitySource: "physical-name",
|
|
2735
|
+
physicalName,
|
|
2736
|
+
extensionName: physicalName,
|
|
2737
|
+
...text$1(row.extversion) === void 0 ? {} : { extensionVersion: text$1(row.extversion) },
|
|
2738
|
+
...text$1(row.namespace) === void 0 ? {} : { schema: text$1(row.namespace) },
|
|
2739
|
+
data,
|
|
2740
|
+
...Object.keys(configuration).length === 0 ? {} : { configuration },
|
|
2741
|
+
dialect: {
|
|
2742
|
+
dialect: "postgresql",
|
|
2743
|
+
version: 1,
|
|
2744
|
+
data: { relocatable: boolean$1(row.extrelocatable) }
|
|
2745
|
+
},
|
|
2746
|
+
reference: physicalReference
|
|
2747
|
+
};
|
|
2748
|
+
}
|
|
2749
|
+
function deferredCatalogObject(objectKind, physicalName, physicalReference, unknownFields = []) {
|
|
2750
|
+
return {
|
|
2751
|
+
kind: "deferred-object",
|
|
2752
|
+
objectKind,
|
|
2753
|
+
id: stableId$1(`deferred_${objectKind}_${physicalName}`),
|
|
2754
|
+
identitySource: "physical-name",
|
|
2755
|
+
physicalName,
|
|
2756
|
+
reference: physicalReference,
|
|
2757
|
+
...unknownFields.length === 0 ? {} : { unknownFields }
|
|
2758
|
+
};
|
|
2759
|
+
}
|
|
2760
|
+
function triggerEvents$1(triggerType) {
|
|
2761
|
+
const events = [];
|
|
2762
|
+
if (triggerType & 4) events.push("insert");
|
|
2763
|
+
if (triggerType & 8) events.push("delete");
|
|
2764
|
+
if (triggerType & 16) events.push("update");
|
|
2765
|
+
if (triggerType & 32) events.push("truncate");
|
|
2766
|
+
return events.sort();
|
|
2767
|
+
}
|
|
2768
|
+
function triggerEnabled(value) {
|
|
2769
|
+
const code = text$1(value)?.toUpperCase();
|
|
2770
|
+
if (code === "D") return false;
|
|
2771
|
+
if (code === "O" || code === "R" || code === "A") return true;
|
|
2772
|
+
}
|
|
2773
|
+
function routineKind(value) {
|
|
2774
|
+
return {
|
|
2775
|
+
f: "function",
|
|
2776
|
+
p: "procedure",
|
|
2777
|
+
a: "aggregate",
|
|
2778
|
+
w: "window"
|
|
2779
|
+
}[text$1(value)] ?? "unknown";
|
|
2780
|
+
}
|
|
2781
|
+
function routineParameterMode(value) {
|
|
2782
|
+
return {
|
|
2783
|
+
i: "in",
|
|
2784
|
+
o: "out",
|
|
2785
|
+
b: "inout",
|
|
2786
|
+
v: "variadic",
|
|
2787
|
+
t: "table"
|
|
2788
|
+
}[text$1(value)];
|
|
2789
|
+
}
|
|
2790
|
+
function routineVolatility(value) {
|
|
2791
|
+
return {
|
|
2792
|
+
i: "immutable",
|
|
2793
|
+
s: "stable",
|
|
2794
|
+
v: "volatile"
|
|
2795
|
+
}[text$1(value)];
|
|
2796
|
+
}
|
|
2797
|
+
function routineParallel(value) {
|
|
2798
|
+
return {
|
|
2799
|
+
s: "safe",
|
|
2800
|
+
r: "restricted",
|
|
2801
|
+
u: "unsafe"
|
|
2802
|
+
}[text$1(value)];
|
|
2803
|
+
}
|
|
2804
|
+
function partitionStrategy(value) {
|
|
2805
|
+
return {
|
|
2806
|
+
r: "range",
|
|
2807
|
+
l: "list",
|
|
2808
|
+
h: "hash"
|
|
2809
|
+
}[text$1(value)] ?? "unknown";
|
|
2810
|
+
}
|
|
2811
|
+
function partitionKeyColumns(value, columns) {
|
|
2812
|
+
const byOrdinal = new Map(columns.map((column) => [column.ordinalPosition, column.physicalName]));
|
|
2813
|
+
return integerArray(value).filter((position) => position > 0).map((position) => byOrdinal.get(position) ?? `attnum_${position}`);
|
|
2814
|
+
}
|
|
2815
|
+
function policyCommand(value) {
|
|
2816
|
+
return {
|
|
2817
|
+
"*": "all",
|
|
2818
|
+
r: "select",
|
|
2819
|
+
a: "insert",
|
|
2820
|
+
w: "update",
|
|
2821
|
+
d: "delete"
|
|
2822
|
+
}[text$1(value)] ?? "unknown";
|
|
2823
|
+
}
|
|
2824
|
+
function storage(value) {
|
|
2825
|
+
return { nativeType: text$1(value) ?? "unknown" };
|
|
2826
|
+
}
|
|
2827
|
+
function factIfPresent(value) {
|
|
2828
|
+
if (value === void 0 || value === null) return void 0;
|
|
2829
|
+
return literalFact(value);
|
|
2830
|
+
}
|
|
2831
|
+
function literalFact(value) {
|
|
2832
|
+
if (value === void 0) return void 0;
|
|
2833
|
+
if (value === null) return {
|
|
2834
|
+
kind: "literal",
|
|
2835
|
+
value: null
|
|
2836
|
+
};
|
|
2837
|
+
if (typeof value === "boolean") return {
|
|
2838
|
+
kind: "literal",
|
|
2839
|
+
value
|
|
2840
|
+
};
|
|
2841
|
+
if (typeof value === "bigint") return {
|
|
2842
|
+
kind: "literal",
|
|
2843
|
+
value
|
|
2844
|
+
};
|
|
2845
|
+
if (typeof value === "number") return Number.isFinite(value) ? {
|
|
2846
|
+
kind: "literal",
|
|
2847
|
+
value
|
|
2848
|
+
} : {
|
|
2849
|
+
kind: "literal",
|
|
2850
|
+
value: String(value)
|
|
2851
|
+
};
|
|
2852
|
+
const textValue = String(value);
|
|
2853
|
+
if (/^[+-]?\d+$/.test(textValue.trim())) try {
|
|
2854
|
+
const integerValue = BigInt(textValue);
|
|
2855
|
+
if (integerValue > BigInt(Number.MAX_SAFE_INTEGER) || integerValue < BigInt(Number.MIN_SAFE_INTEGER)) return {
|
|
2856
|
+
kind: "literal",
|
|
2857
|
+
value: integerValue
|
|
2858
|
+
};
|
|
2859
|
+
} catch {}
|
|
2860
|
+
const numericValue = Number(textValue);
|
|
2861
|
+
return textValue.trim() !== "" && Number.isFinite(numericValue) ? {
|
|
2862
|
+
kind: "literal",
|
|
2863
|
+
value: numericValue
|
|
2864
|
+
} : {
|
|
2865
|
+
kind: "literal",
|
|
2866
|
+
value: textValue
|
|
2867
|
+
};
|
|
2868
|
+
}
|
|
2869
|
+
function relationTable(row) {
|
|
2870
|
+
const physicalName = text$1(row.relname) ?? "unnamed_table";
|
|
2871
|
+
return {
|
|
2872
|
+
kind: "table",
|
|
2873
|
+
id: stableId$1(physicalName),
|
|
2874
|
+
identitySource: "physical-name",
|
|
2875
|
+
physicalName,
|
|
2876
|
+
reference: reference$1("table", physicalName, text$1(row.namespace), "pg_class", "oid", row.oid),
|
|
2877
|
+
columns: [],
|
|
2878
|
+
constraints: [],
|
|
2879
|
+
indexes: [],
|
|
2880
|
+
unknownFields: boolean$1(row.relispartition) ? [{
|
|
2881
|
+
name: "partitioned",
|
|
2882
|
+
value: true
|
|
2883
|
+
}] : void 0
|
|
2884
|
+
};
|
|
2885
|
+
}
|
|
2886
|
+
function deferredObject(row, objectKind = "other") {
|
|
2887
|
+
const physicalName = text$1(row.relname) ?? "unnamed_object";
|
|
2888
|
+
return {
|
|
2889
|
+
kind: "deferred-object",
|
|
2890
|
+
objectKind,
|
|
2891
|
+
id: stableId$1(`deferred:${objectKind}:${physicalName}`),
|
|
2892
|
+
identitySource: "physical-name",
|
|
2893
|
+
physicalName,
|
|
2894
|
+
reference: reference$1("deferred-object", physicalName, text$1(row.namespace), "pg_class", "oid", row.oid)
|
|
2895
|
+
};
|
|
2896
|
+
}
|
|
2897
|
+
function opaqueRelationObject(row, namespace, diagnostics) {
|
|
2898
|
+
const physicalName = text$1(row.relname) ?? "unnamed_object";
|
|
2899
|
+
const relkind = text$1(row.relkind) ?? "unknown";
|
|
2900
|
+
const physicalReference = reference$1("opaque-object", physicalName, text$1(row.namespace) ?? namespace, "pg_class", "oid", row.oid);
|
|
2901
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
2902
|
+
severity: "warning",
|
|
2903
|
+
code: "unmodeled-object",
|
|
2904
|
+
message: `PostgreSQL relation ${physicalName} (${relkind}) was retained as an opaque object`,
|
|
2905
|
+
path: ["opaqueObjects", physicalName],
|
|
2906
|
+
physicalReference,
|
|
2907
|
+
remediation: "Inspect the opaque object before treating it as migration input."
|
|
2908
|
+
}));
|
|
2909
|
+
return {
|
|
2910
|
+
kind: "opaque-object",
|
|
2911
|
+
id: stableId$1(`relation:${relkind}:${physicalName}`),
|
|
2912
|
+
identitySource: "physical-name",
|
|
2913
|
+
physicalName,
|
|
2914
|
+
objectKind: `postgres-relation:${relkind}`,
|
|
2915
|
+
data: {
|
|
2916
|
+
relkind,
|
|
2917
|
+
relispartition: boolean$1(row.relispartition)
|
|
2918
|
+
},
|
|
2919
|
+
reference: physicalReference
|
|
2920
|
+
};
|
|
2921
|
+
}
|
|
2922
|
+
function column$1(row, table, namespace, identityOptionValues) {
|
|
2923
|
+
const physicalName = text$1(row.physical_name) ?? "unnamed_column";
|
|
2924
|
+
const defaultExpression = text$1(row.default_expression);
|
|
2925
|
+
const identityValue = text$1(row.attidentity);
|
|
2926
|
+
const generatedValue = text$1(row.attgenerated);
|
|
2927
|
+
const identity = identityValue === "a" || identityValue === "d" ? {
|
|
2928
|
+
kind: "identity",
|
|
2929
|
+
generation: identityValue === "a" ? "always" : "by-default",
|
|
2930
|
+
options: identityOptionValues ?? {}
|
|
2931
|
+
} : void 0;
|
|
2932
|
+
const generated = (generatedValue === "s" || generatedValue === "v") && defaultExpression ? {
|
|
2933
|
+
kind: "generated",
|
|
2934
|
+
mode: generatedValue === "s" ? "stored" : "virtual",
|
|
2935
|
+
expression: sql$1(defaultExpression, namespace, table, physicalName)
|
|
2936
|
+
} : void 0;
|
|
2937
|
+
const ordinaryDefault = defaultExpression && !identity && !generated ? {
|
|
2938
|
+
kind: "expression",
|
|
2939
|
+
expression: sql$1(defaultExpression, namespace, table, physicalName)
|
|
2940
|
+
} : void 0;
|
|
2941
|
+
return {
|
|
2942
|
+
kind: "column",
|
|
2943
|
+
id: stableId$1(physicalName),
|
|
2944
|
+
identitySource: "physical-name",
|
|
2945
|
+
physicalName,
|
|
2946
|
+
ordinalPosition: number$1(row.ordinal_position) ?? 0,
|
|
2947
|
+
nullable: boolean$1(row.nullable),
|
|
2948
|
+
storage: { nativeType: text$1(row.native_type) ?? "unknown" },
|
|
2949
|
+
...ordinaryDefault ? { default: ordinaryDefault } : {},
|
|
2950
|
+
...generated ? { generated } : {},
|
|
2951
|
+
identity,
|
|
2952
|
+
reference: reference$1("column", physicalName, namespace, "pg_attribute", "attrelid", row.table_oid)
|
|
2953
|
+
};
|
|
2954
|
+
}
|
|
2955
|
+
function constraint(row, table, columnsByNumber, tableByOid, namespace, diagnostics, indexReferences) {
|
|
2956
|
+
const kind = text$1(row.contype);
|
|
2957
|
+
const physicalName = text$1(row.physical_name) ?? `constraint_${text$1(row.oid) ?? "unknown"}`;
|
|
2958
|
+
const columns = integerArray(row.conkey).map((numberValue) => columnsByNumber.get(numberValue) ?? `attnum_${numberValue}`);
|
|
2959
|
+
const common = {
|
|
2960
|
+
id: stableId$1(physicalName),
|
|
2961
|
+
identitySource: "physical-name",
|
|
2962
|
+
physicalName,
|
|
2963
|
+
deferrable: boolean$1(row.condeferrable),
|
|
2964
|
+
initially: boolean$1(row.condeferred) ? "deferred" : "immediate",
|
|
2965
|
+
validated: boolean$1(row.convalidated),
|
|
2966
|
+
reference: reference$1("constraint", physicalName, namespace, "pg_constraint", "oid", row.oid),
|
|
2967
|
+
dialect: row.convalidated === false ? {
|
|
2968
|
+
dialect: "postgresql",
|
|
2969
|
+
version: 1,
|
|
2970
|
+
data: { notValid: true }
|
|
2971
|
+
} : void 0
|
|
2972
|
+
};
|
|
2973
|
+
const backingOid = text$1(row.backing_index_oid);
|
|
2974
|
+
const backing = backingOid ? indexReferences.get(`pg_class:${backingOid}`) : void 0;
|
|
2975
|
+
const backingIndex = backing ? {
|
|
2976
|
+
kind: "index",
|
|
2977
|
+
id: backing.id
|
|
2978
|
+
} : void 0;
|
|
2979
|
+
if (kind === "p") return {
|
|
2980
|
+
kind: "primary-key",
|
|
2981
|
+
...common,
|
|
2982
|
+
columns,
|
|
2983
|
+
...backingIndex === void 0 ? {} : { backingIndex }
|
|
2984
|
+
};
|
|
2985
|
+
if (kind === "u") return {
|
|
2986
|
+
kind: "unique",
|
|
2987
|
+
...common,
|
|
2988
|
+
columns,
|
|
2989
|
+
nulls: boolean$1(row.indnullsnotdistinct) ? "not-distinct" : "distinct",
|
|
2990
|
+
...backingIndex === void 0 ? {} : { backingIndex }
|
|
2991
|
+
};
|
|
2992
|
+
if (kind === "c") return {
|
|
2993
|
+
kind: "check",
|
|
2994
|
+
...common,
|
|
2995
|
+
expression: sql$1(text$1(row.definition) ?? "CHECK (true)", namespace, table, physicalName)
|
|
2996
|
+
};
|
|
2997
|
+
if (kind !== "f") return void 0;
|
|
2998
|
+
const targetTable = tableByOid.get(text$1(row.target_table_oid));
|
|
2999
|
+
if (!targetTable) {
|
|
3000
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
3001
|
+
severity: "error",
|
|
3002
|
+
code: "unresolved-reference",
|
|
3003
|
+
message: `PostgreSQL foreign key target ${text$1(row.target_table_oid) ?? "unknown"} was not found`,
|
|
3004
|
+
path: [
|
|
3005
|
+
"tables",
|
|
3006
|
+
table.id,
|
|
3007
|
+
"constraints",
|
|
3008
|
+
physicalName
|
|
3009
|
+
]
|
|
3010
|
+
}));
|
|
3011
|
+
return;
|
|
3012
|
+
}
|
|
3013
|
+
const targetColumns = integerArray(row.confkey).map((numberValue) => {
|
|
3014
|
+
return targetTable.columns.find((column) => column.ordinalPosition === numberValue)?.physicalName ?? `attnum_${numberValue}`;
|
|
3015
|
+
});
|
|
3016
|
+
return {
|
|
3017
|
+
kind: "foreign-key",
|
|
3018
|
+
...common,
|
|
3019
|
+
columns,
|
|
3020
|
+
target: {
|
|
3021
|
+
table: targetTable.physicalName,
|
|
3022
|
+
columns: targetColumns
|
|
3023
|
+
},
|
|
3024
|
+
onUpdate: referentialAction(row.confupdtype),
|
|
3025
|
+
onDelete: referentialAction(row.confdeltype),
|
|
3026
|
+
match: matchType(row.confmatchtype)
|
|
3027
|
+
};
|
|
3028
|
+
}
|
|
3029
|
+
function mapIndexes(rows, table, columnsByNumber, namespace) {
|
|
3030
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
3031
|
+
for (const row of rows) {
|
|
3032
|
+
const key = text$1(row.index_oid) ?? text$1(row.physical_name) ?? "unknown";
|
|
3033
|
+
const existing = grouped.get(key) ?? [];
|
|
3034
|
+
existing.push(row);
|
|
3035
|
+
grouped.set(key, existing);
|
|
3036
|
+
}
|
|
3037
|
+
return [...grouped.values()].map((indexRows) => {
|
|
3038
|
+
const orderedRows = [...indexRows].sort((left, right) => (number$1(left.position) ?? 0) - (number$1(right.position) ?? 0));
|
|
3039
|
+
const first = orderedRows[0];
|
|
3040
|
+
const physicalName = text$1(first.physical_name) ?? `index_${text$1(first.index_oid) ?? "unknown"}`;
|
|
3041
|
+
const keyCount = number$1(first.indnkeyatts) ?? indexRows.length;
|
|
3042
|
+
const terms = [];
|
|
3043
|
+
const includedColumns = [];
|
|
3044
|
+
for (const row of orderedRows) {
|
|
3045
|
+
const position = number$1(row.position) ?? 0;
|
|
3046
|
+
const attnum = number$1(row.attnum) ?? 0;
|
|
3047
|
+
const columnName = attnum > 0 ? columnsByNumber.get(attnum) : void 0;
|
|
3048
|
+
if (position > keyCount) {
|
|
3049
|
+
if (columnName) includedColumns.push(columnName);
|
|
3050
|
+
continue;
|
|
3051
|
+
}
|
|
3052
|
+
terms.push(columnName ? {
|
|
3053
|
+
kind: "column",
|
|
3054
|
+
column: columnName,
|
|
3055
|
+
position,
|
|
3056
|
+
...indexTermOptions(row, text$1(first.method)),
|
|
3057
|
+
...text$1(row.operator_class) === void 0 ? {} : { operatorClass: text$1(row.operator_class) }
|
|
3058
|
+
} : {
|
|
3059
|
+
kind: "expression",
|
|
3060
|
+
expression: sql$1(text$1(row.term_definition) ?? "/* expression unavailable */", namespace, table, physicalName),
|
|
3061
|
+
position,
|
|
3062
|
+
...indexTermOptions(row, text$1(first.method)),
|
|
3063
|
+
...text$1(row.operator_class) === void 0 ? {} : { operatorClass: text$1(row.operator_class) }
|
|
3064
|
+
});
|
|
3065
|
+
}
|
|
3066
|
+
return {
|
|
3067
|
+
kind: "index",
|
|
3068
|
+
id: stableId$1(physicalName),
|
|
3069
|
+
identitySource: "physical-name",
|
|
3070
|
+
physicalName,
|
|
3071
|
+
unique: boolean$1(first.indisunique),
|
|
3072
|
+
terms,
|
|
3073
|
+
predicate: text$1(first.predicate) ? sql$1(text$1(first.predicate), namespace, table, physicalName) : void 0,
|
|
3074
|
+
includedColumns: includedColumns.length > 0 ? includedColumns : void 0,
|
|
3075
|
+
method: text$1(first.method),
|
|
3076
|
+
dialect: text$1(first.method) && text$1(first.method) !== "btree" ? {
|
|
3077
|
+
dialect: "postgresql",
|
|
3078
|
+
version: 1,
|
|
3079
|
+
data: { method: text$1(first.method) }
|
|
3080
|
+
} : void 0,
|
|
3081
|
+
reference: reference$1("index", physicalName, namespace, "pg_class", "oid", first.index_oid)
|
|
3082
|
+
};
|
|
3083
|
+
});
|
|
3084
|
+
}
|
|
3085
|
+
function mapMetadataRows(rows, namespace, tables, views, sequences, enums, domains, collations, routines, triggers, policies, extensions, deferredObjects, opaqueObjects, indexReferences, relationReferences, diagnostics) {
|
|
3086
|
+
const targets = /* @__PURE__ */ new Map();
|
|
3087
|
+
const add = (relation, oid, object, physicalName, objectReference) => {
|
|
3088
|
+
const ref = objectReference ?? reference$1(object.kind, physicalName, namespace, relation, "oid", oid);
|
|
3089
|
+
targets.set(metadataKey(relation, oid, 0), {
|
|
3090
|
+
object,
|
|
3091
|
+
reference: ref,
|
|
3092
|
+
physicalName
|
|
3093
|
+
});
|
|
3094
|
+
};
|
|
3095
|
+
for (const table of tables) if (table.reference?.catalog !== void 0) add("pg_class", table.reference.catalog.value, {
|
|
3096
|
+
kind: "table",
|
|
3097
|
+
id: table.id
|
|
3098
|
+
}, table.physicalName, table.reference);
|
|
3099
|
+
for (const view of views) if (view.reference?.catalog !== void 0) add("pg_class", view.reference.catalog.value, {
|
|
3100
|
+
kind: view.kind,
|
|
3101
|
+
id: view.id
|
|
3102
|
+
}, view.physicalName, view.reference);
|
|
3103
|
+
for (const sequence of sequences) if (sequence.reference?.catalog !== void 0) add("pg_class", sequence.reference.catalog.value, {
|
|
3104
|
+
kind: "sequence",
|
|
3105
|
+
id: sequence.id
|
|
3106
|
+
}, sequence.physicalName, sequence.reference);
|
|
3107
|
+
for (const deferred of deferredObjects) if (deferred.reference?.catalog !== void 0 && deferred.id !== void 0) add("pg_class", deferred.reference.catalog.value, {
|
|
3108
|
+
kind: "deferred-object",
|
|
3109
|
+
id: deferred.id
|
|
3110
|
+
}, deferred.physicalName, deferred.reference);
|
|
3111
|
+
for (const opaque of opaqueObjects) if (opaque.reference?.catalog !== void 0) add("pg_class", opaque.reference.catalog.value, {
|
|
3112
|
+
kind: "opaque-object",
|
|
3113
|
+
id: opaque.id
|
|
3114
|
+
}, opaque.physicalName, opaque.reference);
|
|
3115
|
+
for (const index of indexReferences.values()) if (index.reference?.catalog !== void 0) add("pg_class", index.reference.catalog.value, {
|
|
3116
|
+
kind: "index",
|
|
3117
|
+
id: index.id
|
|
3118
|
+
}, index.physicalName, index.reference);
|
|
3119
|
+
for (const enumObject of enums) if (enumObject.reference?.catalog !== void 0) add("pg_type", enumObject.reference.catalog.value, {
|
|
3120
|
+
kind: "enum",
|
|
3121
|
+
id: enumObject.id
|
|
3122
|
+
}, enumObject.physicalName, enumObject.reference);
|
|
3123
|
+
for (const domain of domains) if (domain.reference?.catalog !== void 0) add("pg_type", domain.reference.catalog.value, {
|
|
3124
|
+
kind: "domain",
|
|
3125
|
+
id: domain.id
|
|
3126
|
+
}, domain.physicalName, domain.reference);
|
|
3127
|
+
for (const collation of collations) if (collation.reference?.catalog !== void 0) add("pg_collation", collation.reference.catalog.value, {
|
|
3128
|
+
kind: "collation",
|
|
3129
|
+
id: collation.id
|
|
3130
|
+
}, collation.physicalName, collation.reference);
|
|
3131
|
+
for (const routine of routines) if (routine.reference?.catalog !== void 0) add("pg_proc", routine.reference.catalog.value, {
|
|
3132
|
+
kind: "routine",
|
|
3133
|
+
id: routine.id
|
|
3134
|
+
}, routine.physicalName, routine.reference);
|
|
3135
|
+
for (const trigger of triggers) if (trigger.reference?.catalog !== void 0) add("pg_trigger", trigger.reference.catalog.value, {
|
|
3136
|
+
kind: "trigger",
|
|
3137
|
+
id: trigger.id
|
|
3138
|
+
}, trigger.physicalName, trigger.reference);
|
|
3139
|
+
for (const policy of policies) if (policy.reference?.catalog !== void 0) add("pg_policy", policy.reference.catalog.value, {
|
|
3140
|
+
kind: "policy",
|
|
3141
|
+
id: policy.id
|
|
3142
|
+
}, policy.physicalName, policy.reference);
|
|
3143
|
+
for (const extension of extensions) if (extension.reference?.catalog !== void 0) add("pg_extension", extension.reference.catalog.value, {
|
|
3144
|
+
kind: "extension",
|
|
3145
|
+
id: extension.id
|
|
3146
|
+
}, extension.physicalName, extension.reference);
|
|
3147
|
+
for (const table of tables) addNestedColumns(targets, "pg_class", table, namespace);
|
|
3148
|
+
for (const view of views) addNestedColumns(targets, "pg_class", view, namespace);
|
|
3149
|
+
for (const table of tables) for (const constraint of table.constraints) if (constraint.reference?.catalog !== void 0) targets.set(metadataKey("pg_constraint", constraint.reference.catalog.value, 0), {
|
|
3150
|
+
object: {
|
|
3151
|
+
kind: "constraint",
|
|
3152
|
+
id: constraint.id
|
|
3153
|
+
},
|
|
3154
|
+
reference: constraint.reference,
|
|
3155
|
+
physicalName: constraint.physicalName ?? constraint.id
|
|
3156
|
+
});
|
|
3157
|
+
for (const domain of domains) for (const constraint of domain.constraints ?? []) if (constraint.reference?.catalog !== void 0) targets.set(metadataKey("pg_constraint", constraint.reference.catalog.value, 0), {
|
|
3158
|
+
object: {
|
|
3159
|
+
kind: "constraint",
|
|
3160
|
+
id: constraint.id
|
|
3161
|
+
},
|
|
3162
|
+
reference: constraint.reference,
|
|
3163
|
+
physicalName: constraint.physicalName ?? constraint.id
|
|
3164
|
+
});
|
|
3165
|
+
const comments = [];
|
|
3166
|
+
const ownership = [];
|
|
3167
|
+
const opaque = [];
|
|
3168
|
+
for (const [index, row] of rows.entries()) {
|
|
3169
|
+
const relation = text$1(row.catalog_relation) ?? "unknown";
|
|
3170
|
+
const oid = text$1(row.object_oid);
|
|
3171
|
+
const subid = number$1(row.object_subid) ?? 0;
|
|
3172
|
+
const target = targets.get(metadataKey(relation, oid, subid));
|
|
3173
|
+
if (target === void 0) {
|
|
3174
|
+
const unknownReference = reference$1("opaque-object", text$1(row.object_name) ?? `metadata_${oid ?? "unknown"}`, text$1(row.namespace) ?? namespace, relation, "oid", oid);
|
|
3175
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
3176
|
+
severity: "warning",
|
|
3177
|
+
code: "unmodeled-object",
|
|
3178
|
+
message: `PostgreSQL metadata row for ${text$1(row.object_name) ?? "unknown object"} could not be attached to a normalized object`,
|
|
3179
|
+
path: ["metadata", index],
|
|
3180
|
+
physicalReference: unknownReference,
|
|
3181
|
+
remediation: "Inspect the retained opaque metadata record before using it as migration input."
|
|
3182
|
+
}));
|
|
3183
|
+
opaque.push({
|
|
3184
|
+
kind: "opaque-object",
|
|
3185
|
+
id: stableId$1(`metadata_${relation}_${oid ?? "unknown"}_${subid}`),
|
|
3186
|
+
identitySource: "physical-name",
|
|
3187
|
+
physicalName: text$1(row.object_name) ?? `metadata_${oid ?? "unknown"}`,
|
|
3188
|
+
objectKind: `postgres-metadata:${text$1(row.object_kind) ?? "unknown"}`,
|
|
3189
|
+
data: {
|
|
3190
|
+
catalogRelation: relation,
|
|
3191
|
+
objectOid: oid ?? "unknown",
|
|
3192
|
+
objectSubid: subid,
|
|
3193
|
+
...text$1(row.description) === void 0 ? {} : { description: text$1(row.description) },
|
|
3194
|
+
...text$1(row.owner) === void 0 ? {} : { owner: text$1(row.owner) }
|
|
3195
|
+
},
|
|
3196
|
+
reference: unknownReference
|
|
3197
|
+
});
|
|
3198
|
+
continue;
|
|
3199
|
+
}
|
|
3200
|
+
const description = text$1(row.description);
|
|
3201
|
+
if (description !== void 0) comments.push({
|
|
3202
|
+
kind: "comment",
|
|
3203
|
+
id: stableId$1(`${target.object.kind}_${target.object.id}_comment`),
|
|
3204
|
+
object: target.object,
|
|
3205
|
+
text: description,
|
|
3206
|
+
reference: target.reference,
|
|
3207
|
+
provenance: {
|
|
3208
|
+
kind: "catalog",
|
|
3209
|
+
dialect: "postgresql",
|
|
3210
|
+
reference: target.reference
|
|
3211
|
+
}
|
|
3212
|
+
});
|
|
3213
|
+
const owner = text$1(row.owner);
|
|
3214
|
+
if (owner !== void 0) ownership.push({
|
|
3215
|
+
kind: "ownership",
|
|
3216
|
+
id: stableId$1(`${target.object.kind}_${target.object.id}_ownership`),
|
|
3217
|
+
object: target.object,
|
|
3218
|
+
owner,
|
|
3219
|
+
reference: target.reference,
|
|
3220
|
+
provenance: {
|
|
3221
|
+
kind: "catalog",
|
|
3222
|
+
dialect: "postgresql",
|
|
3223
|
+
reference: target.reference
|
|
3224
|
+
}
|
|
3225
|
+
});
|
|
3226
|
+
}
|
|
3227
|
+
return {
|
|
3228
|
+
comments,
|
|
3229
|
+
ownership,
|
|
3230
|
+
opaqueObjects: opaque
|
|
3231
|
+
};
|
|
3232
|
+
}
|
|
3233
|
+
function addNestedColumns(targets, relation, owner, namespace) {
|
|
3234
|
+
const tableOid = owner.reference?.catalog?.value;
|
|
3235
|
+
if (tableOid === void 0) return;
|
|
3236
|
+
for (const column of owner.columns) targets.set(metadataKey(relation, tableOid, column.ordinalPosition), {
|
|
3237
|
+
object: {
|
|
3238
|
+
kind: "column",
|
|
3239
|
+
id: column.id
|
|
3240
|
+
},
|
|
3241
|
+
reference: column.reference ?? reference$1("column", column.physicalName, namespace, "pg_attribute", "attrelid", tableOid),
|
|
3242
|
+
physicalName: column.physicalName
|
|
3243
|
+
});
|
|
3244
|
+
}
|
|
3245
|
+
function metadataKey(relation, oid, subid) {
|
|
3246
|
+
return `${relation}:${text$1(oid) ?? "unknown"}:${number$1(subid) ?? 0}`;
|
|
3247
|
+
}
|
|
3248
|
+
function indexTermOptions(row, method) {
|
|
3249
|
+
const option = number$1(row.indoption);
|
|
3250
|
+
if (method !== "btree" || option === void 0) return {};
|
|
3251
|
+
return {
|
|
3252
|
+
direction: option & 1 ? "DESC" : "ASC",
|
|
3253
|
+
nulls: option & 2 ? "FIRST" : "LAST"
|
|
3254
|
+
};
|
|
3255
|
+
}
|
|
3256
|
+
function sql$1(textValue, namespace, owner, name) {
|
|
3257
|
+
return expression(textValue, "decompiler", owner.reference ?? reference$1("table", name, namespace, "pg_class", "relname", owner.physicalName));
|
|
3258
|
+
}
|
|
3259
|
+
function expression(textValue, provenanceKind, physicalReference) {
|
|
3260
|
+
return {
|
|
3261
|
+
kind: "sql",
|
|
3262
|
+
dialect: "postgresql",
|
|
3263
|
+
text: textValue,
|
|
3264
|
+
provenance: {
|
|
3265
|
+
kind: provenanceKind,
|
|
3266
|
+
dialect: "postgresql",
|
|
3267
|
+
...physicalReference === void 0 ? {} : { reference: physicalReference }
|
|
3268
|
+
}
|
|
3269
|
+
};
|
|
3270
|
+
}
|
|
3271
|
+
function reference$1(kind, name, namespace, relation, key, value = name) {
|
|
3272
|
+
return {
|
|
3273
|
+
kind,
|
|
3274
|
+
name,
|
|
3275
|
+
namespace,
|
|
3276
|
+
catalog: {
|
|
3277
|
+
relation,
|
|
3278
|
+
key,
|
|
3279
|
+
value: typeof value === "number" ? value : String(value)
|
|
3280
|
+
}
|
|
3281
|
+
};
|
|
3282
|
+
}
|
|
3283
|
+
function stableId$1(value) {
|
|
3284
|
+
if (value.length > 0 && !/[.\\\u0000-\u001f\u007f]/.test(value)) return value;
|
|
3285
|
+
let hash = 2166136261;
|
|
3286
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
3287
|
+
hash ^= value.charCodeAt(index);
|
|
3288
|
+
hash = Math.imul(hash, 16777619);
|
|
3289
|
+
}
|
|
3290
|
+
return `introspected_${(hash >>> 0).toString(16)}`;
|
|
3291
|
+
}
|
|
3292
|
+
function groupBy(rows, key) {
|
|
3293
|
+
const result = /* @__PURE__ */ new Map();
|
|
3294
|
+
for (const row of rows) {
|
|
3295
|
+
const value = key(row);
|
|
3296
|
+
const group = result.get(value) ?? [];
|
|
3297
|
+
group.push(row);
|
|
3298
|
+
result.set(value, group);
|
|
3299
|
+
}
|
|
3300
|
+
return result;
|
|
3301
|
+
}
|
|
3302
|
+
function text$1(value) {
|
|
3303
|
+
return value === null || value === void 0 ? void 0 : String(value);
|
|
3304
|
+
}
|
|
3305
|
+
function number$1(value) {
|
|
3306
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
3307
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
3308
|
+
const parsed = Number(value);
|
|
3309
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
3310
|
+
}
|
|
3311
|
+
}
|
|
3312
|
+
function boolean$1(value) {
|
|
3313
|
+
return value === true || value === "t" || value === "true" || value === 1;
|
|
3314
|
+
}
|
|
3315
|
+
function stringArray(value) {
|
|
3316
|
+
if (Array.isArray(value)) return value.map((item) => text$1(item)).filter((item) => item !== void 0);
|
|
3317
|
+
const source = text$1(value)?.trim();
|
|
3318
|
+
if (source === void 0 || source === "") return [];
|
|
3319
|
+
if (source.startsWith("{") && source.endsWith("}")) {
|
|
3320
|
+
const values = [];
|
|
3321
|
+
let current = "";
|
|
3322
|
+
let quoted = false;
|
|
3323
|
+
let escaped = false;
|
|
3324
|
+
for (const character of source.slice(1, -1)) if (escaped) {
|
|
3325
|
+
current += character;
|
|
3326
|
+
escaped = false;
|
|
3327
|
+
} else if (character === "\\" && quoted) escaped = true;
|
|
3328
|
+
else if (character === "\"") quoted = !quoted;
|
|
3329
|
+
else if (character === "," && !quoted) {
|
|
3330
|
+
values.push(current);
|
|
3331
|
+
current = "";
|
|
3332
|
+
} else current += character;
|
|
3333
|
+
if (current !== "" || source !== "{}") values.push(current);
|
|
3334
|
+
return values.filter((value) => value !== "");
|
|
3335
|
+
}
|
|
3336
|
+
return source.split(",").map((item) => item.trim()).filter((item) => item !== "");
|
|
3337
|
+
}
|
|
3338
|
+
function booleanOption(options, name) {
|
|
3339
|
+
const value = options.find((option) => option.startsWith(`${name}=`));
|
|
3340
|
+
if (value === void 0) return void 0;
|
|
3341
|
+
const setting = value.slice(name.length + 1).toLowerCase();
|
|
3342
|
+
if (setting === "true" || setting === "on" || setting === "yes") return true;
|
|
3343
|
+
if (setting === "false" || setting === "off" || setting === "no") return false;
|
|
3344
|
+
}
|
|
3345
|
+
function integerArray(value) {
|
|
3346
|
+
if (Array.isArray(value)) return value.map((item) => number$1(item) ?? 0);
|
|
3347
|
+
const parsed = text$1(value)?.replace(/[{}]/g, "").trim();
|
|
3348
|
+
if (!parsed) return [];
|
|
3349
|
+
return parsed.split(",").map((item) => number$1(item.trim()) ?? 0);
|
|
3350
|
+
}
|
|
3351
|
+
function referentialAction(value) {
|
|
3352
|
+
return {
|
|
3353
|
+
a: "no-action",
|
|
3354
|
+
r: "restrict",
|
|
3355
|
+
c: "cascade",
|
|
3356
|
+
n: "set-null",
|
|
3357
|
+
d: "set-default"
|
|
3358
|
+
}[text$1(value)];
|
|
3359
|
+
}
|
|
3360
|
+
function matchType(value) {
|
|
3361
|
+
return {
|
|
3362
|
+
s: "simple",
|
|
3363
|
+
f: "full",
|
|
3364
|
+
p: "partial"
|
|
3365
|
+
}[text$1(value)];
|
|
3366
|
+
}
|
|
3367
|
+
//#endregion
|
|
3368
|
+
//#region src/introspection/sqlite.ts
|
|
3369
|
+
const sqliteServerQuery = `SELECT sqlite_version() AS version, sqlite_source_id() AS source_id`;
|
|
3370
|
+
const sqliteDatabaseListQuery = `
|
|
3371
|
+
SELECT seq, name, file
|
|
3372
|
+
FROM pragma_database_list()
|
|
3373
|
+
ORDER BY seq
|
|
3374
|
+
`;
|
|
3375
|
+
const sqliteSchemaQuery = `
|
|
3376
|
+
SELECT type, name, tbl_name, sql
|
|
3377
|
+
FROM main.sqlite_schema
|
|
3378
|
+
WHERE name NOT LIKE 'sqlite_%'
|
|
3379
|
+
ORDER BY type, name
|
|
3380
|
+
`;
|
|
3381
|
+
const sqliteTempSchemaQuery = `
|
|
3382
|
+
SELECT type, name, tbl_name, sql
|
|
3383
|
+
FROM temp.sqlite_schema
|
|
3384
|
+
WHERE name NOT LIKE 'sqlite_%'
|
|
3385
|
+
ORDER BY type, name
|
|
3386
|
+
`;
|
|
3387
|
+
const sqliteTableListQuery = `
|
|
3388
|
+
SELECT schema, name, type, ncol, wr, strict
|
|
3389
|
+
FROM pragma_table_list
|
|
3390
|
+
WHERE schema = ? AND name NOT LIKE 'sqlite_%'
|
|
3391
|
+
ORDER BY name
|
|
3392
|
+
`;
|
|
3393
|
+
const sqliteTableInfoQuery = `
|
|
3394
|
+
SELECT cid, name, type, "notnull" AS not_null, dflt_value, pk, hidden
|
|
3395
|
+
FROM pragma_table_xinfo(?, ?)
|
|
3396
|
+
ORDER BY cid
|
|
3397
|
+
`;
|
|
3398
|
+
const sqliteIndexListQuery = `
|
|
3399
|
+
SELECT seq, name, "unique" AS unique_index, origin, partial
|
|
3400
|
+
FROM pragma_index_list(?, ?)
|
|
3401
|
+
ORDER BY seq
|
|
3402
|
+
`;
|
|
3403
|
+
const sqliteIndexInfoQuery = `
|
|
3404
|
+
SELECT seqno, cid, name, "desc" AS descending, coll, key
|
|
3405
|
+
FROM pragma_index_xinfo(?, ?)
|
|
3406
|
+
ORDER BY seqno
|
|
3407
|
+
`;
|
|
3408
|
+
const sqliteForeignKeyQuery = `
|
|
3409
|
+
SELECT id, seq, "table" AS target_table, "from" AS source_column,
|
|
3410
|
+
"to" AS target_column, on_update, on_delete, match
|
|
3411
|
+
FROM pragma_foreign_key_list(?, ?)
|
|
3412
|
+
ORDER BY id, seq
|
|
3413
|
+
`;
|
|
3414
|
+
/** Read the selected SQLite database namespace into the normalized catalog. */
|
|
3415
|
+
async function readSqliteCatalog(connection, options) {
|
|
3416
|
+
const diagnostics = [];
|
|
3417
|
+
if (connection.dialect !== "sqlite") {
|
|
3418
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
3419
|
+
severity: "error",
|
|
3420
|
+
code: "dialect-mismatch",
|
|
3421
|
+
message: "SQLite catalog reading requires a SQLite CatalogConnection",
|
|
3422
|
+
path: ["connection", "dialect"]
|
|
3423
|
+
}));
|
|
3424
|
+
return emptyCatalog(options.namespace, diagnostics);
|
|
3425
|
+
}
|
|
3426
|
+
const serverRows = await query(connection, sqliteServerQuery, [], options, diagnostics, "server");
|
|
3427
|
+
const server = serverInfo(serverRows[0], diagnostics);
|
|
3428
|
+
const databaseRows = await query(connection, sqliteDatabaseListQuery, [], options, diagnostics, "database-list");
|
|
3429
|
+
const databaseNames = databaseRows.map((row) => text(row.name)).filter((name) => name !== void 0);
|
|
3430
|
+
if (databaseNames.length > 0 && !databaseNames.includes(options.namespace)) diagnostics.push(createIntrospectionDiagnostic({
|
|
3431
|
+
severity: "error",
|
|
3432
|
+
code: "missing-catalog-row",
|
|
3433
|
+
message: `SQLite database ${options.namespace} is not attached to the selected connection`,
|
|
3434
|
+
path: ["namespace", options.namespace],
|
|
3435
|
+
remediation: "Attach the database before starting introspection."
|
|
3436
|
+
}));
|
|
3437
|
+
const schemaRows = options.namespace === "main" || options.namespace === "temp" ? await query(connection, options.namespace === "temp" ? sqliteTempSchemaQuery : sqliteSchemaQuery, [], options, diagnostics, "schema") : [];
|
|
3438
|
+
if (options.namespace !== "main" && options.namespace !== "temp" && databaseNames.includes(options.namespace)) diagnostics.push(createIntrospectionDiagnostic({
|
|
3439
|
+
severity: "warning",
|
|
3440
|
+
code: "partial-result",
|
|
3441
|
+
message: `SQLite attached database ${options.namespace} exposes table PRAGMAs but its schema SQL is outside the fixed main/temp catalog statements`,
|
|
3442
|
+
path: [
|
|
3443
|
+
"namespace",
|
|
3444
|
+
options.namespace,
|
|
3445
|
+
"schema"
|
|
3446
|
+
],
|
|
3447
|
+
remediation: "Use a driver adapter that exposes the attached schema through a fixed statement before relying on generated SQL."
|
|
3448
|
+
}));
|
|
3449
|
+
const tableRows = await query(connection, sqliteTableListQuery, [options.namespace], options, diagnostics, "table-list");
|
|
3450
|
+
const tableSql = new Map(schemaRows.map((row) => [text(row.name), text(row.sql)]).filter((entry) => entry[0] !== void 0));
|
|
3451
|
+
const tables = tableRows.filter((row) => normalizeType(row.type) === "table").map((row) => table(row, tableSql.get(text(row.name) ?? "") ?? void 0, options.namespace));
|
|
3452
|
+
const deferredObjects = [];
|
|
3453
|
+
const opaqueObjects = [];
|
|
3454
|
+
for (const row of tableRows) {
|
|
3455
|
+
const type = normalizeType(row.type);
|
|
3456
|
+
if (type !== "virtual" && type !== "shadow") continue;
|
|
3457
|
+
const physicalName = text(row.name) ?? "unnamed_object";
|
|
3458
|
+
deferredObjects.push(deferred(type === "virtual" ? "virtual-table" : "shadow-table", physicalName, tableSql.get(physicalName), options.namespace));
|
|
3459
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
3460
|
+
severity: "warning",
|
|
3461
|
+
code: "unmodeled-object",
|
|
3462
|
+
message: `SQLite ${type} table ${physicalName} is retained as a deferred object`,
|
|
3463
|
+
path: ["deferredObjects", physicalName],
|
|
3464
|
+
physicalReference: reference("deferred-object", physicalName, options.namespace, "pragma_table_list", "name"),
|
|
3465
|
+
remediation: "Inspect the deferred record before using it as migration input."
|
|
3466
|
+
}));
|
|
3467
|
+
}
|
|
3468
|
+
for (const row of databaseRows) {
|
|
3469
|
+
const name = text(row.name);
|
|
3470
|
+
if (!name || name === options.namespace || name === "main" || name === "temp") continue;
|
|
3471
|
+
const boundary = attachedDatabaseObject(row, options.namespace);
|
|
3472
|
+
opaqueObjects.push(boundary);
|
|
3473
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
3474
|
+
severity: "info",
|
|
3475
|
+
code: "partial-result",
|
|
3476
|
+
message: `Attached SQLite database ${name} is outside the selected namespace`,
|
|
3477
|
+
path: [
|
|
3478
|
+
"namespace",
|
|
3479
|
+
"attached",
|
|
3480
|
+
name
|
|
3481
|
+
],
|
|
3482
|
+
physicalReference: boundary.reference,
|
|
3483
|
+
remediation: "Run a separate catalog read with this database name to inspect it."
|
|
3484
|
+
}));
|
|
3485
|
+
}
|
|
3486
|
+
const views = [];
|
|
3487
|
+
for (const row of tableRows.filter((row) => normalizeType(row.type) === "view")) {
|
|
3488
|
+
const physicalName = text(row.name) ?? "unnamed_view";
|
|
3489
|
+
const view = sqliteView(row, tableSql.get(physicalName), options.namespace, diagnostics);
|
|
3490
|
+
if (view.kind === "deferred-object") deferredObjects.push(view);
|
|
3491
|
+
else views.push(view);
|
|
3492
|
+
}
|
|
3493
|
+
const relationReferences = /* @__PURE__ */ new Map();
|
|
3494
|
+
for (const table of tables) relationReferences.set(table.physicalName, {
|
|
3495
|
+
kind: "table",
|
|
3496
|
+
id: table.id
|
|
3497
|
+
});
|
|
3498
|
+
for (const view of views) relationReferences.set(view.physicalName, {
|
|
3499
|
+
kind: view.kind,
|
|
3500
|
+
id: view.id
|
|
3501
|
+
});
|
|
3502
|
+
const triggers = [];
|
|
3503
|
+
for (const currentTable of tables) {
|
|
3504
|
+
const tableName = currentTable.physicalName;
|
|
3505
|
+
const rows = await query(connection, sqliteTableInfoQuery, [tableName, options.namespace], options, diagnostics, `table-xinfo:${tableName}`);
|
|
3506
|
+
const sqlText = tableSql.get(tableName);
|
|
3507
|
+
const rowidPrimaryKey = rows.filter((row) => (number(row.pk) ?? 0) > 0).length === 1;
|
|
3508
|
+
const columns = rows.filter((row) => number(row.hidden) !== 1).map((row) => column(row, currentTable, options.namespace, sqlText, rowidPrimaryKey, diagnostics));
|
|
3509
|
+
currentTable.columns = columns;
|
|
3510
|
+
currentTable.constraints = tableConstraints(currentTable, rows, columns, sqlText, options.namespace);
|
|
3511
|
+
const indexRows = await query(connection, sqliteIndexListQuery, [tableName, options.namespace], options, diagnostics, `index-list:${tableName}`);
|
|
3512
|
+
const mappedIndexes = [];
|
|
3513
|
+
const mappedConstraints = [...currentTable.constraints];
|
|
3514
|
+
for (const indexRow of indexRows) {
|
|
3515
|
+
const indexName = text(indexRow.name);
|
|
3516
|
+
if (!indexName || indexName.startsWith("sqlite_autoindex_") && text(indexRow.origin)?.toLowerCase() !== "u") continue;
|
|
3517
|
+
const index = sqliteIndex(currentTable, indexRow, await query(connection, sqliteIndexInfoQuery, [indexName, options.namespace], options, diagnostics, `index-info:${indexName}`), tableSql.get(indexName), options.namespace, diagnostics, opaqueObjects);
|
|
3518
|
+
if (!index) continue;
|
|
3519
|
+
if (index.kind === "index") mappedIndexes.push(index);
|
|
3520
|
+
else mappedConstraints.push(index);
|
|
3521
|
+
}
|
|
3522
|
+
const foreignRows = await query(connection, sqliteForeignKeyQuery, [tableName, options.namespace], options, diagnostics, `foreign-key:${tableName}`);
|
|
3523
|
+
mappedConstraints.push(...foreignKeys(currentTable, foreignRows, options.namespace));
|
|
3524
|
+
currentTable.indexes = mappedIndexes;
|
|
3525
|
+
currentTable.constraints = mappedConstraints;
|
|
3526
|
+
}
|
|
3527
|
+
for (const view of views) view.columns = (await query(connection, sqliteTableInfoQuery, [view.physicalName, options.namespace], options, diagnostics, `view-xinfo:${view.physicalName}`)).filter((row) => number(row.hidden) !== 1).map((row) => column(row, view, options.namespace, void 0, false, diagnostics));
|
|
3528
|
+
for (const row of schemaRows.filter((row) => normalizeType(row.type) === "trigger")) {
|
|
3529
|
+
const trigger = sqliteTrigger(row, options.namespace, relationReferences, diagnostics);
|
|
3530
|
+
if (trigger.kind === "deferred-object") deferredObjects.push(trigger);
|
|
3531
|
+
else triggers.push(trigger);
|
|
3532
|
+
}
|
|
3533
|
+
for (const row of schemaRows) {
|
|
3534
|
+
const type = normalizeType(row.type);
|
|
3535
|
+
if (type === "table" || type === "view" || type === "trigger" || type === "index") continue;
|
|
3536
|
+
const physicalName = text(row.name) ?? "unnamed_object";
|
|
3537
|
+
opaqueObjects.push(opaqueSchemaObject(row, options.namespace, diagnostics));
|
|
3538
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
3539
|
+
severity: "warning",
|
|
3540
|
+
code: "unmodeled-object",
|
|
3541
|
+
message: `SQLite schema object ${physicalName} (${type || "unknown"}) is retained as opaque data`,
|
|
3542
|
+
path: ["opaqueObjects", physicalName],
|
|
3543
|
+
physicalReference: reference("opaque-object", physicalName, options.namespace, "sqlite_schema", "name")
|
|
3544
|
+
}));
|
|
3545
|
+
}
|
|
3546
|
+
const visibility = databaseRows.length > 0 && options.namespace !== "main" && options.namespace !== "temp" ? "limited" : server.capabilities.visibility;
|
|
3547
|
+
const capabilities = {
|
|
3548
|
+
generatedColumns: server.capabilities.generatedColumns,
|
|
3549
|
+
identityMetadata: server.capabilities.identityMetadata,
|
|
3550
|
+
checkConstraints: server.capabilities.checkConstraints,
|
|
3551
|
+
checkConstraintEnforcement: server.capabilities.checkConstraintEnforcement,
|
|
3552
|
+
expressionDecompilation: server.capabilities.expressionDecompilation,
|
|
3553
|
+
indexExpressions: server.capabilities.indexExpressions,
|
|
3554
|
+
indexPredicates: server.capabilities.indexPredicates,
|
|
3555
|
+
indexIncludedColumns: server.capabilities.indexIncludedColumns,
|
|
3556
|
+
namespaces: server.capabilities.namespaces,
|
|
3557
|
+
visibility
|
|
3558
|
+
};
|
|
3559
|
+
const serverCapabilities = {
|
|
3560
|
+
...server.capabilities,
|
|
3561
|
+
attachedDatabases: true,
|
|
3562
|
+
views: true,
|
|
3563
|
+
triggers: true,
|
|
3564
|
+
virtualTables: true,
|
|
3565
|
+
shadowTables: true,
|
|
3566
|
+
comments: false,
|
|
3567
|
+
ownership: false,
|
|
3568
|
+
typedExtensions: true,
|
|
3569
|
+
affinityFacts: true,
|
|
3570
|
+
generatedSql: true,
|
|
3571
|
+
selectedNamespace: options.namespace,
|
|
3572
|
+
visibility
|
|
3573
|
+
};
|
|
3574
|
+
return Object.freeze({
|
|
3575
|
+
dialect: "sqlite",
|
|
3576
|
+
server: {
|
|
3577
|
+
...server,
|
|
3578
|
+
capabilities: serverCapabilities
|
|
3579
|
+
},
|
|
3580
|
+
namespace: {
|
|
3581
|
+
kind: "sqlite-database",
|
|
3582
|
+
name: options.namespace,
|
|
3583
|
+
reference: reference("namespace", options.namespace, options.namespace, "sqlite_schema", "name"),
|
|
3584
|
+
dialect: sqliteExtension({
|
|
3585
|
+
selectedNamespace: options.namespace,
|
|
3586
|
+
sourceIdAvailable: serverSourceIdAvailable(serverRows[0]),
|
|
3587
|
+
views: true,
|
|
3588
|
+
triggers: true,
|
|
3589
|
+
virtualTables: true,
|
|
3590
|
+
shadowTables: true,
|
|
3591
|
+
comments: false,
|
|
3592
|
+
ownership: false,
|
|
3593
|
+
typedExtensions: true,
|
|
3594
|
+
affinityFacts: true,
|
|
3595
|
+
generatedSql: true,
|
|
3596
|
+
visibility,
|
|
3597
|
+
attachedDatabases: databaseNames.filter((name) => name !== options.namespace)
|
|
3598
|
+
})
|
|
3599
|
+
},
|
|
3600
|
+
tables: Object.freeze(tables),
|
|
3601
|
+
views: Object.freeze(views),
|
|
3602
|
+
triggers: Object.freeze(triggers),
|
|
3603
|
+
deferredObjects: Object.freeze(deferredObjects),
|
|
3604
|
+
opaqueObjects: Object.freeze(opaqueObjects),
|
|
3605
|
+
capabilities,
|
|
3606
|
+
diagnostics: Object.freeze(diagnostics)
|
|
3607
|
+
});
|
|
3608
|
+
}
|
|
3609
|
+
async function query(connection, textValue, parameters, options, diagnostics, operation) {
|
|
3610
|
+
try {
|
|
3611
|
+
return await connection.query({
|
|
3612
|
+
text: textValue,
|
|
3613
|
+
parameters
|
|
3614
|
+
}, { signal: options.signal });
|
|
3615
|
+
} catch {
|
|
3616
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
3617
|
+
severity: "error",
|
|
3618
|
+
code: "query-failed",
|
|
3619
|
+
message: `SQLite catalog query failed while reading ${operation}`,
|
|
3620
|
+
path: [operation],
|
|
3621
|
+
remediation: "Check SQLite metadata visibility and the selected database."
|
|
3622
|
+
}));
|
|
3623
|
+
return [];
|
|
3624
|
+
}
|
|
3625
|
+
}
|
|
3626
|
+
function serverInfo(row, diagnostics) {
|
|
3627
|
+
const rawVersion = text(row?.version) ?? "unknown";
|
|
3628
|
+
const parts = rawVersion.split(".").map((item) => Number(item));
|
|
3629
|
+
const supported = parts.length >= 2 && parts[0] === 3 && parts[1] >= 37;
|
|
3630
|
+
if (!supported) diagnostics.push(createIntrospectionDiagnostic({
|
|
3631
|
+
severity: "error",
|
|
3632
|
+
code: "unsupported-server",
|
|
3633
|
+
message: "SQLite introspection requires SQLite 3.37 or newer",
|
|
3634
|
+
path: ["server", "version"],
|
|
3635
|
+
remediation: "Use SQLite 3.37+ or provide a compatible adapter capability set."
|
|
3636
|
+
}));
|
|
3637
|
+
return {
|
|
3638
|
+
product: "sqlite",
|
|
3639
|
+
rawVersion,
|
|
3640
|
+
parsedVersion: Number.isFinite(parts[0]) ? {
|
|
3641
|
+
major: parts[0],
|
|
3642
|
+
minor: parts[1],
|
|
3643
|
+
patch: parts[2]
|
|
3644
|
+
} : void 0,
|
|
3645
|
+
capabilities: {
|
|
3646
|
+
generatedColumns: supported,
|
|
3647
|
+
identityMetadata: true,
|
|
3648
|
+
checkConstraints: true,
|
|
3649
|
+
checkConstraintEnforcement: "enforced",
|
|
3650
|
+
expressionDecompilation: false,
|
|
3651
|
+
indexExpressions: true,
|
|
3652
|
+
indexPredicates: true,
|
|
3653
|
+
indexIncludedColumns: false,
|
|
3654
|
+
namespaces: false,
|
|
3655
|
+
visibility: "complete",
|
|
3656
|
+
sourceIdAvailable: text(row?.source_id) !== void 0
|
|
3657
|
+
}
|
|
3658
|
+
};
|
|
3659
|
+
}
|
|
3660
|
+
function serverSourceIdAvailable(row) {
|
|
3661
|
+
return text(row?.source_id) !== void 0;
|
|
3662
|
+
}
|
|
3663
|
+
function normalizeType(value) {
|
|
3664
|
+
return text(value)?.trim().toLowerCase() ?? "";
|
|
3665
|
+
}
|
|
3666
|
+
function sqliteView(row, sqlText, namespace, diagnostics) {
|
|
3667
|
+
const physicalName = text(row.name) ?? "unnamed_view";
|
|
3668
|
+
const physicalReference = reference("view", physicalName, namespace, "sqlite_schema", "name");
|
|
3669
|
+
const definition = viewDefinition(sqlText);
|
|
3670
|
+
if (!definition) {
|
|
3671
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
3672
|
+
severity: "error",
|
|
3673
|
+
code: "expression-parse-failed",
|
|
3674
|
+
message: `SQLite view ${physicalName} has no recoverable SELECT definition`,
|
|
3675
|
+
path: [
|
|
3676
|
+
"views",
|
|
3677
|
+
physicalName,
|
|
3678
|
+
"definition"
|
|
3679
|
+
],
|
|
3680
|
+
physicalReference,
|
|
3681
|
+
remediation: "Preserve the CREATE VIEW SQL returned by sqlite_schema."
|
|
3682
|
+
}));
|
|
3683
|
+
return deferred("view", physicalName, sqlText, namespace);
|
|
3684
|
+
}
|
|
3685
|
+
return {
|
|
3686
|
+
kind: "view",
|
|
3687
|
+
id: stableId(physicalName),
|
|
3688
|
+
identitySource: "physical-name",
|
|
3689
|
+
physicalName,
|
|
3690
|
+
columns: [],
|
|
3691
|
+
definition: sql(definition, namespace, {
|
|
3692
|
+
kind: "view",
|
|
3693
|
+
physicalName,
|
|
3694
|
+
reference: physicalReference
|
|
3695
|
+
}, physicalName),
|
|
3696
|
+
reference: physicalReference,
|
|
3697
|
+
provenance: {
|
|
3698
|
+
kind: "create-sql",
|
|
3699
|
+
dialect: "sqlite",
|
|
3700
|
+
reference: physicalReference
|
|
3701
|
+
},
|
|
3702
|
+
dialect: sqliteExtension({ objectKind: "view" })
|
|
3703
|
+
};
|
|
3704
|
+
}
|
|
3705
|
+
function viewDefinition(sqlText) {
|
|
3706
|
+
if (!sqlText) return void 0;
|
|
3707
|
+
return sqlText.match(/\bAS\b([\s\S]*)$/i)?.[1]?.trim().replace(/;\s*$/, "") || void 0;
|
|
3708
|
+
}
|
|
3709
|
+
function attachedDatabaseObject(row, selectedNamespace) {
|
|
3710
|
+
const physicalName = text(row.name) ?? "unnamed_database";
|
|
3711
|
+
const physicalReference = reference("opaque-object", physicalName, selectedNamespace, "pragma_database_list", "name");
|
|
3712
|
+
return {
|
|
3713
|
+
kind: "opaque-object",
|
|
3714
|
+
id: stableId(`attached:${physicalName}`),
|
|
3715
|
+
identitySource: "physical-name",
|
|
3716
|
+
objectKind: "attached-database",
|
|
3717
|
+
physicalName,
|
|
3718
|
+
data: {
|
|
3719
|
+
...number(row.seq) === void 0 ? {} : { sequence: number(row.seq) },
|
|
3720
|
+
...text(row.file) === void 0 ? {} : { file: text(row.file) },
|
|
3721
|
+
selected: false
|
|
3722
|
+
},
|
|
3723
|
+
reference: physicalReference,
|
|
3724
|
+
provenance: {
|
|
3725
|
+
kind: "catalog",
|
|
3726
|
+
dialect: "sqlite",
|
|
3727
|
+
reference: physicalReference
|
|
3728
|
+
},
|
|
3729
|
+
dialect: sqliteExtension({ selectedNamespace })
|
|
3730
|
+
};
|
|
3731
|
+
}
|
|
3732
|
+
function opaqueSchemaObject(row, namespace, _diagnostics) {
|
|
3733
|
+
const physicalName = text(row.name) ?? "unnamed_object";
|
|
3734
|
+
const type = normalizeType(row.type) || "unknown";
|
|
3735
|
+
const physicalReference = reference("opaque-object", physicalName, namespace, "sqlite_schema", "name");
|
|
3736
|
+
const sqlText = text(row.sql);
|
|
3737
|
+
return {
|
|
3738
|
+
kind: "opaque-object",
|
|
3739
|
+
id: stableId(`opaque:${type}:${physicalName}`),
|
|
3740
|
+
identitySource: "physical-name",
|
|
3741
|
+
objectKind: type,
|
|
3742
|
+
physicalName,
|
|
3743
|
+
data: {
|
|
3744
|
+
type,
|
|
3745
|
+
...text(row.tbl_name) === void 0 ? {} : { tableName: text(row.tbl_name) }
|
|
3746
|
+
},
|
|
3747
|
+
...sqlText === void 0 ? {} : { sql: {
|
|
3748
|
+
kind: "sql",
|
|
3749
|
+
dialect: "sqlite",
|
|
3750
|
+
text: sqlText,
|
|
3751
|
+
provenance: {
|
|
3752
|
+
kind: "create-sql",
|
|
3753
|
+
dialect: "sqlite",
|
|
3754
|
+
reference: physicalReference
|
|
3755
|
+
}
|
|
3756
|
+
} },
|
|
3757
|
+
reference: physicalReference,
|
|
3758
|
+
provenance: {
|
|
3759
|
+
kind: "catalog",
|
|
3760
|
+
dialect: "sqlite",
|
|
3761
|
+
reference: physicalReference
|
|
3762
|
+
},
|
|
3763
|
+
dialect: sqliteExtension({ objectKind: type })
|
|
3764
|
+
};
|
|
3765
|
+
}
|
|
3766
|
+
function sqliteTrigger(row, namespace, relations, diagnostics) {
|
|
3767
|
+
const physicalName = text(row.name) ?? "unnamed_trigger";
|
|
3768
|
+
const sqlText = text(row.sql);
|
|
3769
|
+
const physicalReference = reference("trigger", physicalName, namespace, "sqlite_schema", "name");
|
|
3770
|
+
const onMatch = sqlText?.match(/\bON\s+("(?:[^"]|"")*"|`[^`]*`|\[[^\]]*\]|[A-Za-z_][A-Za-z0-9_$]*)/i);
|
|
3771
|
+
const targetName = unquoteIdentifier(onMatch?.[1]) ?? text(row.tbl_name);
|
|
3772
|
+
const target = targetName === void 0 ? void 0 : relations.get(targetName);
|
|
3773
|
+
const beginIndex = sqlText?.search(/\bBEGIN\b/i) ?? -1;
|
|
3774
|
+
const header = sqlText === void 0 || beginIndex < 0 ? void 0 : sqlText.slice(0, beginIndex);
|
|
3775
|
+
const timing = triggerTiming(header);
|
|
3776
|
+
const events = triggerEvents(header);
|
|
3777
|
+
if (!sqlText || !target || !header || beginIndex < 0) {
|
|
3778
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
3779
|
+
severity: "error",
|
|
3780
|
+
code: "unresolved-reference",
|
|
3781
|
+
message: `SQLite trigger ${physicalName} does not have a recoverable body or target`,
|
|
3782
|
+
path: ["triggers", physicalName],
|
|
3783
|
+
physicalReference,
|
|
3784
|
+
remediation: "Retain the CREATE TRIGGER SQL and inspect the trigger after its target is visible."
|
|
3785
|
+
}));
|
|
3786
|
+
return deferred("trigger", physicalName, sqlText, namespace);
|
|
3787
|
+
}
|
|
3788
|
+
if (events.length === 0) diagnostics.push(createIntrospectionDiagnostic({
|
|
3789
|
+
severity: "warning",
|
|
3790
|
+
code: "unsupported-feature",
|
|
3791
|
+
message: `SQLite trigger ${physicalName} has no recognized event`,
|
|
3792
|
+
path: [
|
|
3793
|
+
"triggers",
|
|
3794
|
+
physicalName,
|
|
3795
|
+
"events"
|
|
3796
|
+
],
|
|
3797
|
+
physicalReference
|
|
3798
|
+
}));
|
|
3799
|
+
const bodyText = sqlText.slice(beginIndex + 5).replace(/END\s*;?\s*$/i, "").trim();
|
|
3800
|
+
const condition = triggerCondition(sqlText, onMatch?.index, beginIndex);
|
|
3801
|
+
return {
|
|
3802
|
+
kind: "trigger",
|
|
3803
|
+
id: stableId(physicalName),
|
|
3804
|
+
identitySource: "physical-name",
|
|
3805
|
+
physicalName,
|
|
3806
|
+
table: target,
|
|
3807
|
+
timing,
|
|
3808
|
+
events,
|
|
3809
|
+
orientation: /\bFOR\s+EACH\s+ROW\b/i.test(header) ? "row" : void 0,
|
|
3810
|
+
...condition === void 0 ? {} : { condition: sql(condition, namespace, {
|
|
3811
|
+
kind: target.kind,
|
|
3812
|
+
physicalName: target.id,
|
|
3813
|
+
reference: physicalReference
|
|
3814
|
+
}, physicalName) },
|
|
3815
|
+
body: sql(bodyText || sqlText, namespace, {
|
|
3816
|
+
kind: "trigger",
|
|
3817
|
+
physicalName,
|
|
3818
|
+
reference: physicalReference
|
|
3819
|
+
}, physicalName),
|
|
3820
|
+
reference: physicalReference,
|
|
3821
|
+
provenance: {
|
|
3822
|
+
kind: "create-sql",
|
|
3823
|
+
dialect: "sqlite",
|
|
3824
|
+
reference: physicalReference
|
|
3825
|
+
},
|
|
3826
|
+
dialect: sqliteExtension({
|
|
3827
|
+
objectKind: "trigger",
|
|
3828
|
+
...sqlText === void 0 ? {} : { rawSql: sqlText }
|
|
3829
|
+
})
|
|
3830
|
+
};
|
|
3831
|
+
}
|
|
3832
|
+
function triggerTiming(header) {
|
|
3833
|
+
const value = header?.match(/\b(INSTEAD\s+OF|BEFORE|AFTER)\b/i)?.[1];
|
|
3834
|
+
return value?.toLowerCase() === "before" ? "before" : value?.toLowerCase() === "after" ? "after" : value?.toLowerCase() === "instead of" ? "instead-of" : "unknown";
|
|
3835
|
+
}
|
|
3836
|
+
function triggerEvents(header) {
|
|
3837
|
+
const values = header?.match(/\b(INSERT|UPDATE|DELETE)\b/gi) ?? [];
|
|
3838
|
+
return [...new Set(values.map((value) => value.toLowerCase()))];
|
|
3839
|
+
}
|
|
3840
|
+
function triggerCondition(sqlText, _onIndex, beginIndex) {
|
|
3841
|
+
return sqlText.slice(0, beginIndex).match(/\bWHEN\s+([\s\S]+)$/i)?.[1]?.trim();
|
|
3842
|
+
}
|
|
3843
|
+
function unquoteIdentifier(value) {
|
|
3844
|
+
if (!value) return void 0;
|
|
3845
|
+
const trimmed = value.trim();
|
|
3846
|
+
if (trimmed.length < 2) return trimmed;
|
|
3847
|
+
if (trimmed.startsWith("\"") && trimmed.endsWith("\"") || trimmed.startsWith("`") && trimmed.endsWith("`")) return trimmed.slice(1, -1).replace(/(""|``)/g, (match) => match[0]);
|
|
3848
|
+
if (trimmed.startsWith("[") && trimmed.endsWith("]")) return trimmed.slice(1, -1);
|
|
3849
|
+
return trimmed;
|
|
3850
|
+
}
|
|
3851
|
+
function sqliteAffinity(type) {
|
|
3852
|
+
const normalized = type.trim().toUpperCase();
|
|
3853
|
+
if (/INT/.test(normalized)) return "INTEGER";
|
|
3854
|
+
if (/CHAR|CLOB|TEXT/.test(normalized)) return "TEXT";
|
|
3855
|
+
if (/REAL|FLOA|DOUB/.test(normalized)) return "REAL";
|
|
3856
|
+
if (normalized === "" || normalized === "BLOB") return "BLOB";
|
|
3857
|
+
return "NUMERIC";
|
|
3858
|
+
}
|
|
3859
|
+
function sqliteExtension(data) {
|
|
3860
|
+
return {
|
|
3861
|
+
dialect: "sqlite",
|
|
3862
|
+
version: 1,
|
|
3863
|
+
data
|
|
3864
|
+
};
|
|
3865
|
+
}
|
|
3866
|
+
function indexExpressionFor(sqlText, position) {
|
|
3867
|
+
if (!sqlText) return void 0;
|
|
3868
|
+
const open = sqlText.indexOf("(", sqlText.search(/\bON\b/i));
|
|
3869
|
+
if (open < 0) return void 0;
|
|
3870
|
+
const close = matchingParen(sqlText, open);
|
|
3871
|
+
if (close < 0) return void 0;
|
|
3872
|
+
const term = splitSqlList(sqlText.slice(open + 1, close))[position]?.trim();
|
|
3873
|
+
return term && !isSimpleIdentifier(term) ? term : void 0;
|
|
3874
|
+
}
|
|
3875
|
+
function opaqueIndexExpression(table, indexName, position, info, sqlText, namespace) {
|
|
3876
|
+
const physicalReference = reference("opaque-object", `${indexName}:${position}`, namespace, "pragma_index_xinfo", "seqno", position);
|
|
3877
|
+
return {
|
|
3878
|
+
kind: "opaque-object",
|
|
3879
|
+
id: stableId(`index-expression:${table.physicalName}:${indexName}:${position}`),
|
|
3880
|
+
identitySource: "deterministic-fallback",
|
|
3881
|
+
objectKind: "index-expression-term",
|
|
3882
|
+
physicalName: `${indexName}:${position}`,
|
|
3883
|
+
data: {
|
|
3884
|
+
index: indexName,
|
|
3885
|
+
position,
|
|
3886
|
+
cid: number(info.cid) ?? -2
|
|
3887
|
+
},
|
|
3888
|
+
...sqlText === void 0 ? {} : { sql: sql(sqlText, namespace, table, indexName) },
|
|
3889
|
+
reference: physicalReference,
|
|
3890
|
+
provenance: {
|
|
3891
|
+
kind: "catalog",
|
|
3892
|
+
dialect: "sqlite",
|
|
3893
|
+
reference: physicalReference
|
|
3894
|
+
},
|
|
3895
|
+
dialect: sqliteExtension({ objectKind: "index-expression-term" })
|
|
3896
|
+
};
|
|
3897
|
+
}
|
|
3898
|
+
function matchingParen(source, open) {
|
|
3899
|
+
let depth = 0;
|
|
3900
|
+
let quote;
|
|
3901
|
+
for (let index = open; index < source.length; index++) {
|
|
3902
|
+
const character = source[index];
|
|
3903
|
+
if (quote === "single") {
|
|
3904
|
+
if (character === "'" && source[index + 1] === "'") index++;
|
|
3905
|
+
else if (character === "'") quote = void 0;
|
|
3906
|
+
continue;
|
|
3907
|
+
}
|
|
3908
|
+
if (quote === "double") {
|
|
3909
|
+
if (character === "\"" && source[index + 1] === "\"") index++;
|
|
3910
|
+
else if (character === "\"") quote = void 0;
|
|
3911
|
+
continue;
|
|
3912
|
+
}
|
|
3913
|
+
if (quote === "backtick") {
|
|
3914
|
+
if (character === "`") quote = void 0;
|
|
3915
|
+
continue;
|
|
3916
|
+
}
|
|
3917
|
+
if (quote === "bracket") {
|
|
3918
|
+
if (character === "]") quote = void 0;
|
|
3919
|
+
continue;
|
|
3920
|
+
}
|
|
3921
|
+
if (character === "'") quote = "single";
|
|
3922
|
+
else if (character === "\"") quote = "double";
|
|
3923
|
+
else if (character === "`") quote = "backtick";
|
|
3924
|
+
else if (character === "[") quote = "bracket";
|
|
3925
|
+
else if (character === "(") depth++;
|
|
3926
|
+
else if (character === ")" && --depth === 0) return index;
|
|
3927
|
+
}
|
|
3928
|
+
return -1;
|
|
3929
|
+
}
|
|
3930
|
+
function splitSqlList(source) {
|
|
3931
|
+
const values = [];
|
|
3932
|
+
let start = 0;
|
|
3933
|
+
let depth = 0;
|
|
3934
|
+
let quote;
|
|
3935
|
+
for (let index = 0; index < source.length; index++) {
|
|
3936
|
+
const character = source[index];
|
|
3937
|
+
if (quote === "single") {
|
|
3938
|
+
if (character === "'" && source[index + 1] === "'") index++;
|
|
3939
|
+
else if (character === "'") quote = void 0;
|
|
3940
|
+
continue;
|
|
3941
|
+
}
|
|
3942
|
+
if (quote === "double") {
|
|
3943
|
+
if (character === "\"" && source[index + 1] === "\"") index++;
|
|
3944
|
+
else if (character === "\"") quote = void 0;
|
|
3945
|
+
continue;
|
|
3946
|
+
}
|
|
3947
|
+
if (quote === "backtick") {
|
|
3948
|
+
if (character === "`") quote = void 0;
|
|
3949
|
+
continue;
|
|
3950
|
+
}
|
|
3951
|
+
if (quote === "bracket") {
|
|
3952
|
+
if (character === "]") quote = void 0;
|
|
3953
|
+
continue;
|
|
3954
|
+
}
|
|
3955
|
+
if (character === "'") quote = "single";
|
|
3956
|
+
else if (character === "\"") quote = "double";
|
|
3957
|
+
else if (character === "`") quote = "backtick";
|
|
3958
|
+
else if (character === "[") quote = "bracket";
|
|
3959
|
+
else if (character === "(") depth++;
|
|
3960
|
+
else if (character === ")") depth--;
|
|
3961
|
+
else if (character === "," && depth === 0) {
|
|
3962
|
+
values.push(source.slice(start, index));
|
|
3963
|
+
start = index + 1;
|
|
3964
|
+
}
|
|
3965
|
+
}
|
|
3966
|
+
values.push(source.slice(start));
|
|
3967
|
+
return values;
|
|
3968
|
+
}
|
|
3969
|
+
function isSimpleIdentifier(value) {
|
|
3970
|
+
return /^(?:[A-Za-z_][A-Za-z0-9_$]*|"(?:[^"]|"")*"|`[^`]*`|\[[^\]]*\])(?:\s+(?:ASC|DESC))?$/i.test(value);
|
|
3971
|
+
}
|
|
3972
|
+
function table(row, sqlText, namespace) {
|
|
3973
|
+
const physicalName = text(row.name) ?? "unnamed_table";
|
|
3974
|
+
const withoutRowid = boolean(row.wr);
|
|
3975
|
+
const strict = boolean(row.strict);
|
|
3976
|
+
return {
|
|
3977
|
+
kind: "table",
|
|
3978
|
+
id: stableId(physicalName),
|
|
3979
|
+
identitySource: "physical-name",
|
|
3980
|
+
physicalName,
|
|
3981
|
+
reference: reference("table", physicalName, namespace, "sqlite_schema", "name"),
|
|
3982
|
+
columns: [],
|
|
3983
|
+
constraints: [],
|
|
3984
|
+
indexes: [],
|
|
3985
|
+
dialect: sqliteExtension({
|
|
3986
|
+
tableType: "table",
|
|
3987
|
+
withoutRowid,
|
|
3988
|
+
strict,
|
|
3989
|
+
rowid: !withoutRowid
|
|
3990
|
+
}),
|
|
3991
|
+
unknownFields: [
|
|
3992
|
+
...withoutRowid ? [{
|
|
3993
|
+
name: "withoutRowid",
|
|
3994
|
+
value: true
|
|
3995
|
+
}] : [],
|
|
3996
|
+
...strict ? [{
|
|
3997
|
+
name: "strict",
|
|
3998
|
+
value: true
|
|
3999
|
+
}] : [],
|
|
4000
|
+
...sqlText ? [{
|
|
4001
|
+
name: "createSql",
|
|
4002
|
+
value: sqlText
|
|
4003
|
+
}] : []
|
|
4004
|
+
]
|
|
4005
|
+
};
|
|
4006
|
+
}
|
|
4007
|
+
function deferred(objectKind, physicalName, sqlText, namespace) {
|
|
4008
|
+
return {
|
|
4009
|
+
kind: "deferred-object",
|
|
4010
|
+
id: stableId(`deferred:${objectKind}:${physicalName}`),
|
|
4011
|
+
identitySource: "physical-name",
|
|
4012
|
+
objectKind,
|
|
4013
|
+
physicalName,
|
|
4014
|
+
reference: reference("deferred-object", physicalName, namespace, "sqlite_schema", "name"),
|
|
4015
|
+
dialect: sqliteExtension({ objectKind }),
|
|
4016
|
+
unknownFields: sqlText ? [{
|
|
4017
|
+
name: "createSql",
|
|
4018
|
+
value: sqlText
|
|
4019
|
+
}] : void 0
|
|
4020
|
+
};
|
|
4021
|
+
}
|
|
4022
|
+
function column(row, table, namespace, sqlText, rowidPrimaryKey, diagnostics) {
|
|
4023
|
+
const physicalName = text(row.name) ?? "unnamed_column";
|
|
4024
|
+
const hidden = number(row.hidden) ?? 0;
|
|
4025
|
+
const type = text(row.type) ?? "";
|
|
4026
|
+
const defaultValue = text(row.dflt_value);
|
|
4027
|
+
const generatedExpression = hidden === 2 || hidden === 3 ? generatedExpressionFor(sqlText, physicalName) : void 0;
|
|
4028
|
+
if ((hidden === 2 || hidden === 3) && !generatedExpression) diagnostics.push(createIntrospectionDiagnostic({
|
|
4029
|
+
severity: "error",
|
|
4030
|
+
code: "expression-parse-failed",
|
|
4031
|
+
message: `SQLite generated expression for ${physicalName} could not be recovered`,
|
|
4032
|
+
path: [
|
|
4033
|
+
table.id,
|
|
4034
|
+
"columns",
|
|
4035
|
+
physicalName,
|
|
4036
|
+
"generated"
|
|
4037
|
+
],
|
|
4038
|
+
remediation: "Preserve the CREATE TABLE SQL or use lossy mode."
|
|
4039
|
+
}));
|
|
4040
|
+
const rowid = table.kind === "table" && rowidPrimaryKey && (number(row.pk) ?? 0) > 0 && type.toUpperCase() === "INTEGER" && !/WITHOUT\s+ROWID/i.test(sqlText ?? "");
|
|
4041
|
+
const identity = rowid ? {
|
|
4042
|
+
kind: "identity",
|
|
4043
|
+
generation: "by-default",
|
|
4044
|
+
options: {},
|
|
4045
|
+
dialect: {
|
|
4046
|
+
dialect: "sqlite",
|
|
4047
|
+
version: 1,
|
|
4048
|
+
data: {
|
|
4049
|
+
rowidAlias: true,
|
|
4050
|
+
autoIncrement: /AUTOINCREMENT/i.test(sqlText ?? ""),
|
|
4051
|
+
withoutRowid: false
|
|
4052
|
+
}
|
|
4053
|
+
}
|
|
4054
|
+
} : void 0;
|
|
4055
|
+
return {
|
|
4056
|
+
kind: "column",
|
|
4057
|
+
id: stableId(physicalName),
|
|
4058
|
+
identitySource: "physical-name",
|
|
4059
|
+
physicalName,
|
|
4060
|
+
ordinalPosition: number(row.cid) ?? 0,
|
|
4061
|
+
nullable: !boolean(row.not_null) && !(rowid || (number(row.pk) ?? 0) > 0 && (/WITHOUT\s+ROWID/i.test(sqlText ?? "") || /\bSTRICT\b/i.test(sqlText ?? ""))),
|
|
4062
|
+
storage: { nativeType: type || "BLOB" },
|
|
4063
|
+
default: defaultValue !== void 0 && !generatedExpression ? {
|
|
4064
|
+
kind: "expression",
|
|
4065
|
+
expression: sql(defaultValue, namespace, table, physicalName)
|
|
4066
|
+
} : void 0,
|
|
4067
|
+
generated: generatedExpression ? {
|
|
4068
|
+
kind: "generated",
|
|
4069
|
+
mode: hidden === 2 ? "virtual" : "stored",
|
|
4070
|
+
expression: sql(generatedExpression, namespace, table, physicalName)
|
|
4071
|
+
} : void 0,
|
|
4072
|
+
identity,
|
|
4073
|
+
reference: reference("column", physicalName, namespace, "pragma_table_xinfo", "name"),
|
|
4074
|
+
dialect: sqliteExtension({
|
|
4075
|
+
declaredType: type,
|
|
4076
|
+
affinity: sqliteAffinity(type),
|
|
4077
|
+
hidden
|
|
4078
|
+
})
|
|
4079
|
+
};
|
|
4080
|
+
}
|
|
4081
|
+
function tableConstraints(table, rows, columns, sqlText, namespace) {
|
|
4082
|
+
const primaryNames = new Map(rows.filter((row) => (number(row.pk) ?? 0) > 0).map((row) => [text(row.name), number(row.pk) ?? 0]));
|
|
4083
|
+
const primaryColumns = columns.filter((column) => primaryNames.has(column.physicalName)).sort((left, right) => primaryNames.get(left.physicalName) - primaryNames.get(right.physicalName));
|
|
4084
|
+
const constraints = [];
|
|
4085
|
+
if (primaryColumns.length > 0) {
|
|
4086
|
+
const primary = {
|
|
4087
|
+
kind: "primary-key",
|
|
4088
|
+
id: stableId(`primary_${table.physicalName}`),
|
|
4089
|
+
identitySource: "deterministic-fallback",
|
|
4090
|
+
physicalName: `primary_${table.physicalName}`,
|
|
4091
|
+
columns: primaryColumns.map((column) => column.physicalName),
|
|
4092
|
+
dialect: sqliteExtension({ source: "pragma_table_xinfo" }),
|
|
4093
|
+
reference: reference("constraint", `primary_${table.physicalName}`, namespace, "sqlite_schema", "tbl_name")
|
|
4094
|
+
};
|
|
4095
|
+
constraints.push(primary);
|
|
4096
|
+
}
|
|
4097
|
+
[...sqlText?.matchAll(/CHECK\s*\(([^()]*(?:\([^()]*\)[^()]*)*)\)/gi) ?? []].forEach((match, index) => {
|
|
4098
|
+
const name = `check_${index}_${table.physicalName}`;
|
|
4099
|
+
const check = {
|
|
4100
|
+
kind: "check",
|
|
4101
|
+
id: stableId(name),
|
|
4102
|
+
identitySource: "deterministic-fallback",
|
|
4103
|
+
physicalName: name,
|
|
4104
|
+
expression: sql(match[1] ?? "true", namespace, table, name),
|
|
4105
|
+
dialect: sqliteExtension({ source: "create-sql" })
|
|
4106
|
+
};
|
|
4107
|
+
constraints.push(check);
|
|
4108
|
+
});
|
|
4109
|
+
return constraints;
|
|
4110
|
+
}
|
|
4111
|
+
function sqliteIndex(table, row, infoRows, sqlText, namespace, diagnostics, opaqueObjects) {
|
|
4112
|
+
const physicalName = text(row.name);
|
|
4113
|
+
if (!physicalName) return void 0;
|
|
4114
|
+
const terms = [];
|
|
4115
|
+
const collations = [];
|
|
4116
|
+
for (const info of infoRows.filter((item) => boolean(item.key))) {
|
|
4117
|
+
const position = number(info.seqno) ?? 0;
|
|
4118
|
+
const cid = number(info.cid) ?? -1;
|
|
4119
|
+
const collation = text(info.coll);
|
|
4120
|
+
if (collation) collations.push(collation);
|
|
4121
|
+
if (cid === -1) continue;
|
|
4122
|
+
if (cid === -2) {
|
|
4123
|
+
const expressionText = indexExpressionFor(sqlText, position);
|
|
4124
|
+
if (expressionText) terms.push({
|
|
4125
|
+
kind: "expression",
|
|
4126
|
+
expression: sql(expressionText, namespace, table, physicalName),
|
|
4127
|
+
position,
|
|
4128
|
+
direction: boolean(info.descending) ? "DESC" : "ASC"
|
|
4129
|
+
});
|
|
4130
|
+
else {
|
|
4131
|
+
opaqueObjects.push(opaqueIndexExpression(table, physicalName, position, info, sqlText, namespace));
|
|
4132
|
+
diagnostics.push(createIntrospectionDiagnostic({
|
|
4133
|
+
severity: "error",
|
|
4134
|
+
code: "unsupported-feature",
|
|
4135
|
+
message: `SQLite index ${physicalName} has an expression term that was not recovered`,
|
|
4136
|
+
path: [
|
|
4137
|
+
table.id,
|
|
4138
|
+
"indexes",
|
|
4139
|
+
physicalName,
|
|
4140
|
+
"terms",
|
|
4141
|
+
position
|
|
4142
|
+
],
|
|
4143
|
+
physicalReference: reference("index", physicalName, namespace, "sqlite_schema", "name"),
|
|
4144
|
+
remediation: "Preserve the CREATE INDEX SQL for expression terms."
|
|
4145
|
+
}));
|
|
4146
|
+
}
|
|
4147
|
+
continue;
|
|
4148
|
+
}
|
|
4149
|
+
const columnName = text(info.name);
|
|
4150
|
+
if (cid >= 0 && columnName) terms.push({
|
|
4151
|
+
kind: "column",
|
|
4152
|
+
column: columnName,
|
|
4153
|
+
position,
|
|
4154
|
+
direction: boolean(info.descending) ? "DESC" : "ASC"
|
|
4155
|
+
});
|
|
4156
|
+
else diagnostics.push(createIntrospectionDiagnostic({
|
|
4157
|
+
severity: "error",
|
|
4158
|
+
code: "unsupported-feature",
|
|
4159
|
+
message: `SQLite index ${physicalName} has an expression term that was not recovered`,
|
|
4160
|
+
path: [
|
|
4161
|
+
table.id,
|
|
4162
|
+
"indexes",
|
|
4163
|
+
physicalName,
|
|
4164
|
+
"terms",
|
|
4165
|
+
position
|
|
4166
|
+
],
|
|
4167
|
+
physicalReference: reference("index", physicalName, namespace, "sqlite_schema", "name")
|
|
4168
|
+
}));
|
|
4169
|
+
}
|
|
4170
|
+
const unique = boolean(row.unique_index);
|
|
4171
|
+
if (text(row.origin) === "u") {
|
|
4172
|
+
const internalName = physicalName.startsWith("sqlite_autoindex_");
|
|
4173
|
+
const termNames = terms.map((term) => term.kind === "column" ? term.column : `expression_${term.position}`);
|
|
4174
|
+
const constraintName = internalName ? `unique_${table.physicalName}_${termNames.join("_") || "constraint"}` : physicalName;
|
|
4175
|
+
return {
|
|
4176
|
+
kind: "unique",
|
|
4177
|
+
id: stableId(constraintName),
|
|
4178
|
+
identitySource: internalName ? "deterministic-fallback" : "physical-name",
|
|
4179
|
+
physicalName: constraintName,
|
|
4180
|
+
columns: terms.flatMap((term) => term.kind === "column" ? [term.column] : []),
|
|
4181
|
+
nulls: "distinct",
|
|
4182
|
+
dialect: sqliteExtension({
|
|
4183
|
+
origin: text(row.origin) ?? "unknown",
|
|
4184
|
+
collations,
|
|
4185
|
+
...internalName ? { internalName } : {}
|
|
4186
|
+
}),
|
|
4187
|
+
reference: reference("constraint", constraintName, namespace, "pragma_index_list", "name", physicalName)
|
|
4188
|
+
};
|
|
4189
|
+
}
|
|
4190
|
+
return {
|
|
4191
|
+
kind: "index",
|
|
4192
|
+
id: stableId(physicalName),
|
|
4193
|
+
identitySource: "physical-name",
|
|
4194
|
+
physicalName,
|
|
4195
|
+
unique,
|
|
4196
|
+
terms,
|
|
4197
|
+
dialect: sqliteExtension({
|
|
4198
|
+
origin: text(row.origin) ?? "unknown",
|
|
4199
|
+
partial: boolean(row.partial),
|
|
4200
|
+
collations
|
|
4201
|
+
}),
|
|
4202
|
+
predicate: boolean(row.partial) ? partialPredicate(sqlText, physicalName, namespace, table) : void 0,
|
|
4203
|
+
reference: reference("index", physicalName, namespace, "sqlite_schema", "name")
|
|
4204
|
+
};
|
|
4205
|
+
}
|
|
4206
|
+
function foreignKeys(table, rows, namespace) {
|
|
4207
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
4208
|
+
for (const row of rows) {
|
|
4209
|
+
const id = text(row.id) ?? "0";
|
|
4210
|
+
const group = grouped.get(id) ?? [];
|
|
4211
|
+
group.push(row);
|
|
4212
|
+
grouped.set(id, group);
|
|
4213
|
+
}
|
|
4214
|
+
return [...grouped.entries()].map(([key, group]) => {
|
|
4215
|
+
const first = group[0];
|
|
4216
|
+
const physicalName = `foreign_key_${table.physicalName}_${key}`;
|
|
4217
|
+
return {
|
|
4218
|
+
kind: "foreign-key",
|
|
4219
|
+
id: stableId(physicalName),
|
|
4220
|
+
identitySource: "deterministic-fallback",
|
|
4221
|
+
physicalName,
|
|
4222
|
+
columns: group.sort((left, right) => (number(left.seq) ?? 0) - (number(right.seq) ?? 0)).map((row) => text(row.source_column) ?? "unknown"),
|
|
4223
|
+
target: {
|
|
4224
|
+
table: text(first.target_table) ?? "unknown",
|
|
4225
|
+
columns: group.map((row) => text(row.target_column) ?? "unknown")
|
|
4226
|
+
},
|
|
4227
|
+
onUpdate: action(first.on_update),
|
|
4228
|
+
onDelete: action(first.on_delete),
|
|
4229
|
+
match: match(first.match),
|
|
4230
|
+
dialect: sqliteExtension({ foreignKeyId: key }),
|
|
4231
|
+
reference: reference("constraint", physicalName, namespace, "pragma_foreign_key_list", "id", key)
|
|
4232
|
+
};
|
|
4233
|
+
});
|
|
4234
|
+
}
|
|
4235
|
+
function partialPredicate(sqlText, indexName, namespace, table) {
|
|
4236
|
+
const predicate = (sqlText?.match(/\bWHERE\s+([\s\S]+)$/i))?.[1]?.trim().replace(/;\s*$/, "");
|
|
4237
|
+
return predicate ? sql(predicate, namespace, table, indexName) : void 0;
|
|
4238
|
+
}
|
|
4239
|
+
function generatedExpressionFor(sqlText, columnName) {
|
|
4240
|
+
if (!sqlText) return void 0;
|
|
4241
|
+
const open = sqlText.indexOf("(");
|
|
4242
|
+
if (open < 0) return void 0;
|
|
4243
|
+
const close = matchingParen(sqlText, open);
|
|
4244
|
+
if (close < 0) return void 0;
|
|
4245
|
+
const definitions = splitSqlList(sqlText.slice(open + 1, close));
|
|
4246
|
+
for (const definition of definitions) {
|
|
4247
|
+
const identifier = definition.trim().match(/^("(?:[^"]|"")*"|`[^`]*`|\[[^\]]*\]|[A-Za-z_][A-Za-z0-9_$]*)/)?.[1];
|
|
4248
|
+
if (unquoteIdentifier(identifier) !== columnName) continue;
|
|
4249
|
+
const generated = definition.match(/\bAS\s*\(/i);
|
|
4250
|
+
if (!generated || generated.index === void 0) return void 0;
|
|
4251
|
+
const generatedOpen = definition.indexOf("(", generated.index);
|
|
4252
|
+
if (generatedOpen < 0) return void 0;
|
|
4253
|
+
const generatedClose = matchingParen(definition, generatedOpen);
|
|
4254
|
+
return generatedClose < 0 ? void 0 : definition.slice(generatedOpen + 1, generatedClose).trim();
|
|
4255
|
+
}
|
|
4256
|
+
}
|
|
4257
|
+
function sql(textValue, dialectNamespace, owner, name) {
|
|
4258
|
+
const ownerReference = owner.reference ?? reference(owner.kind, owner.physicalName, dialectNamespace, "sqlite_schema", "name");
|
|
4259
|
+
return {
|
|
4260
|
+
kind: "sql",
|
|
4261
|
+
dialect: "sqlite",
|
|
4262
|
+
text: textValue,
|
|
4263
|
+
provenance: {
|
|
4264
|
+
kind: "create-sql",
|
|
4265
|
+
dialect: "sqlite",
|
|
4266
|
+
reference: reference(ownerReference.kind, name, dialectNamespace, ownerReference.catalog?.relation ?? "sqlite_schema", ownerReference.catalog?.key ?? "name", ownerReference.catalog?.value ?? ownerReference.name)
|
|
4267
|
+
}
|
|
4268
|
+
};
|
|
4269
|
+
}
|
|
4270
|
+
function reference(kind, name, namespace, relation, key, value = name) {
|
|
4271
|
+
return {
|
|
4272
|
+
kind,
|
|
4273
|
+
name,
|
|
4274
|
+
namespace,
|
|
4275
|
+
catalog: {
|
|
4276
|
+
relation,
|
|
4277
|
+
key,
|
|
4278
|
+
value
|
|
4279
|
+
}
|
|
4280
|
+
};
|
|
4281
|
+
}
|
|
4282
|
+
function emptyCatalog(namespace, diagnostics) {
|
|
4283
|
+
return {
|
|
4284
|
+
dialect: "sqlite",
|
|
4285
|
+
server: {
|
|
4286
|
+
product: "sqlite",
|
|
4287
|
+
rawVersion: "unknown",
|
|
4288
|
+
capabilities: {
|
|
4289
|
+
generatedColumns: false,
|
|
4290
|
+
identityMetadata: false,
|
|
4291
|
+
checkConstraints: false,
|
|
4292
|
+
checkConstraintEnforcement: "unknown",
|
|
4293
|
+
expressionDecompilation: false,
|
|
4294
|
+
indexExpressions: false,
|
|
4295
|
+
indexPredicates: false,
|
|
4296
|
+
indexIncludedColumns: false,
|
|
4297
|
+
namespaces: false,
|
|
4298
|
+
visibility: "unknown"
|
|
4299
|
+
}
|
|
4300
|
+
},
|
|
4301
|
+
namespace: {
|
|
4302
|
+
kind: "sqlite-database",
|
|
4303
|
+
name: namespace
|
|
4304
|
+
},
|
|
4305
|
+
tables: [],
|
|
4306
|
+
deferredObjects: [],
|
|
4307
|
+
diagnostics
|
|
4308
|
+
};
|
|
4309
|
+
}
|
|
4310
|
+
function stableId(value) {
|
|
4311
|
+
if (value && !/[.\\\u0000-\u001f\u007f]/.test(value)) return value;
|
|
4312
|
+
let hash = 2166136261;
|
|
4313
|
+
for (const character of value) {
|
|
4314
|
+
hash ^= character.charCodeAt(0);
|
|
4315
|
+
hash = Math.imul(hash, 16777619);
|
|
4316
|
+
}
|
|
4317
|
+
return `introspected_${(hash >>> 0).toString(16)}`;
|
|
4318
|
+
}
|
|
4319
|
+
function text(value) {
|
|
4320
|
+
return value === null || value === void 0 ? void 0 : String(value);
|
|
4321
|
+
}
|
|
4322
|
+
function number(value) {
|
|
4323
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
4324
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
4325
|
+
const result = Number(value);
|
|
4326
|
+
return Number.isFinite(result) ? result : void 0;
|
|
4327
|
+
}
|
|
4328
|
+
}
|
|
4329
|
+
function boolean(value) {
|
|
4330
|
+
return value === true || value === 1 || value === "1" || value === "t" || value === "true";
|
|
4331
|
+
}
|
|
4332
|
+
function action(value) {
|
|
4333
|
+
const normalized = text(value)?.toLowerCase();
|
|
4334
|
+
return normalized === "cascade" ? "cascade" : normalized === "restrict" ? "restrict" : normalized === "set null" ? "set-null" : normalized === "set default" ? "set-default" : "no-action";
|
|
4335
|
+
}
|
|
4336
|
+
function match(value) {
|
|
4337
|
+
const normalized = text(value)?.toLowerCase();
|
|
4338
|
+
return normalized === "full" ? "full" : normalized === "partial" ? "partial" : "simple";
|
|
4339
|
+
}
|
|
4340
|
+
//#endregion
|
|
4341
|
+
export { IntrospectionError, createCompleteIntrospectionCatalog, createIntrospectionDiagnostic, freezeIntrospectionCatalog, hasIntrospectionErrors, introspectedPhysicalIdentityPolicy, mapCatalogToCompleteSnapshot, mapCatalogToSnapshot, mapCatalogToSnapshotV2, mysqlChecksQuery, mysqlCollationsQuery, mysqlColumnsQuery, mysqlEventsQuery, mysqlKeyUsageQuery, mysqlPartitionsQuery, mysqlRoutineParametersQuery, mysqlRoutinesQuery, mysqlServerQuery, mysqlStatisticsQuery, mysqlTablesQuery, mysqlTriggersQuery, mysqlViewsQuery, postgresCollationsQuery, postgresColumnsQuery, postgresConstraintsQuery, postgresDomainConstraintsQuery, postgresDomainsQuery, postgresEnumsQuery, postgresExtensionsQuery, postgresIdentitiesQuery, postgresIndexesQuery, postgresMetadataQuery, postgresPartitionsQuery, postgresPoliciesQuery, postgresRelationsQuery, postgresRoutineParametersQuery, postgresRoutinesQuery, postgresSequencesQuery, postgresServerQuery, postgresTriggersQuery, postgresViewsQuery, readMysqlCatalog, readPostgresCatalog, readSqliteCatalog, sqliteDatabaseListQuery, sqliteForeignKeyQuery, sqliteIndexInfoQuery, sqliteIndexListQuery, sqliteSchemaQuery, sqliteServerQuery, sqliteTableInfoQuery, sqliteTableListQuery, sqliteTempSchemaQuery, toIntrospectionCatalog };
|