@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,356 @@
1
+ import type {
2
+ GeneratorMetadata,
3
+ PostgresColumn,
4
+ PostgresMaterializedView,
5
+ PostgresSchema,
6
+ PostgresTable,
7
+ PostgresType,
8
+ PostgresView,
9
+ } from "../types.ts";
10
+
11
+ type Operation = "Select" | "Insert" | "Update";
12
+
13
+ /**
14
+ * Emits tables/views/materialized views in `GeneratorMetadata` order. Pass
15
+ * input pre-sorted with `sortGeneratorMetadata` for deterministic output.
16
+ */
17
+ export const generateGo = ({
18
+ schemas,
19
+ tables,
20
+ views,
21
+ materializedViews,
22
+ columns,
23
+ types,
24
+ }: GeneratorMetadata): string => {
25
+ const columnsByTableId = columns.reduce(
26
+ (acc, curr) => {
27
+ acc[curr.table_id] ??= [];
28
+ acc[curr.table_id].push(curr);
29
+ return acc;
30
+ },
31
+ {} as Record<string, PostgresColumn[]>,
32
+ );
33
+
34
+ const compositeTypes = types.filter((type) => type.attributes.length > 0);
35
+
36
+ let output = `
37
+ package database
38
+
39
+ ${tables
40
+ .filter((table) => schemas.some((schema) => schema.name === table.schema))
41
+ .flatMap((table) =>
42
+ generateTableStructsForOperations(
43
+ schemas.find((schema) => schema.name === table.schema)!,
44
+ table,
45
+ columnsByTableId[table.id],
46
+ types,
47
+ ["Select", "Insert", "Update"],
48
+ ),
49
+ )
50
+ .join("\n\n")}
51
+
52
+ ${views
53
+ .filter((view) => schemas.some((schema) => schema.name === view.schema))
54
+ .flatMap((view) =>
55
+ generateTableStructsForOperations(
56
+ schemas.find((schema) => schema.name === view.schema)!,
57
+ view,
58
+ columnsByTableId[view.id],
59
+ types,
60
+ ["Select"],
61
+ ),
62
+ )
63
+ .join("\n\n")}
64
+
65
+ ${materializedViews
66
+ .filter((materializedView) =>
67
+ schemas.some((schema) => schema.name === materializedView.schema),
68
+ )
69
+ .flatMap((materializedView) =>
70
+ generateTableStructsForOperations(
71
+ schemas.find((schema) => schema.name === materializedView.schema)!,
72
+ materializedView,
73
+ columnsByTableId[materializedView.id],
74
+ types,
75
+ ["Select"],
76
+ ),
77
+ )
78
+ .join("\n\n")}
79
+
80
+ ${compositeTypes
81
+ .filter((compositeType) =>
82
+ schemas.some((schema) => schema.name === compositeType.schema),
83
+ )
84
+ .map((compositeType) =>
85
+ generateCompositeTypeStruct(
86
+ schemas.find((schema) => schema.name === compositeType.schema)!,
87
+ compositeType,
88
+ types,
89
+ ),
90
+ )
91
+ .join("\n\n")}
92
+ `.trim();
93
+
94
+ return output;
95
+ };
96
+
97
+ /**
98
+ * Converts a Postgres name to PascalCase.
99
+ *
100
+ * @example
101
+ * ```ts
102
+ * formatForGoTypeName('pokedex') // Pokedex
103
+ * formatForGoTypeName('pokemon_center') // PokemonCenter
104
+ * formatForGoTypeName('victory-road') // VictoryRoad
105
+ * formatForGoTypeName('pokemon league') // PokemonLeague
106
+ * ```
107
+ */
108
+ function formatForGoTypeName(name: string): string {
109
+ return name
110
+ .split(/[^a-zA-Z0-9]/)
111
+ .map((word) => {
112
+ if (word) {
113
+ return `${word[0].toUpperCase()}${word.slice(1)}`;
114
+ } else {
115
+ return "";
116
+ }
117
+ })
118
+ .join("");
119
+ }
120
+
121
+ function generateTableStruct(
122
+ schema: PostgresSchema,
123
+ table: PostgresTable | PostgresView | PostgresMaterializedView,
124
+ columns: PostgresColumn[] | undefined,
125
+ types: PostgresType[],
126
+ operation: Operation,
127
+ ): string {
128
+ // Storing columns as a tuple of [formattedName, type, name] rather than creating the string
129
+ // representation of the line allows us to pre-format the entries. Go formats
130
+ // struct fields to be aligned, e.g.:
131
+ // ```go
132
+ // type Pokemon struct {
133
+ // id int `json:"id"`
134
+ // name string `json:"name"`
135
+ // }
136
+ const columnEntries: [string, string, string][] =
137
+ columns?.map((column) => {
138
+ let nullable: boolean;
139
+ if (operation === "Insert") {
140
+ nullable =
141
+ column.is_nullable ||
142
+ column.is_identity ||
143
+ column.is_generated ||
144
+ !!column.default_value;
145
+ } else if (operation === "Update") {
146
+ nullable = true;
147
+ } else {
148
+ nullable = column.is_nullable;
149
+ }
150
+ return [
151
+ formatForGoTypeName(column.name),
152
+ pgTypeToGoType(column.format, nullable, types),
153
+ column.name,
154
+ ];
155
+ }) ?? [];
156
+
157
+ const [maxFormattedNameLength, maxTypeLength] = columnEntries.reduce(
158
+ ([maxFormattedName, maxType], [formattedName, type]) => {
159
+ return [
160
+ Math.max(maxFormattedName, formattedName.length),
161
+ Math.max(maxType, type.length),
162
+ ];
163
+ },
164
+ [0, 0],
165
+ );
166
+
167
+ // Pad the formatted name and type to align the struct fields, then join
168
+ // create the final string representation of the struct fields.
169
+ const formattedColumnEntries = columnEntries.map(
170
+ ([formattedName, type, name]) => {
171
+ return ` ${formattedName.padEnd(maxFormattedNameLength)} ${type.padEnd(
172
+ maxTypeLength,
173
+ )} \`json:"${name}"\``;
174
+ },
175
+ );
176
+
177
+ return `
178
+ type ${formatForGoTypeName(schema.name)}${formatForGoTypeName(table.name)}${operation} struct {
179
+ ${formattedColumnEntries.join("\n")}
180
+ }
181
+ `.trim();
182
+ }
183
+
184
+ function generateTableStructsForOperations(
185
+ schema: PostgresSchema,
186
+ table: PostgresTable | PostgresView | PostgresMaterializedView,
187
+ columns: PostgresColumn[] | undefined,
188
+ types: PostgresType[],
189
+ operations: Operation[],
190
+ ): string[] {
191
+ return operations.map((operation) =>
192
+ generateTableStruct(schema, table, columns, types, operation),
193
+ );
194
+ }
195
+
196
+ function generateCompositeTypeStruct(
197
+ schema: PostgresSchema,
198
+ type: PostgresType,
199
+ types: PostgresType[],
200
+ ): string {
201
+ // Use the type_id of the attributes to find the types of the attributes
202
+ const typeWithRetrievedAttributes = {
203
+ ...type,
204
+ attributes: type.attributes.map((attribute) => {
205
+ const type = types.find((type) => type.id === attribute.type_id);
206
+ return {
207
+ ...attribute,
208
+ type,
209
+ };
210
+ }),
211
+ };
212
+ const attributeEntries: [string, string, string][] =
213
+ typeWithRetrievedAttributes.attributes.map((attribute) => [
214
+ formatForGoTypeName(attribute.name),
215
+ pgTypeToGoType(attribute.type!.format, false),
216
+ attribute.name,
217
+ ]);
218
+
219
+ const [maxFormattedNameLength, maxTypeLength] = attributeEntries.reduce(
220
+ ([maxFormattedName, maxType], [formattedName, type]) => {
221
+ return [
222
+ Math.max(maxFormattedName, formattedName.length),
223
+ Math.max(maxType, type.length),
224
+ ];
225
+ },
226
+ [0, 0],
227
+ );
228
+
229
+ // Pad the formatted name and type to align the struct fields, then join
230
+ // create the final string representation of the struct fields.
231
+ const formattedAttributeEntries = attributeEntries.map(
232
+ ([formattedName, type, name]) => {
233
+ return ` ${formattedName.padEnd(maxFormattedNameLength)} ${type.padEnd(
234
+ maxTypeLength,
235
+ )} \`json:"${name}"\``;
236
+ },
237
+ );
238
+
239
+ return `
240
+ type ${formatForGoTypeName(schema.name)}${formatForGoTypeName(type.name)} struct {
241
+ ${formattedAttributeEntries.join("\n")}
242
+ }
243
+ `.trim();
244
+ }
245
+
246
+ // Note: the type map uses `interface{ } `, not `any`, to remain compatible with
247
+ // older versions of Go.
248
+ const GO_TYPE_MAP = {
249
+ // Bool
250
+ bool: "bool",
251
+
252
+ // Numbers
253
+ int2: "int16",
254
+ int4: "int32",
255
+ int8: "int64",
256
+ float4: "float32",
257
+ float8: "float64",
258
+ numeric: "float64",
259
+
260
+ // Strings
261
+ bytea: "[]byte",
262
+ bpchar: "string",
263
+ varchar: "string",
264
+ date: "string",
265
+ text: "string",
266
+ citext: "string",
267
+ time: "string",
268
+ timetz: "string",
269
+ timestamp: "string",
270
+ timestamptz: "string",
271
+ interval: "string",
272
+ uuid: "string",
273
+ vector: "string",
274
+
275
+ // JSON
276
+ json: "interface{}",
277
+ jsonb: "interface{}",
278
+
279
+ // Range
280
+ int4range: "string",
281
+ int4multirange: "string",
282
+ int8range: "string",
283
+ int8multirange: "string",
284
+ numrange: "string",
285
+ nummultirange: "string",
286
+ tsrange: "string",
287
+ tsmultirange: "string",
288
+ tstzrange: "string",
289
+ tstzmultirange: "string",
290
+ daterange: "string",
291
+ datemultirange: "string",
292
+
293
+ // Misc
294
+ void: "interface{}",
295
+ record: "map[string]interface{}",
296
+ } as const;
297
+
298
+ type GoType = (typeof GO_TYPE_MAP)[keyof typeof GO_TYPE_MAP];
299
+
300
+ const GO_NULLABLE_TYPE_MAP: Record<GoType, string> = {
301
+ string: "*string",
302
+ bool: "*bool",
303
+ int16: "*int16",
304
+ int32: "*int32",
305
+ int64: "*int64",
306
+ float32: "*float32",
307
+ float64: "*float64",
308
+ "[]byte": "[]byte",
309
+ "interface{}": "interface{}",
310
+ "map[string]interface{}": "map[string]interface{}",
311
+ };
312
+
313
+ function pgTypeToGoType(
314
+ pgType: string,
315
+ nullable: boolean,
316
+ types: PostgresType[] = [],
317
+ ): string {
318
+ let goType: GoType | undefined = undefined;
319
+ if (pgType in GO_TYPE_MAP) {
320
+ goType = GO_TYPE_MAP[pgType as keyof typeof GO_TYPE_MAP];
321
+ }
322
+
323
+ // Enums
324
+ const enumType = types.find(
325
+ (type) => type.name === pgType && type.enums.length > 0,
326
+ );
327
+ if (enumType) {
328
+ goType = "string";
329
+ }
330
+
331
+ if (goType) {
332
+ if (nullable) {
333
+ return GO_NULLABLE_TYPE_MAP[goType];
334
+ }
335
+ return goType;
336
+ }
337
+
338
+ // Composite types
339
+ const compositeType = types.find(
340
+ (type) => type.name === pgType && type.attributes.length > 0,
341
+ );
342
+ if (compositeType) {
343
+ // TODO: generate composite types
344
+ // return formatForGoTypeName(pgType)
345
+ return "map[string]interface{}";
346
+ }
347
+
348
+ // Arrays
349
+ if (pgType.startsWith("_")) {
350
+ const innerType = pgTypeToGoType(pgType.slice(1), nullable, types);
351
+ return `[]${innerType} `;
352
+ }
353
+
354
+ // Fallback
355
+ return "interface{}";
356
+ }
@@ -0,0 +1,13 @@
1
+ export { sortGeneratorMetadata } from "../sort.ts";
2
+ export { generateGo } from "./go.ts";
3
+ export { generatePython } from "./python.ts";
4
+ export {
5
+ generateTypescript,
6
+ type GenerateTypescriptOptions,
7
+ pgTypeToTsType,
8
+ } from "./typescript.ts";
9
+ export {
10
+ type AccessControl,
11
+ generateSwift,
12
+ type GenerateSwiftOptions,
13
+ } from "./swift.ts";