@supabase/postgrest-typegen 0.0.1 → 0.2.0

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.
@@ -16,6 +16,13 @@ export interface GenerateTypescriptOptions {
16
16
  * env read. Default `'public'`.
17
17
  */
18
18
  defaultSchema?: string;
19
+ /**
20
+ * Formatter used on the generated output. Defaults to `oxfmt`, called
21
+ * inline. Callers on a latency-sensitive request path (e.g. postgres-meta's
22
+ * hosted `/generators/typescript` route) can substitute a worker-pool-backed
23
+ * formatter here instead of blocking the event loop on every call.
24
+ */
25
+ format?: (code: string) => Promise<string>;
19
26
  }
20
27
  /**
21
28
  * Does not re-sort collections; pass input pre-sorted with
@@ -3,8 +3,20 @@
3
3
  // literals (relying on Array#toString) to build the output. Preserving that is required for
4
4
  // byte-parity, and the offending expressions sit inside template literals where a targeted
5
5
  // disable comment would corrupt the emitted string.
6
- import prettier from "prettier";
6
+ import { format as oxfmtFormat } from "oxfmt";
7
7
  import { VALID_FUNCTION_ARGS_MODE, VALID_UNNAMED_FUNCTION_ARG_TYPES, } from "./constants.js";
8
+ const defaultFormat = async (code) => {
9
+ const { code: formatted, errors } = await oxfmtFormat("output.ts", code, {
10
+ semi: false,
11
+ printWidth: 80,
12
+ });
13
+ if (errors.length > 0) {
14
+ throw new Error(`oxfmt failed to format generated TypeScript output: ${errors
15
+ .map((error) => error.message)
16
+ .join("; ")}`);
17
+ }
18
+ return formatted;
19
+ };
8
20
  /**
9
21
  * Does not re-sort collections; pass input pre-sorted with
10
22
  * `sortGeneratorMetadata` first. Still merge-sorts tables+foreign tables and
@@ -13,7 +25,7 @@ import { VALID_FUNCTION_ARGS_MODE, VALID_UNNAMED_FUNCTION_ARG_TYPES, } from "./c
13
25
  */
