postgresdk 0.1.1-alpha.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.
Files changed (96) hide show
  1. package/README.md +15 -0
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +5833 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/emit-client.d.ts +3 -0
  7. package/dist/emit-client.d.ts.map +1 -0
  8. package/dist/emit-client.js +114 -0
  9. package/dist/emit-client.js.map +1 -0
  10. package/dist/emit-include-builder.d.ts +2 -0
  11. package/dist/emit-include-builder.d.ts.map +1 -0
  12. package/dist/emit-include-builder.js +30 -0
  13. package/dist/emit-include-builder.js.map +1 -0
  14. package/dist/emit-include-loader.d.ts +9 -0
  15. package/dist/emit-include-loader.d.ts.map +1 -0
  16. package/dist/emit-include-loader.js +299 -0
  17. package/dist/emit-include-loader.js.map +1 -0
  18. package/dist/emit-include-spec.d.ts +2 -0
  19. package/dist/emit-include-spec.d.ts.map +1 -0
  20. package/dist/emit-include-spec.js +26 -0
  21. package/dist/emit-include-spec.js.map +1 -0
  22. package/dist/emit-logger.d.ts +1 -0
  23. package/dist/emit-logger.d.ts.map +1 -0
  24. package/dist/emit-logger.js +35 -0
  25. package/dist/emit-logger.js.map +1 -0
  26. package/dist/emit-routes.d.ts +20 -0
  27. package/dist/emit-routes.d.ts.map +1 -0
  28. package/dist/emit-routes.js +208 -0
  29. package/dist/emit-routes.js.map +1 -0
  30. package/dist/emit-types.d.ts +5 -0
  31. package/dist/emit-types.d.ts.map +1 -0
  32. package/dist/emit-types.js +51 -0
  33. package/dist/emit-types.js.map +1 -0
  34. package/dist/emit-zod.d.ts +5 -0
  35. package/dist/emit-zod.d.ts.map +1 -0
  36. package/dist/emit-zod.js +43 -0
  37. package/dist/emit-zod.js.map +1 -0
  38. package/dist/gen.config.d.ts +10 -0
  39. package/dist/gen.config.js +10 -0
  40. package/dist/gen.config.js.map +1 -0
  41. package/dist/index.d.ts +1 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +5793 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/introspect.d.ts +26 -0
  46. package/dist/introspect.d.ts.map +1 -0
  47. package/dist/introspect.js +132 -0
  48. package/dist/introspect.js.map +1 -0
  49. package/dist/rel-classify.d.ts +10 -0
  50. package/dist/rel-classify.d.ts.map +1 -0
  51. package/dist/rel-classify.js +52 -0
  52. package/dist/rel-classify.js.map +1 -0
  53. package/dist/src/cli.d.ts +2 -0
  54. package/dist/src/cli.js +39 -0
  55. package/dist/src/cli.js.map +1 -0
  56. package/dist/src/emit-client.d.ts +3 -0
  57. package/dist/src/emit-client.js +114 -0
  58. package/dist/src/emit-client.js.map +1 -0
  59. package/dist/src/emit-include-builder.d.ts +2 -0
  60. package/dist/src/emit-include-builder.js +30 -0
  61. package/dist/src/emit-include-builder.js.map +1 -0
  62. package/dist/src/emit-include-loader.d.ts +9 -0
  63. package/dist/src/emit-include-loader.js +299 -0
  64. package/dist/src/emit-include-loader.js.map +1 -0
  65. package/dist/src/emit-include-spec.d.ts +2 -0
  66. package/dist/src/emit-include-spec.js +26 -0
  67. package/dist/src/emit-include-spec.js.map +1 -0
  68. package/dist/src/emit-logger.d.ts +1 -0
  69. package/dist/src/emit-logger.js +35 -0
  70. package/dist/src/emit-logger.js.map +1 -0
  71. package/dist/src/emit-routes.d.ts +20 -0
  72. package/dist/src/emit-routes.js +208 -0
  73. package/dist/src/emit-routes.js.map +1 -0
  74. package/dist/src/emit-types.d.ts +5 -0
  75. package/dist/src/emit-types.js +51 -0
  76. package/dist/src/emit-types.js.map +1 -0
  77. package/dist/src/emit-zod.d.ts +5 -0
  78. package/dist/src/emit-zod.js +43 -0
  79. package/dist/src/emit-zod.js.map +1 -0
  80. package/dist/src/index.d.ts +1 -0
  81. package/dist/src/index.js +83 -0
  82. package/dist/src/index.js.map +1 -0
  83. package/dist/src/introspect.d.ts +26 -0
  84. package/dist/src/introspect.js +132 -0
  85. package/dist/src/introspect.js.map +1 -0
  86. package/dist/src/rel-classify.d.ts +10 -0
  87. package/dist/src/rel-classify.js +52 -0
  88. package/dist/src/rel-classify.js.map +1 -0
  89. package/dist/src/utils.d.ts +6 -0
  90. package/dist/src/utils.js +17 -0
  91. package/dist/src/utils.js.map +1 -0
  92. package/dist/utils.d.ts +6 -0
  93. package/dist/utils.d.ts.map +1 -0
  94. package/dist/utils.js +17 -0
  95. package/dist/utils.js.map +1 -0
  96. package/package.json +49 -0
