@supabase/postgrest-typegen 0.0.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 (78) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +133 -0
  3. package/dist/generation/constants.d.ts +9 -0
  4. package/dist/generation/constants.js +10 -0
  5. package/dist/generation/go.d.ts +6 -0
  6. package/dist/generation/go.js +233 -0
  7. package/dist/generation/index.d.ts +5 -0
  8. package/dist/generation/index.js +5 -0
  9. package/dist/generation/python.d.ts +6 -0
  10. package/dist/generation/python.js +339 -0
  11. package/dist/generation/swift.d.ts +11 -0
  12. package/dist/generation/swift.js +309 -0
  13. package/dist/generation/typescript.d.ts +32 -0
  14. package/dist/generation/typescript.js +796 -0
  15. package/dist/index.d.ts +4 -0
  16. package/dist/index.js +4 -0
  17. package/dist/introspection/index.d.ts +27 -0
  18. package/dist/introspection/index.js +70 -0
  19. package/dist/introspection/normalize.d.ts +31 -0
  20. package/dist/introspection/normalize.js +65 -0
  21. package/dist/introspection/relationships.d.ts +47 -0
  22. package/dist/introspection/relationships.js +85 -0
  23. package/dist/introspection/sql/columns.sql.d.ts +7 -0
  24. package/dist/introspection/sql/columns.sql.js +122 -0
  25. package/dist/introspection/sql/common.d.ts +16 -0
  26. package/dist/introspection/sql/common.js +1 -0
  27. package/dist/introspection/sql/foreign_tables.sql.d.ts +6 -0
  28. package/dist/introspection/sql/foreign_tables.sql.js +18 -0
  29. package/dist/introspection/sql/functions.sql.d.ts +5 -0
  30. package/dist/introspection/sql/functions.sql.js +148 -0
  31. package/dist/introspection/sql/helpers.d.ts +12 -0
  32. package/dist/introspection/sql/helpers.js +28 -0
  33. package/dist/introspection/sql/materialized_views.sql.d.ts +4 -0
  34. package/dist/introspection/sql/materialized_views.sql.js +19 -0
  35. package/dist/introspection/sql/primary_keys.sql.d.ts +4 -0
  36. package/dist/introspection/sql/primary_keys.sql.js +32 -0
  37. package/dist/introspection/sql/schemas.sql.d.ts +6 -0
  38. package/dist/introspection/sql/schemas.sql.js +24 -0
  39. package/dist/introspection/sql/table.sql.d.ts +4 -0
  40. package/dist/introspection/sql/table.sql.js +41 -0
  41. package/dist/introspection/sql/table_relationships.sql.d.ts +2 -0
  42. package/dist/introspection/sql/table_relationships.sql.js +49 -0
  43. package/dist/introspection/sql/types.sql.d.ts +5 -0
  44. package/dist/introspection/sql/types.sql.js +65 -0
  45. package/dist/introspection/sql/views.sql.d.ts +4 -0
  46. package/dist/introspection/sql/views.sql.js +20 -0
  47. package/dist/introspection/sql/views_key_dependencies.sql.d.ts +2 -0
  48. package/dist/introspection/sql/views_key_dependencies.sql.js +195 -0
  49. package/dist/sort.d.ts +35 -0
  50. package/dist/sort.js +48 -0
  51. package/dist/types.d.ts +372 -0
  52. package/dist/types.js +207 -0
  53. package/package.json +87 -0
  54. package/src/generation/constants.ts +11 -0
  55. package/src/generation/go.ts +356 -0
  56. package/src/generation/index.ts +13 -0
  57. package/src/generation/python.ts +461 -0
  58. package/src/generation/swift.ts +481 -0
  59. package/src/generation/typescript.ts +1144 -0
  60. package/src/index.ts +4 -0
  61. package/src/introspection/index.ts +124 -0
  62. package/src/introspection/normalize.ts +71 -0
  63. package/src/introspection/relationships.ts +173 -0
  64. package/src/introspection/sql/columns.sql.ts +131 -0
  65. package/src/introspection/sql/common.ts +18 -0
  66. package/src/introspection/sql/foreign_tables.sql.ts +26 -0
  67. package/src/introspection/sql/functions.sql.ts +159 -0
  68. package/src/introspection/sql/helpers.ts +33 -0
  69. package/src/introspection/sql/materialized_views.sql.ts +25 -0
  70. package/src/introspection/sql/primary_keys.sql.ts +38 -0
  71. package/src/introspection/sql/schemas.sql.ts +32 -0
  72. package/src/introspection/sql/table.sql.ts +47 -0
  73. package/src/introspection/sql/table_relationships.sql.ts +53 -0
  74. package/src/introspection/sql/types.sql.ts +74 -0
  75. package/src/introspection/sql/views.sql.ts +26 -0
  76. package/src/introspection/sql/views_key_dependencies.sql.ts +199 -0
  77. package/src/sort.ts +102 -0
  78. package/src/types.ts +237 -0
