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":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,2BAA2B;AAC3B,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AACtC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;AAC1F,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC;AAEpC,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,eAAe,OAAO,EAAE,CAAC,CAAC;IACtC,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,CAAE,CAAC;AACtC,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 @@
1
+ {"version":3,"file":"emit-client.d.ts","sourceRoot":"","sources":["../src/emit-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAG1C,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,UA8FtC;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,KAAK,EAAE,UAmB9C"}
@@ -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 @@
1
+ {"version":3,"file":"emit-include-builder.d.ts","sourceRoot":"","sources":["../src/emit-include-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,UA4BhE"}
@@ -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;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-include-loader.d.ts","sourceRoot":"","sources":["../src/emit-include-loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE1C;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,UAgT7E"}
@@ -0,0 +1,299 @@
1
+ /**
2
+ * Emit a generic include loader that:
3
+ * - Walks the include spec
4
+ * - Loads children in batches per edge kind
5
+ * - Stitches onto parent rows (mutates copies)
6
+ */
7
+ export function emitIncludeLoader(graph, model, maxDepth) {
8
+ // Precompute helpful maps for FK discovery
9
+ const fkIndex = {};
10
+ for (const t of Object.values(model.tables)) {
11
+ fkIndex[t.name] = t.fks.map((f) => ({ from: f.from, toTable: f.toTable, to: f.to }));
12
+ }
13
+ return `/* Generated. Do not edit. */
14
+ import { RELATION_GRAPH } from "./include-builder";
15
+
16
+ // Minimal types to keep the file self-contained
17
+ type Graph = typeof RELATION_GRAPH;
18
+ type TableName = keyof Graph;
19
+ type IncludeSpec = any;
20
+
21
+ // Debug helpers (enabled with SDK_DEBUG=1)
22
+ const DEBUG = process.env.SDK_DEBUG === "1" || process.env.SDK_DEBUG === "true";
23
+ const log = {
24
+ debug: (...args: any[]) => { if (DEBUG) console.debug("[sdk:include]", ...args); },
25
+ warn: (...args: any[]) => console.warn("[sdk:include]", ...args),
26
+ error: (...args: any[]) => console.error("[sdk:include]", ...args),
27
+ };
28
+
29
+ // Helpers for PK/FK discovery from model (inlined)
30
+ const FK_INDEX = ${JSON.stringify(fkIndex, null, 2)} as const;
31
+ const PKS = ${JSON.stringify(Object.fromEntries(Object.values(model.tables).map((t) => [t.name, t.pk])), null, 2)} as const;
32
+
33
+ // Build WHERE predicate for OR-of-AND on composite values
34
+ function buildOrAndPredicate(cols: string[], count: number, startIndex: number) {
35
+ // Generates: (c1=$i AND c2=$i+1) OR (c1=$j AND c2=$j+1) ...
36
+ const groups: string[] = [];
37
+ let idx = startIndex;
38
+ for (let k = 0; k < count; k++) {
39
+ const parts = cols.map((c, j) => \`"\${c}" = $\${idx + j}\`);
40
+ groups.push('(' + parts.join(' AND ') + ')');
41
+ idx += cols.length;
42
+ }
43
+ return groups.join(' OR ');
44
+ }
45
+
46
+ // Extract distinct tuples from rows
47
+ function distinctTuples(rows: any[], cols: string[]): any[] {
48
+ const s = new Set<string>();
49
+ const res: any[] = [];
50
+ for (const r of rows) {
51
+ const tup = cols.map(c => r[c]);
52
+ const key = JSON.stringify(tup);
53
+ if (!s.has(key)) {
54
+ s.add(key);
55
+ res.push(tup);
56
+ }
57
+ }
58
+ return res;
59
+ }
60
+
61
+ // Index rows by tuple key
62
+ function indexByTuple(rows: any[], cols: string[]) {
63
+ const map = new Map<string, any>();
64
+ for (const r of rows) {
65
+ const key = JSON.stringify(cols.map(c => r[c]));
66
+ map.set(key, r);
67
+ }
68
+ return map;
69
+ }
70
+
71
+ // Group rows by tuple key (1:N)
72
+ function groupByTuple(rows: any[], cols: string[]) {
73
+ const map = new Map<string, any[]>();
74
+ for (const r of rows) {
75
+ const key = JSON.stringify(cols.map(c => r[c]));
76
+ const arr = map.get(key) ?? [];
77
+ arr.push(r);
78
+ map.set(key, arr);
79
+ }
80
+ return map;
81
+ }
82
+
83
+ // Public entry
84
+ export async function loadIncludes(
85
+ root: TableName,
86
+ parents: any[],
87
+ spec: IncludeSpec | undefined,
88
+ pg: { query: (text: string, params?: any[]) => Promise<{ rows: any[] }> },
89
+ maxDepth: number = ${maxDepth}
90
+ ) {
91
+ try {
92
+ if (!spec || !parents.length) return parents;
93
+ log.debug("loadIncludes root/spec/rows", root, Object.keys(spec ?? {}).length, parents.length);
94
+
95
+ // Deep clone parents to avoid mutating caller refs
96
+ const cloned = parents.map(p => ({ ...p }));
97
+ await walk(root, cloned, spec, 0);
98
+ return cloned;
99
+ } catch (e: any) {
100
+ log.error("loadIncludes error:", e?.message ?? e, e?.stack);
101
+ // Never throw to the route; return base rows
102
+ return parents;
103
+ }
104
+
105
+ async function walk(table: TableName, rows: any[], s: any, depth: number): Promise<void> {
106
+ if (!s || depth >= maxDepth || rows.length === 0) return;
107
+ const rels: any = (RELATION_GRAPH as any)[table] || {};
108
+ log.debug("walk", { table, depth, keys: Object.keys(s) });
109
+
110
+ // Process each requested relation at this level
111
+ for (const key of Object.keys(s)) {
112
+ const rel = rels[key];
113
+ if (!rel) {
114
+ log.warn(\`Unknown include key '\${key}' on '\${table}' — skipping\`);
115
+ continue;
116
+ }
117
+ const target = rel.target as TableName;
118
+
119
+ // Safely run each loader; never let one bad edge 500 the route
120
+ if (rel.via) {
121
+ // M:N via junction
122
+ try {
123
+ await loadManyToMany(table, target, rel.via as string, rows, key);
124
+ } catch (e: any) {
125
+ log.error("loadManyToMany failed", { table, key, via: rel.via, target }, e?.message ?? e);
126
+ for (const r of rows) r[key] = [];
127
+ }
128
+ // Recurse if nested include specified
129
+ const childSpec = s[key] && typeof s[key] === "object" ? (s[key] as any).include : undefined;
130
+ if (childSpec) {
131
+ const children = rows.flatMap(r => (r[key] ?? []));
132
+ try {
133
+ await walk(target, children, childSpec, depth + 1);
134
+ } catch (e: any) {
135
+ log.error("walk nested (via) failed", { table: String(target), key }, e?.message ?? e);
136
+ }
137
+ }
138
+ continue;
139
+ }
140
+
141
+ if (rel.kind === "many") {
142
+ // 1:N target has FK to current
143
+ try {
144
+ await loadOneToMany(table, target, rows, key);
145
+ } catch (e: any) {
146
+ log.error("loadOneToMany failed", { table, key, target }, e?.message ?? e);
147
+ for (const r of rows) r[key] = [];
148
+ }
149
+ const childSpec = s[key] && typeof s[key] === "object" ? (s[key] as any).include : undefined;
150
+ if (childSpec) {
151
+ const children = rows.flatMap(r => (r[key] ?? []));
152
+ try {
153
+ await walk(target, children, childSpec, depth + 1);
154
+ } catch (e: any) {
155
+ log.error("walk nested (many) failed", { table: String(target), key }, e?.message ?? e);
156
+ }
157
+ }
158
+ } else {
159
+ // kind === "one"
160
+ // Could be belongs-to (current has FK to target) OR has-one (target unique-FK to current)
161
+ const currFks = (FK_INDEX as any)[table] as Array<{from:string[];toTable:string;to:string[]}>;
162
+ const toTarget = currFks.find(f => f.toTable === target);
163
+ if (toTarget) {
164
+ try {
165
+ await loadBelongsTo(table, target, rows, key);
166
+ } catch (e: any) {
167
+ log.error("loadBelongsTo failed", { table, key, target }, e?.message ?? e);
168
+ for (const r of rows) r[key] = null;
169
+ }
170
+ } else {
171
+ try {
172
+ await loadHasOne(table, target, rows, key);
173
+ } catch (e: any) {
174
+ log.error("loadHasOne failed", { table, key, target }, e?.message ?? e);
175
+ for (const r of rows) r[key] = null;
176
+ }
177
+ }
178
+ const childSpec = s[key] && typeof s[key] === "object" ? (s[key] as any).include : undefined;
179
+ if (childSpec) {
180
+ const children = rows.map(r => r[key]).filter(Boolean);
181
+ try {
182
+ await walk(target, children, childSpec, depth + 1);
183
+ } catch (e: any) {
184
+ log.error("walk nested (one) failed", { table: String(target), key }, e?.message ?? e);
185
+ }
186
+ }
187
+ }
188
+ }
189
+ }
190
+
191
+ async function loadBelongsTo(curr: TableName, target: TableName, rows: any[], key: string) {
192
+ // current has FK cols referencing target PK
193
+ const fk = (FK_INDEX as any)[curr].find((f: any) => f.toTable === target);
194
+ if (!fk) { for (const r of rows) r[key] = null; return; }
195
+ const tuples = distinctTuples(rows, fk.from).filter(t => t.every((v: any) => v != null));
196
+ if (!tuples.length) { for (const r of rows) r[key] = null; return; }
197
+
198
+ // Query target WHERE target.pk IN tuples
199
+ const pkCols = (PKS as any)[target] as string[];
200
+ const where = buildOrAndPredicate(pkCols, tuples.length, 1);
201
+ const params = tuples.flat();
202
+ const sql = \`SELECT * FROM "\${target}" WHERE \${where}\`;
203
+ log.debug("belongsTo SQL", { curr, target, key, sql, paramsCount: params.length });
204
+ const { rows: targets } = await pg.query(sql, params);
205
+
206
+ const idx = indexByTuple(targets, pkCols);
207
+ for (const r of rows) {
208
+ const tup = fk.from.map((c: string) => r[c]);
209
+ const keyStr = JSON.stringify(tup);
210
+ r[key] = idx.get(keyStr) ?? null;
211
+ }
212
+ }
213
+
214
+ async function loadHasOne(curr: TableName, target: TableName, rows: any[], key: string) {
215
+ // target has FK cols referencing current PK (unique)
216
+ const fk = (FK_INDEX as any)[target].find((f: any) => f.toTable === curr);
217
+ if (!fk) { for (const r of rows) r[key] = null; return; }
218
+
219
+ const pkCols = (PKS as any)[curr] as string[];
220
+ const tuples = distinctTuples(rows, pkCols).filter(t => t.every((v: any) => v != null));
221
+ if (!tuples.length) { for (const r of rows) r[key] = null; return; }
222
+
223
+ // SELECT target WHERE fk IN tuples
224
+ const where = buildOrAndPredicate(fk.from, tuples.length, 1);
225
+ const params = tuples.flat();
226
+ const sql = \`SELECT * FROM "\${target}" WHERE \${where}\`;
227
+ log.debug("hasOne SQL", { curr, target, key, sql, paramsCount: params.length });
228
+ const { rows: targets } = await pg.query(sql, params);
229
+
230
+ const idx = indexByTuple(targets, fk.from);
231
+ for (const r of rows) {
232
+ const keyStr = JSON.stringify(pkCols.map((c: string) => r[c]));
233
+ r[key] = idx.get(keyStr) ?? null;
234
+ }
235
+ }
236
+
237
+ async function loadOneToMany(curr: TableName, target: TableName, rows: any[], key: string) {
238
+ // target has FK cols referencing current PK
239
+ const fk = (FK_INDEX as any)[target].find((f: any) => f.toTable === curr);
240
+ if (!fk) { for (const r of rows) r[key] = []; return; }
241
+
242
+ const pkCols = (PKS as any)[curr] as string[];
243
+ const tuples = distinctTuples(rows, pkCols).filter(t => t.every((v: any) => v != null));
244
+ if (!tuples.length) { for (const r of rows) r[key] = []; return; }
245
+
246
+ const where = buildOrAndPredicate(fk.from, tuples.length, 1);
247
+ const params = tuples.flat();
248
+ const sql = \`SELECT * FROM "\${target}" WHERE \${where}\`;
249
+ log.debug("oneToMany SQL", { curr, target, key, sql, paramsCount: params.length });
250
+ const { rows: children } = await pg.query(sql, params);
251
+
252
+ const groups = groupByTuple(children, fk.from);
253
+ for (const r of rows) {
254
+ const keyStr = JSON.stringify(pkCols.map((c: string) => r[c]));
255
+ r[key] = groups.get(keyStr) ?? [];
256
+ }
257
+ }
258
+
259
+ async function loadManyToMany(curr: TableName, target: TableName, via: string, rows: any[], key: string) {
260
+ // via has two FKs: one to curr, one to target
261
+ const toCurr = (FK_INDEX as any)[via].find((f: any) => f.toTable === curr);
262
+ const toTarget = (FK_INDEX as any)[via].find((f: any) => f.toTable === target);
263
+ if (!toCurr || !toTarget) { for (const r of rows) r[key] = []; return; }
264
+
265
+ const pkCols = (PKS as any)[curr] as string[];
266
+ const tuples = distinctTuples(rows, pkCols).filter(t => t.every((v: any) => v != null));
267
+ if (!tuples.length) { for (const r of rows) r[key] = []; return; }
268
+
269
+ // 1) Load junction rows for current parents
270
+ const whereVia = buildOrAndPredicate(toCurr.from, tuples.length, 1);
271
+ const sqlVia = \`SELECT * FROM "\${via}" WHERE \${whereVia}\`;
272
+ const paramsVia = tuples.flat();
273
+ log.debug("manyToMany junction SQL", { curr, target, via, key, sql: sqlVia, paramsCount: paramsVia.length });
274
+ const { rows: jrows } = await pg.query(sqlVia, paramsVia);
275
+
276
+ if (!jrows.length) { for (const r of rows) r[key] = []; return; }
277
+
278
+ // 2) Load targets by distinct target fk tuples in junction
279
+ const tTuples = distinctTuples(jrows, toTarget.from);
280
+ const whereT = buildOrAndPredicate((PKS as any)[target], tTuples.length, 1);
281
+ const sqlT = \`SELECT * FROM "\${target}" WHERE \${whereT}\`;
282
+ const paramsT = tTuples.flat();
283
+ log.debug("manyToMany target SQL", { curr, target, via, key, sql: sqlT, paramsCount: paramsT.length });
284
+ const { rows: targets } = await pg.query(sqlT, paramsT);
285
+
286
+ const tIdx = indexByTuple(targets, (PKS as any)[target]);
287
+
288
+ // 3) Group junction rows by current pk tuple, map to target rows
289
+ const byCurr = groupByTuple(jrows, toCurr.from);
290
+ for (const r of rows) {
291
+ const currKey = JSON.stringify(pkCols.map((c: string) => r[c]));
292
+ const j = byCurr.get(currKey) ?? [];
293
+ r[key] = j.map(jr => tIdx.get(JSON.stringify(toTarget.from.map((c: string) => jr[c])))).filter(Boolean);
294
+ }
295
+ }
296
+ }
297
+ `;
298
+ }
299
+ //# sourceMappingURL=emit-include-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-include-loader.js","sourceRoot":"","sources":["../src/emit-include-loader.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAY,EAAE,KAAY,EAAE,QAAgB;IAC5E,2CAA2C;IAC3C,MAAM,OAAO,GAQT,EAAE,CAAC;IACP,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5C,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IACvF,CAAC;IAED,OAAO;;;;;;;;;;;;;;;;;mBAiBU,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;cACrC,IAAI,CAAC,SAAS,CACxB,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAC1E,IAAI,EACJ,CAAC,CACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBA0DoB,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgN9B,CAAC;AACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Graph } from "./rel-classify";
2
+ export declare function emitIncludeSpec(graph: Graph): string;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-include-spec.d.ts","sourceRoot":"","sources":["../src/emit-include-spec.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,UAsB3C"}
@@ -0,0 +1,26 @@
1
+ export function emitIncludeSpec(graph) {
2
+ let out = `/* Generated. Do not edit. */\n`;
3
+ const tables = Object.keys(graph);
4
+ for (const table of tables) {
5
+ const rels = graph[table] ?? {};
6
+ const entries = Object.entries(rels);
7
+ out += `export type ${toPascal(table)}IncludeSpec = {\n`;
8
+ for (const [relKey, edge] of entries) {
9
+ if (edge.kind === "many") {
10
+ out += ` ${relKey}?: boolean | { include?: ${toPascal(edge.target)}IncludeSpec; limit?: number; offset?: number; };\n`;
11
+ }
12
+ else {
13
+ out += ` ${relKey}?: boolean | ${toPascal(edge.target)}IncludeSpec;\n`;
14
+ }
15
+ }
16
+ out += `};\n\n`;
17
+ }
18
+ return out;
19
+ }
20
+ function toPascal(s) {
21
+ return s
22
+ .split(/[_\s-]+/)
23
+ .map((w) => (w?.[0] ? w[0].toUpperCase() + w.slice(1) : ""))
24
+ .join("");
25
+ }
26
+ //# sourceMappingURL=emit-include-spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-include-spec.js","sourceRoot":"","sources":["../src/emit-include-spec.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,eAAe,CAAC,KAAY;IAC1C,IAAI,GAAG,GAAG,iCAAiC,CAAC;IAE5C,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAErC,GAAG,IAAI,eAAe,QAAQ,CAAC,KAAK,CAAC,mBAAmB,CAAC;QACzD,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,OAAO,EAAE,CAAC;YACrC,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBACzB,GAAG,IAAI,KAAK,MAAM,4BAA4B,QAAQ,CACpD,IAAI,CAAC,MAAM,CACZ,oDAAoD,CAAC;YACxD,CAAC;iBAAM,CAAC;gBACN,GAAG,IAAI,KAAK,MAAM,gBAAgB,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC;YAC1E,CAAC;QACH,CAAC;QACD,GAAG,IAAI,QAAQ,CAAC;IAClB,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,QAAQ,CAAC,CAAS;IACzB,OAAO,CAAC;SACL,KAAK,CAAC,SAAS,CAAC;SAChB,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;SAC3D,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function emitLogger(): string;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-logger.d.ts","sourceRoot":"","sources":["../src/emit-logger.ts"],"names":[],"mappings":"AACA,wBAAgB,UAAU,WAgCzB"}
@@ -0,0 +1,35 @@
1
+ /* Emits a tiny logger used by generated server routes. */
2
+ export function emitLogger() {
3
+ return `/* Generated. Do not edit. */
4
+ const DEBUG = process.env.SDK_DEBUG === "1" || process.env.SDK_DEBUG === "true";
5
+
6
+ export const logger = {
7
+ debug: (...args: any[]) => { if (DEBUG) console.debug("[sdk:debug]", ...args); },
8
+ info: (...args: any[]) => { if (DEBUG) console.info ("[sdk:info ]", ...args); },
9
+ warn: (...args: any[]) => { console.warn ("[sdk:warn ]", ...args); },
10
+ error: (...args: any[]) => { console.error("[sdk:error]", ...args); },
11
+ };
12
+
13
+ export function safe<T extends (c: any) => any>(handler: T) {
14
+ return async (c: any) => {
15
+ try {
16
+ const res = await handler(c);
17
+ // If a handler returns a Response with 5xx, log the body in debug
18
+ if (typeof res?.status === "number" && res.status >= 500) {
19
+ try {
20
+ const clone = res.clone?.();
21
+ const text = clone ? await clone.text() : "";
22
+ logger.error(\`5xx response: \${c.req.method} \${c.req.path}\`, text);
23
+ } catch {}
24
+ }
25
+ return res;
26
+ } catch (e: any) {
27
+ logger.error(\`Unhandled error in \${c.req.method} \${c.req.path}\`, e?.stack ?? e);
28
+ const body = { error: e?.message ?? "Internal error", ...(process.env.SDK_DEBUG ? { stack: e?.stack } : {}) };
29
+ return c.json(body, 500);
30
+ }
31
+ };
32
+ }
33
+ `;
34
+ }
35
+ //# sourceMappingURL=emit-logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-logger.js","sourceRoot":"","sources":["../src/emit-logger.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,MAAM,UAAU,UAAU;IACxB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BR,CAAC;AACF,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { Table } from "./introspect";
2
+ import type { Graph } from "./rel-classify";
3
+ /**
4
+ * Emits a Hono router for one table, using generated Zod schemas.
5
+ *
6
+ * Expects:
7
+ * - Generated file at ../zod/<table>.ts exporting Insert<Type>Schema & Update<Type>Schema
8
+ * - deps: { pg: Pool | Client } with .query(text, params)
9
+ *
10
+ * Endpoints:
11
+ * POST /v1/<table> create (Insert<Type>Schema)
12
+ * GET /v1/<table>/:...pk get by pk
13
+ * POST /v1/<table>/list list (limit/offset; includes)
14
+ * PATCH /v1/<table>/:...pk update (Update<Type>Schema)
15
+ * DELETE /v1/<table>/:...pk delete (or soft-delete)
16
+ */
17
+ export declare function emitRoutes(table: Table, _graph: Graph, opts: {
18
+ softDeleteColumn: string | null;
19
+ includeDepthLimit: number;
20
+ }): string;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-routes.d.ts","sourceRoot":"","sources":["../src/emit-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAG5C;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,KAAK,EACb,IAAI,EAAE;IAAE,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,UA+MrE"}