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 @@
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 @@
1
+ {"version":3,"file":"introspect.d.ts","sourceRoot":"","sources":["../src/introspect.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,MAAM,GAAG;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,QAAQ,EAAE,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,WAAW,CAAC;IAC5D,QAAQ,EAAE,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,WAAW,CAAC;CAC7D,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC;IACpB,GAAG,EAAE,UAAU,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACjC,CAAC;AAoBF,wBAAsB,UAAU,CAAC,gBAAgB,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAqJzF"}
@@ -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 @@
1
+ {"version":3,"file":"rel-classify.d.ts","sourceRoot":"","sources":["../src/rel-classify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAS,MAAM,cAAc,CAAC;AAEjD,MAAM,MAAM,IAAI,GAAG;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,KAAK,GAAG,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;AAKzD,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAsD9C"}
@@ -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,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+ import { resolve } from "node:path";
3
+ import { generate } from "./index.js";
4
+ const args = process.argv.slice(2);
5
+ // Handle --version
6
+ if (args.includes("--version") || args.includes("-v")) {
7
+ console.log("postgresdk v0.1.0");
8
+ process.exit(0);
9
+ }
10
+ // Handle --help
11
+ if (args.includes("--help") || args.includes("-h")) {
12
+ console.log(`
13
+ postgresdk - Generate typed SDK from PostgreSQL
14
+
15
+ Usage:
16
+ postgresdk [options]
17
+
18
+ Options:
19
+ -c, --config <path> Path to config file (default: postgresdk.config.ts)
20
+ -v, --version Show version
21
+ -h, --help Show help
22
+ `);
23
+ process.exit(0);
24
+ }
25
+ // Get config path
26
+ let configPath = "postgresdk.config.ts";
27
+ const configIndex = args.findIndex(a => a === "-c" || a === "--config");
28
+ if (configIndex !== -1 && args[configIndex + 1]) {
29
+ configPath = args[configIndex + 1];
30
+ }
31
+ // Run generator
32
+ try {
33
+ await generate(resolve(process.cwd(), configPath));
34
+ }
35
+ catch (err) {
36
+ console.error("❌ Generation failed:", err);
37
+ process.exit(1);
38
+ }
39
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,mBAAmB;AACnB,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;IACtD,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACjC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,gBAAgB;AAChB,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;IACnD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;CAUb,CAAC,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,kBAAkB;AAClB,IAAI,UAAU,GAAG,sBAAsB,CAAC;AACxC,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,UAAU,CAAC,CAAC;AACxE,IAAI,WAAW,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,EAAE,CAAC;IAChD,UAAU,GAAG,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC;AACrC,CAAC;AAED,gBAAgB;AAChB,IAAI,CAAC;IACH,MAAM,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC;AACrD,CAAC;AAAC,OAAO,GAAG,EAAE,CAAC;IACb,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,GAAG,CAAC,CAAC;IAC3C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Table } from "./introspect";
2
+ export declare function emitClient(table: Table): string;
3
+ export declare function emitClientIndex(tables: Table[]): string;
@@ -0,0 +1,114 @@
1
+ import { pascal } from "./utils";
2
+ export function emitClient(table) {
3
+ const Type = pascal(table.name);
4
+ // Normalize PKs
5
+ const pkCols = Array.isArray(table.pk)
6
+ ? table.pk
7
+ : table.pk
8
+ ? [table.pk]
9
+ : [];
10
+ const safePk = pkCols.length ? pkCols : ["id"];
11
+ const hasCompositePk = safePk.length > 1;
12
+ const pkType = hasCompositePk ? `{ ${safePk.map((c) => `${c}: string`).join("; ")} }` : `string`;
13
+ const pkPathExpr = hasCompositePk ? safePk.map((c) => `pk.${c}`).join(` + "/" + `) : `pk`;
14
+ return `/* Generated. Do not edit. */
15
+ import type { ${Type}IncludeSpec } from "./include-spec";
16
+ import type { Insert${Type}, Update${Type}, Select${Type} } from "./types/${table.name}";
17
+
18
+ export class ${Type}Client {
19
+ constructor(
20
+ private baseUrl: string,
21
+ private fetchFn: typeof fetch = fetch,
22
+ private auth?: () => Promise<Record<string,string>>
23
+ ) {}
24
+
25
+ private async headers(json = false) {
26
+ const extra = (await this.auth?.()) ?? {};
27
+ return json ? { "Content-Type": "application/json", ...extra } : extra;
28
+ }
29
+
30
+ private async okOrThrow(res: Response, action: string) {
31
+ if (!res.ok) {
32
+ let detail = "";
33
+ try { detail = await res.text(); } catch {}
34
+ throw new Error(\`\${action} ${table.name} failed: \${res.status} \${detail}\`);
35
+ }
36
+ }
37
+
38
+ async create(data: Insert${Type}): Promise<Select${Type}> {
39
+ const res = await this.fetchFn(\`\${this.baseUrl}/v1/${table.name}\`, {
40
+ method: "POST",
41
+ headers: await this.headers(true),
42
+ body: JSON.stringify(data),
43
+ });
44
+ await this.okOrThrow(res, "create");
45
+ return (await res.json()) as Select${Type};
46
+ }
47
+
48
+ async getByPk(pk: ${pkType}): Promise<Select${Type} | null> {
49
+ const path = ${pkPathExpr};
50
+ const res = await this.fetchFn(\`\${this.baseUrl}/v1/${table.name}/\${path}\`, {
51
+ headers: await this.headers(),
52
+ });
53
+ if (res.status === 404) return null;
54
+ await this.okOrThrow(res, "get");
55
+ return (await res.json()) as Select${Type};
56
+ }
57
+
58
+ async list(params?: { include?: ${Type}IncludeSpec; limit?: number; offset?: number }): Promise<Select${Type}[]> {
59
+ const res = await this.fetchFn(\`\${this.baseUrl}/v1/${table.name}/list\`, {
60
+ method: "POST",
61
+ headers: await this.headers(true),
62
+ body: JSON.stringify(params ?? {}),
63
+ });
64
+ await this.okOrThrow(res, "list");
65
+ return (await res.json()) as Select${Type}[];
66
+ }
67
+
68
+ async update(pk: ${pkType}, patch: Update${Type}): Promise<Select${Type} | null> {
69
+ const path = ${pkPathExpr};
70
+ const res = await this.fetchFn(\`\${this.baseUrl}/v1/${table.name}/\${path}\`, {
71
+ method: "PATCH",
72
+ headers: await this.headers(true),
73
+ body: JSON.stringify(patch),
74
+ });
75
+ if (res.status === 404) return null;
76
+ await this.okOrThrow(res, "update");
77
+ return (await res.json()) as Select${Type};
78
+ }
79
+
80
+ async delete(pk: ${pkType}): Promise<Select${Type} | null> {
81
+ const path = ${pkPathExpr};
82
+ const res = await this.fetchFn(\`\${this.baseUrl}/v1/${table.name}/\${path}\`, {
83
+ method: "DELETE",
84
+ headers: await this.headers(),
85
+ });
86
+ if (res.status === 404) return null;
87
+ await this.okOrThrow(res, "delete");
88
+ return (await res.json()) as Select${Type};
89
+ }
90
+ }
91
+ `;
92
+ }
93
+ export function emitClientIndex(tables) {
94
+ let out = `/* Generated. Do not edit. */\n`;
95
+ for (const t of tables) {
96
+ out += `import { ${pascal(t.name)}Client } from "./${t.name}";\n`;
97
+ }
98
+ out += `\nexport class SDK {\n`;
99
+ for (const t of tables) {
100
+ out += ` public ${t.name}: ${pascal(t.name)}Client;\n`;
101
+ }
102
+ out += `\n constructor(cfg: { baseUrl: string; fetch?: typeof fetch; auth?: () => Promise<Record<string,string>> }) {\n`;
103
+ out += ` const f = cfg.fetch ?? fetch;\n`;
104
+ for (const t of tables) {
105
+ out += ` this.${t.name} = new ${pascal(t.name)}Client(cfg.baseUrl, f, cfg.auth);\n`;
106
+ }
107
+ out += ` }\n`;
108
+ out += `}\n`;
109
+ for (const t of tables)
110
+ out += `export { ${pascal(t.name)}Client } from "./${t.name}";\n`;
111
+ out += `export * from "./include-spec";\n`;
112
+ return out;
113
+ }
114
+ //# sourceMappingURL=emit-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-client.js","sourceRoot":"","sources":["../../src/emit-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Graph } from "./rel-classify";
2
+ export declare function emitIncludeBuilder(graph: Graph, maxDepth: number): string;
@@ -0,0 +1,30 @@
1
+ export function emitIncludeBuilder(graph, maxDepth) {
2
+ return `// Generated. Do not edit.
3
+ export const RELATION_GRAPH = ${JSON.stringify(graph, null, 2)} as const;
4
+ type TableName = keyof typeof RELATION_GRAPH;
5
+
6
+ export function buildWith(root: TableName, spec: any, maxDepth = ${maxDepth}) {
7
+ return walk(root as string, spec, 0);
8
+ function walk(table: string, s: any, depth: number): any {
9
+ if (!s || depth >= maxDepth) return undefined;
10
+ const rels: any = (RELATION_GRAPH as any)[table] || {};
11
+ const out: any = {};
12
+ for (const key of Object.keys(s)) {
13
+ const rel = rels[key];
14
+ if (!rel) throw new Error(\`Unknown include key '\${key}' on table '\${table}'\`);
15
+ const v = s[key];
16
+ if (v === true) out[key] = true;
17
+ else if (v && typeof v === "object") {
18
+ const child = "include" in v ? walk(rel.target, v.include, depth + 1) : undefined;
19
+ out[key] = child ? { with: child } : true;
20
+ }
21
+ }
22
+ return Object.keys(out).length ? out : undefined;
23
+ }
24
+ }
25
+
26
+ export const buildWithFor = (t: TableName) =>
27
+ (spec?: any, depth = ${maxDepth}) => (spec ? buildWith(t, spec, depth) : undefined);
28
+ `;
29
+ }
30
+ //# sourceMappingURL=emit-include-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-include-builder.js","sourceRoot":"","sources":["../../src/emit-include-builder.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,kBAAkB,CAAC,KAAY,EAAE,QAAgB;IAC/D,OAAO;gCACuB,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;;;mEAGK,QAAQ;;;;;;;;;;;;;;;;;;;;;yBAqBlD,QAAQ;CAChC,CAAC;AACF,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { Graph } from "./rel-classify";
2
+ import type { Model } from "./introspect";
3
+ /**
4
+ * Emit a generic include loader that:
5
+ * - Walks the include spec
6
+ * - Loads children in batches per edge kind
7
+ * - Stitches onto parent rows (mutates copies)
8
+ */
9
+ export declare function emitIncludeLoader(graph: Graph, model: Model, maxDepth: number): string;