postgresdk 0.18.1 → 0.18.2

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 (85) hide show
  1. package/dist/cli.js +0 -0
  2. package/package.json +1 -1
  3. package/dist/cli.d.ts.map +0 -1
  4. package/dist/cli.js.map +0 -1
  5. package/dist/core/operations.d.ts +0 -68
  6. package/dist/emit-api-contract.d.ts +0 -60
  7. package/dist/emit-client.d.ts.map +0 -1
  8. package/dist/emit-client.js +0 -114
  9. package/dist/emit-client.js.map +0 -1
  10. package/dist/emit-include-builder.d.ts.map +0 -1
  11. package/dist/emit-include-builder.js +0 -30
  12. package/dist/emit-include-builder.js.map +0 -1
  13. package/dist/emit-include-loader.d.ts.map +0 -1
  14. package/dist/emit-include-loader.js +0 -299
  15. package/dist/emit-include-loader.js.map +0 -1
  16. package/dist/emit-include-spec.d.ts.map +0 -1
  17. package/dist/emit-include-spec.js +0 -26
  18. package/dist/emit-include-spec.js.map +0 -1
  19. package/dist/emit-logger.d.ts.map +0 -1
  20. package/dist/emit-logger.js +0 -35
  21. package/dist/emit-logger.js.map +0 -1
  22. package/dist/emit-router.d.ts +0 -5
  23. package/dist/emit-routes.d.ts.map +0 -1
  24. package/dist/emit-routes.js +0 -208
  25. package/dist/emit-routes.js.map +0 -1
  26. package/dist/emit-server-index.d.ts +0 -5
  27. package/dist/emit-types.d.ts.map +0 -1
  28. package/dist/emit-types.js +0 -51
  29. package/dist/emit-types.js.map +0 -1
  30. package/dist/emit-zod.d.ts.map +0 -1
  31. package/dist/emit-zod.js +0 -43
  32. package/dist/emit-zod.js.map +0 -1
  33. package/dist/gen.config.d.ts +0 -10
  34. package/dist/gen.config.js +0 -10
  35. package/dist/gen.config.js.map +0 -1
  36. package/dist/index.d.ts.map +0 -1
  37. package/dist/index.js.map +0 -1
  38. package/dist/introspect.d.ts.map +0 -1
  39. package/dist/introspect.js +0 -132
  40. package/dist/introspect.js.map +0 -1
  41. package/dist/rel-classify.d.ts.map +0 -1
  42. package/dist/rel-classify.js +0 -52
  43. package/dist/rel-classify.js.map +0 -1
  44. package/dist/src/cli.d.ts +0 -2
  45. package/dist/src/cli.js +0 -39
  46. package/dist/src/cli.js.map +0 -1
  47. package/dist/src/emit-client.d.ts +0 -3
  48. package/dist/src/emit-client.js +0 -114
  49. package/dist/src/emit-client.js.map +0 -1
  50. package/dist/src/emit-include-builder.d.ts +0 -2
  51. package/dist/src/emit-include-builder.js +0 -30
  52. package/dist/src/emit-include-builder.js.map +0 -1
  53. package/dist/src/emit-include-loader.d.ts +0 -9
  54. package/dist/src/emit-include-loader.js +0 -299
  55. package/dist/src/emit-include-loader.js.map +0 -1
  56. package/dist/src/emit-include-spec.d.ts +0 -2
  57. package/dist/src/emit-include-spec.js +0 -26
  58. package/dist/src/emit-include-spec.js.map +0 -1
  59. package/dist/src/emit-logger.d.ts +0 -1
  60. package/dist/src/emit-logger.js +0 -35
  61. package/dist/src/emit-logger.js.map +0 -1
  62. package/dist/src/emit-routes.d.ts +0 -20
  63. package/dist/src/emit-routes.js +0 -208
  64. package/dist/src/emit-routes.js.map +0 -1
  65. package/dist/src/emit-types.d.ts +0 -5
  66. package/dist/src/emit-types.js +0 -51
  67. package/dist/src/emit-types.js.map +0 -1
  68. package/dist/src/emit-zod.d.ts +0 -5
  69. package/dist/src/emit-zod.js +0 -43
  70. package/dist/src/emit-zod.js.map +0 -1
  71. package/dist/src/index.d.ts +0 -1
  72. package/dist/src/index.js +0 -83
  73. package/dist/src/index.js.map +0 -1
  74. package/dist/src/introspect.d.ts +0 -26
  75. package/dist/src/introspect.js +0 -132
  76. package/dist/src/introspect.js.map +0 -1
  77. package/dist/src/rel-classify.d.ts +0 -10
  78. package/dist/src/rel-classify.js +0 -52
  79. package/dist/src/rel-classify.js.map +0 -1
  80. package/dist/src/utils.d.ts +0 -6
  81. package/dist/src/utils.js +0 -17
  82. package/dist/src/utils.js.map +0 -1
  83. package/dist/utils.d.ts.map +0 -1
  84. package/dist/utils.js +0 -17
  85. package/dist/utils.js.map +0 -1