14
26
  export const generateTypescript = async (metadata, opts = {}) => {
15
27
  const { schemas, tables, foreignTables, views, materializedViews, columns, relationships, functions, types, } = metadata;
16
- const { detectOneToOneRelationships = false, postgrestVersion, defaultSchema = "public", } = opts;
28
+ const { detectOneToOneRelationships = false, postgrestVersion, defaultSchema = "public", format = defaultFormat, } = opts;
17
29
  // Ordering of all collections (incl. relationships, columns, args below) is
18
30
  // provided by `sortGeneratorMetadata`; this generator no longer re-sorts.
19
31
  const introspectionBySchema = Object.fromEntries(schemas.map((s) => [
@@ -705,10 +717,7 @@ export const Constants = {
705
717
  })}
706
718
  } as const
707
719
  `;
708
- output = await prettier.format(output, {
709
- parser: "typescript",
710
- semi: false,
711
- });
720
+ output = await format(output);
712
721
  return output;
713
722
  };
714
723
  // TODO: Make this more robust. Currently doesn't handle range types - returns them as unknown.
@@ -32,27 +32,33 @@ export async function introspect(db, opts = {}) {
32
32
  const systemExcludingFilter = filterByList(included, excluded, DEFAULT_SYSTEM_SCHEMAS);
33
33
  const plainFilter = filterByList(included, excluded);
34
34
  const queryRows = async (sql) => normalizeRows((await db.query(sql)).rows);
35
- const schemas = await queryRows(SCHEMAS_SQL({
36
- includeSystemSchemas: false,
37
- nameFilter: systemExcludingFilter,
38
- }));
39
- const tables = await queryRows(TABLES_SQL({ schemaFilter: systemExcludingFilter }));
40
- const foreignTables = await queryRows(FOREIGN_TABLES_SQL({ schemaFilter: plainFilter }));
41
- const views = await queryRows(VIEWS_SQL({ schemaFilter: systemExcludingFilter }));
42
- const materializedViews = await queryRows(MATERIALIZED_VIEWS_SQL({ schemaFilter: plainFilter }));
43
- const columns = await queryRows(COLUMNS_SQL({ schemaFilter: systemExcludingFilter }));
44
- const primaryKeys = await queryRows(PRIMARY_KEYS_SQL({ schemaFilter: systemExcludingFilter }));
45
- const relationships = await listRelationships(db, {
46
- includedSchemas: included,
47
- excludedSchemas: excluded,
48
- });
49
- const functions = await queryRows(FUNCTIONS_SQL({ schemaFilter: systemExcludingFilter }));
50
- // types: includeSystemSchemas true (no schema filter), table + array types included.
51
- const types = await queryRows(TYPES_SQL({
52
- schemaFilter: "",
53
- includeTableTypes: true,
54
- includeArrayTypes: true,
55
- }));
35
+ // Issued concurrently, matching postgres-meta's CLI path which ran its nine
36
+ // introspection queries under Promise.all. A pooled Queryable runs them in
37
+ // parallel; a single-connection one pipelines them, which is no worse than
38
+ // awaiting each in turn.
39
+ const [schemas, tables, foreignTables, views, materializedViews, columns, primaryKeys, relationships, functions, types,] = await Promise.all([
40
+ queryRows(SCHEMAS_SQL({
41
+ includeSystemSchemas: false,
42
+ nameFilter: systemExcludingFilter,
43
+ })),
44
+ queryRows(TABLES_SQL({ schemaFilter: systemExcludingFilter })),
45
+ queryRows(FOREIGN_TABLES_SQL({ schemaFilter: plainFilter })),
46
+ queryRows(VIEWS_SQL({ schemaFilter: systemExcludingFilter })),
47
+ queryRows(MATERIALIZED_VIEWS_SQL({ schemaFilter: plainFilter })),
48
+ queryRows(COLUMNS_SQL({ schemaFilter: systemExcludingFilter })),
49
+ queryRows(PRIMARY_KEYS_SQL({ schemaFilter: systemExcludingFilter })),
50
+ listRelationships(db, {
51
+ includedSchemas: included,
52
+ excludedSchemas: excluded,
53
+ }),
54
+ queryRows(FUNCTIONS_SQL({ schemaFilter: systemExcludingFilter })),
55
+ // types: includeSystemSchemas true (no schema filter), table + array types included.
56
+ queryRows(TYPES_SQL({
57
+ schemaFilter: "",
58
+ includeTableTypes: true,
59
+ includeArrayTypes: true,
60
+ })),
61
+ ]);
56
62
  return {
57
63
  version: GENERATOR_METADATA_VERSION,
58
64
  schemas: schemas.filter(({ name }) => !excludedSchemas.includes(name) &&
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supabase/postgrest-typegen",
3
- "version": "0.0.1",
3
+ "version": "0.2.0",
4
4
  "description": "Type generation for PostgREST from PostgreSQL schemas",
5
5
  "keywords": [
6
6
  "codegen",
@@ -62,8 +62,8 @@
62
62
  },
63
63
  "dependencies": {
64
64
  "arktype": "2.2.3",
65
- "pg-format": "1.0.4",
66
- "prettier": "3.5.3"
65
+ "oxfmt": "0.65.0",
66
+ "pg-format": "1.0.4"
67
67
  },
68
68
  "devDependencies": {
69
69
  "@testcontainers/postgresql": "^12.1.0",
@@ -74,7 +74,6 @@
74
74
  "@types/pg": "^8.23.1",
75
75
  "@types/pg-format": "^1.0.5",
76
76
  "knip": "^6.32.3",
77
- "oxfmt": "0.65.0",
78
77
  "oxlint": "1.80.0",
79
78
  "oxlint-tsgolint": "7.0.2001",
80
79
  "pg": "^8.23.0",
@@ -3,7 +3,7 @@
3
3
  // literals (relying on Array#toString) to build the output. Preserving that is required for
4
4
  // byte-parity, and the offending expressions sit inside template literals where a targeted
5
5
  // disable comment would corrupt the emitted string.
6
- import prettier from "prettier";
6
+ import { format as oxfmtFormat } from "oxfmt";
7
7
  import type {
8
8
  GeneratorMetadata,
9
9
  PostgresColumn,
@@ -35,8 +35,30 @@ export interface GenerateTypescriptOptions {
35
35
  * env read. Default `'public'`.
36
36
  */
37
37
  defaultSchema?: string;
38
+ /**
39
+ * Formatter used on the generated output. Defaults to `oxfmt`, called
40
+ * inline. Callers on a latency-sensitive request path (e.g. postgres-meta's
41
+ * hosted `/generators/typescript` route) can substitute a worker-pool-backed
42
+ * formatter here instead of blocking the event loop on every call.
43
+ */
44
+ format?: (code: string) => Promise<string>;
38
45
  }
39
46
 
47
+ const defaultFormat = async (code: string): Promise<string> => {
48
+ const { code: formatted, errors } = await oxfmtFormat("output.ts", code, {
49
+ semi: false,
50
+ printWidth: 80,
51
+ });
52
+ if (errors.length > 0) {
53
+ throw new Error(
54
+ `oxfmt failed to format generated TypeScript output: ${errors
55
+ .map((error) => error.message)
56
+ .join("; ")}`,
57
+ );
58
+ }
59
+ return formatted;
60
+ };
61
+
40
62
  type TsRelationship = Pick<
41
63
  GeneratorMetadata["relationships"][number],
42
64
  | "foreign_key_name"
@@ -71,6 +93,7 @@ export const generateTypescript = async (
71
93
  detectOneToOneRelationships = false,
72
94
  postgrestVersion,
73
95
  defaultSchema = "public",
96
+ format = defaultFormat,
74
97
  } = opts;
75
98
  // Ordering of all collections (incl. relationships, columns, args below) is
76
99
  // provided by `sortGeneratorMetadata`; this generator no longer re-sorts.
@@ -1016,10 +1039,7 @@ export const Constants = {
1016
1039
  } as const
1017
1040
  `;
1018
1041
 
1019
- output = await prettier.format(output, {
1020
- parser: "typescript",
1021
- semi: false,
1022
- });
1042
+ output = await format(output);
1023
1043
  return output;
1024
1044
  };
