postgresdk 0.16.12 → 0.16.13
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.
- package/README.md +9 -0
- package/dist/cli.js +55 -8
- package/dist/emit-types.d.ts +1 -1
- package/dist/emit-zod.d.ts +1 -1
- package/dist/index.js +22 -7
- package/dist/types.d.ts +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -146,6 +146,7 @@ export default {
|
|
|
146
146
|
schema: "public", // Database schema to introspect
|
|
147
147
|
outDir: "./api", // Output directory (or { client: "./sdk", server: "./api" })
|
|
148
148
|
softDeleteColumn: null, // Column name for soft deletes (e.g., "deleted_at")
|
|
149
|
+
numericMode: "auto", // "auto" | "number" | "string" - How to type numeric columns
|
|
149
150
|
includeMethodsDepth: 2, // Max depth for nested includes
|
|
150
151
|
dateType: "date", // "date" | "string" - How to handle timestamps
|
|
151
152
|
serverFramework: "hono", // Currently only hono is supported
|
|
@@ -175,6 +176,14 @@ export default {
|
|
|
175
176
|
};
|
|
176
177
|
```
|
|
177
178
|
|
|
179
|
+
#### Type Mapping (numericMode)
|
|
180
|
+
|
|
181
|
+
Controls how PostgreSQL numeric types map to TypeScript:
|
|
182
|
+
|
|
183
|
+
- **`"auto"` (default)**: `int2`/`int4`/floats → `number`, `int8`/`numeric` → `string`
|
|
184
|
+
- **`"number"`**: All numeric → `number` (⚠️ unsafe for bigint - JS can't handle values > 2^53)
|
|
185
|
+
- **`"string"`**: All numeric → `string` (safe but requires parsing)
|
|
186
|
+
|
|
178
187
|
### Database Drivers
|
|
179
188
|
|
|
180
189
|
The generated code works with any PostgreSQL client that implements a simple `query` interface:
|
package/dist/cli.js
CHANGED
|
@@ -1751,6 +1751,15 @@ function extractConfigFields(configContent) {
|
|
|
1751
1751
|
isCommented: !!depthMatch[1]
|
|
1752
1752
|
});
|
|
1753
1753
|
}
|
|
1754
|
+
const numericModeMatch = configContent.match(/^\s*(\/\/)?\s*numericMode:\s*"(.+)"/m);
|
|
1755
|
+
if (numericModeMatch) {
|
|
1756
|
+
fields.push({
|
|
1757
|
+
key: "numericMode",
|
|
1758
|
+
value: numericModeMatch[2],
|
|
1759
|
+
description: "How to type numeric columns in TypeScript",
|
|
1760
|
+
isCommented: !!numericModeMatch[1]
|
|
1761
|
+
});
|
|
1762
|
+
}
|
|
1754
1763
|
const frameworkMatch = configContent.match(/^\s*(\/\/)?\s*serverFramework:\s*"(.+)"/m);
|
|
1755
1764
|
if (frameworkMatch) {
|
|
1756
1765
|
fields.push({
|
|
@@ -1918,7 +1927,16 @@ export default {
|
|
|
1918
1927
|
* @example "deleted_at"
|
|
1919
1928
|
*/
|
|
1920
1929
|
${getFieldLine("softDeleteColumn", existingFields, mergeStrategy, "null", userChoices)}
|
|
1921
|
-
|
|
1930
|
+
|
|
1931
|
+
/**
|
|
1932
|
+
* How to type numeric columns in TypeScript
|
|
1933
|
+
* - "auto": int2/int4/float → number, int8/numeric → string (recommended)
|
|
1934
|
+
* - "number": All numeric types become TypeScript number (unsafe for bigint)
|
|
1935
|
+
* - "string": All numeric types become TypeScript string (legacy)
|
|
1936
|
+
* @default "auto"
|
|
1937
|
+
*/
|
|
1938
|
+
${getFieldLine("numericMode", existingFields, mergeStrategy, '"auto"', userChoices)}
|
|
1939
|
+
|
|
1922
1940
|
/**
|
|
1923
1941
|
* Maximum depth for nested relationship includes to prevent infinite loops
|
|
1924
1942
|
* @default 2
|
|
@@ -2347,6 +2365,20 @@ export default {
|
|
|
2347
2365
|
*/
|
|
2348
2366
|
// softDeleteColumn: null,
|
|
2349
2367
|
|
|
2368
|
+
/**
|
|
2369
|
+
* How to type numeric columns in TypeScript
|
|
2370
|
+
* Options:
|
|
2371
|
+
* - "auto": int2/int4/float → number, int8/numeric → string (recommended, default)
|
|
2372
|
+
* - "number": All numeric types become TypeScript number (unsafe for bigint)
|
|
2373
|
+
* - "string": All numeric types become TypeScript string (legacy behavior)
|
|
2374
|
+
*
|
|
2375
|
+
* Auto mode is safest - keeps JavaScript-safe integers as numbers,
|
|
2376
|
+
* but preserves precision for bigint/numeric by using strings.
|
|
2377
|
+
*
|
|
2378
|
+
* Default: "auto"
|
|
2379
|
+
*/
|
|
2380
|
+
// numericMode: "auto",
|
|
2381
|
+
|
|
2350
2382
|
/**
|
|
2351
2383
|
* Maximum depth for nested relationship includes to prevent infinite loops
|
|
2352
2384
|
* Default: 2
|
|
@@ -2879,10 +2911,20 @@ function emitZod(table, opts, enums) {
|
|
|
2879
2911
|
return `z.string()`;
|
|
2880
2912
|
if (t === "bool" || t === "boolean")
|
|
2881
2913
|
return `z.boolean()`;
|
|
2882
|
-
if (t === "int2" || t === "int4" || t === "int8")
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2914
|
+
if (t === "int2" || t === "int4" || t === "int8") {
|
|
2915
|
+
if (opts.numericMode === "number")
|
|
2916
|
+
return `z.number()`;
|
|
2917
|
+
if (opts.numericMode === "string")
|
|
2918
|
+
return `z.string()`;
|
|
2919
|
+
return t === "int2" || t === "int4" ? `z.number()` : `z.string()`;
|
|
2920
|
+
}
|
|
2921
|
+
if (t === "numeric" || t === "float4" || t === "float8") {
|
|
2922
|
+
if (opts.numericMode === "number")
|
|
2923
|
+
return `z.number()`;
|
|
2924
|
+
if (opts.numericMode === "string")
|
|
2925
|
+
return `z.string()`;
|
|
2926
|
+
return t === "float4" || t === "float8" ? `z.number()` : `z.string()`;
|
|
2927
|
+
}
|
|
2886
2928
|
if (t === "jsonb" || t === "json")
|
|
2887
2929
|
return `z.unknown()`;
|
|
2888
2930
|
if (t === "date" || t.startsWith("timestamp"))
|
|
@@ -4346,7 +4388,11 @@ function tsTypeFor(pgType, opts, enums) {
|
|
|
4346
4388
|
if (t === "bool" || t === "boolean")
|
|
4347
4389
|
return "boolean";
|
|
4348
4390
|
if (t === "int2" || t === "int4" || t === "int8" || t === "float4" || t === "float8" || t === "numeric") {
|
|
4349
|
-
|
|
4391
|
+
if (opts.numericMode === "number")
|
|
4392
|
+
return "number";
|
|
4393
|
+
if (opts.numericMode === "string")
|
|
4394
|
+
return "string";
|
|
4395
|
+
return t === "int2" || t === "int4" || t === "float4" || t === "float8" ? "number" : "string";
|
|
4350
4396
|
}
|
|
4351
4397
|
if (t === "date" || t.startsWith("timestamp"))
|
|
4352
4398
|
return "string";
|
|
@@ -6551,10 +6597,11 @@ async function generate(configPath) {
|
|
|
6551
6597
|
console.log(`[Index] About to process ${Object.keys(model.tables || {}).length} tables for generation`);
|
|
6552
6598
|
}
|
|
6553
6599
|
for (const table of Object.values(model.tables)) {
|
|
6554
|
-
const
|
|
6600
|
+
const numericMode = cfg.numericMode ?? "auto";
|
|
6601
|
+
const typesSrc = emitTypes(table, { numericMode }, model.enums);
|
|
6555
6602
|
files.push({ path: join(serverDir, "types", `${table.name}.ts`), content: typesSrc });
|
|
6556
6603
|
files.push({ path: join(clientDir, "types", `${table.name}.ts`), content: typesSrc });
|
|
6557
|
-
const zodSrc = emitZod(table, { numericMode
|
|
6604
|
+
const zodSrc = emitZod(table, { numericMode }, model.enums);
|
|
6558
6605
|
files.push({ path: join(serverDir, "zod", `${table.name}.ts`), content: zodSrc });
|
|
6559
6606
|
files.push({ path: join(clientDir, "zod", `${table.name}.ts`), content: zodSrc });
|
|
6560
6607
|
const paramsZodSrc = emitParamsZod(table, graph);
|
package/dist/emit-types.d.ts
CHANGED
package/dist/emit-zod.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1978,10 +1978,20 @@ function emitZod(table, opts, enums) {
|
|
|
1978
1978
|
return `z.string()`;
|
|
1979
1979
|
if (t === "bool" || t === "boolean")
|
|
1980
1980
|
return `z.boolean()`;
|
|
1981
|
-
if (t === "int2" || t === "int4" || t === "int8")
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1981
|
+
if (t === "int2" || t === "int4" || t === "int8") {
|
|
1982
|
+
if (opts.numericMode === "number")
|
|
1983
|
+
return `z.number()`;
|
|
1984
|
+
if (opts.numericMode === "string")
|
|
1985
|
+
return `z.string()`;
|
|
1986
|
+
return t === "int2" || t === "int4" ? `z.number()` : `z.string()`;
|
|
1987
|
+
}
|
|
1988
|
+
if (t === "numeric" || t === "float4" || t === "float8") {
|
|
1989
|
+
if (opts.numericMode === "number")
|
|
1990
|
+
return `z.number()`;
|
|
1991
|
+
if (opts.numericMode === "string")
|
|
1992
|
+
return `z.string()`;
|
|
1993
|
+
return t === "float4" || t === "float8" ? `z.number()` : `z.string()`;
|
|
1994
|
+
}
|
|
1985
1995
|
if (t === "jsonb" || t === "json")
|
|
1986
1996
|
return `z.unknown()`;
|
|
1987
1997
|
if (t === "date" || t.startsWith("timestamp"))
|
|
@@ -3445,7 +3455,11 @@ function tsTypeFor(pgType, opts, enums) {
|
|
|
3445
3455
|
if (t === "bool" || t === "boolean")
|
|
3446
3456
|
return "boolean";
|
|
3447
3457
|
if (t === "int2" || t === "int4" || t === "int8" || t === "float4" || t === "float8" || t === "numeric") {
|
|
3448
|
-
|
|
3458
|
+
if (opts.numericMode === "number")
|
|
3459
|
+
return "number";
|
|
3460
|
+
if (opts.numericMode === "string")
|
|
3461
|
+
return "string";
|
|
3462
|
+
return t === "int2" || t === "int4" || t === "float4" || t === "float8" ? "number" : "string";
|
|
3449
3463
|
}
|
|
3450
3464
|
if (t === "date" || t.startsWith("timestamp"))
|
|
3451
3465
|
return "string";
|
|
@@ -5650,10 +5664,11 @@ async function generate(configPath) {
|
|
|
5650
5664
|
console.log(`[Index] About to process ${Object.keys(model.tables || {}).length} tables for generation`);
|
|
5651
5665
|
}
|
|
5652
5666
|
for (const table of Object.values(model.tables)) {
|
|
5653
|
-
const
|
|
5667
|
+
const numericMode = cfg.numericMode ?? "auto";
|
|
5668
|
+
const typesSrc = emitTypes(table, { numericMode }, model.enums);
|
|
5654
5669
|
files.push({ path: join(serverDir, "types", `${table.name}.ts`), content: typesSrc });
|
|
5655
5670
|
files.push({ path: join(clientDir, "types", `${table.name}.ts`), content: typesSrc });
|
|
5656
|
-
const zodSrc = emitZod(table, { numericMode
|
|
5671
|
+
const zodSrc = emitZod(table, { numericMode }, model.enums);
|
|
5657
5672
|
files.push({ path: join(serverDir, "zod", `${table.name}.ts`), content: zodSrc });
|
|
5658
5673
|
files.push({ path: join(clientDir, "zod", `${table.name}.ts`), content: zodSrc });
|
|
5659
5674
|
const paramsZodSrc = emitParamsZod(table, graph);
|
package/dist/types.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export interface Config {
|
|
|
24
24
|
};
|
|
25
25
|
softDeleteColumn?: string | null;
|
|
26
26
|
dateType?: "date" | "string";
|
|
27
|
+
numericMode?: "string" | "number" | "auto";
|
|
27
28
|
includeMethodsDepth?: number;
|
|
28
29
|
skipJunctionTables?: boolean;
|
|
29
30
|
serverFramework?: "hono" | "express" | "fastify";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "postgresdk",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.13",
|
|
4
4
|
"description": "Generate a typed server/client SDK from a Postgres schema (includes, Zod, Hono).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"scripts": {
|
|
24
24
|
"build": "bun build src/cli.ts src/index.ts --outdir dist --target node --format esm --external=pg --external=zod --external=hono --external=prompts --external=node:* && tsc -p tsconfig.build.json --emitDeclarationOnly",
|
|
25
|
-
"test": "bun test:init && bun test:gen && bun test test/test-where-clause.test.ts && bun test test/test-where-or-and.test.ts && bun test test/test-nested-include-options.test.ts && bun test test/test-include-methods-with-options.test.ts && bun test:gen-with-tests && bun test:pull && bun test:enums && bun test:typecheck && bun test:drizzle-e2e",
|
|
25
|
+
"test": "bun test:init && bun test:gen && bun test test/test-where-clause.test.ts && bun test test/test-where-or-and.test.ts && bun test test/test-nested-include-options.test.ts && bun test test/test-include-methods-with-options.test.ts && bun test:gen-with-tests && bun test:pull && bun test:enums && bun test:typecheck && bun test:drizzle-e2e && bun test test/test-numeric-mode-integration.test.ts",
|
|
26
26
|
"test:init": "bun test/test-init.ts",
|
|
27
27
|
"test:gen": "bun test/test-gen.ts",
|
|
28
28
|
"test:gen-with-tests": "bun test/test-gen-with-tests.ts",
|