@typed-sql/postgres 2.0.0-rc.1 → 2.1.0-rc.1
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/CHANGELOG.md +201 -0
- package/README.md +17 -0
- package/dist/packages/postgres/src/bulk.d.ts.map +1 -1
- package/dist/packages/postgres/src/bulk.js +1 -1
- package/dist/packages/postgres/src/bulk.js.map +1 -1
- package/dist/packages/postgres/src/capabilities.d.ts +19 -0
- package/dist/packages/postgres/src/capabilities.d.ts.map +1 -0
- package/dist/packages/postgres/src/capabilities.js +120 -0
- package/dist/packages/postgres/src/capabilities.js.map +1 -0
- package/dist/packages/postgres/src/catalog/generated/14.d.ts +4 -0
- package/dist/packages/postgres/src/catalog/generated/14.d.ts.map +1 -0
- package/dist/packages/postgres/src/catalog/generated/14.js +2018 -0
- package/dist/packages/postgres/src/catalog/generated/14.js.map +1 -0
- package/dist/packages/postgres/src/catalog/generated/15.d.ts +4 -0
- package/dist/packages/postgres/src/catalog/generated/15.d.ts.map +1 -0
- package/dist/packages/postgres/src/catalog/generated/15.js +2012 -0
- package/dist/packages/postgres/src/catalog/generated/15.js.map +1 -0
- package/dist/packages/postgres/src/catalog/generated/16.d.ts +4 -0
- package/dist/packages/postgres/src/catalog/generated/16.d.ts.map +1 -0
- package/dist/packages/postgres/src/catalog/generated/16.js +2012 -0
- package/dist/packages/postgres/src/catalog/generated/16.js.map +1 -0
- package/dist/packages/postgres/src/catalog/generated/17.d.ts +4 -0
- package/dist/packages/postgres/src/catalog/generated/17.d.ts.map +1 -0
- package/dist/packages/postgres/src/catalog/generated/17.js +2012 -0
- package/dist/packages/postgres/src/catalog/generated/17.js.map +1 -0
- package/dist/packages/postgres/src/catalog/generated/18.d.ts +4 -0
- package/dist/packages/postgres/src/catalog/generated/18.d.ts.map +1 -0
- package/dist/packages/postgres/src/catalog/generated/18.js +2048 -0
- package/dist/packages/postgres/src/catalog/generated/18.js.map +1 -0
- package/dist/packages/postgres/src/catalog/generated/19.d.ts +4 -0
- package/dist/packages/postgres/src/catalog/generated/19.d.ts.map +1 -0
- package/dist/packages/postgres/src/catalog/generated/19.js +2048 -0
- package/dist/packages/postgres/src/catalog/generated/19.js.map +1 -0
- package/dist/packages/postgres/src/catalog/index.d.ts +14 -0
- package/dist/packages/postgres/src/catalog/index.d.ts.map +1 -0
- package/dist/packages/postgres/src/catalog/index.js +86 -0
- package/dist/packages/postgres/src/catalog/index.js.map +1 -0
- package/dist/packages/postgres/src/catalog/types.d.ts +46 -0
- package/dist/packages/postgres/src/catalog/types.d.ts.map +1 -0
- package/dist/packages/postgres/src/catalog/types.js +2 -0
- package/dist/packages/postgres/src/catalog/types.js.map +1 -0
- package/dist/packages/postgres/src/expression-evidence.d.ts +11 -0
- package/dist/packages/postgres/src/expression-evidence.d.ts.map +1 -0
- package/dist/packages/postgres/src/expression-evidence.js +33 -0
- package/dist/packages/postgres/src/expression-evidence.js.map +1 -0
- package/dist/packages/postgres/src/extensions.d.ts +61 -0
- package/dist/packages/postgres/src/extensions.d.ts.map +1 -0
- package/dist/packages/postgres/src/extensions.js +311 -0
- package/dist/packages/postgres/src/extensions.js.map +1 -0
- package/dist/packages/postgres/src/index.d.ts +13 -0
- package/dist/packages/postgres/src/index.d.ts.map +1 -1
- package/dist/packages/postgres/src/index.js +51 -17
- package/dist/packages/postgres/src/index.js.map +1 -1
- package/dist/packages/postgres/src/parser/index.d.ts +8 -0
- package/dist/packages/postgres/src/parser/index.d.ts.map +1 -0
- package/dist/packages/postgres/src/parser/index.js +4 -0
- package/dist/packages/postgres/src/parser/index.js.map +1 -0
- package/dist/packages/postgres/src/parser/parser.d.ts +14 -0
- package/dist/packages/postgres/src/parser/parser.d.ts.map +1 -0
- package/dist/packages/postgres/src/parser/parser.js +2683 -0
- package/dist/packages/postgres/src/parser/parser.js.map +1 -0
- package/dist/packages/postgres/src/parser/tokenizer.d.ts +15 -0
- package/dist/packages/postgres/src/parser/tokenizer.d.ts.map +1 -0
- package/dist/packages/postgres/src/parser/tokenizer.js +470 -0
- package/dist/packages/postgres/src/parser/tokenizer.js.map +1 -0
- package/dist/packages/postgres/src/parser/types.d.ts +652 -0
- package/dist/packages/postgres/src/parser/types.d.ts.map +1 -0
- package/dist/packages/postgres/src/parser/types.js +9 -0
- package/dist/packages/postgres/src/parser/types.js.map +1 -0
- package/dist/packages/postgres/src/parser/walk.d.ts +13 -0
- package/dist/packages/postgres/src/parser/walk.d.ts.map +1 -0
- package/dist/packages/postgres/src/parser/walk.js +374 -0
- package/dist/packages/postgres/src/parser/walk.js.map +1 -0
- package/dist/packages/postgres/src/pg.d.ts +35 -4
- package/dist/packages/postgres/src/pg.d.ts.map +1 -1
- package/dist/packages/postgres/src/pg.js +355 -40
- package/dist/packages/postgres/src/pg.js.map +1 -1
- package/dist/packages/postgres/src/prepared.d.ts +5 -3
- package/dist/packages/postgres/src/prepared.d.ts.map +1 -1
- package/dist/packages/postgres/src/prepared.js +23 -15
- package/dist/packages/postgres/src/prepared.js.map +1 -1
- package/dist/packages/postgres/src/provider.d.ts +149 -11
- package/dist/packages/postgres/src/provider.d.ts.map +1 -1
- package/dist/packages/postgres/src/provider.js +652 -42
- package/dist/packages/postgres/src/provider.js.map +1 -1
- package/dist/packages/postgres/src/resolver.d.ts +1 -1
- package/dist/packages/postgres/src/resolver.d.ts.map +1 -1
- package/dist/packages/postgres/src/resolver.js +2767 -203
- package/dist/packages/postgres/src/resolver.js.map +1 -1
- package/dist/packages/postgres/src/routing.d.ts.map +1 -1
- package/dist/packages/postgres/src/routing.js +1 -1
- package/dist/packages/postgres/src/routing.js.map +1 -1
- package/dist/packages/postgres/src/runtime-compatibility.d.ts +14 -0
- package/dist/packages/postgres/src/runtime-compatibility.d.ts.map +1 -0
- package/dist/packages/postgres/src/runtime-compatibility.js +63 -0
- package/dist/packages/postgres/src/runtime-compatibility.js.map +1 -0
- package/dist/packages/postgres/src/runtime.d.ts +10 -1
- package/dist/packages/postgres/src/runtime.d.ts.map +1 -1
- package/dist/packages/postgres/src/runtime.js +50 -2
- package/dist/packages/postgres/src/runtime.js.map +1 -1
- package/dist/packages/postgres/src/semantics.d.ts +1 -1
- package/dist/packages/postgres/src/semantics.d.ts.map +1 -1
- package/dist/packages/postgres/src/semantics.js +19 -6
- package/dist/packages/postgres/src/semantics.js.map +1 -1
- package/dist/packages/postgres/src/support.d.ts +29 -0
- package/dist/packages/postgres/src/support.d.ts.map +1 -0
- package/dist/packages/postgres/src/support.js +45 -0
- package/dist/packages/postgres/src/support.js.map +1 -0
- package/dist/packages/postgres/src/type-policy.d.ts.map +1 -1
- package/dist/packages/postgres/src/type-policy.js +34 -43
- package/dist/packages/postgres/src/type-policy.js.map +1 -1
- package/dist/packages/postgres/src/type-resolution.d.ts +33 -0
- package/dist/packages/postgres/src/type-resolution.d.ts.map +1 -0
- package/dist/packages/postgres/src/type-resolution.js +906 -0
- package/dist/packages/postgres/src/type-resolution.js.map +1 -0
- package/package.json +7 -4
|
@@ -1,20 +1,62 @@
|
|
|
1
|
+
import { defineSchemaSnapshotV2, fingerprintSchemaExpression } from "@typed-sql/schema";
|
|
2
|
+
import { postgresServerEvidence } from "./capabilities.js";
|
|
3
|
+
import { postgresCoreCatalog } from "./catalog/index.js";
|
|
4
|
+
import { fingerprintPostgresExpressionSql } from "./expression-evidence.js";
|
|
5
|
+
import { introspectPostgresExtensionManifests } from "./extensions.js";
|
|
1
6
|
import { defaultPostgresTypePolicy, mapPostgresType } from "./type-policy.js";
|
|
7
|
+
import { POSTGRES_DIALECT_VERSION } from "./version.js";
|
|
2
8
|
export const postgresCatalogQueries = {
|
|
3
|
-
version:
|
|
9
|
+
version: `
|
|
10
|
+
SELECT current_setting('server_version') AS server_version,
|
|
11
|
+
current_setting('standard_conforming_strings') AS standard_conforming_strings,
|
|
12
|
+
current_setting('search_path') AS search_path,
|
|
13
|
+
ARRAY(SELECT extname || ':' || extversion FROM pg_catalog.pg_extension ORDER BY extname) AS extensions
|
|
14
|
+
`,
|
|
15
|
+
relations: `
|
|
16
|
+
SELECT
|
|
17
|
+
n.nspname AS schema_name,
|
|
18
|
+
c.relname AS table_name,
|
|
19
|
+
c.relkind AS relation_kind,
|
|
20
|
+
c.relispartition AS is_partition,
|
|
21
|
+
pn.nspname AS partition_parent_schema,
|
|
22
|
+
pc.relname AS partition_parent_table,
|
|
23
|
+
pt.partstrat AS partition_strategy
|
|
24
|
+
FROM pg_catalog.pg_class AS c
|
|
25
|
+
JOIN pg_catalog.pg_namespace AS n ON n.oid = c.relnamespace
|
|
26
|
+
LEFT JOIN pg_catalog.pg_inherits AS inh ON inh.inhrelid = c.oid AND c.relispartition
|
|
27
|
+
LEFT JOIN pg_catalog.pg_class AS pc ON pc.oid = inh.inhparent
|
|
28
|
+
LEFT JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace
|
|
29
|
+
LEFT JOIN pg_catalog.pg_partitioned_table AS pt ON pt.partrelid = c.oid
|
|
30
|
+
WHERE c.relkind IN ('r', 'p', 'v', 'm', 'f')
|
|
31
|
+
AND n.nspname NOT IN ('pg_catalog', 'information_schema')
|
|
32
|
+
AND n.nspname NOT LIKE 'pg_toast%'
|
|
33
|
+
AND ($1::text[] IS NULL OR n.nspname = ANY($1::text[]))
|
|
34
|
+
ORDER BY n.nspname, c.relname
|
|
35
|
+
`,
|
|
4
36
|
columns: `
|
|
5
37
|
SELECT
|
|
6
38
|
n.nspname AS schema_name,
|
|
7
39
|
c.relname AS table_name,
|
|
8
40
|
a.attname AS column_name,
|
|
41
|
+
(a.attnum - 1) AS column_position,
|
|
42
|
+
c.relkind AS relation_kind,
|
|
9
43
|
format_type(a.atttypid, a.atttypmod) AS database_type,
|
|
44
|
+
'pg:' || a.atttypid::text AS type_identity,
|
|
10
45
|
a.attnotnull AS not_null,
|
|
11
46
|
(t.typcategory = 'A') AS is_array,
|
|
12
|
-
pg_get_expr(ad.adbin, ad.adrelid) AS default_expression
|
|
47
|
+
pg_get_expr(ad.adbin, ad.adrelid) AS default_expression,
|
|
48
|
+
a.attgenerated AS generated_kind,
|
|
49
|
+
a.attidentity AS identity_kind,
|
|
50
|
+
CASE WHEN a.attcollation = 0 THEN NULL ELSE quote_ident(cn.nspname) || '.' || quote_ident(coll.collname) END AS collation_name,
|
|
51
|
+
((pg_relation_is_updatable(c.oid, true) & 8) = 8 AND a.attgenerated = '') AS insertable,
|
|
52
|
+
((pg_relation_is_updatable(c.oid, true) & 4) = 4 AND a.attgenerated = '') AS updatable
|
|
13
53
|
FROM pg_catalog.pg_attribute AS a
|
|
14
54
|
JOIN pg_catalog.pg_class AS c ON c.oid = a.attrelid
|
|
15
55
|
JOIN pg_catalog.pg_namespace AS n ON n.oid = c.relnamespace
|
|
16
56
|
JOIN pg_catalog.pg_type AS t ON t.oid = a.atttypid
|
|
17
57
|
LEFT JOIN pg_catalog.pg_attrdef AS ad ON ad.adrelid = a.attrelid AND ad.adnum = a.attnum
|
|
58
|
+
LEFT JOIN pg_catalog.pg_collation AS coll ON coll.oid = a.attcollation
|
|
59
|
+
LEFT JOIN pg_catalog.pg_namespace AS cn ON cn.oid = coll.collnamespace
|
|
18
60
|
WHERE a.attnum > 0
|
|
19
61
|
AND NOT a.attisdropped
|
|
20
62
|
AND c.relkind IN ('r', 'p', 'v', 'm', 'f')
|
|
@@ -24,7 +66,8 @@ export const postgresCatalogQueries = {
|
|
|
24
66
|
ORDER BY n.nspname, c.relname, a.attnum
|
|
25
67
|
`,
|
|
26
68
|
enums: `
|
|
27
|
-
SELECT n.nspname AS schema_name, t.typname AS type_name, e.enumlabel AS enum_label
|
|
69
|
+
SELECT n.nspname AS schema_name, t.typname AS type_name, e.enumlabel AS enum_label,
|
|
70
|
+
e.enumsortorder::double precision AS enum_position
|
|
28
71
|
FROM pg_catalog.pg_type AS t
|
|
29
72
|
JOIN pg_catalog.pg_namespace AS n ON n.oid = t.typnamespace
|
|
30
73
|
JOIN pg_catalog.pg_enum AS e ON e.enumtypid = t.oid
|
|
@@ -36,8 +79,15 @@ export const postgresCatalogQueries = {
|
|
|
36
79
|
SELECT
|
|
37
80
|
n.nspname AS schema_name,
|
|
38
81
|
t.typname AS domain_name,
|
|
82
|
+
'pg:' || t.oid::text AS type_identity,
|
|
39
83
|
format_type(t.typbasetype, t.typtypmod) AS database_type,
|
|
40
|
-
t.typnotnull AS not_null
|
|
84
|
+
t.typnotnull AS not_null,
|
|
85
|
+
ARRAY(
|
|
86
|
+
SELECT pg_get_constraintdef(con.oid, true)
|
|
87
|
+
FROM pg_catalog.pg_constraint AS con
|
|
88
|
+
WHERE con.contypid = t.oid
|
|
89
|
+
ORDER BY con.conname
|
|
90
|
+
) AS check_expressions
|
|
41
91
|
FROM pg_catalog.pg_type AS t
|
|
42
92
|
JOIN pg_catalog.pg_namespace AS n ON n.oid = t.typnamespace
|
|
43
93
|
WHERE t.typtype = 'd'
|
|
@@ -49,25 +99,227 @@ export const postgresCatalogQueries = {
|
|
|
49
99
|
SELECT
|
|
50
100
|
n.nspname AS schema_name,
|
|
51
101
|
p.proname AS function_name,
|
|
102
|
+
'pg:' || p.oid::text AS routine_identity,
|
|
103
|
+
p.prokind AS routine_kind,
|
|
52
104
|
ARRAY(
|
|
53
105
|
SELECT format_type(argument_oid, NULL)
|
|
54
|
-
FROM unnest(p.proargtypes::oid[]) WITH ORDINALITY AS arguments(argument_oid, position)
|
|
106
|
+
FROM unnest(COALESCE(p.proallargtypes, p.proargtypes::oid[])) WITH ORDINALITY AS arguments(argument_oid, position)
|
|
55
107
|
ORDER BY position
|
|
56
108
|
) AS argument_types,
|
|
109
|
+
COALESCE(p.proargnames, ARRAY[]::text[]) AS argument_names,
|
|
110
|
+
ARRAY(
|
|
111
|
+
SELECT mode::text
|
|
112
|
+
FROM unnest(COALESCE(p.proargmodes, ARRAY[]::"char"[])) WITH ORDINALITY AS modes(mode, position)
|
|
113
|
+
ORDER BY position
|
|
114
|
+
) AS argument_modes,
|
|
115
|
+
p.pronargdefaults AS argument_defaults,
|
|
57
116
|
format_type(p.prorettype, NULL) AS database_return_type,
|
|
58
117
|
p.proretset AS set_returning,
|
|
59
|
-
p.provolatile AS volatility
|
|
118
|
+
p.provolatile AS volatility,
|
|
119
|
+
p.proisstrict AS strict,
|
|
120
|
+
p.proparallel AS parallel_safety
|
|
60
121
|
FROM pg_catalog.pg_proc AS p
|
|
61
122
|
JOIN pg_catalog.pg_namespace AS n ON n.oid = p.pronamespace
|
|
62
|
-
WHERE p.prokind
|
|
123
|
+
WHERE p.prokind IN ('f', 'p', 'a', 'w')
|
|
63
124
|
AND n.nspname NOT IN ('pg_catalog', 'information_schema')
|
|
64
125
|
AND ($1::text[] IS NULL OR n.nspname = ANY($1::text[]))
|
|
65
126
|
ORDER BY n.nspname, p.proname, p.oid
|
|
66
127
|
`,
|
|
128
|
+
constraints(serverMajor) {
|
|
129
|
+
const nullsNotDistinct = serverMajor >= 15 ? "i.indnullsnotdistinct" : "NULL::boolean";
|
|
130
|
+
return `
|
|
131
|
+
SELECT
|
|
132
|
+
n.nspname AS schema_name,
|
|
133
|
+
c.relname AS table_name,
|
|
134
|
+
con.conname AS constraint_name,
|
|
135
|
+
con.contype AS constraint_type,
|
|
136
|
+
ARRAY(
|
|
137
|
+
SELECT a.attname::text FROM unnest(con.conkey) WITH ORDINALITY AS keys(attnum, position)
|
|
138
|
+
JOIN pg_catalog.pg_attribute AS a ON a.attrelid = con.conrelid AND a.attnum = keys.attnum
|
|
139
|
+
ORDER BY keys.position
|
|
140
|
+
) AS columns,
|
|
141
|
+
rn.nspname AS referenced_schema,
|
|
142
|
+
rc.relname AS referenced_table,
|
|
143
|
+
ARRAY(
|
|
144
|
+
SELECT a.attname::text FROM unnest(con.confkey) WITH ORDINALITY AS keys(attnum, position)
|
|
145
|
+
JOIN pg_catalog.pg_attribute AS a ON a.attrelid = con.confrelid AND a.attnum = keys.attnum
|
|
146
|
+
ORDER BY keys.position
|
|
147
|
+
) AS referenced_columns,
|
|
148
|
+
con.confmatchtype AS match_type,
|
|
149
|
+
con.confupdtype AS update_action,
|
|
150
|
+
con.confdeltype AS delete_action,
|
|
151
|
+
con.condeferrable AS deferrable,
|
|
152
|
+
con.condeferred AS initially_deferred,
|
|
153
|
+
${nullsNotDistinct} AS nulls_not_distinct,
|
|
154
|
+
(array_position(con.conkey, 0) IS NOT NULL) AS expression_based,
|
|
155
|
+
CASE
|
|
156
|
+
WHEN con.contype = 'c' THEN pg_get_expr(con.conbin, con.conrelid)
|
|
157
|
+
WHEN con.contype = 'x' THEN pg_get_expr(i.indpred, i.indrelid)
|
|
158
|
+
ELSE NULL
|
|
159
|
+
END AS predicate_expression,
|
|
160
|
+
CASE WHEN con.contype = 'x' THEN ARRAY(SELECT opr::regoperator::text FROM unnest(con.conexclop) AS opr) ELSE NULL END
|
|
161
|
+
AS exclusion_operators
|
|
162
|
+
FROM pg_catalog.pg_constraint AS con
|
|
163
|
+
JOIN pg_catalog.pg_class AS c ON c.oid = con.conrelid
|
|
164
|
+
JOIN pg_catalog.pg_namespace AS n ON n.oid = c.relnamespace
|
|
165
|
+
LEFT JOIN pg_catalog.pg_class AS rc ON rc.oid = con.confrelid
|
|
166
|
+
LEFT JOIN pg_catalog.pg_namespace AS rn ON rn.oid = rc.relnamespace
|
|
167
|
+
LEFT JOIN pg_catalog.pg_index AS i ON i.indexrelid = con.conindid
|
|
168
|
+
WHERE con.contype IN ('p', 'u', 'f', 'c', 'x')
|
|
169
|
+
AND n.nspname NOT IN ('pg_catalog', 'information_schema')
|
|
170
|
+
AND ($1::text[] IS NULL OR n.nspname = ANY($1::text[]))
|
|
171
|
+
ORDER BY n.nspname, c.relname, con.conname
|
|
172
|
+
`;
|
|
173
|
+
},
|
|
174
|
+
indexes: `
|
|
175
|
+
SELECT
|
|
176
|
+
n.nspname AS schema_name,
|
|
177
|
+
c.relname AS table_name,
|
|
178
|
+
ic.relname AS index_name,
|
|
179
|
+
i.indisunique AS unique,
|
|
180
|
+
am.amname AS method,
|
|
181
|
+
ARRAY(
|
|
182
|
+
SELECT CASE WHEN keys.attnum = 0 THEN NULL ELSE a.attname::text END
|
|
183
|
+
FROM unnest(i.indkey::smallint[]) WITH ORDINALITY AS keys(attnum, position)
|
|
184
|
+
LEFT JOIN pg_catalog.pg_attribute AS a ON a.attrelid = i.indrelid AND a.attnum = keys.attnum
|
|
185
|
+
WHERE keys.position <= i.indnkeyatts ORDER BY keys.position
|
|
186
|
+
) AS key_columns,
|
|
187
|
+
ARRAY(
|
|
188
|
+
SELECT CASE WHEN keys.attnum = 0 THEN pg_get_indexdef(i.indexrelid, keys.position::int, true) ELSE NULL END
|
|
189
|
+
FROM unnest(i.indkey::smallint[]) WITH ORDINALITY AS keys(attnum, position)
|
|
190
|
+
WHERE keys.position <= i.indnkeyatts ORDER BY keys.position
|
|
191
|
+
) AS key_expressions,
|
|
192
|
+
ARRAY(SELECT ((i.indoption[position - 1] & 1) = 1) FROM generate_series(1, i.indnkeyatts) AS position)
|
|
193
|
+
AS descending,
|
|
194
|
+
ARRAY(SELECT ((i.indoption[position - 1] & 2) = 2) FROM generate_series(1, i.indnkeyatts) AS position)
|
|
195
|
+
AS nulls_first,
|
|
196
|
+
ARRAY(
|
|
197
|
+
SELECT opc.opcname::text FROM unnest(i.indclass::oid[]) WITH ORDINALITY AS classes(oid, position)
|
|
198
|
+
JOIN pg_catalog.pg_opclass AS opc ON opc.oid = classes.oid ORDER BY classes.position
|
|
199
|
+
) AS operator_classes,
|
|
200
|
+
ARRAY(
|
|
201
|
+
SELECT CASE WHEN collations.oid = 0 THEN NULL ELSE coll.collname::text END
|
|
202
|
+
FROM unnest(i.indcollation::oid[]) WITH ORDINALITY AS collations(oid, position)
|
|
203
|
+
LEFT JOIN pg_catalog.pg_collation AS coll ON coll.oid = collations.oid ORDER BY collations.position
|
|
204
|
+
) AS collations,
|
|
205
|
+
ARRAY(
|
|
206
|
+
SELECT a.attname::text FROM unnest(i.indkey::smallint[]) WITH ORDINALITY AS keys(attnum, position)
|
|
207
|
+
JOIN pg_catalog.pg_attribute AS a ON a.attrelid = i.indrelid AND a.attnum = keys.attnum
|
|
208
|
+
WHERE keys.position > i.indnkeyatts ORDER BY keys.position
|
|
209
|
+
) AS included_columns,
|
|
210
|
+
pg_get_expr(i.indpred, i.indrelid) AS predicate_expression,
|
|
211
|
+
i.indisvalid AS valid
|
|
212
|
+
FROM pg_catalog.pg_index AS i
|
|
213
|
+
JOIN pg_catalog.pg_class AS c ON c.oid = i.indrelid
|
|
214
|
+
JOIN pg_catalog.pg_namespace AS n ON n.oid = c.relnamespace
|
|
215
|
+
JOIN pg_catalog.pg_class AS ic ON ic.oid = i.indexrelid
|
|
216
|
+
JOIN pg_catalog.pg_am AS am ON am.oid = ic.relam
|
|
217
|
+
WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
|
|
218
|
+
AND ($1::text[] IS NULL OR n.nspname = ANY($1::text[]))
|
|
219
|
+
ORDER BY n.nspname, c.relname, ic.relname
|
|
220
|
+
`,
|
|
221
|
+
composites: `
|
|
222
|
+
SELECT n.nspname AS schema_name, t.typname AS type_name, 'pg:' || t.oid::text AS type_identity,
|
|
223
|
+
a.attname AS field_name, 'pg:' || a.atttypid::text AS field_type_identity,
|
|
224
|
+
format_type(a.atttypid, a.atttypmod) AS field_database_type, a.attnotnull AS field_not_null,
|
|
225
|
+
a.attnum AS field_position
|
|
226
|
+
FROM pg_catalog.pg_type AS t
|
|
227
|
+
JOIN pg_catalog.pg_namespace AS n ON n.oid = t.typnamespace
|
|
228
|
+
JOIN pg_catalog.pg_class AS c ON c.oid = t.typrelid
|
|
229
|
+
JOIN pg_catalog.pg_attribute AS a ON a.attrelid = c.oid AND a.attnum > 0 AND NOT a.attisdropped
|
|
230
|
+
WHERE t.typtype = 'c' AND c.relkind = 'c'
|
|
231
|
+
AND n.nspname NOT IN ('pg_catalog', 'information_schema')
|
|
232
|
+
AND ($1::text[] IS NULL OR n.nspname = ANY($1::text[]))
|
|
233
|
+
ORDER BY n.nspname, t.typname, a.attnum
|
|
234
|
+
`,
|
|
235
|
+
ranges: `
|
|
236
|
+
SELECT n.nspname AS schema_name, t.typname AS type_name, 'pg:' || t.oid::text AS type_identity,
|
|
237
|
+
format_type(t.oid, NULL) AS database_type, 'pg:' || r.rngsubtype::text AS subtype_identity, false AS multirange
|
|
238
|
+
FROM pg_catalog.pg_range AS r
|
|
239
|
+
JOIN pg_catalog.pg_type AS t ON t.oid = r.rngtypid
|
|
240
|
+
JOIN pg_catalog.pg_namespace AS n ON n.oid = t.typnamespace
|
|
241
|
+
WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
|
|
242
|
+
AND ($1::text[] IS NULL OR n.nspname = ANY($1::text[]))
|
|
243
|
+
UNION ALL
|
|
244
|
+
SELECT n.nspname AS schema_name, t.typname AS type_name, 'pg:' || t.oid::text AS type_identity,
|
|
245
|
+
format_type(t.oid, NULL) AS database_type, 'pg:' || r.rngsubtype::text AS subtype_identity, true AS multirange
|
|
246
|
+
FROM pg_catalog.pg_range AS r
|
|
247
|
+
JOIN pg_catalog.pg_type AS t ON t.oid = r.rngmultitypid
|
|
248
|
+
JOIN pg_catalog.pg_namespace AS n ON n.oid = t.typnamespace
|
|
249
|
+
WHERE r.rngmultitypid <> 0
|
|
250
|
+
AND n.nspname NOT IN ('pg_catalog', 'information_schema')
|
|
251
|
+
AND ($1::text[] IS NULL OR n.nspname = ANY($1::text[]))
|
|
252
|
+
ORDER BY schema_name, type_name
|
|
253
|
+
`,
|
|
67
254
|
};
|
|
68
255
|
function qualifiedKey(schema, name) {
|
|
69
256
|
return schema === "public" ? name : `${schema}.${name}`;
|
|
70
257
|
}
|
|
258
|
+
function relationKind(kind) {
|
|
259
|
+
if (kind === "v")
|
|
260
|
+
return "view";
|
|
261
|
+
if (kind === "m")
|
|
262
|
+
return "materialized-view";
|
|
263
|
+
if (kind === "f")
|
|
264
|
+
return "foreign-table";
|
|
265
|
+
return "table";
|
|
266
|
+
}
|
|
267
|
+
function foreignKeyAction(action) {
|
|
268
|
+
if (action === "r")
|
|
269
|
+
return "restrict";
|
|
270
|
+
if (action === "c")
|
|
271
|
+
return "cascade";
|
|
272
|
+
if (action === "n")
|
|
273
|
+
return "set-null";
|
|
274
|
+
if (action === "d")
|
|
275
|
+
return "set-default";
|
|
276
|
+
if (action === "a")
|
|
277
|
+
return "no-action";
|
|
278
|
+
return "unknown";
|
|
279
|
+
}
|
|
280
|
+
function argumentMode(mode) {
|
|
281
|
+
if (mode === "o" || mode === "t")
|
|
282
|
+
return "out";
|
|
283
|
+
if (mode === "b")
|
|
284
|
+
return "inout";
|
|
285
|
+
if (mode === "v")
|
|
286
|
+
return "variadic";
|
|
287
|
+
return "in";
|
|
288
|
+
}
|
|
289
|
+
function routineKind(kind) {
|
|
290
|
+
if (kind === "p")
|
|
291
|
+
return "procedure";
|
|
292
|
+
if (kind === "a")
|
|
293
|
+
return "aggregate";
|
|
294
|
+
if (kind === "w")
|
|
295
|
+
return "window";
|
|
296
|
+
return "function";
|
|
297
|
+
}
|
|
298
|
+
function partitionStrategy(strategy) {
|
|
299
|
+
if (strategy === "h")
|
|
300
|
+
return "hash";
|
|
301
|
+
if (strategy === "l")
|
|
302
|
+
return "list";
|
|
303
|
+
if (strategy === "r")
|
|
304
|
+
return "range";
|
|
305
|
+
return undefined;
|
|
306
|
+
}
|
|
307
|
+
function parallelSafety(safety) {
|
|
308
|
+
if (safety === "r")
|
|
309
|
+
return "restricted";
|
|
310
|
+
if (safety === "s")
|
|
311
|
+
return "safe";
|
|
312
|
+
if (safety === "u")
|
|
313
|
+
return "unsafe";
|
|
314
|
+
return "unknown";
|
|
315
|
+
}
|
|
316
|
+
function polymorphicFamily(types) {
|
|
317
|
+
if (types.some((type) => /^anycompatible/u.test(type)))
|
|
318
|
+
return "postgres-anycompatible";
|
|
319
|
+
if (types.some((type) => /^any/u.test(type)))
|
|
320
|
+
return "postgres-anyelement";
|
|
321
|
+
return undefined;
|
|
322
|
+
}
|
|
71
323
|
function redactError(error, connectionString) {
|
|
72
324
|
const message = error instanceof Error ? error.message : String(error);
|
|
73
325
|
return new Error(message.replaceAll(connectionString, "[REDACTED_DATABASE_URL]"));
|
|
@@ -128,22 +380,40 @@ export class PostgresSchemaProvider {
|
|
|
128
380
|
return withConnection(input, this.#options, async (client) => {
|
|
129
381
|
const schemaFilter = this.#options.includeSchemas === undefined ? null : [...this.#options.includeSchemas];
|
|
130
382
|
const values = [schemaFilter];
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
383
|
+
const versionResult = await client.query(postgresCatalogQueries.version);
|
|
384
|
+
const serverRow = versionResult.rows[0];
|
|
385
|
+
if (serverRow === undefined)
|
|
386
|
+
throw new TypeError("PostgreSQL introspection did not return a server version");
|
|
387
|
+
const version = serverRow.server_version;
|
|
388
|
+
const serverMajor = Number.parseInt(version, 10);
|
|
389
|
+
// A pg Client supports one active query. Keep catalog reads sequential inside the same
|
|
390
|
+
// repeatable-read transaction so this remains valid with pg 9 and driver-compatible clients.
|
|
391
|
+
const enumResult = await client.query(postgresCatalogQueries.enums, values);
|
|
392
|
+
const domainResult = await client.query(postgresCatalogQueries.domains, values);
|
|
393
|
+
const relationResult = await client.query(postgresCatalogQueries.relations, values);
|
|
394
|
+
const columnResult = await client.query(postgresCatalogQueries.columns, values);
|
|
395
|
+
const functionResult = await client.query(postgresCatalogQueries.functions, values);
|
|
396
|
+
const constraintResult = await client.query(postgresCatalogQueries.constraints(serverMajor), values);
|
|
397
|
+
const indexResult = await client.query(postgresCatalogQueries.indexes, values);
|
|
398
|
+
const compositeResult = await client.query(postgresCatalogQueries.composites, values);
|
|
399
|
+
const rangeResult = await client.query(postgresCatalogQueries.ranges, values);
|
|
400
|
+
const enumRows = new Map();
|
|
139
401
|
for (const row of enumResult.rows) {
|
|
140
402
|
const key = qualifiedKey(row.schema_name, row.type_name);
|
|
141
|
-
const
|
|
142
|
-
if (
|
|
143
|
-
|
|
403
|
+
const rows = enumRows.get(key);
|
|
404
|
+
if (rows === undefined)
|
|
405
|
+
enumRows.set(key, [row]);
|
|
144
406
|
else
|
|
145
|
-
|
|
407
|
+
rows.push(row);
|
|
146
408
|
}
|
|
409
|
+
const enums = Object.fromEntries([...enumRows]
|
|
410
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
411
|
+
.map(([key, rows]) => [
|
|
412
|
+
key,
|
|
413
|
+
rows
|
|
414
|
+
.sort((left, right) => (left.enum_position ?? 0) - (right.enum_position ?? 0))
|
|
415
|
+
.map(({ enum_label }) => enum_label),
|
|
416
|
+
]));
|
|
147
417
|
const policy = this.#options.typePolicy ?? defaultPostgresTypePolicy;
|
|
148
418
|
const domains = {};
|
|
149
419
|
for (const row of domainResult.rows) {
|
|
@@ -156,48 +426,388 @@ export class PostgresSchemaProvider {
|
|
|
156
426
|
};
|
|
157
427
|
}
|
|
158
428
|
const partialSchema = { formatVersion: 1, dialect: "postgres", tables: {}, enums, domains };
|
|
159
|
-
const
|
|
429
|
+
const types = {};
|
|
430
|
+
for (const [key, labels] of Object.entries(enums)) {
|
|
431
|
+
const schemaName = enumResult.rows.find((row) => qualifiedKey(row.schema_name, row.type_name) === key)?.schema_name;
|
|
432
|
+
const name = key.slice(key.lastIndexOf(".") + 1);
|
|
433
|
+
types[key] = {
|
|
434
|
+
kind: "enum",
|
|
435
|
+
name,
|
|
436
|
+
...(schemaName === undefined ? {} : { schema: schemaName }),
|
|
437
|
+
identity: `postgres:${schemaName ?? "public"}.${name}`,
|
|
438
|
+
databaseType: key,
|
|
439
|
+
tsType: mapPostgresType(key, policy, partialSchema),
|
|
440
|
+
labels,
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
for (const [key, domain] of Object.entries(domains)) {
|
|
444
|
+
const row = domainResult.rows.find((item) => qualifiedKey(item.schema_name, item.domain_name) === key);
|
|
445
|
+
types[key] = {
|
|
446
|
+
kind: "domain",
|
|
447
|
+
name: domain.name,
|
|
448
|
+
...(row === undefined ? {} : { schema: row.schema_name }),
|
|
449
|
+
identity: row?.type_identity ?? `postgres:${key}`,
|
|
450
|
+
databaseType: domain.databaseType,
|
|
451
|
+
tsType: domain.tsType,
|
|
452
|
+
baseTypeIdentity: domain.databaseType,
|
|
453
|
+
nullable: domain.nullable,
|
|
454
|
+
checks: (row?.check_expressions ?? []).map(fingerprintSchemaExpression).sort(),
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
const compositeGroups = new Map();
|
|
458
|
+
for (const row of compositeResult.rows) {
|
|
459
|
+
const key = qualifiedKey(row.schema_name, row.type_name);
|
|
460
|
+
const rows = compositeGroups.get(key);
|
|
461
|
+
if (rows === undefined)
|
|
462
|
+
compositeGroups.set(key, [row]);
|
|
463
|
+
else
|
|
464
|
+
rows.push(row);
|
|
465
|
+
}
|
|
466
|
+
for (const [key, rows] of compositeGroups) {
|
|
467
|
+
const first = rows[0];
|
|
468
|
+
types[key] = {
|
|
469
|
+
kind: "composite",
|
|
470
|
+
name: first.type_name,
|
|
471
|
+
schema: first.schema_name,
|
|
472
|
+
identity: first.type_identity,
|
|
473
|
+
databaseType: key,
|
|
474
|
+
tsType: "unknown",
|
|
475
|
+
fields: rows
|
|
476
|
+
.sort((left, right) => (left.field_position ?? 0) - (right.field_position ?? 0))
|
|
477
|
+
.map((row) => ({
|
|
478
|
+
name: row.field_name,
|
|
479
|
+
typeIdentity: row.field_type_identity,
|
|
480
|
+
databaseType: row.field_database_type,
|
|
481
|
+
tsType: mapPostgresType(row.field_database_type, policy, partialSchema),
|
|
482
|
+
nullable: !row.field_not_null,
|
|
483
|
+
})),
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
for (const row of rangeResult.rows) {
|
|
487
|
+
const key = qualifiedKey(row.schema_name, row.type_name);
|
|
488
|
+
types[key] = {
|
|
489
|
+
kind: row.multirange ? "multirange" : "range",
|
|
490
|
+
name: row.type_name,
|
|
491
|
+
schema: row.schema_name,
|
|
492
|
+
identity: row.type_identity,
|
|
493
|
+
databaseType: row.database_type,
|
|
494
|
+
tsType: mapPostgresType(row.database_type, policy, partialSchema),
|
|
495
|
+
subtypeIdentity: row.subtype_identity,
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
const relations = {};
|
|
499
|
+
for (const row of relationResult.rows) {
|
|
500
|
+
const parent = row.partition_parent_table === null
|
|
501
|
+
? undefined
|
|
502
|
+
: qualifiedKey(row.partition_parent_schema ?? "public", row.partition_parent_table);
|
|
503
|
+
const strategy = partitionStrategy(row.partition_strategy);
|
|
504
|
+
const capabilities = {
|
|
505
|
+
...(row.relation_kind === "p" ? { partitioned: true } : {}),
|
|
506
|
+
...(row.is_partition ? { partition: true } : {}),
|
|
507
|
+
...(parent === undefined ? {} : { partitionParent: parent }),
|
|
508
|
+
...(strategy === undefined ? {} : { partitionStrategy: strategy }),
|
|
509
|
+
};
|
|
510
|
+
relations[qualifiedKey(row.schema_name, row.table_name)] = {
|
|
511
|
+
schema: row.schema_name,
|
|
512
|
+
name: row.table_name,
|
|
513
|
+
kind: relationKind(row.relation_kind),
|
|
514
|
+
columns: {},
|
|
515
|
+
constraints: [],
|
|
516
|
+
indexes: [],
|
|
517
|
+
...(Object.keys(capabilities).length === 0 ? {} : { capabilities }),
|
|
518
|
+
};
|
|
519
|
+
}
|
|
160
520
|
for (const row of columnResult.rows) {
|
|
161
521
|
const tableKey = qualifiedKey(row.schema_name, row.table_name);
|
|
162
|
-
const existing =
|
|
522
|
+
const existing = relations[tableKey];
|
|
163
523
|
const columns = existing === undefined ? {} : { ...existing.columns };
|
|
164
524
|
const domain = domains[row.database_type];
|
|
165
525
|
columns[row.column_name] = {
|
|
166
526
|
name: row.column_name,
|
|
527
|
+
position: row.column_position ?? Object.keys(columns).length,
|
|
167
528
|
databaseType: row.database_type,
|
|
529
|
+
typeIdentity: row.type_identity ?? row.database_type,
|
|
168
530
|
tsType: mapPostgresType(row.database_type, policy, partialSchema),
|
|
169
531
|
nullable: !row.not_null && (domain?.nullable ?? true),
|
|
170
|
-
|
|
171
|
-
|
|
532
|
+
nullabilitySource: domain === undefined ? "declared" : "domain",
|
|
533
|
+
default: row.generated_kind === "s" ? "none" : row.default_expression === null ? "none" : "present",
|
|
534
|
+
...(row.default_expression === null || row.generated_kind === "s"
|
|
535
|
+
? {}
|
|
536
|
+
: { defaultExpressionHash: fingerprintSchemaExpression(row.default_expression) }),
|
|
537
|
+
generated: row.generated_kind === "s" ? "stored" : "none",
|
|
538
|
+
...(row.generated_kind === "s" && row.default_expression !== null
|
|
539
|
+
? { generatedExpressionHash: fingerprintSchemaExpression(row.default_expression) }
|
|
540
|
+
: {}),
|
|
541
|
+
identity: row.identity_kind === "a" ? "always" : row.identity_kind === "d" ? "by-default" : "none",
|
|
542
|
+
...(row.collation_name === undefined || row.collation_name === null ? {} : { collation: row.collation_name }),
|
|
543
|
+
...(row.is_array ? { dimensions: [] } : {}),
|
|
544
|
+
classification: "normal",
|
|
545
|
+
insertable: row.insertable ?? (row.relation_kind !== "v" && row.relation_kind !== "m"),
|
|
546
|
+
updatable: row.updatable ?? (row.relation_kind !== "v" && row.relation_kind !== "m"),
|
|
547
|
+
};
|
|
548
|
+
relations[tableKey] = {
|
|
549
|
+
schema: row.schema_name,
|
|
550
|
+
name: row.table_name,
|
|
551
|
+
kind: relationKind(row.relation_kind),
|
|
552
|
+
columns,
|
|
553
|
+
constraints: existing?.constraints ?? [],
|
|
554
|
+
indexes: existing?.indexes ?? [],
|
|
555
|
+
...(existing?.capabilities === undefined ? {} : { capabilities: existing.capabilities }),
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
for (const row of columnResult.rows) {
|
|
559
|
+
if (types[row.database_type] !== undefined)
|
|
560
|
+
continue;
|
|
561
|
+
const tsType = mapPostgresType(row.database_type, policy, partialSchema);
|
|
562
|
+
const common = {
|
|
563
|
+
name: row.database_type,
|
|
564
|
+
identity: row.type_identity ?? row.database_type,
|
|
565
|
+
databaseType: row.database_type,
|
|
566
|
+
tsType,
|
|
567
|
+
};
|
|
568
|
+
types[row.database_type] = row.is_array
|
|
569
|
+
? {
|
|
570
|
+
kind: "collection",
|
|
571
|
+
...common,
|
|
572
|
+
elementTypeIdentity: row.database_type.replace(/\[\]$/u, ""),
|
|
573
|
+
dimensions: [],
|
|
574
|
+
}
|
|
575
|
+
: tsType === policy.unknown
|
|
576
|
+
? {
|
|
577
|
+
kind: "opaque",
|
|
578
|
+
...common,
|
|
579
|
+
reason: "The PostgreSQL type has no configured type-policy mapping.",
|
|
580
|
+
}
|
|
581
|
+
: { kind: "scalar", ...common };
|
|
582
|
+
}
|
|
583
|
+
for (const row of constraintResult.rows) {
|
|
584
|
+
const relationKey = qualifiedKey(row.schema_name, row.table_name);
|
|
585
|
+
const relation = relations[relationKey];
|
|
586
|
+
if (relation === undefined)
|
|
587
|
+
continue;
|
|
588
|
+
const base = {
|
|
589
|
+
name: row.constraint_name,
|
|
590
|
+
identity: `${row.schema_name}.${row.table_name}.${row.constraint_name}`,
|
|
591
|
+
columns: row.columns,
|
|
592
|
+
partial: row.predicate_expression === null ? false : row.predicate_expression === undefined ? "unknown" : true,
|
|
593
|
+
expressionBased: row.expression_based ?? false,
|
|
594
|
+
deferrable: row.deferrable,
|
|
595
|
+
initiallyDeferred: row.initially_deferred,
|
|
172
596
|
};
|
|
173
|
-
|
|
597
|
+
const constraint = row.constraint_type === "p"
|
|
598
|
+
? { kind: "primary-key", ...base, nullsDistinct: false }
|
|
599
|
+
: row.constraint_type === "u"
|
|
600
|
+
? {
|
|
601
|
+
kind: "unique",
|
|
602
|
+
...base,
|
|
603
|
+
nullsDistinct: row.nulls_not_distinct == null ? "unknown" : !row.nulls_not_distinct,
|
|
604
|
+
}
|
|
605
|
+
: row.constraint_type === "f"
|
|
606
|
+
? {
|
|
607
|
+
kind: "foreign-key",
|
|
608
|
+
...base,
|
|
609
|
+
referencedRelation: row.referenced_table === undefined || row.referenced_table === null
|
|
610
|
+
? "unknown"
|
|
611
|
+
: qualifiedKey(row.referenced_schema ?? "public", row.referenced_table),
|
|
612
|
+
referencedColumns: row.referenced_columns ?? [],
|
|
613
|
+
match: row.match_type === "f" ? "full" : row.match_type === "p" ? "partial" : "simple",
|
|
614
|
+
onUpdate: foreignKeyAction(row.update_action),
|
|
615
|
+
onDelete: foreignKeyAction(row.delete_action),
|
|
616
|
+
}
|
|
617
|
+
: row.constraint_type === "c"
|
|
618
|
+
? {
|
|
619
|
+
kind: "check",
|
|
620
|
+
...base,
|
|
621
|
+
predicate: row.predicate_expression === undefined ? "unknown" : "present",
|
|
622
|
+
...(row.predicate_expression === undefined || row.predicate_expression === null
|
|
623
|
+
? {}
|
|
624
|
+
: { predicateHash: fingerprintPostgresExpressionSql(row.predicate_expression) }),
|
|
625
|
+
}
|
|
626
|
+
: {
|
|
627
|
+
kind: "exclusion",
|
|
628
|
+
...base,
|
|
629
|
+
elements: (row.exclusion_operators ?? []).map((operator, index) => ({
|
|
630
|
+
...(row.columns[index] === undefined
|
|
631
|
+
? { expressionHash: fingerprintSchemaExpression(`${base.identity}:${index}`) }
|
|
632
|
+
: { column: row.columns[index] }),
|
|
633
|
+
operator,
|
|
634
|
+
})),
|
|
635
|
+
...(row.predicate_expression === undefined || row.predicate_expression === null
|
|
636
|
+
? {}
|
|
637
|
+
: { predicateHash: fingerprintPostgresExpressionSql(row.predicate_expression) }),
|
|
638
|
+
};
|
|
639
|
+
relations[relationKey] = { ...relation, constraints: [...relation.constraints, constraint] };
|
|
174
640
|
}
|
|
175
|
-
const
|
|
176
|
-
|
|
641
|
+
for (const row of indexResult.rows) {
|
|
642
|
+
const relationKey = qualifiedKey(row.schema_name, row.table_name);
|
|
643
|
+
const relation = relations[relationKey];
|
|
644
|
+
if (relation === undefined)
|
|
645
|
+
continue;
|
|
646
|
+
const index = {
|
|
647
|
+
name: row.index_name,
|
|
648
|
+
identity: `${row.schema_name}.${row.table_name}.${row.index_name}`,
|
|
649
|
+
unique: row.unique,
|
|
650
|
+
method: row.method,
|
|
651
|
+
columns: row.key_columns.map((column, offset) => ({
|
|
652
|
+
...(column === null
|
|
653
|
+
? {
|
|
654
|
+
expressionHash: fingerprintPostgresExpressionSql(row.key_expressions[offset] ?? `${row.index_name}:${offset}`),
|
|
655
|
+
}
|
|
656
|
+
: { column }),
|
|
657
|
+
...(row.descending[offset] ? { descending: true } : {}),
|
|
658
|
+
nulls: row.nulls_first[offset] ? "first" : "last",
|
|
659
|
+
...(row.operator_classes[offset] === undefined || row.operator_classes[offset] === null
|
|
660
|
+
? {}
|
|
661
|
+
: { operatorClass: row.operator_classes[offset] }),
|
|
662
|
+
...(row.collations[offset] === undefined || row.collations[offset] === null
|
|
663
|
+
? {}
|
|
664
|
+
: { collation: row.collations[offset] }),
|
|
665
|
+
})),
|
|
666
|
+
...(row.included_columns.length === 0 ? {} : { includedColumns: row.included_columns }),
|
|
667
|
+
predicate: row.predicate_expression === null ? "none" : "present",
|
|
668
|
+
...(row.predicate_expression === null
|
|
669
|
+
? {}
|
|
670
|
+
: { predicateHash: fingerprintPostgresExpressionSql(row.predicate_expression) }),
|
|
671
|
+
valid: row.valid,
|
|
672
|
+
};
|
|
673
|
+
relations[relationKey] = { ...relation, indexes: [...relation.indexes, index] };
|
|
674
|
+
}
|
|
675
|
+
const schemaForFunctions = {
|
|
676
|
+
...partialSchema,
|
|
677
|
+
tables: Object.fromEntries(Object.entries(relations).map(([key, relation]) => [
|
|
678
|
+
key,
|
|
679
|
+
{
|
|
680
|
+
name: relation.name,
|
|
681
|
+
...(relation.schema === undefined ? {} : { schema: relation.schema }),
|
|
682
|
+
columns: Object.fromEntries(Object.entries(relation.columns).map(([columnKey, column]) => [
|
|
683
|
+
columnKey,
|
|
684
|
+
{
|
|
685
|
+
name: column.name,
|
|
686
|
+
databaseType: column.databaseType,
|
|
687
|
+
tsType: column.tsType,
|
|
688
|
+
nullable: column.nullable,
|
|
689
|
+
},
|
|
690
|
+
])),
|
|
691
|
+
},
|
|
692
|
+
])),
|
|
693
|
+
};
|
|
694
|
+
const routines = {};
|
|
177
695
|
for (const row of functionResult.rows) {
|
|
178
696
|
const name = qualifiedKey(row.schema_name, row.function_name);
|
|
179
|
-
const
|
|
180
|
-
|
|
697
|
+
const modes = row.argument_modes ?? [];
|
|
698
|
+
const inputPositions = row.argument_types
|
|
699
|
+
.map((_, index) => index)
|
|
700
|
+
.filter((index) => argumentMode(modes[index]) !== "out");
|
|
701
|
+
const defaultStart = inputPositions.length - (row.argument_defaults ?? 0);
|
|
702
|
+
const argumentsList = row.argument_types.map((databaseType, index) => ({
|
|
703
|
+
...(row.argument_names?.[index] == null ? {} : { name: row.argument_names[index] }),
|
|
704
|
+
mode: argumentMode(modes[index]),
|
|
705
|
+
typeIdentity: databaseType,
|
|
706
|
+
databaseType,
|
|
707
|
+
tsType: mapPostgresType(databaseType, policy, schemaForFunctions),
|
|
708
|
+
default: inputPositions.indexOf(index) >= defaultStart && defaultStart >= 0
|
|
709
|
+
? "present"
|
|
710
|
+
: "none",
|
|
711
|
+
}));
|
|
712
|
+
const outputArguments = argumentsList.filter(({ mode }) => mode === "out" || mode === "inout");
|
|
713
|
+
const kind = routineKind(row.routine_kind);
|
|
714
|
+
const result = kind === "procedure"
|
|
715
|
+
? { kind: "command" }
|
|
716
|
+
: outputArguments.length > 0
|
|
717
|
+
? {
|
|
718
|
+
kind: "table",
|
|
719
|
+
columns: Object.fromEntries(outputArguments.map((argument, position) => [
|
|
720
|
+
argument.name ?? `column${position + 1}`,
|
|
721
|
+
{
|
|
722
|
+
name: argument.name ?? `column${position + 1}`,
|
|
723
|
+
position,
|
|
724
|
+
databaseType: argument.databaseType,
|
|
725
|
+
typeIdentity: argument.typeIdentity,
|
|
726
|
+
tsType: argument.tsType,
|
|
727
|
+
nullable: true,
|
|
728
|
+
nullabilitySource: "unknown",
|
|
729
|
+
default: "none",
|
|
730
|
+
generated: "none",
|
|
731
|
+
identity: "none",
|
|
732
|
+
classification: "normal",
|
|
733
|
+
insertable: false,
|
|
734
|
+
updatable: false,
|
|
735
|
+
},
|
|
736
|
+
])),
|
|
737
|
+
}
|
|
738
|
+
: row.database_return_type === "record"
|
|
739
|
+
? { kind: "record", columns: {} }
|
|
740
|
+
: {
|
|
741
|
+
kind: row.set_returning ? "set" : "scalar",
|
|
742
|
+
typeIdentity: row.database_return_type,
|
|
743
|
+
databaseType: row.database_return_type,
|
|
744
|
+
tsType: mapPostgresType(row.database_return_type, policy, schemaForFunctions),
|
|
745
|
+
nullable: !row.strict,
|
|
746
|
+
};
|
|
747
|
+
const family = polymorphicFamily([...row.argument_types, row.database_return_type]);
|
|
748
|
+
const routine = {
|
|
181
749
|
name: row.function_name,
|
|
182
750
|
schema: row.schema_name,
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
...(row.set_returning ? { setReturning: true } : {}),
|
|
751
|
+
identity: row.routine_identity ?? `${name}(${row.argument_types.join(",")})`,
|
|
752
|
+
kind,
|
|
753
|
+
arguments: argumentsList,
|
|
754
|
+
result,
|
|
188
755
|
volatility: row.volatility === "i" ? "immutable" : row.volatility === "s" ? "stable" : "volatile",
|
|
756
|
+
deterministic: row.volatility === "i" ? true : "unknown",
|
|
757
|
+
dataAccess: "unknown",
|
|
758
|
+
nullInput: row.strict === undefined ? "unknown" : row.strict ? "strict" : "called",
|
|
759
|
+
...(family === undefined ? {} : { polymorphicFamily: family }),
|
|
760
|
+
extension: {
|
|
761
|
+
version: "1",
|
|
762
|
+
attributes: { parallelSafety: parallelSafety(row.parallel_safety) },
|
|
763
|
+
},
|
|
189
764
|
};
|
|
765
|
+
const overloads = routines[name];
|
|
766
|
+
if (overloads === undefined)
|
|
767
|
+
routines[name] = [routine];
|
|
768
|
+
else
|
|
769
|
+
overloads.push(routine);
|
|
190
770
|
}
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
|
|
771
|
+
const namespaces = Object.fromEntries([
|
|
772
|
+
...new Set([
|
|
773
|
+
...columnResult.rows.map(({ schema_name }) => schema_name),
|
|
774
|
+
...relationResult.rows.map(({ schema_name }) => schema_name),
|
|
775
|
+
...enumResult.rows.map(({ schema_name }) => schema_name),
|
|
776
|
+
...domainResult.rows.map(({ schema_name }) => schema_name),
|
|
777
|
+
...functionResult.rows.map(({ schema_name }) => schema_name),
|
|
778
|
+
]),
|
|
779
|
+
]
|
|
780
|
+
.sort()
|
|
781
|
+
.map((name) => [name, { name, kind: "schema" }]));
|
|
782
|
+
const snapshot = defineSchemaSnapshotV2({
|
|
783
|
+
formatVersion: 2,
|
|
194
784
|
dialect: "postgres",
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
785
|
+
dialectVersion: POSTGRES_DIALECT_VERSION,
|
|
786
|
+
server: postgresServerEvidence(version, serverRow.extensions ?? [], {
|
|
787
|
+
...(serverRow.standard_conforming_strings === undefined
|
|
788
|
+
? {}
|
|
789
|
+
: { standardConformingStrings: serverRow.standard_conforming_strings }),
|
|
790
|
+
...(serverRow.search_path === undefined ? {} : { searchPath: serverRow.search_path }),
|
|
791
|
+
visibilityScope: "current-role",
|
|
792
|
+
}),
|
|
793
|
+
namespaces,
|
|
794
|
+
types,
|
|
795
|
+
relations,
|
|
796
|
+
routines,
|
|
797
|
+
extension: {
|
|
798
|
+
version: "1",
|
|
799
|
+
attributes: {
|
|
800
|
+
catalogRevision: postgresCoreCatalog(serverMajor)?.revision ?? "unknown",
|
|
801
|
+
evidenceScope: "current-role",
|
|
802
|
+
partitionRelationships: "captured",
|
|
803
|
+
routineParallelSafety: "captured",
|
|
804
|
+
},
|
|
805
|
+
},
|
|
806
|
+
});
|
|
807
|
+
if ((this.#options.extensionManifests?.length ?? 0) === 0)
|
|
808
|
+
return snapshot;
|
|
809
|
+
return (await introspectPostgresExtensionManifests(snapshot, this.#options.extensionManifests ?? [], client))
|
|
810
|
+
.snapshot;
|
|
201
811
|
});
|
|
202
812
|
}
|
|
203
813
|
}
|