@@ -1,208 +0,0 @@
1
- import { pascal } from "./utils";
2
- /**
3
- * Emits a Hono router for one table, using generated Zod schemas.
4
- *
5
- * Expects:
6
- * - Generated file at ../zod/<table>.ts exporting Insert<Type>Schema & Update<Type>Schema
7
- * - deps: { pg: Pool | Client } with .query(text, params)
8
- *
9
- * Endpoints:
10
- * POST /v1/<table> create (Insert<Type>Schema)
11
- * GET /v1/<table>/:...pk get by pk
12
- * POST /v1/<table>/list list (limit/offset; includes)
13
- * PATCH /v1/<table>/:...pk update (Update<Type>Schema)
14
- * DELETE /v1/<table>/:...pk delete (or soft-delete)
15
- */
16
- export function emitRoutes(table, _graph, opts) {
17
- const fileTableName = table.name; // SQL table name for file/route
18
- const Type = pascal(table.name); // PascalCase for type/schemas
19
- // Normalize pk to an array and fallback to ["id"] if empty
20
- const rawPk = table.pk;
21
- const pkCols = Array.isArray(rawPk) ? rawPk : rawPk ? [rawPk] : [];
22
- const safePkCols = pkCols.length ? pkCols : ["id"];
23
- const hasCompositePk = safePkCols.length > 1;
24
- const pkPath = hasCompositePk ? safePkCols.map((c) => `:${c}`).join("/") : `:${safePkCols[0]}`;
25
- const softDel = opts.softDeleteColumn && table.columns.some((c) => c.name === opts.softDeleteColumn) ? opts.softDeleteColumn : null;
26
- // IMPORTANT: interpolate column names at generator time (no escaping/backslashes here)
27
- const wherePkSql = hasCompositePk
28
- ? safePkCols.map((c, i) => `"${c}" = $${i + 1}`).join(" AND ")
29
- : `"${safePkCols[0]}" = $1`;
30
- const getPkParams = hasCompositePk
31
- ? `const pkValues = [${safePkCols.map((c) => `c.req.param("${c}")`).join(", ")}];`
32
- : `const pkValues = [c.req.param("${safePkCols[0]}")];`;
33
- // Build SET clause indices for UPDATE (PK params first, then update values)
34
- // These strings are emitted into generated code, so we DO escape ${...} intentionally here.
35
- const updateSetSql = hasCompositePk
36
- ? `Object.keys(updateData).map((k, i) => \`"\${k}" = $\${i + ${safePkCols.length} + 1}\`).join(", ")`
37
- : `Object.keys(updateData).map((k, i) => \`"\${k}" = $\${i + 2}\`).join(", ")`;
38
- // Prevent updating PK columns
39
- const pkFilter = safePkCols.length
40
- ? `const updateData = Object.fromEntries(Object.entries(parsed.data).filter(([k]) => !new Set(${JSON.stringify(safePkCols)}).has(k)));`
41
- : `const updateData = parsed.data;`;
42
- return `/* Generated. Do not edit. */
43
- import { Hono } from "hono";
44
- import { z } from "zod";
45
- import { Insert${Type}Schema, Update${Type}Schema } from "../zod/${fileTableName}";
46
- import { loadIncludes } from "../include-loader";
47
-
48
- const DEBUG = process.env.SDK_DEBUG === "1" || process.env.SDK_DEBUG === "true";
49
- const log = {
50
- debug: (...args: any[]) => { if (DEBUG) console.debug("[sdk]", ...args); },
51
- error: (...args: any[]) => console.error("[sdk]", ...args),
52
- };
53
-
54
- const listSchema = z.object({
55
- include: z.any().optional(), // TODO: typed include spec in later pass
56
- limit: z.number().int().positive().max(100).optional(),
57
- offset: z.number().int().min(0).optional(),
58
- orderBy: z.any().optional() // TODO: typed orderBy in a later pass
59
- });
60
-
61
- export function register${Type}Routes(app: Hono, deps: { pg: { query: (text: string, params?: any[]) => Promise<{ rows: any[] }> } }) {
62
- const base = "/v1/${fileTableName}";
63
-
64
- // CREATE
65
- app.post(base, async (c) => {
66
- try {
67
- const body = await c.req.json().catch(() => ({}));
68
- log.debug("POST ${fileTableName} body:", body);
69
- const parsed = Insert${Type}Schema.safeParse(body);
70
- if (!parsed.success) {
71
- const issues = parsed.error.flatten();
72
- log.debug("POST ${fileTableName} invalid:", issues);
73
- return c.json({ error: "Invalid body", issues }, 400);
74
- }
75
-
76
- const data = parsed.data;
77
- const cols = Object.keys(data);
78
- const vals = Object.values(data);
79
- if (!cols.length) return c.json({ error: "No fields provided" }, 400);
80
-
81
- const placeholders = cols.map((_, i) => '$' + (i + 1)).join(", ");
82
- const text = \`INSERT INTO "${fileTableName}" (\${cols.map(c => '"' + c + '"').join(", ")})
83
- VALUES (\${placeholders})
84
- RETURNING *\`;
85
- log.debug("SQL:", text, "vals:", vals);
86
- const { rows } = await deps.pg.query(text, vals);
87
- return c.json(rows[0] ?? null, rows[0] ? 201 : 500);
88
- } catch (e: any) {
89
- log.error("POST ${fileTableName} error:", e?.stack ?? e);
90
- return c.json({ error: e?.message ?? "Internal error", ...(DEBUG ? { stack: e?.stack } : {}) }, 500);
91
- }
92
- });
93
-
94
- // GET BY PK
95
- app.get(\`\${base}/${pkPath}\`, async (c) => {
96
- try {
97
- ${getPkParams}
98
- const text = \`SELECT * FROM "${fileTableName}" WHERE ${wherePkSql} LIMIT 1\`;
99
- log.debug("GET ${fileTableName} by PK:", pkValues, "SQL:", text);
100
- const { rows } = await deps.pg.query(text, pkValues);
101
- if (!rows[0]) return c.json(null, 404);
102
- return c.json(rows[0]);
103
- } catch (e: any) {
104
- log.error("GET ${fileTableName} error:", e?.stack ?? e);
105
- return c.json({ error: e?.message ?? "Internal error", ...(DEBUG ? { stack: e?.stack } : {}) }, 500);
106
- }
107
- });
108
-
109
- // LIST
110
- app.post(\`\${base}/list\`, async (c) => {
111
- try {
112
- const body = listSchema.safeParse(await c.req.json().catch(() => ({})));
113
- if (!body.success) {
114
- const issues = body.error.flatten();
115
- log.debug("LIST ${fileTableName} invalid:", issues);
116
- return c.json({ error: "Invalid body", issues }, 400);
117
- }
118
- const { include, limit = 50, offset = 0 } = body.data;
119
-
120
- const where = ${softDel ? `\`WHERE "${softDel}" IS NULL\`` : `""`};
121
- const text = \`SELECT * FROM "${fileTableName}" \${where} LIMIT $1 OFFSET $2\`;
122
- log.debug("LIST ${fileTableName} SQL:", text, "params:", [limit, offset]);
123
- const { rows } = await deps.pg.query(text, [limit, offset]);
124
-
125
- if (!include) {
126
- log.debug("LIST ${fileTableName} rows:", rows.length);
127
- return c.json(rows);
128
- }
129
-
130
- // Attempt include stitching with explicit error handling
131
- log.debug("LIST ${fileTableName} include spec:", include);
132
- try {
133
- const stitched = await loadIncludes("${fileTableName}", rows, include, deps.pg, ${opts.includeDepthLimit});
134
- log.debug("LIST ${fileTableName} stitched count:", Array.isArray(stitched) ? stitched.length : "n/a");
135
- return c.json(stitched);
136
- } catch (e: any) {
137
- const strict = process.env.SDK_STRICT_INCLUDE === "1" || process.env.SDK_STRICT_INCLUDE === "true";
138
- const msg = e?.message ?? String(e);
139
- const stack = e?.stack;
140
- log.error("LIST ${fileTableName} include stitch FAILED:", msg, stack);
141
-
142
- if (strict) {
143
- return c.json({ error: "include-stitch-failed", message: msg, ...(DEBUG ? { stack: e?.stack } : {}) }, 500);
144
- }
145
- // Non-strict fallback: return base rows plus error metadata
146
- return c.json({ data: rows, includeError: { message: msg, ...(DEBUG ? { stack: e?.stack } : {}) } }, 200);
147
- }
148
- } catch (e: any) {
149
- log.error("LIST ${fileTableName} error:", e?.stack ?? e);
150
- return c.json({ error: e?.message ?? "Internal error", ...(DEBUG ? { stack: e?.stack } : {}) }, 500);
151
- }
152
- });
153
-
154
- // UPDATE
155
- app.patch(\`\${base}/${pkPath}\`, async (c) => {
156
- try {
157
- ${getPkParams}
158
- const body = await c.req.json().catch(() => ({}));
159
- log.debug("PATCH ${fileTableName} pk:", pkValues, "patch:", body);
160
- const parsed = Update${Type}Schema.safeParse(body);
161
- if (!parsed.success) {
162
- const issues = parsed.error.flatten();
163
- log.debug("PATCH ${fileTableName} invalid:", issues);
164
- return c.json({ error: "Invalid body", issues: issues }, 400);
165
- }
166
-
167
- ${pkFilter}
168
- if (!Object.keys(updateData).length) return c.json({ error: "No updatable fields provided" }, 400);
169
-
170
- const setSql = ${updateSetSql};
171
- const text = \`UPDATE "${fileTableName}" SET \${setSql} WHERE ${wherePkSql} RETURNING *\`;
172
- const params = ${hasCompositePk ? `[...pkValues, ...Object.values(updateData)]` : `[pkValues[0], ...Object.values(updateData)]`};
173
- log.debug("PATCH ${fileTableName} SQL:", text, "params:", params);
174
- const { rows } = await deps.pg.query(text, params);
175
- if (!rows[0]) return c.json(null, 404);
176
- return c.json(rows[0]);
177
- } catch (e: any) {
178
- log.error("PATCH ${fileTableName} error:", e?.stack ?? e);
179
- return c.json({ error: e?.message ?? "Internal error", ...(DEBUG ? { stack: e?.stack } : {}) }, 500);
180
- }
181
- });
182
-
183
- // DELETE (soft or hard)
184
- app.delete(\`\${base}/${pkPath}\`, async (c) => {
185
- try {
186
- ${getPkParams}
187
- ${softDel
188
- ? `
189
- const text = \`UPDATE "${fileTableName}" SET "${softDel}" = NOW() WHERE ${wherePkSql} RETURNING *\`;
190
- log.debug("DELETE (soft) ${fileTableName} SQL:", text, "pk:", pkValues);
191
- const { rows } = await deps.pg.query(text, pkValues);
192
- if (!rows[0]) return c.json(null, 404);
193
- return c.json(rows[0]);`
194
- : `
195
- const text = \`DELETE FROM "${fileTableName}" WHERE ${wherePkSql} RETURNING *\`;
196
- log.debug("DELETE ${fileTableName} SQL:", text, "pk:", pkValues);
197
- const { rows } = await deps.pg.query(text, pkValues);
198
- if (!rows[0]) return c.json(null, 404);
199
- return c.json(rows[0]);`}
200
- } catch (e: any) {
201
- log.error("DELETE ${fileTableName} error:", e?.stack ?? e);
202
- return c.json({ error: e?.message ?? "Internal error", ...(DEBUG ? { stack: e?.stack } : {}) }, 500);
203
- }
204
- });
205
- }
206
- `;
207
- }
208
- //# sourceMappingURL=emit-routes.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"emit-routes.js","sourceRoot":"","sources":["../../src/emit-routes.ts"],"names":[],"mappings":"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"}
@@ -1,5 +0,0 @@
1
- import type { Table } from "./introspect";
2
- export declare function emitTypes(table: Table, opts: {
3
- dateType: "date" | "string";
4
- numericMode: "string" | "number";
5
- }): string;
@@ -1,51 +0,0 @@
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
@@ -1 +0,0 @@
1
- {"version":3,"file":"emit-types.js","sourceRoot":"","sources":["../../src/emit-types.ts"],"names":[],"mappings":"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"}
@@ -1,5 +0,0 @@
1
- import type { Table } from "./introspect";
2
- export declare function emitZod(table: Table, opts: {
3
- dateType: "date" | "string";
4
- numericMode: "string" | "number";
5
- }): string;
@@ -1,43 +0,0 @@
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
@@ -1 +0,0 @@
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"}
@@ -1 +0,0 @@
1
- export {};
package/dist/src/index.js DELETED
@@ -1,83 +0,0 @@
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
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
@@ -1,26 +0,0 @@
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>;
@@ -1,132 +0,0 @@
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
@@ -1 +0,0 @@
1
- {"version":3,"file":"introspect.js","sourceRoot":"","sources":["../../src/introspect.ts"],"names":[],"mappings":"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"}
@@ -1,10 +0,0 @@
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;
@@ -1,52 +0,0 @@
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