@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.
Files changed (116) hide show
  1. package/CHANGELOG.md +201 -0
  2. package/README.md +17 -0
  3. package/dist/packages/postgres/src/bulk.d.ts.map +1 -1
  4. package/dist/packages/postgres/src/bulk.js +1 -1
  5. package/dist/packages/postgres/src/bulk.js.map +1 -1
  6. package/dist/packages/postgres/src/capabilities.d.ts +19 -0
  7. package/dist/packages/postgres/src/capabilities.d.ts.map +1 -0
  8. package/dist/packages/postgres/src/capabilities.js +120 -0
  9. package/dist/packages/postgres/src/capabilities.js.map +1 -0
  10. package/dist/packages/postgres/src/catalog/generated/14.d.ts +4 -0
  11. package/dist/packages/postgres/src/catalog/generated/14.d.ts.map +1 -0
  12. package/dist/packages/postgres/src/catalog/generated/14.js +2018 -0
  13. package/dist/packages/postgres/src/catalog/generated/14.js.map +1 -0
  14. package/dist/packages/postgres/src/catalog/generated/15.d.ts +4 -0
  15. package/dist/packages/postgres/src/catalog/generated/15.d.ts.map +1 -0
  16. package/dist/packages/postgres/src/catalog/generated/15.js +2012 -0
  17. package/dist/packages/postgres/src/catalog/generated/15.js.map +1 -0
  18. package/dist/packages/postgres/src/catalog/generated/16.d.ts +4 -0
  19. package/dist/packages/postgres/src/catalog/generated/16.d.ts.map +1 -0
  20. package/dist/packages/postgres/src/catalog/generated/16.js +2012 -0
  21. package/dist/packages/postgres/src/catalog/generated/16.js.map +1 -0
  22. package/dist/packages/postgres/src/catalog/generated/17.d.ts +4 -0
  23. package/dist/packages/postgres/src/catalog/generated/17.d.ts.map +1 -0
  24. package/dist/packages/postgres/src/catalog/generated/17.js +2012 -0
  25. package/dist/packages/postgres/src/catalog/generated/17.js.map +1 -0
  26. package/dist/packages/postgres/src/catalog/generated/18.d.ts +4 -0
  27. package/dist/packages/postgres/src/catalog/generated/18.d.ts.map +1 -0
  28. package/dist/packages/postgres/src/catalog/generated/18.js +2048 -0
  29. package/dist/packages/postgres/src/catalog/generated/18.js.map +1 -0
  30. package/dist/packages/postgres/src/catalog/generated/19.d.ts +4 -0
  31. package/dist/packages/postgres/src/catalog/generated/19.d.ts.map +1 -0
  32. package/dist/packages/postgres/src/catalog/generated/19.js +2048 -0
  33. package/dist/packages/postgres/src/catalog/generated/19.js.map +1 -0
  34. package/dist/packages/postgres/src/catalog/index.d.ts +14 -0
  35. package/dist/packages/postgres/src/catalog/index.d.ts.map +1 -0
  36. package/dist/packages/postgres/src/catalog/index.js +86 -0
  37. package/dist/packages/postgres/src/catalog/index.js.map +1 -0
  38. package/dist/packages/postgres/src/catalog/types.d.ts +46 -0
  39. package/dist/packages/postgres/src/catalog/types.d.ts.map +1 -0
  40. package/dist/packages/postgres/src/catalog/types.js +2 -0
  41. package/dist/packages/postgres/src/catalog/types.js.map +1 -0
  42. package/dist/packages/postgres/src/expression-evidence.d.ts +11 -0
  43. package/dist/packages/postgres/src/expression-evidence.d.ts.map +1 -0
  44. package/dist/packages/postgres/src/expression-evidence.js +33 -0
  45. package/dist/packages/postgres/src/expression-evidence.js.map +1 -0
  46. package/dist/packages/postgres/src/extensions.d.ts +61 -0
  47. package/dist/packages/postgres/src/extensions.d.ts.map +1 -0
  48. package/dist/packages/postgres/src/extensions.js +311 -0
  49. package/dist/packages/postgres/src/extensions.js.map +1 -0
  50. package/dist/packages/postgres/src/index.d.ts +13 -0
  51. package/dist/packages/postgres/src/index.d.ts.map +1 -1
  52. package/dist/packages/postgres/src/index.js +51 -17
  53. package/dist/packages/postgres/src/index.js.map +1 -1
  54. package/dist/packages/postgres/src/parser/index.d.ts +8 -0
  55. package/dist/packages/postgres/src/parser/index.d.ts.map +1 -0
  56. package/dist/packages/postgres/src/parser/index.js +4 -0
  57. package/dist/packages/postgres/src/parser/index.js.map +1 -0
  58. package/dist/packages/postgres/src/parser/parser.d.ts +14 -0
  59. package/dist/packages/postgres/src/parser/parser.d.ts.map +1 -0
  60. package/dist/packages/postgres/src/parser/parser.js +2683 -0
  61. package/dist/packages/postgres/src/parser/parser.js.map +1 -0
  62. package/dist/packages/postgres/src/parser/tokenizer.d.ts +15 -0
  63. package/dist/packages/postgres/src/parser/tokenizer.d.ts.map +1 -0
  64. package/dist/packages/postgres/src/parser/tokenizer.js +470 -0
  65. package/dist/packages/postgres/src/parser/tokenizer.js.map +1 -0
  66. package/dist/packages/postgres/src/parser/types.d.ts +652 -0
  67. package/dist/packages/postgres/src/parser/types.d.ts.map +1 -0
  68. package/dist/packages/postgres/src/parser/types.js +9 -0
  69. package/dist/packages/postgres/src/parser/types.js.map +1 -0
  70. package/dist/packages/postgres/src/parser/walk.d.ts +13 -0
  71. package/dist/packages/postgres/src/parser/walk.d.ts.map +1 -0
  72. package/dist/packages/postgres/src/parser/walk.js +374 -0
  73. package/dist/packages/postgres/src/parser/walk.js.map +1 -0
  74. package/dist/packages/postgres/src/pg.d.ts +35 -4
  75. package/dist/packages/postgres/src/pg.d.ts.map +1 -1
  76. package/dist/packages/postgres/src/pg.js +355 -40
  77. package/dist/packages/postgres/src/pg.js.map +1 -1
  78. package/dist/packages/postgres/src/prepared.d.ts +5 -3
  79. package/dist/packages/postgres/src/prepared.d.ts.map +1 -1
  80. package/dist/packages/postgres/src/prepared.js +23 -15
  81. package/dist/packages/postgres/src/prepared.js.map +1 -1
  82. package/dist/packages/postgres/src/provider.d.ts +149 -11
  83. package/dist/packages/postgres/src/provider.d.ts.map +1 -1
  84. package/dist/packages/postgres/src/provider.js +652 -42
  85. package/dist/packages/postgres/src/provider.js.map +1 -1
  86. package/dist/packages/postgres/src/resolver.d.ts +1 -1
  87. package/dist/packages/postgres/src/resolver.d.ts.map +1 -1
  88. package/dist/packages/postgres/src/resolver.js +2767 -203
  89. package/dist/packages/postgres/src/resolver.js.map +1 -1
  90. package/dist/packages/postgres/src/routing.d.ts.map +1 -1
  91. package/dist/packages/postgres/src/routing.js +1 -1
  92. package/dist/packages/postgres/src/routing.js.map +1 -1
  93. package/dist/packages/postgres/src/runtime-compatibility.d.ts +14 -0
  94. package/dist/packages/postgres/src/runtime-compatibility.d.ts.map +1 -0
  95. package/dist/packages/postgres/src/runtime-compatibility.js +63 -0
  96. package/dist/packages/postgres/src/runtime-compatibility.js.map +1 -0
  97. package/dist/packages/postgres/src/runtime.d.ts +10 -1
  98. package/dist/packages/postgres/src/runtime.d.ts.map +1 -1
  99. package/dist/packages/postgres/src/runtime.js +50 -2
  100. package/dist/packages/postgres/src/runtime.js.map +1 -1
  101. package/dist/packages/postgres/src/semantics.d.ts +1 -1
  102. package/dist/packages/postgres/src/semantics.d.ts.map +1 -1
  103. package/dist/packages/postgres/src/semantics.js +19 -6
  104. package/dist/packages/postgres/src/semantics.js.map +1 -1
  105. package/dist/packages/postgres/src/support.d.ts +29 -0
  106. package/dist/packages/postgres/src/support.d.ts.map +1 -0
  107. package/dist/packages/postgres/src/support.js +45 -0
  108. package/dist/packages/postgres/src/support.js.map +1 -0
  109. package/dist/packages/postgres/src/type-policy.d.ts.map +1 -1
  110. package/dist/packages/postgres/src/type-policy.js +34 -43
  111. package/dist/packages/postgres/src/type-policy.js.map +1 -1
  112. package/dist/packages/postgres/src/type-resolution.d.ts +33 -0
  113. package/dist/packages/postgres/src/type-resolution.d.ts.map +1 -0
  114. package/dist/packages/postgres/src/type-resolution.js +906 -0
  115. package/dist/packages/postgres/src/type-resolution.js.map +1 -0
  116. 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: "SELECT current_setting('server_version') AS server_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 = 'f'
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 [versionResult, enumResult, domainResult, columnResult, functionResult] = await Promise.all([
132
- client.query(postgresCatalogQueries.version),
133
- client.query(postgresCatalogQueries.enums, values),
134
- client.query(postgresCatalogQueries.domains, values),
135
- client.query(postgresCatalogQueries.columns, values),
136
- client.query(postgresCatalogQueries.functions, values),
137
- ]);
138
- const enums = {};
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 values = enums[key];
142
- if (values === undefined)
143
- enums[key] = [row.enum_label];
403
+ const rows = enumRows.get(key);
404
+ if (rows === undefined)
405
+ enumRows.set(key, [row]);
144
406
  else
145
- values.push(row.enum_label);
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 tables = {};
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 = tables[tableKey];
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
- ...(row.is_array ? { array: true } : {}),
171
- ...(row.default_expression === null ? {} : { defaultExpression: row.default_expression }),
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
- tables[tableKey] = { schema: row.schema_name, name: row.table_name, columns };
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 schemaForFunctions = { ...partialSchema, tables };
176
- const functions = {};
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 key = `${name}(${row.argument_types.join(",")})`;
180
- functions[key] = {
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
- argumentTypes: row.argument_types,
184
- databaseReturnType: row.database_return_type,
185
- returnType: mapPostgresType(row.database_return_type, policy, schemaForFunctions),
186
- nullable: true,
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 version = versionResult.rows[0]?.server_version;
192
- return {
193
- formatVersion: 1,
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
- ...(version === undefined ? {} : { version }),
196
- tables,
197
- ...(Object.keys(enums).length === 0 ? {} : { enums }),
198
- ...(Object.keys(domains).length === 0 ? {} : { domains }),
199
- ...(Object.keys(functions).length === 0 ? {} : { functions }),
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
  }