@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
package/src/sort.ts ADDED
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Canonical ordering pass for {@link GeneratorMetadata}.
3
+ *
4
+ * The language generators consume the metadata collections in array order.
5
+ * This pass is the single, generator-agnostic stabilizer: it returns a new
6
+ * `GeneratorMetadata` whose every collection is ordered so that any producer
7
+ * (the bundled SQL `introspect()` or a custom injected adapter) yields
8
+ * byte-stable codegen. Generators document that they expect input pre-sorted
9
+ * with this function; ordering is intentionally NOT enforced inside
10
+ * `introspect()` so the concern lives in one place.
11
+ *
12
+ * **The TypeScript generator is the source of truth for ordering.** The keys
13
+ * below replicate the sorts that `generateTypescript` historically applied
14
+ * internally (schemas/tables/views/functions/types/columns/relationships by
15
+ * name; function args by name), so that generator can drop its own sorting and
16
+ * stay byte-identical. The other generators then inherit the same canonical
17
+ * order for free.
18
+ *
19
+ * Keys are **semantic** (schema + name + signature), never oid: equivalent
20
+ * databases assign different oids, so an oid sort would still churn output
21
+ * across environments. `id` is only a final tie-breaker for a total order.
22
+ *
23
+ * Composite type `attributes` and enum values are left untouched — their order
24
+ * is semantically meaningful (struct field / enum-label order) and must be
25
+ * preserved. Function `args` are sorted by name because PostgREST RPC args are
26
+ * addressed by name (the generated type is an object), matching TypeScript.
27
+ */
28
+ import type { GeneratorMetadata, PostgresRelationship } from "./types.ts";
29
+
30
+ // Relations (tables/views/materialized views/foreign tables) and types share a
31
+ // (schema, name) identity within a database; `id` breaks any residual tie.
32
+ const bySchemaName = (
33
+ a: { schema: string; name: string; id: number },
34
+ b: { schema: string; name: string; id: number },
35
+ ): number =>
36
+ a.schema.localeCompare(b.schema) ||
37
+ a.name.localeCompare(b.name) ||
38
+ a.id - b.id;
39
+
40
+ // Mirrors the TypeScript generator's historical `relationships.sort`.
41
+ const byRelationship = (
42
+ a: PostgresRelationship,
43
+ b: PostgresRelationship,
44
+ ): number =>
45
+ a.foreign_key_name.localeCompare(b.foreign_key_name) ||
46
+ a.referenced_relation.localeCompare(b.referenced_relation) ||
47
+ JSON.stringify(a.referenced_columns).localeCompare(
48
+ JSON.stringify(b.referenced_columns),
49
+ );
50
+
51
+ /**
52
+ * Return a new {@link GeneratorMetadata} with every collection ordered by a
53
+ * stable, total, semantic key (matching the TypeScript generator's ordering).
54
+ * Pure (does not mutate the input) and idempotent. Apply this after
55
+ * introspection and before any `generate*` call.
56
+ */
57
+ export function sortGeneratorMetadata(
58
+ metadata: GeneratorMetadata,
59
+ ): GeneratorMetadata {
60
+ return {
61
+ version: metadata.version,
62
+ schemas: [...metadata.schemas].sort(
63
+ (a, b) => a.name.localeCompare(b.name) || a.id - b.id,
64
+ ),
65
+ tables: [...metadata.tables].sort(bySchemaName),
66
+ foreignTables: [...metadata.foreignTables].sort(bySchemaName),
67
+ views: [...metadata.views].sort(bySchemaName),
68
+ materializedViews: [...metadata.materializedViews].sort(bySchemaName),
69
+ // Group columns by their table's (schema, name); name-order within a table
70
+ // (matches the TypeScript generator's per-table `columns.sort(by name)`).
71
+ columns: [...metadata.columns].sort(
72
+ (a, b) =>
73
+ a.schema.localeCompare(b.schema) ||
74
+ a.table.localeCompare(b.table) ||
75
+ a.name.localeCompare(b.name),
76
+ ),
77
+ // Grouped by table like `columns`; within a table the SQL's declared
78
+ // column order (`array_position(indkey, attnum)`) is preserved by the
79
+ // stable sort, since composite key order is meaningful.
80
+ primaryKeys: [...metadata.primaryKeys].sort(
81
+ (a, b) =>
82
+ a.schema.localeCompare(b.schema) ||
83
+ a.table_name.localeCompare(b.table_name),
84
+ ),
85
+ relationships: [...metadata.relationships].sort(byRelationship),
86
+ // Functions can overload, so the signature is part of the identity. Args
87
+ // are addressed by name in generated RPC types, so sort them by name too.
88
+ functions: [...metadata.functions]
89
+ .sort(
90
+ (a, b) =>
91
+ a.schema.localeCompare(b.schema) ||
92
+ a.name.localeCompare(b.name) ||
93
+ a.identity_argument_types.localeCompare(b.identity_argument_types) ||
94
+ a.id - b.id,
95
+ )
96
+ .map((fn) => ({
97
+ ...fn,
98
+ args: [...fn.args].sort((a, b) => a.name.localeCompare(b.name)),
99
+ })),
100
+ types: [...metadata.types].sort(bySchemaName),
101
+ };
102
+ }
package/src/types.ts ADDED
@@ -0,0 +1,237 @@
1
+ /**
2
+ * Public metadata contract for type generation.
3
+ *
4
+ * ArkType is the single source of truth: each `Postgres*` schema below is a
5
+ * runtime validator, and the corresponding exported type is derived from it via
6
+ * `.infer`. The shapes are kept identical to postgres-meta's `src/lib/types.ts`
7
+ * so that postgres-meta can consume this package as a drop-in replacement for
8
+ * its embedded templates (a compile-time equivalence test pins this).
9
+ *
10
+ * `GeneratorMetadata` is the pluggable contract: the SQL introspector is the
11
+ * default producer, but any source able to produce this shape can feed the
12
+ * language generators. Because the producer may be an injected adapter,
13
+ * `parseGeneratorMetadata` is offered so integrators can validate a result at
14
+ * runtime instead of blindly casting it. Validation is deliberately *not* baked
15
+ * into `introspect()` — it is an opt-in helper.
16
+ */
17
+ import { type } from "arktype";
18
+
19
+ const postgresColumnSchema = type({
20
+ table_id: "number",
21
+ schema: "string",
22
+ table: "string",
23
+ /** `<table_id>.<ordinal_position>` */
24
+ id: "string",
25
+ ordinal_position: "number",
26
+ name: "string",
27
+ default_value: "unknown",
28
+ data_type: "string",
29
+ format: "string",
30
+ /**
31
+ * Schema owning `format`'s type. Bare enum/composite/domain names are
32
+ * ambiguous across schemas (two schemas can each define an enum named
33
+ * `mood`); this disambiguates without changing `format` itself.
34
+ */
35
+ type_schema: "string",
36
+ is_identity: "boolean",
37
+ identity_generation: "'ALWAYS' | 'BY DEFAULT' | null",
38
+ is_generated: "boolean",
39
+ is_nullable: "boolean",
40
+ is_updatable: "boolean",
41
+ is_unique: "boolean",
42
+ enums: "string[]",
43
+ check: "string | null",
44
+ comment: "string | null",
45
+ });
46
+ export type PostgresColumn = typeof postgresColumnSchema.infer;
47
+
48
+ const postgresForeignTableSchema = type({
49
+ id: "number",
50
+ schema: "string",
51
+ name: "string",
52
+ comment: "string | null",
53
+ "columns?": postgresColumnSchema.array(),
54
+ });
55
+ export type PostgresForeignTable = typeof postgresForeignTableSchema.infer;
56
+
57
+ const postgresFunctionSchema = type({
58
+ id: "number",
59
+ schema: "string",
60
+ name: "string",
61
+ language: "string",
62
+ definition: "string",
63
+ complete_statement: "string",
64
+ args: type({
65
+ mode: "'in' | 'out' | 'inout' | 'variadic' | 'table'",
66
+ name: "string",
67
+ type_id: "number",
68
+ // `introspect()` emits `null` for the OUT columns of RETURNS TABLE /
69
+ // OUT-arg functions: the introspection SQL sizes `arg_has_defaults` from
70
+ // the input-arg count while `arg_modes`/`arg_types` include output args,
71
+ // so the trailing rows are padded with NULL. postgres-meta types this as a
72
+ // plain boolean, but the opt-in validator must accept the real output.
73
+ has_default: "boolean | null",
74
+ }).array(),
75
+ argument_types: "string",
76
+ identity_argument_types: "string",
77
+ return_type_id: "number",
78
+ return_type: "string",
79
+ return_type_relation_id: "number | null",
80
+ is_set_returning_function: "boolean",
81
+ prorows: "number | null",
82
+ behavior: "'IMMUTABLE' | 'STABLE' | 'VOLATILE'",
83
+ security_definer: "boolean",
84
+ config_params: type({ "[string]": "string" }).or("null"),
85
+ });
86
+ export type PostgresFunction = typeof postgresFunctionSchema.infer;
87
+
88
+ const postgresMaterializedViewSchema = type({
89
+ id: "number",
90
+ schema: "string",
91
+ name: "string",
92
+ is_populated: "boolean",
93
+ comment: "string | null",
94
+ "columns?": postgresColumnSchema.array(),
95
+ });
96
+ export type PostgresMaterializedView =
97
+ typeof postgresMaterializedViewSchema.infer;
98
+
99
+ const postgresPrimaryKeySchema = type({
100
+ schema: "string",
101
+ table_name: "string",
102
+ name: "string",
103
+ table_id: "number",
104
+ });
105
+ export type PostgresPrimaryKey = typeof postgresPrimaryKeySchema.infer;
106
+
107
+ const postgresRelationshipSchema = type({
108
+ foreign_key_name: "string",
109
+ schema: "string",
110
+ relation: "string",
111
+ columns: "string[]",
112
+ is_one_to_one: "boolean",
113
+ referenced_schema: "string",
114
+ referenced_relation: "string",
115
+ referenced_columns: "string[]",
116
+ });
117
+ export type PostgresRelationship = typeof postgresRelationshipSchema.infer;
118
+
119
+ const postgresSchemaSchema = type({
120
+ id: "number",
121
+ name: "string",
122
+ owner: "string",
123
+ });
124
+ export type PostgresSchema = typeof postgresSchemaSchema.infer;
125
+
126
+ const postgresTableSchema = type({
127
+ id: "number",
128
+ schema: "string",
129
+ name: "string",
130
+ rls_enabled: "boolean",
131
+ rls_forced: "boolean",
132
+ replica_identity: "'DEFAULT' | 'INDEX' | 'FULL' | 'NOTHING'",
133
+ bytes: "number",
134
+ size: "string",
135
+ live_rows_estimate: "number",
136
+ dead_rows_estimate: "number",
137
+ comment: "string | null",
138
+ "columns?": postgresColumnSchema.array(),
139
+ });
140
+ export type PostgresTable = typeof postgresTableSchema.infer;
141
+
142
+ const postgresTypeSchema = type({
143
+ id: "number",
144
+ name: "string",
145
+ schema: "string",
146
+ format: "string",
147
+ enums: "string[]",
148
+ attributes: type({ name: "string", type_id: "number" }).array(),
149
+ comment: "string | null",
150
+ type_relation_id: "number | null",
151
+ });
152
+ export type PostgresType = typeof postgresTypeSchema.infer;
153
+
154
+ const postgresViewSchema = type({
155
+ id: "number",
156
+ schema: "string",
157
+ name: "string",
158
+ is_updatable: "boolean",
159
+ comment: "string | null",
160
+ "columns?": postgresColumnSchema.array(),
161
+ });
162
+ export type PostgresView = typeof postgresViewSchema.infer;
163
+
164
+ /**
165
+ * Bumped whenever `GeneratorMetadata`'s shape changes in a way a consumer
166
+ * should branch on. Out-of-process consumers (a generator in another
167
+ * language's SDK repo, fed JSON over a process boundary) only see the
168
+ * serialized document, so a shape change is otherwise undetectable until
169
+ * something breaks at read time.
170
+ */
171
+ export const GENERATOR_METADATA_VERSION = 1;
172
+
173
+ /**
174
+ * The complete set of introspected metadata required to generate types.
175
+ * Produced by `introspect()` (the default SQL-based producer) or any other
176
+ * source able to satisfy this shape. The table-like collections drop the
177
+ * optional `columns` field (mirroring `Omit<…, "columns">`); columns are
178
+ * carried separately on `columns`.
179
+ */
180
+ export const generatorMetadataSchema = type({
181
+ version: `${GENERATOR_METADATA_VERSION}`,
182
+ schemas: postgresSchemaSchema.array(),
183
+ tables: postgresTableSchema.omit("columns").array(),
184
+ foreignTables: postgresForeignTableSchema.omit("columns").array(),
185
+ views: postgresViewSchema.omit("columns").array(),
186
+ materializedViews: postgresMaterializedViewSchema.omit("columns").array(),
187
+ columns: postgresColumnSchema.array(),
188
+ primaryKeys: postgresPrimaryKeySchema.array(),
189
+ relationships: postgresRelationshipSchema.array(),
190
+ functions: postgresFunctionSchema.array(),
191
+ types: postgresTypeSchema.array(),
192
+ });
193
+ export type GeneratorMetadata = typeof generatorMetadataSchema.infer;
194
+
195
+ /**
196
+ * JSON Schema for {@link generatorMetadataSchema}, published so out-of-process
197
+ * consumers (a generator living in its own SDK repo, not this package) can
198
+ * validate or generate types against the contract without depending on
199
+ * ArkType or this package's TypeScript types.
200
+ */
201
+ export const generatorMetadataJsonSchema =
202
+ generatorMetadataSchema.toJsonSchema();
203
+
204
+ /**
205
+ * Serialize a {@link GeneratorMetadata} value to the JSON document that
206
+ * crosses the process boundary to an out-of-process generator (e.g. `dart
207
+ * run supabase_typegen`). `GeneratorMetadata` is plain, JSON-safe data, so
208
+ * this is a thin, explicit boundary rather than a transform, kept as a named
209
+ * export so every caller serializes the contract the same way.
210
+ */
211
+ export function serializeGeneratorMetadata(
212
+ metadata: GeneratorMetadata,
213
+ ): string {
214
+ return JSON.stringify(metadata);
215
+ }
216
+
217
+ /**
218
+ * Validate an unknown value against the {@link generatorMetadataSchema} and
219
+ * return it typed as {@link GeneratorMetadata}. Throws a `TypeError` with
220
+ * ArkType's human-readable summary if validation fails.
221
+ *
222
+ * Offered as an opt-in helper so any integrator producing `GeneratorMetadata`
223
+ * through an injected adapter can verify the result at runtime instead of
224
+ * casting. `introspect()` does not call this — wrap its result yourself when
225
+ * you want the guarantee:
226
+ *
227
+ * ```ts
228
+ * const metadata = parseGeneratorMetadata(await introspect(db));
229
+ * ```
230
+ */
231
+ export function parseGeneratorMetadata(data: unknown): GeneratorMetadata {
232
+ const out = generatorMetadataSchema(data);
233
+ if (out instanceof type.errors) {
234
+ throw new TypeError(`Invalid GeneratorMetadata: ${out.summary}`);
235
+ }
236
+ return out;
237
+ }