1025
1045
 
@@ -62,45 +62,48 @@ export async function introspect(
62
62
  const queryRows = async (sql: string) =>
63
63
  normalizeRows((await db.query(sql)).rows);
64
64
 
65
- const schemas = await queryRows(
66
- SCHEMAS_SQL({
67
- includeSystemSchemas: false,
68
- nameFilter: systemExcludingFilter,
69
- }),
70
- );
71
- const tables = await queryRows(
72
- TABLES_SQL({ schemaFilter: systemExcludingFilter }),
73
- );
74
- const foreignTables = await queryRows(
75
- FOREIGN_TABLES_SQL({ schemaFilter: plainFilter }),
76
- );
77
- const views = await queryRows(
78
- VIEWS_SQL({ schemaFilter: systemExcludingFilter }),
79
- );
80
- const materializedViews = await queryRows(
81
- MATERIALIZED_VIEWS_SQL({ schemaFilter: plainFilter }),
82
- );
83
- const columns = await queryRows(
84
- COLUMNS_SQL({ schemaFilter: systemExcludingFilter }),
85
- );
86
- const primaryKeys = await queryRows(
87
- PRIMARY_KEYS_SQL({ schemaFilter: systemExcludingFilter }),
88
- );
89
- const relationships = await listRelationships(db, {
90
- includedSchemas: included,
91
- excludedSchemas: excluded,
92
- });
93
- const functions = await queryRows(
94
- FUNCTIONS_SQL({ schemaFilter: systemExcludingFilter }),
95
- );
96
- // types: includeSystemSchemas true (no schema filter), table + array types included.
97
- const types = await queryRows(
98
- TYPES_SQL({
99
- schemaFilter: "",
100
- includeTableTypes: true,
101
- includeArrayTypes: true,
65
+ // Issued concurrently, matching postgres-meta's CLI path which ran its nine
66
+ // introspection queries under Promise.all. A pooled Queryable runs them in
67
+ // parallel; a single-connection one pipelines them, which is no worse than
68
+ // awaiting each in turn.
69
+ const [
70
+ schemas,
71
+ tables,
72
+ foreignTables,
73
+ views,
74
+ materializedViews,
75
+ columns,
76
+ primaryKeys,
77
+ relationships,
78
+ functions,
79
+ types,
80
+ ] = await Promise.all([
81
+ queryRows(
82
+ SCHEMAS_SQL({
83
+ includeSystemSchemas: false,
84
+ nameFilter: systemExcludingFilter,
85
+ }),
86
+ ),
87
+ queryRows(TABLES_SQL({ schemaFilter: systemExcludingFilter })),
88
+ queryRows(FOREIGN_TABLES_SQL({ schemaFilter: plainFilter })),
89
+ queryRows(VIEWS_SQL({ schemaFilter: systemExcludingFilter })),
90
+ queryRows(MATERIALIZED_VIEWS_SQL({ schemaFilter: plainFilter })),
91
+ queryRows(COLUMNS_SQL({ schemaFilter: systemExcludingFilter })),
92
+ queryRows(PRIMARY_KEYS_SQL({ schemaFilter: systemExcludingFilter })),
93
+ listRelationships(db, {
94
+ includedSchemas: included,
95
+ excludedSchemas: excluded,
102
96
  }),
103
- );
97
+ queryRows(FUNCTIONS_SQL({ schemaFilter: systemExcludingFilter })),
98
+ // types: includeSystemSchemas true (no schema filter), table + array types included.
99
+ queryRows(
100
+ TYPES_SQL({
101
+ schemaFilter: "",
102
+ includeTableTypes: true,
103
+ includeArrayTypes: true,
104
+ }),
105
+ ),
106
+ ]);
104
107
 
105
108
  return {
106
109
  version: GENERATOR_METADATA_VERSION,