@@ -0,0 +1,51 @@
1
+ function tsTypeFor(pgType, opts) {
2
+ const t = pgType.toLowerCase();
3
+ if (t.startsWith("_"))
4
+ return `${tsTypeFor(t.slice(1), opts)}[]`;
5
+ if (t === "uuid")
6
+ return "string";
7
+ if (t === "bool" || t === "boolean")
8
+ return "boolean";
9
+ if (t === "int2" || t === "int4" || t === "int8" || t === "float4" || t === "float8" || t === "numeric") {
10
+ return opts.numericMode === "number" ? "number" : "string";
11
+ }
12
+ if (t === "date" || t.startsWith("timestamp"))
13
+ return opts.dateType === "date" ? "Date" : "string";
14
+ if (t === "json" || t === "jsonb")
15
+ return "unknown";
16
+ return "string";
17
+ }
18
+ const pascal = (s) => s
19
+ .split(/[_\s-]+/)
20
+ .map((w) => (w?.[0] ? w[0].toUpperCase() + w.slice(1) : ""))
21
+ .join("");
22
+ export function emitTypes(table, opts) {
23
+ const Type = pascal(table.name);
24
+ const insertFields = table.columns
25
+ .map((col) => {
26
+ const base = tsTypeFor(col.pgType, opts);
27
+ const optional = col.hasDefault || col.nullable ? "?" : "";
28
+ const valueType = col.nullable ? `${base} | null` : base;
29
+ return ` ${col.name}${optional}: ${valueType};`;
30
+ })
31
+ .join("\n");
32
+ const selectFields = table.columns
33
+ .map((col) => {
34
+ const base = tsTypeFor(col.pgType, opts);
35
+ const valueType = col.nullable ? `${base} | null` : base;
36
+ return ` ${col.name}: ${valueType};`;
37
+ })
38
+ .join("\n");
39
+ return `/* Generated. Do not edit. */
40
+ export type Insert${Type} = {
41
+ ${insertFields}
42
+ };
43
+
44
+ export type Update${Type} = Partial<Insert${Type}>;
45
+
46
+ export type Select${Type} = {
47
+ ${selectFields}
48
+ };
49
+ `;
50
+ }
51
+ //# sourceMappingURL=emit-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-types.js","sourceRoot":"","sources":["../../src/emit-types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { Table } from "./introspect";
2
+ export declare function emitZod(table: Table, opts: {
3
+ dateType: "date" | "string";
4
+ numericMode: "string" | "number";
5
+ }): string;
@@ -0,0 +1,43 @@
1
+ import { pascal } from "./utils";
2
+ export function emitZod(table, opts) {
3
+ const Type = pascal(table.name);
4
+ const zFor = (pg) => {
5
+ if (pg === "uuid")
6
+ return `z.string().uuid()`;
7
+ if (pg === "bool" || pg === "boolean")
8
+ return `z.boolean()`;
9
+ if (pg === "int2" || pg === "int4" || pg === "int8")
10
+ return opts.numericMode === "number" ? `z.number()` : `z.string()`;
11
+ if (pg === "numeric" || pg === "float4" || pg === "float8")
12
+ return opts.numericMode === "number" ? `z.number()` : `z.string()`;
13
+ if (pg === "jsonb" || pg === "json")
14
+ return `z.unknown()`;
15
+ if (pg === "date" || pg.startsWith("timestamp"))
16
+ return opts.dateType === "date" ? `z.date()` : `z.string()`;
17
+ if (pg.startsWith("_"))
18
+ return `z.array(${zFor(pg.slice(1))})`;
19
+ return `z.string()`; // text/varchar/unknown
20
+ };
21
+ const fields = table.columns
22
+ .map((c) => {
23
+ let z = zFor(c.pgType);
24
+ if (c.nullable)
25
+ z += `.nullable()`;
26
+ if (c.hasDefault)
27
+ z += `.optional()`;
28
+ return ` ${c.name}: ${z}`;
29
+ })
30
+ .join(",\n");
31
+ return `import { z } from "zod";
32
+
33
+ export const Insert${Type}Schema = z.object({
34
+ ${fields}
35
+ });
36
+
37
+ export const Update${Type}Schema = Insert${Type}Schema.partial();
38
+
39
+ export type Insert${Type} = z.infer<typeof Insert${Type}Schema>;
40
+ export type Update${Type} = z.infer<typeof Update${Type}Schema>;
41
+ `;
42
+ }
43
+ //# sourceMappingURL=emit-zod.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-zod.js","sourceRoot":"","sources":["../../src/emit-zod.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,MAAM,UAAU,OAAO,CAAC,KAAY,EAAE,IAAuE;IAC3G,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEhC,MAAM,IAAI,GAAG,CAAC,EAAU,EAAU,EAAE;QAClC,IAAI,EAAE,KAAK,MAAM;YAAE,OAAO,mBAAmB,CAAC;QAC9C,IAAI,EAAE,KAAK,MAAM,IAAI,EAAE,KAAK,SAAS;YAAE,OAAO,aAAa,CAAC;QAC5D,IAAI,EAAE,KAAK,MAAM,IAAI,EAAE,KAAK,MAAM,IAAI,EAAE,KAAK,MAAM;YACjD,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC;QACrE,IAAI,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,QAAQ,IAAI,EAAE,KAAK,QAAQ;YACxD,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC;QACrE,IAAI,EAAE,KAAK,OAAO,IAAI,EAAE,KAAK,MAAM;YAAE,OAAO,aAAa,CAAC;QAC1D,IAAI,EAAE,KAAK,MAAM,IAAI,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC;YAAE,OAAO,IAAI,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC;QAC7G,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,WAAW,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QAC/D,OAAO,YAAY,CAAC,CAAC,uBAAuB;IAC9C,CAAC,CAAC;IAEF,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO;SACzB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACvB,IAAI,CAAC,CAAC,QAAQ;YAAE,CAAC,IAAI,aAAa,CAAC;QACnC,IAAI,CAAC,CAAC,UAAU;YAAE,CAAC,IAAI,aAAa,CAAC;QACrC,OAAO,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;IAC7B,CAAC,CAAC;SACD,IAAI,CAAC,KAAK,CAAC,CAAC;IAEf,OAAO;;qBAEY,IAAI;EACvB,MAAM;;;qBAGa,IAAI,kBAAkB,IAAI;;oBAE3B,IAAI,2BAA2B,IAAI;oBACnC,IAAI,2BAA2B,IAAI;CACtD,CAAC;AACF,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,83 @@
1
+ import cfg from "../gen.config";
2
+ import { join } from "path";
3
+ import { introspect } from "./introspect";
4
+ import { buildGraph } from "./rel-classify";
5
+ import { emitIncludeSpec } from "./emit-include-spec";
6
+ import { emitIncludeBuilder } from "./emit-include-builder";
7
+ import { emitZod } from "./emit-zod";
8
+ import { emitRoutes } from "./emit-routes";
9
+ import { emitClient, emitClientIndex } from "./emit-client";
10
+ import { emitIncludeLoader } from "./emit-include-loader";
11
+ import { emitTypes } from "./emit-types";
12
+ import { emitLogger } from "./emit-logger";
13
+ import { ensureDirs, writeFiles } from "./utils";
14
+ (async () => {
15
+ const model = await introspect(cfg.connectionString, cfg.schema);
16
+ const graph = buildGraph(model);
17
+ const serverDir = cfg.outServer;
18
+ const clientDir = cfg.outClient;
19
+ const normDateType = cfg.dateType === "string" ? "string" : "date";
20
+ await ensureDirs([
21
+ serverDir,
22
+ join(serverDir, "types"),
23
+ join(serverDir, "zod"),
24
+ join(serverDir, "routes"),
25
+ clientDir,
26
+ join(clientDir, "types"),
27
+ ]);
28
+ const files = [];
29
+ // include-spec (shared)
30
+ const includeSpec = emitIncludeSpec(graph);
31
+ files.push({ path: join(serverDir, "include-spec.ts"), content: includeSpec });
32
+ files.push({ path: join(clientDir, "include-spec.ts"), content: includeSpec });
33
+ // include-builder (server)
34
+ files.push({
35
+ path: join(serverDir, "include-builder.ts"),
36
+ content: emitIncludeBuilder(graph, cfg.includeDepthLimit),
37
+ });
38
+ // include-loader (server)
39
+ files.push({
40
+ path: join(serverDir, "include-loader.ts"),
41
+ content: emitIncludeLoader(graph, model, cfg.includeDepthLimit),
42
+ });
43
+ // logger (server)
44
+ files.push({ path: join(serverDir, "logger.ts"), content: emitLogger() });
45
+ // per-table outputs
46
+ for (const table of Object.values(model.tables)) {
47
+ // types (server + client)
48
+ const typesSrc = emitTypes(table, { dateType: normDateType, numericMode: "string" });
49
+ files.push({ path: join(serverDir, "types", `${table.name}.ts`), content: typesSrc });
50
+ files.push({ path: join(clientDir, "types", `${table.name}.ts`), content: typesSrc });
51
+ // zod
52
+ files.push({
53
+ path: join(serverDir, "zod", `${table.name}.ts`),
54
+ content: emitZod(table, { dateType: normDateType, numericMode: "string" }),
55
+ });
56
+ // routes
57
+ files.push({
58
+ path: join(serverDir, "routes", `${table.name}.ts`),
59
+ content: emitRoutes(table, graph, {
60
+ softDeleteColumn: cfg.softDeleteColumn ?? null,
61
+ includeDepthLimit: cfg.includeDepthLimit ?? 3,
62
+ }),
63
+ });
64
+ // client
65
+ files.push({
66
+ path: join(clientDir, `${table.name}.ts`),
67
+ content: emitClient(table),
68
+ });
69
+ }
70
+ // client index (SDK)
71
+ files.push({
72
+ path: join(clientDir, "index.ts"),
73
+ content: emitClientIndex(Object.values(model.tables)),
74
+ });
75
+ await writeFiles(files);
76
+ console.log(`✓ Generated ${files.length} files`);
77
+ console.log(` server: ${serverDir}`);
78
+ console.log(` client: ${clientDir}`);
79
+ })().catch((e) => {
80
+ console.error("❌ Generation failed", e);
81
+ process.exit(1);
82
+ });
83
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ export type Column = {
2
+ name: string;
3
+ pgType: string;
4
+ nullable: boolean;
5
+ hasDefault: boolean;
6
+ };
7
+ export type ForeignKey = {
8
+ from: string[];
9
+ toTable: string;
10
+ to: string[];
11
+ onDelete: "cascade" | "restrict" | "set null" | "no action";
12
+ onUpdate: "cascade" | "restrict" | "set null" | "no action";
13
+ };
14
+ export type Table = {
15
+ name: string;
16
+ columns: Column[];
17
+ pk: string[];
18
+ uniques: string[][];
19
+ fks: ForeignKey[];
20
+ };
21
+ export type Model = {
22
+ schema: string;
23
+ tables: Record<string, Table>;
24
+ enums: Record<string, string[]>;
25
+ };
26
+ export declare function introspect(connectionString: string, schema: string): Promise<Model>;
@@ -0,0 +1,132 @@
1
+ import { Client } from "pg";
2
+ function ensureTable(tables, name) {
3
+ if (!tables[name])
4
+ tables[name] = { name, columns: [], pk: [], uniques: [], fks: [] };
5
+ return tables[name];
6
+ }
7
+ function decodeAction(ch) {
8
+ switch (ch) {
9
+ case "c":
10
+ return "cascade";
11
+ case "r":
12
+ return "restrict";
13
+ case "n":
14
+ return "set null";
15
+ default:
16
+ return "no action";
17
+ }
18
+ }
19
+ export async function introspect(connectionString, schema) {
20
+ const pg = new Client({ connectionString });
21
+ await pg.connect();
22
+ const tables = {};
23
+ const enums = {};
24
+ try {
25
+ const tablesRows = await pg.query(`
26
+ SELECT c.oid, c.relname AS table
27
+ FROM pg_class c
28
+ JOIN pg_namespace n ON n.oid = c.relnamespace
29
+ WHERE c.relkind = 'r' AND n.nspname = $1
30
+ ORDER BY c.relname
31
+ `, [schema]);
32
+ for (const r of tablesRows.rows)
33
+ ensureTable(tables, r.table);
34
+ const colsRows = await pg.query(`
35
+ SELECT table_name, column_name, is_nullable, udt_name, data_type, column_default
36
+ FROM information_schema.columns
37
+ WHERE table_schema = $1
38
+ ORDER BY table_name, ordinal_position
39
+ `, [schema]);
40
+ for (const r of colsRows.rows) {
41
+ const t = ensureTable(tables, r.table_name);
42
+ t.columns.push({
43
+ name: r.column_name,
44
+ pgType: (r.udt_name ?? r.data_type).toLowerCase(),
45
+ nullable: r.is_nullable === "YES",
46
+ hasDefault: r.column_default != null,
47
+ });
48
+ }
49
+ const pkRows = await pg.query(`
50
+ SELECT
51
+ tc.table_name,
52
+ COALESCE(json_agg(kcu.column_name ORDER BY kcu.ordinal_position), '[]'::json) AS cols
53
+ FROM information_schema.table_constraints tc
54
+ JOIN information_schema.key_column_usage kcu
55
+ ON tc.constraint_name = kcu.constraint_name
56
+ AND tc.table_schema = kcu.table_schema
57
+ WHERE tc.constraint_type = 'PRIMARY KEY'
58
+ AND tc.table_schema = $1
59
+ GROUP BY tc.table_name
60
+ `, [schema]);
61
+ for (const r of pkRows.rows) {
62
+ const t = ensureTable(tables, r.table_name);
63
+ t.pk = (r.cols ?? []).slice();
64
+ }
65
+ const uniqRows = await pg.query(`
66
+ SELECT
67
+ tc.table_name,
68
+ COALESCE(json_agg(kcu.column_name ORDER BY kcu.ordinal_position), '[]'::json) AS cols
69
+ FROM information_schema.table_constraints tc
70
+ JOIN information_schema.key_column_usage kcu
71
+ ON tc.constraint_name = kcu.constraint_name
72
+ AND tc.table_schema = kcu.table_schema
73
+ WHERE tc.constraint_type = 'UNIQUE'
74
+ AND tc.table_schema = $1
75
+ GROUP BY tc.table_name, tc.constraint_name
76
+ `, [schema]);
77
+ for (const r of uniqRows.rows) {
78
+ const t = ensureTable(tables, r.table_name);
79
+ if (r.cols && r.cols.length)
80
+ t.uniques.push(r.cols);
81
+ }
82
+ const fkRows = await pg.query(`
83
+ SELECT
84
+ con.oid AS con_oid,
85
+ src.relname AS src_table,
86
+ tgt.relname AS tgt_table,
87
+ con.confdeltype,
88
+ con.confupdtype,
89
+ COALESCE(json_agg(src_att.attname ORDER BY ord.n), '[]'::json) AS src_cols,
90
+ COALESCE(json_agg(tgt_att.attname ORDER BY ord.n), '[]'::json) AS tgt_cols
91
+ FROM pg_constraint con
92
+ JOIN pg_class src ON src.oid = con.conrelid
93
+ JOIN pg_class tgt ON tgt.oid = con.confrelid
94
+ JOIN LATERAL generate_subscripts(con.conkey, 1) ord(n) ON true
95
+ JOIN pg_attribute src_att ON src_att.attrelid = src.oid AND src_att.attnum = con.conkey[ord.n]
96
+ JOIN pg_attribute tgt_att ON tgt_att.attrelid = tgt.oid AND tgt_att.attnum = con.confkey[ord.n]
97
+ JOIN pg_namespace ns ON ns.oid = src.relnamespace
98
+ WHERE con.contype = 'f'
99
+ AND ns.nspname = $1
100
+ GROUP BY con.oid, src.relname, tgt.relname, con.confdeltype, con.confupdtype
101
+ ORDER BY src.relname, con.oid
102
+ `, [schema]);
103
+ for (const r of fkRows.rows) {
104
+ const t = ensureTable(tables, r.src_table);
105
+ t.fks.push({
106
+ from: (r.src_cols ?? []).slice(),
107
+ toTable: r.tgt_table,
108
+ to: (r.tgt_cols ?? []).slice(),
109
+ onDelete: decodeAction(r.confdeltype),
110
+ onUpdate: decodeAction(r.confupdtype),
111
+ });
112
+ }
113
+ const enumRows = await pg.query(`
114
+ SELECT t.typname AS enum_name, e.enumlabel
115
+ FROM pg_type t
116
+ JOIN pg_enum e ON e.enumtypid = t.oid
117
+ JOIN pg_namespace n ON n.oid = t.typnamespace
118
+ WHERE n.nspname = $1
119
+ ORDER BY t.typname, e.enumsortorder
120
+ `, [schema]);
121
+ for (const r of enumRows.rows) {
122
+ if (!enums[r.enum_name])
123
+ enums[r.enum_name] = [];
124
+ enums[r.enum_name].push(r.enumlabel);
125
+ }
126
+ }
127
+ finally {
128
+ await pg.end();
129
+ }
130
+ return { schema, tables, enums };
131
+ }
132
+ //# sourceMappingURL=introspect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"introspect.js","sourceRoot":"","sources":["../../src/introspect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { Model } from "./introspect";
2
+ export type Edge = {
3
+ from: string;
4
+ key: string;
5
+ kind: "one" | "many";
6
+ target: string;
7
+ via?: string;
8
+ };
9
+ export type Graph = Record<string, Record<string, Edge>>;
10
+ export declare function buildGraph(model: Model): Graph;
@@ -0,0 +1,52 @@
1
+ const singular = (s) => (s.endsWith("s") ? s.slice(0, -1) : s);
2
+ const plural = (s) => (s.endsWith("s") ? s : s + "s");
3
+ export function buildGraph(model) {
4
+ const graph = {};
5
+ const tables = Object.values(model.tables);
6
+ // init nodes
7
+ for (const t of tables)
8
+ graph[t.name] = graph[t.name] ?? {};
9
+ // 1) 1:N & 1:1 from FKs
10
+ for (const child of tables) {
11
+ for (const fk of child.fks) {
12
+ const parent = tables.find((t) => t.name === fk.toTable);
13
+ if (!parent)
14
+ continue;
15
+ // cache nodes so TS knows they're not undefined
16
+ const childNode = (graph[child.name] ??= {});
17
+ const parentNode = (graph[parent.name] ??= {});
18
+ const upKey = singular(parent.name);
19
+ const downKey = plural(child.name);
20
+ if (!(upKey in childNode)) {
21
+ childNode[upKey] = { from: child.name, key: upKey, kind: "one", target: parent.name };
22
+ }
23
+ if (!(downKey in parentNode)) {
24
+ parentNode[downKey] = { from: parent.name, key: downKey, kind: "many", target: child.name };
25
+ }
26
+ }
27
+ }
28
+ // 2) M:N via junction (two FKs)
29
+ for (const j of tables) {
30
+ if ((j.fks?.length ?? 0) !== 2)
31
+ continue;
32
+ const [fkA, fkB] = j.fks;
33
+ if (!fkA || !fkB)
34
+ continue;
35
+ const A = fkA.toTable;
36
+ const B = fkB.toTable;
37
+ if (!A || !B || A === B)
38
+ continue;
39
+ const aNode = (graph[A] ??= {});
40
+ const bNode = (graph[B] ??= {});
41
+ const aKey = plural(B);
42
+ const bKey = plural(A);
43
+ if (!(aKey in aNode)) {
44
+ aNode[aKey] = { from: A, key: aKey, kind: "many", target: B, via: j.name };
45
+ }
46
+ if (!(bKey in bNode)) {
47
+ bNode[bKey] = { from: B, key: bKey, kind: "many", target: A, via: j.name };
48
+ }
49
+ }
50
+ return graph;
51
+ }
52
+ //# sourceMappingURL=rel-classify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rel-classify.js","sourceRoot":"","sources":["../../src/rel-classify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare const pascal: (s: string) => string;
2
+ export declare function writeFiles(files: Array<{
3
+ path: string;
4
+ content: string;
5
+ }>): Promise<void>;
6
+ export declare function ensureDirs(dirs: string[]): Promise<void>;
@@ -0,0 +1,17 @@
1
+ import { mkdir, writeFile } from "fs/promises";
2
+ import { dirname } from "path";
3
+ export const pascal = (s) => s
4
+ .split(/[_\s-]+/)
5
+ .map((w) => (w?.[0] ? w[0].toUpperCase() + w.slice(1) : ""))
6
+ .join("");
7
+ export async function writeFiles(files) {
8
+ for (const f of files) {
9
+ await mkdir(dirname(f.path), { recursive: true });
10
+ await writeFile(f.path, f.content, "utf-8");
11
+ }
12
+ }
13
+ export async function ensureDirs(dirs) {
14
+ for (const d of dirs)
15
+ await mkdir(d, { recursive: true });
16
+ }
17
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,EAAE,CAClC,CAAC;KACE,KAAK,CAAC,SAAS,CAAC;KAChB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;KAC3D,IAAI,CAAC,EAAE,CAAC,CAAC;AAEd,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,KAA+C;IAC9E,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,MAAM,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAc;IAC7C,KAAK,MAAM,CAAC,IAAI,IAAI;QAAE,MAAM,KAAK,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,6 @@
1
+ export declare const pascal: (s: string) => string;
2
+ export declare function writeFiles(files: Array<{
3
+ path: string;
4
+ content: string;
5
+ }>): Promise<void>;
6
+ export declare function ensureDirs(dirs: string[]): Promise<void>;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,MAAM,GAAI,GAAG,MAAM,WAInB,CAAC;AAEd,wBAAsB,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,iBAK/E;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,iBAE9C"}
package/dist/utils.js ADDED
@@ -0,0 +1,17 @@
1
+ import { mkdir, writeFile } from "fs/promises";
2
+ import { dirname } from "path";
3
+ export const pascal = (s) => s
4
+ .split(/[_\s-]+/)
5
+ .map((w) => (w?.[0] ? w[0].toUpperCase() + w.slice(1) : ""))
6
+ .join("");
7
+ export async function writeFiles(files) {
8
+ for (const f of files) {
9
+ await mkdir(dirname(f.path), { recursive: true });
10
+ await writeFile(f.path, f.content, "utf-8");
11
+ }
12
+ }
13
+ export async function ensureDirs(dirs) {
14
+ for (const d of dirs)
15
+ await mkdir(d, { recursive: true });
16
+ }
17
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,EAAE,CAClC,CAAC;KACE,KAAK,CAAC,SAAS,CAAC;KAChB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;KAC3D,IAAI,CAAC,EAAE,CAAC,CAAC;AAEd,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,KAA+C;IAC9E,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,MAAM,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAc;IAC7C,KAAK,MAAM,CAAC,IAAI,IAAI;QAAE,MAAM,KAAK,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC5D,CAAC"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "postgresdk",
3
+ "version": "0.1.1-alpha.0",
4
+ "description": "Generate a typed server/client SDK from a Postgres schema (includes, Zod, Hono).",
5
+ "type": "module",
6
+ "bin": {
7
+ "postgresdk": "./dist/cli.js"
8
+ },
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md",
18
+ "LICENSE"
19
+ ],
20
+ "engines": {
21
+ "node": ">=18.17"
22
+ },
23
+ "scripts": {
24
+ "build": "bun build src/cli.ts --outdir dist --target node --format esm && bun build src/index.ts --outdir dist --target node --format esm && tsc -p tsconfig.build.json --emitDeclarationOnly",
25
+ "test": "bun test/test-gen.ts",
26
+ "prepublishOnly": "npm run build",
27
+ "publish:patch": "./publish.sh",
28
+ "publish:minor": "./publish.sh",
29
+ "publish:major": "./publish.sh"
30
+ },
31
+ "dependencies": {
32
+ "pg": "^8.16.3",
33
+ "zod": "^4.0.15",
34
+ "hono": "^4.9.0"
35
+ },
36
+ "devDependencies": {
37
+ "typescript": "^5.5.0",
38
+ "@types/node": "^20.0.0",
39
+ "@types/pg": "^8.15.5"
40
+ },
41
+ "license": "MIT",
42
+ "keywords": [
43
+ "postgres",
44
+ "sdk",
45
+ "codegen",
46
+ "zod",
47
+ "hono"
48
+ ]
49
+ }