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,208 @@
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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-routes.js","sourceRoot":"","sources":["../src/emit-routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { Table } from "./introspect";
2
+ export declare function emitTypes(table: Table, opts: {
3
+ dateType: "date" | "string";
4
+ numericMode: "string" | "number";
5
+ }): string;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-types.d.ts","sourceRoot":"","sources":["../src/emit-types.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAqB1C,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAAC;IAAC,WAAW,EAAE,QAAQ,GAAG,QAAQ,CAAA;CAAE,UA+B9G"}
@@ -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":"AAGA,SAAS,SAAS,CAAC,MAAc,EAAE,IAAuE;IACxG,MAAM,CAAC,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IAC/B,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC;IACjE,IAAI,CAAC,KAAK,MAAM;QAAE,OAAO,QAAQ,CAAC;IAClC,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACtD,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;QACxG,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC7D,CAAC;IACD,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,IAAI,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;IACnG,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,OAAO;QAAE,OAAO,SAAS,CAAC;IACpD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,EAAE,CAC3B,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,UAAU,SAAS,CAAC,KAAY,EAAE,IAAuE;IAC7G,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEhC,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO;SAC/B,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACX,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACzC,MAAM,QAAQ,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,MAAM,SAAS,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;QACzD,OAAO,KAAK,GAAG,CAAC,IAAI,GAAG,QAAQ,KAAK,SAAS,GAAG,CAAC;IACnD,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO;SAC/B,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACX,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACzC,MAAM,SAAS,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;QACzD,OAAO,KAAK,GAAG,CAAC,IAAI,KAAK,SAAS,GAAG,CAAC;IACxC,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,OAAO;oBACW,IAAI;EACtB,YAAY;;;oBAGM,IAAI,oBAAoB,IAAI;;oBAE5B,IAAI;EACtB,YAAY;;CAEb,CAAC;AACF,CAAC"}
@@ -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 @@
1
+ {"version":3,"file":"emit-zod.d.ts","sourceRoot":"","sources":["../src/emit-zod.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAG1C,wBAAgB,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAAC;IAAC,WAAW,EAAE,QAAQ,GAAG,QAAQ,CAAA;CAAE,UAoC5G"}
@@ -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,10 @@
1
+ declare const _default: {
2
+ connectionString: string;
3
+ schema: string;
4
+ outServer: string;
5
+ outClient: string;
6
+ softDeleteColumn: any;
7
+ includeDepthLimit: number;
8
+ dateType: string;
9
+ };
10
+ export default _default;
@@ -0,0 +1,10 @@
1
+ export default {
2
+ connectionString: "postgres://user:pass@localhost:5432/testdb",
3
+ schema: "public",
4
+ outServer: "gen/generated/server",
5
+ outClient: "gen/generated/client",
6
+ softDeleteColumn: null,
7
+ includeDepthLimit: 3,
8
+ dateType: "date"
9
+ };
10
+ //# sourceMappingURL=gen.config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gen.config.js","sourceRoot":"","sources":["../gen.config.ts"],"names":[],"mappings":"AAAA,eAAe;IACb,gBAAgB,EAAE,4CAA4C;IAC9D,MAAM,EAAE,QAAQ;IAChB,SAAS,EAAE,sBAAsB;IACjC,SAAS,EAAE,sBAAsB;IACjC,gBAAgB,EAAE,IAAI;IACtB,iBAAiB,EAAE,CAAC;IACpB,QAAQ,EAAE,MAAM;CACjB,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function generate(configPath: string): Promise<void>;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}