@@ -0,0 +1,1144 @@
1
+ // oxlint-disable typescript/restrict-template-expressions -- this is a verbatim port of
2
+ // postgres-meta's template, which intentionally interpolates arrays/values into template
3
+ // literals (relying on Array#toString) to build the output. Preserving that is required for
4
+ // byte-parity, and the offending expressions sit inside template literals where a targeted
5
+ // disable comment would corrupt the emitted string.
6
+ import prettier from "prettier";
7
+ import type {
8
+ GeneratorMetadata,
9
+ PostgresColumn,
10
+ PostgresFunction,
11
+ PostgresSchema,
12
+ PostgresTable,
13
+ PostgresType,
14
+ PostgresView,
15
+ } from "../types.ts";
16
+ import {
17
+ VALID_FUNCTION_ARGS_MODE,
18
+ VALID_UNNAMED_FUNCTION_ARG_TYPES,
19
+ } from "./constants.ts";
20
+
21
+ export interface GenerateTypescriptOptions {
22
+ /**
23
+ * Emit `isOneToOne` on each relationship entry. Mirrors postgres-meta's
24
+ * `detect_one_to_one_relationships` query flag. Default `false`.
25
+ */
26
+ detectOneToOneRelationships?: boolean;
27
+ /**
28
+ * When set, emit `__InternalSupabase.PostgrestVersion` so `createClient`
29
+ * can be instantiated with the right options automatically.
30
+ */
31
+ postgrestVersion?: string;
32
+ /**
33
+ * Schema treated as the default for the generated `Tables`/`Enums`/etc.
34
+ * helper types. Replaces postgres-meta's `GENERATE_TYPES_DEFAULT_SCHEMA`
35
+ * env read. Default `'public'`.
36
+ */
37
+ defaultSchema?: string;
38
+ }
39
+
40
+ type TsRelationship = Pick<
41
+ GeneratorMetadata["relationships"][number],
42
+ | "foreign_key_name"
43
+ | "columns"
44
+ | "is_one_to_one"
45
+ | "referenced_relation"
46
+ | "referenced_columns"
47
+ >;
48
+
49
+ /**
50
+ * Does not re-sort collections; pass input pre-sorted with
51
+ * `sortGeneratorMetadata` first. Still merge-sorts tables+foreign tables and
52
+ * views+materialized views per schema, since that cross-collection grouping
53
+ * can't be expressed by the single-collection `sortGeneratorMetadata` pass.
54
+ */
55
+ export const generateTypescript = async (
56
+ metadata: GeneratorMetadata,
57
+ opts: GenerateTypescriptOptions = {},
58
+ ): Promise<string> => {
59
+ const {
60
+ schemas,
61
+ tables,
62
+ foreignTables,
63
+ views,
64
+ materializedViews,
65
+ columns,
66
+ relationships,
67
+ functions,
68
+ types,
69
+ } = metadata;
70
+ const {
71
+ detectOneToOneRelationships = false,
72
+ postgrestVersion,
73
+ defaultSchema = "public",
74
+ } = opts;
75
+ // Ordering of all collections (incl. relationships, columns, args below) is
76
+ // provided by `sortGeneratorMetadata`; this generator no longer re-sorts.
77
+ const introspectionBySchema = Object.fromEntries<{
78
+ tables: {
79
+ table: Pick<PostgresTable, "id" | "name" | "schema" | "columns">;
80
+ relationships: TsRelationship[];
81
+ }[];
82
+ views: {
83
+ view: PostgresView;
84
+ relationships: TsRelationship[];
85
+ }[];
86
+ functions: { fn: PostgresFunction; inArgs: PostgresFunction["args"] }[];
87
+ enums: PostgresType[];
88
+ compositeTypes: PostgresType[];
89
+ }>(
90
+ schemas.map((s) => [
91
+ s.name,
92
+ { tables: [], views: [], functions: [], enums: [], compositeTypes: [] },
93
+ ]),
94
+ );
95
+ const columnsByTableId: Record<number, PostgresColumn[]> = {};
96
+ const tablesNamesByTableId: Record<number, string> = {};
97
+ const relationTypeByIds = new Map<number, (typeof types)[number]>();
98
+ // group types by id for quicker lookup
99
+ const typesById = new Map<number, (typeof types)[number]>();
100
+ const tablesLike = [
101
+ ...tables,
102
+ ...foreignTables,
103
+ ...views,
104
+ ...materializedViews,
105
+ ];
106
+
107
+ for (const tableLike of tablesLike) {
108
+ columnsByTableId[tableLike.id] = [];
109
+ tablesNamesByTableId[tableLike.id] = tableLike.name;
110
+ }
111
+ for (const column of columns) {
112
+ if (column.table_id in columnsByTableId) {
113
+ columnsByTableId[column.table_id].push(column);
114
+ }
115
+ }
116
+
117
+ for (const type of types) {
118
+ typesById.set(type.id, type);
119
+ // Save all the types that are relation types for quicker lookup
120
+ if (type.type_relation_id) {
121
+ relationTypeByIds.set(type.id, type);
122
+ }
123
+ if (type.schema in introspectionBySchema) {
124
+ if (type.enums.length > 0) {
125
+ introspectionBySchema[type.schema].enums.push(type);
126
+ }
127
+ if (type.attributes.length > 0) {
128
+ introspectionBySchema[type.schema].compositeTypes.push(type);
129
+ }
130
+ }
131
+ }
132
+
133
+ const relationshipsByRelation = new Map<
134
+ string,
135
+ GeneratorMetadata["relationships"]
136
+ >();
137
+ for (const relationship of relationships) {
138
+ const key = `${relationship.schema}.${relationship.relation}`;
139
+ let bucket = relationshipsByRelation.get(key);
140
+ if (!bucket) {
141
+ bucket = [];
142
+ relationshipsByRelation.set(key, bucket);
143
+ }
144
+ bucket.push(relationship);
145
+ }
146
+
147
+ function getRelationships(object: {
148
+ schema: string;
149
+ name: string;
150
+ }): Pick<
151
+ GeneratorMetadata["relationships"][number],
152
+ | "foreign_key_name"
153
+ | "columns"
154
+ | "is_one_to_one"
155
+ | "referenced_relation"
156
+ | "referenced_columns"
157
+ >[] {
158
+ const candidates = relationshipsByRelation.get(
159
+ `${object.schema}.${object.name}`,
160
+ );
161
+ if (!candidates) return [];
162
+ return candidates.filter(
163
+ (relationship) => relationship.referenced_schema === object.schema,
164
+ );
165
+ }
166
+
167
+ function generateRelationshiptTsDefinition(
168
+ relationship: TsRelationship,
169
+ ): string {
170
+ return `{
171
+ foreignKeyName: ${JSON.stringify(relationship.foreign_key_name)}
172
+ columns: ${JSON.stringify(relationship.columns)}${
173
+ detectOneToOneRelationships
174
+ ? `\nisOneToOne: ${relationship.is_one_to_one}`
175
+ : ""
176
+ }
177
+ referencedRelation: ${JSON.stringify(relationship.referenced_relation)}
178
+ referencedColumns: ${JSON.stringify(relationship.referenced_columns)}
179
+ }`;
180
+ }
181
+
182
+ for (const table of tables) {
183
+ if (table.schema in introspectionBySchema) {
184
+ introspectionBySchema[table.schema].tables.push({
185
+ table,
186
+ relationships: getRelationships(table),
187
+ });
188
+ }
189
+ }
190
+ for (const table of foreignTables) {
191
+ if (table.schema in introspectionBySchema) {
192
+ introspectionBySchema[table.schema].tables.push({
193
+ table,
194
+ relationships: getRelationships(table),
195
+ });
196
+ }
197
+ }
198
+ for (const view of views) {
199
+ if (view.schema in introspectionBySchema) {
200
+ introspectionBySchema[view.schema].views.push({
201
+ view,
202
+ relationships: getRelationships(view),
203
+ });
204
+ }
205
+ }
206
+ for (const materializedView of materializedViews) {
207
+ if (materializedView.schema in introspectionBySchema) {
208
+ introspectionBySchema[materializedView.schema].views.push({
209
+ view: {
210
+ ...materializedView,
211
+ is_updatable: false,
212
+ },
213
+ relationships: getRelationships(materializedView),
214
+ });
215
+ }
216
+ }
217
+ // Helper function to get table/view name from relation id
218
+ const getTableNameFromRelationId = (
219
+ relationId: number | null,
220
+ returnTypeId: number | null,
221
+ ): string | null => {
222
+ if (!relationId) return null;
223
+
224
+ if (tablesNamesByTableId[relationId])
225
+ return tablesNamesByTableId[relationId];
226
+ // if it's a composite type we use the type name as relation name to allow sub-selecting fields of the composite type
227
+ const reltype = returnTypeId ? relationTypeByIds.get(returnTypeId) : null;
228
+ return reltype ? reltype.name : null;
229
+ };
230
+
231
+ for (const func of functions) {
232
+ if (func.schema in introspectionBySchema) {
233
+ // Get all input args (in, inout, variadic modes)
234
+ const inArgs = func.args.filter(({ mode }) =>
235
+ VALID_FUNCTION_ARGS_MODE.has(mode),
236
+ );
237
+
238
+ if (
239
+ // Case 1: Function has no parameters
240
+ inArgs.length === 0 ||
241
+ // Case 2: All input args are named
242
+ !inArgs.some(({ name }) => name === "") ||
243
+ // Case 3: All unnamed args have default values AND are valid types
244
+ inArgs.every((arg) => {
245
+ if (arg.name === "") {
246
+ return (
247
+ arg.has_default &&
248
+ VALID_UNNAMED_FUNCTION_ARG_TYPES.has(arg.type_id)
249
+ );
250
+ }
251
+ return true;
252
+ }) ||
253
+ // Case 4: Single unnamed parameter of valid type (json, jsonb, text)
254
+ // Exclude all functions definitions that have only one single argument unnamed argument that isn't
255
+ // a json/jsonb/text as it won't be considered by PostgREST
256
+ (inArgs.length === 1 &&
257
+ inArgs[0].name === "" &&
258
+ (VALID_UNNAMED_FUNCTION_ARG_TYPES.has(inArgs[0].type_id) ||
259
+ // OR if the function have a single unnamed args which is another table (embeded function)
260
+ (relationTypeByIds.get(inArgs[0].type_id) &&
261
+ getTableNameFromRelationId(
262
+ func.return_type_relation_id,
263
+ func.return_type_id,
264
+ )) ||
265
+ // OR if the function takes a table row but doesn't qualify as embedded (for error reporting)
266
+ (relationTypeByIds.get(inArgs[0].type_id) &&
267
+ !getTableNameFromRelationId(
268
+ func.return_type_relation_id,
269
+ func.return_type_id,
270
+ ))))
271
+ ) {
272
+ introspectionBySchema[func.schema].functions.push({ fn: func, inArgs });
273
+ }
274
+ }
275
+ }
276
+ // These per-schema groups MERGE multiple metadata collections — `.tables`
277
+ // combines tables + foreign tables, `.views` combines views + materialized
278
+ // views — so the cross-collection name sort can't be expressed by the
279
+ // single-collection `sortGeneratorMetadata` pass and stays here.
280
+ for (const schema in introspectionBySchema) {
281
+ introspectionBySchema[schema].tables.sort((a, b) =>
282
+ a.table.name.localeCompare(b.table.name),
283
+ );
284
+ introspectionBySchema[schema].views.sort((a, b) =>
285
+ a.view.name.localeCompare(b.view.name),
286
+ );
287
+ introspectionBySchema[schema].functions.sort((a, b) =>
288
+ a.fn.name.localeCompare(b.fn.name),
289
+ );
290
+ introspectionBySchema[schema].enums.sort((a, b) =>
291
+ a.name.localeCompare(b.name),
292
+ );
293
+ introspectionBySchema[schema].compositeTypes.sort((a, b) =>
294
+ a.name.localeCompare(b.name),
295
+ );
296
+ }
297
+
298
+ const getFunctionTsReturnType = (
299
+ fn: PostgresFunction,
300
+ returnType: string,
301
+ ) => {
302
+ // Determine if this function should have SetofOptions
303
+ let setofOptionsInfo = "";
304
+
305
+ const returnTableName = getTableNameFromRelationId(
306
+ fn.return_type_relation_id,
307
+ fn.return_type_id,
308
+ );
309
+ const returnsSetOfTable =
310
+ fn.is_set_returning_function && fn.return_type_relation_id !== null;
311
+ const returnsMultipleRows = fn.prorows !== null && fn.prorows > 1;
312
+ // Case 1: if the function returns a table, we need to add SetofOptions to allow selecting sub fields of the table
313
+ // Those can be used in rpc to select sub fields of a table
314
+ if (returnTableName) {
315
+ setofOptionsInfo = `SetofOptions: {
316
+ from: "*"
317
+ to: ${JSON.stringify(returnTableName)}
318
+ isOneToOne: ${Boolean(!returnsMultipleRows)}
319
+ isSetofReturn: ${fn.is_set_returning_function}
320
+ }`;
321
+ }
322
+ // Case 2: if the function has a single table argument, we need to add SetofOptions to allow selecting sub fields of the table
323
+ // and set the right "from" and "to" values to allow selecting from a table row
324
+ if (fn.args.length === 1) {
325
+ const relationType = relationTypeByIds.get(fn.args[0].type_id);
326
+
327
+ // Only add SetofOptions for functions with table arguments (embedded functions)
328
+ // or specific functions that RETURNS table-name
329
+ if (relationType) {
330
+ const sourceTable = relationType.format;
331
+ // Case 1: Standard embedded function with proper setof detection
332
+ if (returnsSetOfTable && returnTableName) {
333
+ setofOptionsInfo = `SetofOptions: {
334
+ from: ${JSON.stringify(sourceTable)}
335
+ to: ${JSON.stringify(returnTableName)}
336
+ isOneToOne: ${Boolean(!returnsMultipleRows)}
337
+ isSetofReturn: true
338
+ }`;
339
+ } // Case 2: Handle RETURNS table-name those are always a one to one relationship
340
+ else if (returnTableName && !returnsSetOfTable) {
341
+ const targetTable = returnTableName;
342
+ setofOptionsInfo = `SetofOptions: {
343
+ from: ${JSON.stringify(sourceTable)}
344
+ to: ${JSON.stringify(targetTable)}
345
+ isOneToOne: true
346
+ isSetofReturn: false
347
+ }`;
348
+ }
349
+ }
350
+ }
351
+
352
+ // A ROWS 1 estimate may only collapse the array type when SetofOptions is also emitted
353
+ // (returnTableName resolved): postgrest-js relies on isOneToOne to restore the array shape
354
+ // for direct RPC calls. Without that metadata PostgREST still returns an array, so the
355
+ // collapse would make the type diverge from the actual response.
356
+ const collapsibleSingleRow =
357
+ !returnsMultipleRows && returnTableName !== null;
358
+ return `${returnType}${fn.is_set_returning_function && !collapsibleSingleRow ? "[]" : ""}
359
+ ${setofOptionsInfo ? `${setofOptionsInfo}` : ""}`;
360
+ };
361
+
362
+ const getFunctionReturnType = (
363
+ schema: PostgresSchema,
364
+ fn: PostgresFunction,
365
+ ): string => {
366
+ // Case 1: `returns table`.
367
+ const tableArgs = fn.args.filter(({ mode }) => mode === "table");
368
+ if (tableArgs.length > 0) {
369
+ const argsNameAndType = tableArgs.map(({ name, type_id }) => {
370
+ const type = typesById.get(type_id);
371
+ let tsType = "unknown";
372
+ if (type) {
373
+ tsType = pgTypeToTsType(schema, type.name, {
374
+ types,
375
+ schemas,
376
+ tables,
377
+ views,
378
+ });
379
+ }
380
+ return { name, type: tsType };
381
+ });
382
+
383
+ return `{
384
+ ${argsNameAndType.map(({ name, type }) => `${JSON.stringify(name)}: ${type}`)}
385
+ }`;
386
+ }
387
+
388
+ // Case 2: returns a relation's row type.
389
+ const relation =
390
+ introspectionBySchema[schema.name]?.tables.find(
391
+ ({ table: { id } }) => id === fn.return_type_relation_id,
392
+ )?.table ||
393
+ introspectionBySchema[schema.name]?.views.find(
394
+ ({ view: { id } }) => id === fn.return_type_relation_id,
395
+ )?.view;
396
+ if (relation) {
397
+ return `{
398
+ ${columnsByTableId[relation.id]
399
+ .map((column) =>
400
+ generateColumnTsDefinition(
401
+ schema,
402
+ {
403
+ name: column.name,
404
+ format: column.format,
405
+ type_schema: column.type_schema,
406
+ is_nullable: column.is_nullable,
407
+ is_optional: false,
408
+ },
409
+ {
410
+ types,
411
+ schemas,
412
+ tables,
413
+ views,
414
+ },
415
+ ),
416
+ )
417
+ .join(",\n")}
418
+ }`;
419
+ }
420
+
421
+ // Case 3: returns base/array/composite/enum type.
422
+ const type = typesById.get(fn.return_type_id);
423
+ if (type) {
424
+ return pgTypeToTsType(schema, type.name, {
425
+ types,
426
+ schemas,
427
+ tables,
428
+ views,
429
+ });
430
+ }
431
+
432
+ return "unknown";
433
+ };
434
+ // Special error case for functions that take table row but don't qualify as embedded functions
435
+ const hasTableRowError = (
436
+ fn: PostgresFunction,
437
+ inArgs: PostgresFunction["args"],
438
+ ) => {
439
+ if (
440
+ inArgs.length === 1 &&
441
+ inArgs[0].name === "" &&
442
+ relationTypeByIds.get(inArgs[0].type_id) &&
443
+ !getTableNameFromRelationId(fn.return_type_relation_id, fn.return_type_id)
444
+ ) {
445
+ return true;
446
+ }
447
+ return false;
448
+ };
449
+
450
+ // Check for generic conflict cases that need error reporting
451
+ const getConflictError = (
452
+ schema: PostgresSchema,
453
+ fns: Array<{ fn: PostgresFunction; inArgs: PostgresFunction["args"] }>,
454
+ fn: PostgresFunction,
455
+ inArgs: PostgresFunction["args"],
456
+ ) => {
457
+ // If there is a single function definition, there is no conflict
458
+ if (fns.length <= 1) return null;
459
+
460
+ // Generic conflict detection patterns
461
+ // Pattern 1: No-args vs default-args conflicts
462
+ if (inArgs.length === 0) {
463
+ const conflictingFns = fns.filter(
464
+ ({ fn: otherFn, inArgs: otherInArgs }) => {
465
+ if (otherFn === fn) return false;
466
+ return (
467
+ otherInArgs.length === 1 &&
468
+ otherInArgs[0].name === "" &&
469
+ otherInArgs[0].has_default
470
+ );
471
+ },
472
+ );
473
+
474
+ if (conflictingFns.length > 0) {
475
+ const conflictingFn = conflictingFns[0];
476
+ const returnTypeName =
477
+ typesById.get(conflictingFn.fn.return_type_id)?.name || "unknown";
478
+ return `Could not choose the best candidate function between: ${schema.name}.${fn.name}(), ${schema.name}.${fn.name}( => ${returnTypeName}). Try renaming the parameters or the function itself in the database so function overloading can be resolved`;
479
+ }
480
+ }
481
+
482
+ // Pattern 2: Same parameter name but different types (unresolvable overloads)
483
+ if (inArgs.length === 1 && inArgs[0].name !== "") {
484
+ const conflictingFns = fns.filter(
485
+ ({ fn: otherFn, inArgs: otherInArgs }) => {
486
+ if (otherFn === fn) return false;
487
+ return (
488
+ otherInArgs.length === 1 &&
489
+ otherInArgs[0].name === inArgs[0].name &&
490
+ otherInArgs[0].type_id !== inArgs[0].type_id
491
+ );
492
+ },
493
+ );
494
+
495
+ if (conflictingFns.length > 0) {
496
+ const allConflictingFunctions = [{ fn, inArgs }, ...conflictingFns];
497
+ const conflictList = allConflictingFunctions
498
+ .sort((a, b) => {
499
+ const aArgs = a.inArgs;
500
+ const bArgs = b.inArgs;
501
+ return (aArgs[0]?.type_id || 0) - (bArgs[0]?.type_id || 0);
502
+ })
503
+ .map((f) => {
504
+ const args = f.inArgs;
505
+ return `${schema.name}.${fn.name}(${args
506
+ .map(
507
+ (a) =>
508
+ `${a.name || ""} => ${typesById.get(a.type_id)?.name || "unknown"}`,
509
+ )
510
+ .join(", ")})`;
511
+ })
512
+ .join(", ");
513
+
514
+ return `Could not choose the best candidate function between: ${conflictList}. Try renaming the parameters or the function itself in the database so function overloading can be resolved`;
515
+ }
516
+ }
517
+
518
+ return null;
519
+ };
520
+
521
+ const getFunctionSignatures = (
522
+ schema: PostgresSchema,
523
+ fns: Array<{ fn: PostgresFunction; inArgs: PostgresFunction["args"] }>,
524
+ ) => {
525
+ return fns
526
+ .map(({ fn, inArgs }) => {
527
+ let argsType = "never";
528
+ let returnType = getFunctionReturnType(schema, fn);
529
+
530
+ // Check for specific error cases
531
+ const conflictError = getConflictError(schema, fns, fn, inArgs);
532
+ if (conflictError) {
533
+ if (inArgs.length > 0) {
534
+ const argsNameAndType = inArgs.map(
535
+ ({ name, type_id, has_default }) => {
536
+ const type = typesById.get(type_id);
537
+ let tsType = "unknown";
538
+ if (type) {
539
+ tsType = pgTypeToTsType(schema, type.name, {
540
+ types,
541
+ schemas,
542
+ tables,
543
+ views,
544
+ });
545
+ }
546
+ return { name, type: tsType, has_default };
547
+ },
548
+ );
549
+ argsType = `{ ${argsNameAndType.map(
550
+ ({ name, type, has_default }) =>
551
+ `${JSON.stringify(name)}${has_default ? "?" : ""}: ${type}`,
552
+ )} }`;
553
+ }
554
+ returnType = `{ error: true } & ${JSON.stringify(conflictError)}`;
555
+ } else if (hasTableRowError(fn, inArgs)) {
556
+ // Special case for computed fields returning scalars functions
557
+ if (inArgs.length > 0) {
558
+ const argsNameAndType = inArgs.map(
559
+ ({ name, type_id, has_default }) => {
560
+ const type = typesById.get(type_id);
561
+ let tsType = "unknown";
562
+ if (type) {
563
+ tsType = pgTypeToTsType(schema, type.name, {
564
+ types,
565
+ schemas,
566
+ tables,
567
+ views,
568
+ });
569
+ }
570
+ return { name, type: tsType, has_default };
571
+ },
572
+ );
573
+ argsType = `{ ${argsNameAndType.map(
574
+ ({ name, type, has_default }) =>
575
+ `${JSON.stringify(name)}${has_default ? "?" : ""}: ${type}`,
576
+ )} }`;
577
+ }
578
+ returnType = `{ error: true } & ${JSON.stringify(
579
+ `the function ${schema.name}.${fn.name} with parameter or with a single unnamed json/jsonb parameter, but no matches were found in the schema cache`,
580
+ )}`;
581
+ } else if (inArgs.length > 0) {
582
+ const argsNameAndType = inArgs.map(
583
+ ({ name, type_id, has_default }) => {
584
+ const type = typesById.get(type_id);
585
+ let tsType = "unknown";
586
+ if (type) {
587
+ tsType = pgTypeToTsType(schema, type.name, {
588
+ types,
589
+ schemas,
590
+ tables,
591
+ views,
592
+ });
593
+ }
594
+ return { name, type: tsType, has_default };
595
+ },
596
+ );
597
+ argsType = `{ ${argsNameAndType.map(
598
+ ({ name, type, has_default }) =>
599
+ `${JSON.stringify(name)}${has_default ? "?" : ""}: ${type}`,
600
+ )} }`;
601
+ }
602
+
603
+ return `{ Args: ${argsType}; Returns: ${getFunctionTsReturnType(fn, returnType)} }`;
604
+ })
605
+ .join(" |\n");
606
+ };
607
+
608
+ const internal_supabase_schema = postgrestVersion
609
+ ? `// Allows to automatically instantiate createClient with right options
610
+ // instead of createClient<Database, { PostgrestVersion: 'XX' }>(URL, KEY)
611
+ __InternalSupabase: {
612
+ PostgrestVersion: '${postgrestVersion}'
613
+ }`
614
+ : "";
615
+
616
+ function generateNullableUnionTsType(tsType: string, isNullable: boolean) {
617
+ // Only add the null union if the type is not unknown as unknown already includes null
618
+ if (tsType === "unknown" || tsType === "any" || !isNullable) {
619
+ return tsType;
620
+ }
621
+ return `${tsType} | null`;
622
+ }
623
+
624
+ function generateColumnTsDefinition(
625
+ schema: PostgresSchema,
626
+ column: {
627
+ name: string;
628
+ format: string;
629
+ type_schema: string;
630
+ is_nullable: boolean;
631
+ is_optional: boolean;
632
+ },
633
+ context: {
634
+ types: PostgresType[];
635
+ schemas: PostgresSchema[];
636
+ tables: PostgresTable[];
637
+ views: PostgresView[];
638
+ },
639
+ ) {
640
+ return `${JSON.stringify(column.name)}${column.is_optional ? "?" : ""}: ${generateNullableUnionTsType(
641
+ pgTypeToTsType(schema, column.format, context, column.type_schema),
642
+ column.is_nullable,
643
+ )}`;
644
+ }
645
+
646
+ let output = `
647
+ export type Json = string | number | boolean | null | { [key: string]: Json | undefined } | Json[]
648
+
649
+ export type Database = {
650
+ ${internal_supabase_schema}
651
+ ${schemas.map((schema) => {
652
+ const {
653
+ tables: schemaTables,
654
+ views: schemaViews,
655
+ functions: schemaFunctions,
656
+ enums: schemaEnums,
657
+ compositeTypes: schemaCompositeTypes,
658
+ } = introspectionBySchema[schema.name];
659
+ return `${JSON.stringify(schema.name)}: {
660
+ Tables: {
661
+ ${
662
+ schemaTables.length === 0
663
+ ? "[_ in never]: never"
664
+ : schemaTables.map(
665
+ ({
666
+ table,
667
+ relationships,
668
+ }) => `${JSON.stringify(table.name)}: {
669
+ Row: {
670
+ ${[
671
+ ...columnsByTableId[table.id].map((column) =>
672
+ generateColumnTsDefinition(
673
+ schema,
674
+ {
675
+ name: column.name,
676
+ format: column.format,
677
+ type_schema: column.type_schema,
678
+ is_nullable: column.is_nullable,
679
+ is_optional: false,
680
+ },
681
+ { types, schemas, tables, views },
682
+ ),
683
+ ),
684
+ ...schemaFunctions
685
+ .filter(({ fn }) => fn.argument_types === table.name)
686
+ .map(({ fn }) => {
687
+ return `${JSON.stringify(fn.name)}: ${generateNullableUnionTsType(
688
+ getFunctionReturnType(schema, fn),
689
+ true,
690
+ )}`;
691
+ }),
692
+ ]}
693
+ }
694
+ Insert: {
695
+ ${columnsByTableId[table.id].map((column) => {
696
+ if (column.identity_generation === "ALWAYS") {
697
+ return `${JSON.stringify(column.name)}?: never`;
698
+ }
699
+ return generateColumnTsDefinition(
700
+ schema,
701
+ {
702
+ name: column.name,
703
+ format: column.format,
704
+ type_schema: column.type_schema,
705
+ is_nullable: column.is_nullable,
706
+ is_optional:
707
+ column.is_nullable ||
708
+ column.is_identity ||
709
+ column.default_value !== null,
710
+ },
711
+ { types, schemas, tables, views },
712
+ );
713
+ })}
714
+ }
715
+ Update: {
716
+ ${columnsByTableId[table.id].map((column) => {
717
+ if (column.identity_generation === "ALWAYS") {
718
+ return `${JSON.stringify(column.name)}?: never`;
719
+ }
720
+
721
+ return generateColumnTsDefinition(
722
+ schema,
723
+ {
724
+ name: column.name,
725
+ format: column.format,
726
+ type_schema: column.type_schema,
727
+ is_nullable: column.is_nullable,
728
+ is_optional: true,
729
+ },
730
+ { types, schemas, tables, views },
731
+ );
732
+ })}
733
+ }
734
+ Relationships: [
735
+ ${relationships.map(generateRelationshiptTsDefinition)}
736
+ ]
737
+ }`,
738
+ )
739
+ }
740
+ }
741
+ Views: {
742
+ ${
743
+ schemaViews.length === 0
744
+ ? "[_ in never]: never"
745
+ : schemaViews.map(
746
+ ({
747
+ view,
748
+ relationships,
749
+ }) => `${JSON.stringify(view.name)}: {
750
+ Row: {
751
+ ${[
752
+ ...columnsByTableId[view.id].map((column) =>
753
+ generateColumnTsDefinition(
754
+ schema,
755
+ {
756
+ name: column.name,
757
+ format: column.format,
758
+ type_schema: column.type_schema,
759
+ is_nullable: column.is_nullable,
760
+ is_optional: false,
761
+ },
762
+ { types, schemas, tables, views },
763
+ ),
764
+ ),
765
+ ...schemaFunctions
766
+ .filter(({ fn }) => fn.argument_types === view.name)
767
+ .map(
768
+ ({ fn }) =>
769
+ `${JSON.stringify(fn.name)}: ${generateNullableUnionTsType(
770
+ getFunctionReturnType(schema, fn),
771
+ true,
772
+ )}`,
773
+ ),
774
+ ]}
775
+ }
776
+ ${
777
+ view.is_updatable
778
+ ? `Insert: {
779
+ ${columnsByTableId[view.id].map((column) => {
780
+ if (!column.is_updatable) {
781
+ return `${JSON.stringify(column.name)}?: never`;
782
+ }
783
+ return generateColumnTsDefinition(
784
+ schema,
785
+ {
786
+ name: column.name,
787
+ format: column.format,
788
+ type_schema: column.type_schema,
789
+ is_nullable: true,
790
+ is_optional: true,
791
+ },
792
+ { types, schemas, tables, views },
793
+ );
794
+ })}
795
+ }
796
+ Update: {
797
+ ${columnsByTableId[view.id].map((column) => {
798
+ if (!column.is_updatable) {
799
+ return `${JSON.stringify(column.name)}?: never`;
800
+ }
801
+ return generateColumnTsDefinition(
802
+ schema,
803
+ {
804
+ name: column.name,
805
+ format: column.format,
806
+ type_schema: column.type_schema,
807
+ is_nullable: true,
808
+ is_optional: true,
809
+ },
810
+ { types, schemas, tables, views },
811
+ );
812
+ })}
813
+ }
814
+ `
815
+ : ""
816
+ }Relationships: [
817
+ ${relationships.map(generateRelationshiptTsDefinition)}
818
+ ]
819
+ }`,
820
+ )
821
+ }
822
+ }
823
+ Functions: {
824
+ ${(() => {
825
+ if (schemaFunctions.length === 0) {
826
+ return "[_ in never]: never";
827
+ }
828
+ const schemaFunctionsGroupedByName = schemaFunctions.reduce(
829
+ (acc, curr) => {
830
+ acc[curr.fn.name] ??= [];
831
+ acc[curr.fn.name].push(curr);
832
+ return acc;
833
+ },
834
+ {} as Record<string, typeof schemaFunctions>,
835
+ );
836
+ for (const fnName in schemaFunctionsGroupedByName) {
837
+ schemaFunctionsGroupedByName[fnName].sort(
838
+ (a, b) =>
839
+ a.fn.argument_types.localeCompare(b.fn.argument_types) ||
840
+ a.fn.return_type.localeCompare(b.fn.return_type),
841
+ );
842
+ }
843
+
844
+ return Object.entries(schemaFunctionsGroupedByName)
845
+ .map(([fnName, fns]) => {
846
+ const functionSignatures = getFunctionSignatures(schema, fns);
847
+ return `${JSON.stringify(fnName)}:\n${functionSignatures}`;
848
+ })
849
+ .join(",\n");
850
+ })()}
851
+ }
852
+ Enums: {
853
+ ${
854
+ schemaEnums.length === 0
855
+ ? "[_ in never]: never"
856
+ : schemaEnums.map(
857
+ (enum_) =>
858
+ `${JSON.stringify(enum_.name)}: ${enum_.enums
859
+ .map((variant) => JSON.stringify(variant))
860
+ .join("|")}`,
861
+ )
862
+ }
863
+ }
864
+ CompositeTypes: {
865
+ ${
866
+ schemaCompositeTypes.length === 0
867
+ ? "[_ in never]: never"
868
+ : schemaCompositeTypes.map(
869
+ ({ name, attributes }) =>
870
+ `${JSON.stringify(name)}: {
871
+ ${attributes.map(({ name, type_id }) => {
872
+ const type = typesById.get(type_id);
873
+ let tsType = "unknown";
874
+ if (type) {
875
+ tsType = `${generateNullableUnionTsType(
876
+ pgTypeToTsType(schema, type.name, {
877
+ types,
878
+ schemas,
879
+ tables,
880
+ views,
881
+ }),
882
+ true,
883
+ )}`;
884
+ }
885
+ return `${JSON.stringify(name)}: ${tsType}`;
886
+ })}
887
+ }`,
888
+ )
889
+ }
890
+ }
891
+ }`;
892
+ })}
893
+ }
894
+
895
+ type DatabaseWithoutInternals = Omit<Database, '__InternalSupabase'>
896
+
897
+ type DefaultSchema = DatabaseWithoutInternals[Extract<keyof Database, ${JSON.stringify(
898
+ defaultSchema,
899
+ )}>]
900
+
901
+ export type Tables<
902
+ DefaultSchemaTableNameOrOptions extends
903
+ | keyof (DefaultSchema["Tables"] & DefaultSchema["Views"])
904
+ | { schema: keyof DatabaseWithoutInternals },
905
+ TableName extends DefaultSchemaTableNameOrOptions extends {
906
+ schema: keyof DatabaseWithoutInternals
907
+ }
908
+ ? keyof (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] &
909
+ DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Views"])
910
+ : never = never
911
+ > = DefaultSchemaTableNameOrOptions extends { schema: keyof DatabaseWithoutInternals }
912
+ ? (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] &
913
+ DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Views"])[TableName] extends {
914
+ Row: infer R
915
+ }
916
+ ? R
917
+ : never
918
+ : DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema["Tables"] & DefaultSchema["Views"])
919
+ ? (DefaultSchema["Tables"] & DefaultSchema["Views"])[DefaultSchemaTableNameOrOptions] extends {
920
+ Row: infer R
921
+ }
922
+ ? R
923
+ : never
924
+ : never
925
+
926
+ export type TablesInsert<
927
+ DefaultSchemaTableNameOrOptions extends
928
+ | keyof DefaultSchema["Tables"]
929
+ | { schema: keyof DatabaseWithoutInternals },
930
+ TableName extends DefaultSchemaTableNameOrOptions extends {
931
+ schema: keyof DatabaseWithoutInternals
932
+ }
933
+ ? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"]
934
+ : never = never
935
+ > = DefaultSchemaTableNameOrOptions extends { schema: keyof DatabaseWithoutInternals }
936
+ ? DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends {
937
+ Insert: infer I
938
+ }
939
+ ? I
940
+ : never
941
+ : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"]
942
+ ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends {
943
+ Insert: infer I
944
+ }
945
+ ? I
946
+ : never
947
+ : never
948
+
949
+ export type TablesUpdate<
950
+ DefaultSchemaTableNameOrOptions extends
951
+ | keyof DefaultSchema["Tables"]
952
+ | { schema: keyof DatabaseWithoutInternals },
953
+ TableName extends DefaultSchemaTableNameOrOptions extends {
954
+ schema: keyof DatabaseWithoutInternals
955
+ }
956
+ ? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"]
957
+ : never = never
958
+ > = DefaultSchemaTableNameOrOptions extends { schema: keyof DatabaseWithoutInternals }
959
+ ? DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends {
960
+ Update: infer U
961
+ }
962
+ ? U
963
+ : never
964
+ : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"]
965
+ ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends {
966
+ Update: infer U
967
+ }
968
+ ? U
969
+ : never
970
+ : never
971
+
972
+ export type Enums<
973
+ DefaultSchemaEnumNameOrOptions extends
974
+ | keyof DefaultSchema["Enums"]
975
+ | { schema: keyof DatabaseWithoutInternals },
976
+ EnumName extends DefaultSchemaEnumNameOrOptions extends {
977
+ schema: keyof DatabaseWithoutInternals
978
+ }
979
+ ? keyof DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"]
980
+ : never = never
981
+ > = DefaultSchemaEnumNameOrOptions extends { schema: keyof DatabaseWithoutInternals }
982
+ ? DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"][EnumName]
983
+ : DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema["Enums"]
984
+ ? DefaultSchema["Enums"][DefaultSchemaEnumNameOrOptions]
985
+ : never
986
+
987
+ export type CompositeTypes<
988
+ PublicCompositeTypeNameOrOptions extends
989
+ | keyof DefaultSchema["CompositeTypes"]
990
+ | { schema: keyof DatabaseWithoutInternals },
991
+ CompositeTypeName extends PublicCompositeTypeNameOrOptions extends {
992
+ schema: keyof DatabaseWithoutInternals
993
+ }
994
+ ? keyof DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"]
995
+ : never = never
996
+ > = PublicCompositeTypeNameOrOptions extends { schema: keyof DatabaseWithoutInternals }
997
+ ? DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"][CompositeTypeName]
998
+ : PublicCompositeTypeNameOrOptions extends keyof DefaultSchema["CompositeTypes"]
999
+ ? DefaultSchema["CompositeTypes"][PublicCompositeTypeNameOrOptions]
1000
+ : never
1001
+
1002
+ export const Constants = {
1003
+ ${schemas.map((schema) => {
1004
+ const schemaEnums = introspectionBySchema[schema.name].enums;
1005
+ return `${JSON.stringify(schema.name)}: {
1006
+ Enums: {
1007
+ ${schemaEnums.map(
1008
+ (enum_) =>
1009
+ `${JSON.stringify(enum_.name)}: [${enum_.enums
1010
+ .map((variant) => JSON.stringify(variant))
1011
+ .join(", ")}]`,
1012
+ )}
1013
+ }
1014
+ }`;
1015
+ })}
1016
+ } as const
1017
+ `;
1018
+
1019
+ output = await prettier.format(output, {
1020
+ parser: "typescript",
1021
+ semi: false,
1022
+ });
1023
+ return output;
1024
+ };
1025
+
1026
+ // TODO: Make this more robust. Currently doesn't handle range types - returns them as unknown.
1027
+ export const pgTypeToTsType = (
1028
+ schema: PostgresSchema,
1029
+ pgType: string,
1030
+ {
1031
+ types,
1032
+ schemas,
1033
+ tables,
1034
+ views,
1035
+ }: {
1036
+ types: PostgresType[];
1037
+ schemas: PostgresSchema[];
1038
+ tables: PostgresTable[];
1039
+ views: PostgresView[];
1040
+ },
1041
+ // The schema that actually owns `pgType` (a column's `type_schema`), when
1042
+ // known. Disambiguates same-named enums/composites across schemas; falls
1043
+ // back to `schema.name` (the table's own schema) when not provided, e.g.
1044
+ // for function args/return types where no equivalent field exists yet.
1045
+ typeSchema?: string,
1046
+ ): string => {
1047
+ if (pgType === "bool") {
1048
+ return "boolean";
1049
+ } else if (
1050
+ ["int2", "int4", "int8", "float4", "float8", "numeric"].includes(pgType)
1051
+ ) {
1052
+ return "number";
1053
+ } else if (
1054
+ [
1055
+ "bytea",
1056
+ "bpchar",
1057
+ "varchar",
1058
+ "date",
1059
+ "text",
1060
+ "citext",
1061
+ "time",
1062
+ "timetz",
1063
+ "timestamp",
1064
+ "timestamptz",
1065
+ "uuid",
1066
+ "vector",
1067
+ "interval",
1068
+ ].includes(pgType)
1069
+ ) {
1070
+ return "string";
1071
+ } else if (["json", "jsonb"].includes(pgType)) {
1072
+ return "Json";
1073
+ } else if (pgType === "void") {
1074
+ return "undefined";
1075
+ } else if (pgType === "record") {
1076
+ return "Record<string, unknown>";
1077
+ } else if (pgType.startsWith("_")) {
1078
+ return `(${pgTypeToTsType(
1079
+ schema,
1080
+ pgType.substring(1),
1081
+ { types, schemas, tables, views },
1082
+ typeSchema,
1083
+ )})[]`;
1084
+ } else {
1085
+ const preferredSchema = typeSchema ?? schema.name;
1086
+ const enumTypes = types.filter(
1087
+ (type) => type.name === pgType && type.enums.length > 0,
1088
+ );
1089
+ if (enumTypes.length > 0) {
1090
+ const enumType =
1091
+ enumTypes.find((type) => type.schema === preferredSchema) ||
1092
+ enumTypes[0];
1093
+ if (schemas.some(({ name }) => name === enumType.schema)) {
1094
+ return `Database[${JSON.stringify(enumType.schema)}]['Enums'][${JSON.stringify(
1095
+ enumType.name,
1096
+ )}]`;
1097
+ }
1098
+ return enumType.enums.map((variant) => JSON.stringify(variant)).join("|");
1099
+ }
1100
+
1101
+ const compositeTypes = types.filter(
1102
+ (type) => type.name === pgType && type.attributes.length > 0,
1103
+ );
1104
+ if (compositeTypes.length > 0) {
1105
+ const compositeType =
1106
+ compositeTypes.find((type) => type.schema === preferredSchema) ||
1107
+ compositeTypes[0];
1108
+ if (schemas.some(({ name }) => name === compositeType.schema)) {
1109
+ return `Database[${JSON.stringify(
1110
+ compositeType.schema,
1111
+ )}]['CompositeTypes'][${JSON.stringify(compositeType.name)}]`;
1112
+ }
1113
+ return "unknown";
1114
+ }
1115
+
1116
+ const tableRowTypes = tables.filter((table) => table.name === pgType);
1117
+ if (tableRowTypes.length > 0) {
1118
+ const tableRowType =
1119
+ tableRowTypes.find((type) => type.schema === preferredSchema) ||
1120
+ tableRowTypes[0];
1121
+ if (schemas.some(({ name }) => name === tableRowType.schema)) {
1122
+ return `Database[${JSON.stringify(tableRowType.schema)}]['Tables'][${JSON.stringify(
1123
+ tableRowType.name,
1124
+ )}]['Row']`;
1125
+ }
1126
+ return "unknown";
1127
+ }
1128
+
1129
+ const viewRowTypes = views.filter((view) => view.name === pgType);
1130
+ if (viewRowTypes.length > 0) {
1131
+ const viewRowType =
1132
+ viewRowTypes.find((type) => type.schema === preferredSchema) ||
1133
+ viewRowTypes[0];
1134
+ if (schemas.some(({ name }) => name === viewRowType.schema)) {
1135
+ return `Database[${JSON.stringify(viewRowType.schema)}]['Views'][${JSON.stringify(
1136
+ viewRowType.name,
1137
+ )}]['Row']`;
1138
+ }
1139
+ return "unknown";
1140
+ }
1141
+
1142
+ return "unknown";
1143
+ }
1144
+ };