postgresdk 0.12.0 → 0.12.1
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 +1 -1
- package/dist/cli.js +87 -27
- package/dist/emit-types.d.ts +1 -1
- package/dist/emit-zod.d.ts +1 -1
- package/dist/index.js +87 -27
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Generate a typed server/client SDK from your PostgreSQL database schema.
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
9
|
- 🚀 **Instant SDK Generation** - Point at your PostgreSQL database and get a complete SDK
|
|
10
|
-
- 🔒 **Type Safety** - Full TypeScript types derived from your database schema
|
|
10
|
+
- 🔒 **Type Safety** - Full TypeScript types derived from your database schema (including enum types)
|
|
11
11
|
- ✅ **Runtime Validation** - Zod schemas for request/response validation
|
|
12
12
|
- 🔗 **Smart Relationships** - Automatic handling of 1:N and M:N relationships with eager loading
|
|
13
13
|
- 🔐 **Built-in Auth** - API key and JWT authentication
|
package/dist/cli.js
CHANGED
|
@@ -780,6 +780,7 @@ function generateResourceWithSDK(table, model, graph, config) {
|
|
|
780
780
|
const basePath = `/v1/${tableName}`;
|
|
781
781
|
const hasSinglePK = table.pk.length === 1;
|
|
782
782
|
const pkField = hasSinglePK ? table.pk[0] : "id";
|
|
783
|
+
const enums = model.enums || {};
|
|
783
784
|
const sdkMethods = [];
|
|
784
785
|
const endpoints = [];
|
|
785
786
|
sdkMethods.push({
|
|
@@ -803,7 +804,7 @@ const filtered = await sdk.${tableName}.list({
|
|
|
803
804
|
method: "GET",
|
|
804
805
|
path: basePath,
|
|
805
806
|
description: `List all ${tableName} records`,
|
|
806
|
-
queryParameters: generateQueryParams(table),
|
|
807
|
+
queryParameters: generateQueryParams(table, enums),
|
|
807
808
|
responseBody: `${Type}[]`
|
|
808
809
|
});
|
|
809
810
|
if (hasSinglePK) {
|
|
@@ -911,7 +912,7 @@ const filtered = await sdk.${tableName}.${method.name}({
|
|
|
911
912
|
});
|
|
912
913
|
}
|
|
913
914
|
}
|
|
914
|
-
const fields = table.columns.map((col) => generateFieldContract(col, table));
|
|
915
|
+
const fields = table.columns.map((col) => generateFieldContract(col, table, enums));
|
|
915
916
|
return {
|
|
916
917
|
name: Type,
|
|
917
918
|
tableName,
|
|
@@ -926,11 +927,11 @@ const filtered = await sdk.${tableName}.${method.name}({
|
|
|
926
927
|
fields
|
|
927
928
|
};
|
|
928
929
|
}
|
|
929
|
-
function generateFieldContract(column, table) {
|
|
930
|
+
function generateFieldContract(column, table, enums) {
|
|
930
931
|
const field = {
|
|
931
932
|
name: column.name,
|
|
932
|
-
type: postgresTypeToJsonType(column.pgType),
|
|
933
|
-
tsType: postgresTypeToTsType(column),
|
|
933
|
+
type: postgresTypeToJsonType(column.pgType, enums),
|
|
934
|
+
tsType: postgresTypeToTsType(column, enums),
|
|
934
935
|
required: !column.nullable && !column.hasDefault,
|
|
935
936
|
description: generateFieldDescription(column, table)
|
|
936
937
|
};
|
|
@@ -943,16 +944,41 @@ function generateFieldContract(column, table) {
|
|
|
943
944
|
}
|
|
944
945
|
return field;
|
|
945
946
|
}
|
|
946
|
-
function postgresTypeToTsType(column) {
|
|
947
|
+
function postgresTypeToTsType(column, enums) {
|
|
948
|
+
const pgType = column.pgType.toLowerCase();
|
|
949
|
+
if (enums[pgType]) {
|
|
950
|
+
const enumType = enums[pgType].map((v) => `"${v}"`).join(" | ");
|
|
951
|
+
if (column.nullable) {
|
|
952
|
+
return `${enumType} | null`;
|
|
953
|
+
}
|
|
954
|
+
return enumType;
|
|
955
|
+
}
|
|
956
|
+
if (pgType.startsWith("_")) {
|
|
957
|
+
const enumName = pgType.slice(1);
|
|
958
|
+
const enumValues = enums[enumName];
|
|
959
|
+
if (enumValues) {
|
|
960
|
+
const enumType = enumValues.map((v) => `"${v}"`).join(" | ");
|
|
961
|
+
const arrayType = `(${enumType})[]`;
|
|
962
|
+
if (column.nullable) {
|
|
963
|
+
return `${arrayType} | null`;
|
|
964
|
+
}
|
|
965
|
+
return arrayType;
|
|
966
|
+
}
|
|
967
|
+
}
|
|
947
968
|
const baseType = (() => {
|
|
948
|
-
switch (
|
|
969
|
+
switch (pgType) {
|
|
949
970
|
case "int":
|
|
971
|
+
case "int2":
|
|
972
|
+
case "int4":
|
|
973
|
+
case "int8":
|
|
950
974
|
case "integer":
|
|
951
975
|
case "smallint":
|
|
952
976
|
case "bigint":
|
|
953
977
|
case "decimal":
|
|
954
978
|
case "numeric":
|
|
955
979
|
case "real":
|
|
980
|
+
case "float4":
|
|
981
|
+
case "float8":
|
|
956
982
|
case "double precision":
|
|
957
983
|
case "float":
|
|
958
984
|
return "number";
|
|
@@ -970,9 +996,16 @@ function postgresTypeToTsType(column) {
|
|
|
970
996
|
return "string";
|
|
971
997
|
case "text[]":
|
|
972
998
|
case "varchar[]":
|
|
999
|
+
case "_text":
|
|
1000
|
+
case "_varchar":
|
|
973
1001
|
return "string[]";
|
|
974
1002
|
case "int[]":
|
|
975
1003
|
case "integer[]":
|
|
1004
|
+
case "_int":
|
|
1005
|
+
case "_int2":
|
|
1006
|
+
case "_int4":
|
|
1007
|
+
case "_int8":
|
|
1008
|
+
case "_integer":
|
|
976
1009
|
return "number[]";
|
|
977
1010
|
default:
|
|
978
1011
|
return "string";
|
|
@@ -1054,7 +1087,7 @@ function generateExampleValue(column) {
|
|
|
1054
1087
|
return `'example value'`;
|
|
1055
1088
|
}
|
|
1056
1089
|
}
|
|
1057
|
-
function generateQueryParams(table) {
|
|
1090
|
+
function generateQueryParams(table, enums) {
|
|
1058
1091
|
const params = {
|
|
1059
1092
|
limit: "number - Max records to return (default: 50)",
|
|
1060
1093
|
offset: "number - Records to skip",
|
|
@@ -1065,7 +1098,7 @@ function generateQueryParams(table) {
|
|
|
1065
1098
|
for (const col of table.columns) {
|
|
1066
1099
|
if (filterCount >= 3)
|
|
1067
1100
|
break;
|
|
1068
|
-
const type = postgresTypeToJsonType(col.pgType);
|
|
1101
|
+
const type = postgresTypeToJsonType(col.pgType, enums);
|
|
1069
1102
|
params[col.name] = `${type} - Filter by ${col.name}`;
|
|
1070
1103
|
if (type === "string") {
|
|
1071
1104
|
params[`${col.name}_like`] = `string - Search in ${col.name}`;
|
|
@@ -1078,15 +1111,27 @@ function generateQueryParams(table) {
|
|
|
1078
1111
|
params["..."] = "Additional filters for all fields";
|
|
1079
1112
|
return params;
|
|
1080
1113
|
}
|
|
1081
|
-
function postgresTypeToJsonType(pgType) {
|
|
1082
|
-
|
|
1114
|
+
function postgresTypeToJsonType(pgType, enums) {
|
|
1115
|
+
const t = pgType.toLowerCase();
|
|
1116
|
+
if (enums[t]) {
|
|
1117
|
+
return t;
|
|
1118
|
+
}
|
|
1119
|
+
if (t.startsWith("_") && enums[t.slice(1)]) {
|
|
1120
|
+
return `${t.slice(1)}[]`;
|
|
1121
|
+
}
|
|
1122
|
+
switch (t) {
|
|
1083
1123
|
case "int":
|
|
1124
|
+
case "int2":
|
|
1125
|
+
case "int4":
|
|
1126
|
+
case "int8":
|
|
1084
1127
|
case "integer":
|
|
1085
1128
|
case "smallint":
|
|
1086
1129
|
case "bigint":
|
|
1087
1130
|
case "decimal":
|
|
1088
1131
|
case "numeric":
|
|
1089
1132
|
case "real":
|
|
1133
|
+
case "float4":
|
|
1134
|
+
case "float8":
|
|
1090
1135
|
case "double precision":
|
|
1091
1136
|
case "float":
|
|
1092
1137
|
return "number";
|
|
@@ -1104,9 +1149,16 @@ function postgresTypeToJsonType(pgType) {
|
|
|
1104
1149
|
return "uuid";
|
|
1105
1150
|
case "text[]":
|
|
1106
1151
|
case "varchar[]":
|
|
1152
|
+
case "_text":
|
|
1153
|
+
case "_varchar":
|
|
1107
1154
|
return "string[]";
|
|
1108
1155
|
case "int[]":
|
|
1109
1156
|
case "integer[]":
|
|
1157
|
+
case "_int":
|
|
1158
|
+
case "_int2":
|
|
1159
|
+
case "_int4":
|
|
1160
|
+
case "_int8":
|
|
1161
|
+
case "_integer":
|
|
1110
1162
|
return "number[]";
|
|
1111
1163
|
default:
|
|
1112
1164
|
return "string";
|
|
@@ -2566,23 +2618,28 @@ export const buildWithFor = (t: TableName) =>
|
|
|
2566
2618
|
|
|
2567
2619
|
// src/emit-zod.ts
|
|
2568
2620
|
init_utils();
|
|
2569
|
-
function emitZod(table, opts) {
|
|
2621
|
+
function emitZod(table, opts, enums) {
|
|
2570
2622
|
const Type = pascal(table.name);
|
|
2571
2623
|
const zFor = (pg) => {
|
|
2572
|
-
|
|
2624
|
+
const t = pg.toLowerCase();
|
|
2625
|
+
if (enums[t]) {
|
|
2626
|
+
const values = enums[t].map((v) => `"${v}"`).join(", ");
|
|
2627
|
+
return `z.enum([${values}])`;
|
|
2628
|
+
}
|
|
2629
|
+
if (t === "uuid")
|
|
2573
2630
|
return `z.string()`;
|
|
2574
|
-
if (
|
|
2631
|
+
if (t === "bool" || t === "boolean")
|
|
2575
2632
|
return `z.boolean()`;
|
|
2576
|
-
if (
|
|
2633
|
+
if (t === "int2" || t === "int4" || t === "int8")
|
|
2577
2634
|
return opts.numericMode === "number" ? `z.number()` : `z.string()`;
|
|
2578
|
-
if (
|
|
2635
|
+
if (t === "numeric" || t === "float4" || t === "float8")
|
|
2579
2636
|
return opts.numericMode === "number" ? `z.number()` : `z.string()`;
|
|
2580
|
-
if (
|
|
2637
|
+
if (t === "jsonb" || t === "json")
|
|
2581
2638
|
return `z.unknown()`;
|
|
2582
|
-
if (
|
|
2639
|
+
if (t === "date" || t.startsWith("timestamp"))
|
|
2583
2640
|
return `z.string()`;
|
|
2584
|
-
if (
|
|
2585
|
-
return `z.array(${zFor(
|
|
2641
|
+
if (t.startsWith("_"))
|
|
2642
|
+
return `z.array(${zFor(t.slice(1))})`;
|
|
2586
2643
|
return `z.string()`;
|
|
2587
2644
|
};
|
|
2588
2645
|
const selectFields = table.columns.map((c) => {
|
|
@@ -3510,10 +3567,13 @@ export async function loadIncludes(
|
|
|
3510
3567
|
}
|
|
3511
3568
|
|
|
3512
3569
|
// src/emit-types.ts
|
|
3513
|
-
function tsTypeFor(pgType, opts) {
|
|
3570
|
+
function tsTypeFor(pgType, opts, enums) {
|
|
3514
3571
|
const t = pgType.toLowerCase();
|
|
3572
|
+
if (enums[t]) {
|
|
3573
|
+
return enums[t].map((v) => `"${v}"`).join(" | ");
|
|
3574
|
+
}
|
|
3515
3575
|
if (t.startsWith("_"))
|
|
3516
|
-
return
|
|
3576
|
+
return `(${tsTypeFor(t.slice(1), opts, enums)})[]`;
|
|
3517
3577
|
if (t === "uuid")
|
|
3518
3578
|
return "string";
|
|
3519
3579
|
if (t === "bool" || t === "boolean")
|
|
@@ -3528,17 +3588,17 @@ function tsTypeFor(pgType, opts) {
|
|
|
3528
3588
|
return "string";
|
|
3529
3589
|
}
|
|
3530
3590
|
var pascal2 = (s) => s.split(/[_\s-]+/).map((w) => w?.[0] ? w[0].toUpperCase() + w.slice(1) : "").join("");
|
|
3531
|
-
function emitTypes(table, opts) {
|
|
3591
|
+
function emitTypes(table, opts, enums) {
|
|
3532
3592
|
const Type = pascal2(table.name);
|
|
3533
3593
|
const insertFields = table.columns.map((col) => {
|
|
3534
|
-
const base = tsTypeFor(col.pgType, opts);
|
|
3594
|
+
const base = tsTypeFor(col.pgType, opts, enums);
|
|
3535
3595
|
const optional = col.hasDefault || col.nullable ? "?" : "";
|
|
3536
3596
|
const valueType = col.nullable ? `${base} | null` : base;
|
|
3537
3597
|
return ` ${col.name}${optional}: ${valueType};`;
|
|
3538
3598
|
}).join(`
|
|
3539
3599
|
`);
|
|
3540
3600
|
const selectFields = table.columns.map((col) => {
|
|
3541
|
-
const base = tsTypeFor(col.pgType, opts);
|
|
3601
|
+
const base = tsTypeFor(col.pgType, opts, enums);
|
|
3542
3602
|
const valueType = col.nullable ? `${base} | null` : base;
|
|
3543
3603
|
return ` ${col.name}: ${valueType};`;
|
|
3544
3604
|
}).join(`
|
|
@@ -5276,10 +5336,10 @@ async function generate(configPath) {
|
|
|
5276
5336
|
console.log(`[Index] About to process ${Object.keys(model.tables || {}).length} tables for generation`);
|
|
5277
5337
|
}
|
|
5278
5338
|
for (const table of Object.values(model.tables)) {
|
|
5279
|
-
const typesSrc = emitTypes(table, { numericMode: "string" });
|
|
5339
|
+
const typesSrc = emitTypes(table, { numericMode: "string" }, model.enums);
|
|
5280
5340
|
files.push({ path: join(serverDir, "types", `${table.name}.ts`), content: typesSrc });
|
|
5281
5341
|
files.push({ path: join(clientDir, "types", `${table.name}.ts`), content: typesSrc });
|
|
5282
|
-
const zodSrc = emitZod(table, { numericMode: "string" });
|
|
5342
|
+
const zodSrc = emitZod(table, { numericMode: "string" }, model.enums);
|
|
5283
5343
|
files.push({ path: join(serverDir, "zod", `${table.name}.ts`), content: zodSrc });
|
|
5284
5344
|
files.push({ path: join(clientDir, "zod", `${table.name}.ts`), content: zodSrc });
|
|
5285
5345
|
const paramsZodSrc = emitParamsZod(table, graph);
|
package/dist/emit-types.d.ts
CHANGED
package/dist/emit-zod.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -779,6 +779,7 @@ function generateResourceWithSDK(table, model, graph, config) {
|
|
|
779
779
|
const basePath = `/v1/${tableName}`;
|
|
780
780
|
const hasSinglePK = table.pk.length === 1;
|
|
781
781
|
const pkField = hasSinglePK ? table.pk[0] : "id";
|
|
782
|
+
const enums = model.enums || {};
|
|
782
783
|
const sdkMethods = [];
|
|
783
784
|
const endpoints = [];
|
|
784
785
|
sdkMethods.push({
|
|
@@ -802,7 +803,7 @@ const filtered = await sdk.${tableName}.list({
|
|
|
802
803
|
method: "GET",
|
|
803
804
|
path: basePath,
|
|
804
805
|
description: `List all ${tableName} records`,
|
|
805
|
-
queryParameters: generateQueryParams(table),
|
|
806
|
+
queryParameters: generateQueryParams(table, enums),
|
|
806
807
|
responseBody: `${Type}[]`
|
|
807
808
|
});
|
|
808
809
|
if (hasSinglePK) {
|
|
@@ -910,7 +911,7 @@ const filtered = await sdk.${tableName}.${method.name}({
|
|
|
910
911
|
});
|
|
911
912
|
}
|
|
912
913
|
}
|
|
913
|
-
const fields = table.columns.map((col) => generateFieldContract(col, table));
|
|
914
|
+
const fields = table.columns.map((col) => generateFieldContract(col, table, enums));
|
|
914
915
|
return {
|
|
915
916
|
name: Type,
|
|
916
917
|
tableName,
|
|
@@ -925,11 +926,11 @@ const filtered = await sdk.${tableName}.${method.name}({
|
|
|
925
926
|
fields
|
|
926
927
|
};
|
|
927
928
|
}
|
|
928
|
-
function generateFieldContract(column, table) {
|
|
929
|
+
function generateFieldContract(column, table, enums) {
|
|
929
930
|
const field = {
|
|
930
931
|
name: column.name,
|
|
931
|
-
type: postgresTypeToJsonType(column.pgType),
|
|
932
|
-
tsType: postgresTypeToTsType(column),
|
|
932
|
+
type: postgresTypeToJsonType(column.pgType, enums),
|
|
933
|
+
tsType: postgresTypeToTsType(column, enums),
|
|
933
934
|
required: !column.nullable && !column.hasDefault,
|
|
934
935
|
description: generateFieldDescription(column, table)
|
|
935
936
|
};
|
|
@@ -942,16 +943,41 @@ function generateFieldContract(column, table) {
|
|
|
942
943
|
}
|
|
943
944
|
return field;
|
|
944
945
|
}
|
|
945
|
-
function postgresTypeToTsType(column) {
|
|
946
|
+
function postgresTypeToTsType(column, enums) {
|
|
947
|
+
const pgType = column.pgType.toLowerCase();
|
|
948
|
+
if (enums[pgType]) {
|
|
949
|
+
const enumType = enums[pgType].map((v) => `"${v}"`).join(" | ");
|
|
950
|
+
if (column.nullable) {
|
|
951
|
+
return `${enumType} | null`;
|
|
952
|
+
}
|
|
953
|
+
return enumType;
|
|
954
|
+
}
|
|
955
|
+
if (pgType.startsWith("_")) {
|
|
956
|
+
const enumName = pgType.slice(1);
|
|
957
|
+
const enumValues = enums[enumName];
|
|
958
|
+
if (enumValues) {
|
|
959
|
+
const enumType = enumValues.map((v) => `"${v}"`).join(" | ");
|
|
960
|
+
const arrayType = `(${enumType})[]`;
|
|
961
|
+
if (column.nullable) {
|
|
962
|
+
return `${arrayType} | null`;
|
|
963
|
+
}
|
|
964
|
+
return arrayType;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
946
967
|
const baseType = (() => {
|
|
947
|
-
switch (
|
|
968
|
+
switch (pgType) {
|
|
948
969
|
case "int":
|
|
970
|
+
case "int2":
|
|
971
|
+
case "int4":
|
|
972
|
+
case "int8":
|
|
949
973
|
case "integer":
|
|
950
974
|
case "smallint":
|
|
951
975
|
case "bigint":
|
|
952
976
|
case "decimal":
|
|
953
977
|
case "numeric":
|
|
954
978
|
case "real":
|
|
979
|
+
case "float4":
|
|
980
|
+
case "float8":
|
|
955
981
|
case "double precision":
|
|
956
982
|
case "float":
|
|
957
983
|
return "number";
|
|
@@ -969,9 +995,16 @@ function postgresTypeToTsType(column) {
|
|
|
969
995
|
return "string";
|
|
970
996
|
case "text[]":
|
|
971
997
|
case "varchar[]":
|
|
998
|
+
case "_text":
|
|
999
|
+
case "_varchar":
|
|
972
1000
|
return "string[]";
|
|
973
1001
|
case "int[]":
|
|
974
1002
|
case "integer[]":
|
|
1003
|
+
case "_int":
|
|
1004
|
+
case "_int2":
|
|
1005
|
+
case "_int4":
|
|
1006
|
+
case "_int8":
|
|
1007
|
+
case "_integer":
|
|
975
1008
|
return "number[]";
|
|
976
1009
|
default:
|
|
977
1010
|
return "string";
|
|
@@ -1053,7 +1086,7 @@ function generateExampleValue(column) {
|
|
|
1053
1086
|
return `'example value'`;
|
|
1054
1087
|
}
|
|
1055
1088
|
}
|
|
1056
|
-
function generateQueryParams(table) {
|
|
1089
|
+
function generateQueryParams(table, enums) {
|
|
1057
1090
|
const params = {
|
|
1058
1091
|
limit: "number - Max records to return (default: 50)",
|
|
1059
1092
|
offset: "number - Records to skip",
|
|
@@ -1064,7 +1097,7 @@ function generateQueryParams(table) {
|
|
|
1064
1097
|
for (const col of table.columns) {
|
|
1065
1098
|
if (filterCount >= 3)
|
|
1066
1099
|
break;
|
|
1067
|
-
const type = postgresTypeToJsonType(col.pgType);
|
|
1100
|
+
const type = postgresTypeToJsonType(col.pgType, enums);
|
|
1068
1101
|
params[col.name] = `${type} - Filter by ${col.name}`;
|
|
1069
1102
|
if (type === "string") {
|
|
1070
1103
|
params[`${col.name}_like`] = `string - Search in ${col.name}`;
|
|
@@ -1077,15 +1110,27 @@ function generateQueryParams(table) {
|
|
|
1077
1110
|
params["..."] = "Additional filters for all fields";
|
|
1078
1111
|
return params;
|
|
1079
1112
|
}
|
|
1080
|
-
function postgresTypeToJsonType(pgType) {
|
|
1081
|
-
|
|
1113
|
+
function postgresTypeToJsonType(pgType, enums) {
|
|
1114
|
+
const t = pgType.toLowerCase();
|
|
1115
|
+
if (enums[t]) {
|
|
1116
|
+
return t;
|
|
1117
|
+
}
|
|
1118
|
+
if (t.startsWith("_") && enums[t.slice(1)]) {
|
|
1119
|
+
return `${t.slice(1)}[]`;
|
|
1120
|
+
}
|
|
1121
|
+
switch (t) {
|
|
1082
1122
|
case "int":
|
|
1123
|
+
case "int2":
|
|
1124
|
+
case "int4":
|
|
1125
|
+
case "int8":
|
|
1083
1126
|
case "integer":
|
|
1084
1127
|
case "smallint":
|
|
1085
1128
|
case "bigint":
|
|
1086
1129
|
case "decimal":
|
|
1087
1130
|
case "numeric":
|
|
1088
1131
|
case "real":
|
|
1132
|
+
case "float4":
|
|
1133
|
+
case "float8":
|
|
1089
1134
|
case "double precision":
|
|
1090
1135
|
case "float":
|
|
1091
1136
|
return "number";
|
|
@@ -1103,9 +1148,16 @@ function postgresTypeToJsonType(pgType) {
|
|
|
1103
1148
|
return "uuid";
|
|
1104
1149
|
case "text[]":
|
|
1105
1150
|
case "varchar[]":
|
|
1151
|
+
case "_text":
|
|
1152
|
+
case "_varchar":
|
|
1106
1153
|
return "string[]";
|
|
1107
1154
|
case "int[]":
|
|
1108
1155
|
case "integer[]":
|
|
1156
|
+
case "_int":
|
|
1157
|
+
case "_int2":
|
|
1158
|
+
case "_int4":
|
|
1159
|
+
case "_int8":
|
|
1160
|
+
case "_integer":
|
|
1109
1161
|
return "number[]";
|
|
1110
1162
|
default:
|
|
1111
1163
|
return "string";
|
|
@@ -1806,23 +1858,28 @@ export const buildWithFor = (t: TableName) =>
|
|
|
1806
1858
|
|
|
1807
1859
|
// src/emit-zod.ts
|
|
1808
1860
|
init_utils();
|
|
1809
|
-
function emitZod(table, opts) {
|
|
1861
|
+
function emitZod(table, opts, enums) {
|
|
1810
1862
|
const Type = pascal(table.name);
|
|
1811
1863
|
const zFor = (pg) => {
|
|
1812
|
-
|
|
1864
|
+
const t = pg.toLowerCase();
|
|
1865
|
+
if (enums[t]) {
|
|
1866
|
+
const values = enums[t].map((v) => `"${v}"`).join(", ");
|
|
1867
|
+
return `z.enum([${values}])`;
|
|
1868
|
+
}
|
|
1869
|
+
if (t === "uuid")
|
|
1813
1870
|
return `z.string()`;
|
|
1814
|
-
if (
|
|
1871
|
+
if (t === "bool" || t === "boolean")
|
|
1815
1872
|
return `z.boolean()`;
|
|
1816
|
-
if (
|
|
1873
|
+
if (t === "int2" || t === "int4" || t === "int8")
|
|
1817
1874
|
return opts.numericMode === "number" ? `z.number()` : `z.string()`;
|
|
1818
|
-
if (
|
|
1875
|
+
if (t === "numeric" || t === "float4" || t === "float8")
|
|
1819
1876
|
return opts.numericMode === "number" ? `z.number()` : `z.string()`;
|
|
1820
|
-
if (
|
|
1877
|
+
if (t === "jsonb" || t === "json")
|
|
1821
1878
|
return `z.unknown()`;
|
|
1822
|
-
if (
|
|
1879
|
+
if (t === "date" || t.startsWith("timestamp"))
|
|
1823
1880
|
return `z.string()`;
|
|
1824
|
-
if (
|
|
1825
|
-
return `z.array(${zFor(
|
|
1881
|
+
if (t.startsWith("_"))
|
|
1882
|
+
return `z.array(${zFor(t.slice(1))})`;
|
|
1826
1883
|
return `z.string()`;
|
|
1827
1884
|
};
|
|
1828
1885
|
const selectFields = table.columns.map((c) => {
|
|
@@ -2750,10 +2807,13 @@ export async function loadIncludes(
|
|
|
2750
2807
|
}
|
|
2751
2808
|
|
|
2752
2809
|
// src/emit-types.ts
|
|
2753
|
-
function tsTypeFor(pgType, opts) {
|
|
2810
|
+
function tsTypeFor(pgType, opts, enums) {
|
|
2754
2811
|
const t = pgType.toLowerCase();
|
|
2812
|
+
if (enums[t]) {
|
|
2813
|
+
return enums[t].map((v) => `"${v}"`).join(" | ");
|
|
2814
|
+
}
|
|
2755
2815
|
if (t.startsWith("_"))
|
|
2756
|
-
return
|
|
2816
|
+
return `(${tsTypeFor(t.slice(1), opts, enums)})[]`;
|
|
2757
2817
|
if (t === "uuid")
|
|
2758
2818
|
return "string";
|
|
2759
2819
|
if (t === "bool" || t === "boolean")
|
|
@@ -2768,17 +2828,17 @@ function tsTypeFor(pgType, opts) {
|
|
|
2768
2828
|
return "string";
|
|
2769
2829
|
}
|
|
2770
2830
|
var pascal2 = (s) => s.split(/[_\s-]+/).map((w) => w?.[0] ? w[0].toUpperCase() + w.slice(1) : "").join("");
|
|
2771
|
-
function emitTypes(table, opts) {
|
|
2831
|
+
function emitTypes(table, opts, enums) {
|
|
2772
2832
|
const Type = pascal2(table.name);
|
|
2773
2833
|
const insertFields = table.columns.map((col) => {
|
|
2774
|
-
const base = tsTypeFor(col.pgType, opts);
|
|
2834
|
+
const base = tsTypeFor(col.pgType, opts, enums);
|
|
2775
2835
|
const optional = col.hasDefault || col.nullable ? "?" : "";
|
|
2776
2836
|
const valueType = col.nullable ? `${base} | null` : base;
|
|
2777
2837
|
return ` ${col.name}${optional}: ${valueType};`;
|
|
2778
2838
|
}).join(`
|
|
2779
2839
|
`);
|
|
2780
2840
|
const selectFields = table.columns.map((col) => {
|
|
2781
|
-
const base = tsTypeFor(col.pgType, opts);
|
|
2841
|
+
const base = tsTypeFor(col.pgType, opts, enums);
|
|
2782
2842
|
const valueType = col.nullable ? `${base} | null` : base;
|
|
2783
2843
|
return ` ${col.name}: ${valueType};`;
|
|
2784
2844
|
}).join(`
|
|
@@ -4516,10 +4576,10 @@ async function generate(configPath) {
|
|
|
4516
4576
|
console.log(`[Index] About to process ${Object.keys(model.tables || {}).length} tables for generation`);
|
|
4517
4577
|
}
|
|
4518
4578
|
for (const table of Object.values(model.tables)) {
|
|
4519
|
-
const typesSrc = emitTypes(table, { numericMode: "string" });
|
|
4579
|
+
const typesSrc = emitTypes(table, { numericMode: "string" }, model.enums);
|
|
4520
4580
|
files.push({ path: join(serverDir, "types", `${table.name}.ts`), content: typesSrc });
|
|
4521
4581
|
files.push({ path: join(clientDir, "types", `${table.name}.ts`), content: typesSrc });
|
|
4522
|
-
const zodSrc = emitZod(table, { numericMode: "string" });
|
|
4582
|
+
const zodSrc = emitZod(table, { numericMode: "string" }, model.enums);
|
|
4523
4583
|
files.push({ path: join(serverDir, "zod", `${table.name}.ts`), content: zodSrc });
|
|
4524
4584
|
files.push({ path: join(clientDir, "zod", `${table.name}.ts`), content: zodSrc });
|
|
4525
4585
|
const paramsZodSrc = emitParamsZod(table, graph);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "postgresdk",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.1",
|
|
4
4
|
"description": "Generate a typed server/client SDK from a Postgres schema (includes, Zod, Hono).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -22,11 +22,12 @@
|
|
|
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:gen-with-tests && bun test:pull && 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:gen-with-tests && bun test:pull && bun test:enums && bun test:typecheck && bun test:drizzle-e2e",
|
|
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",
|
|
29
29
|
"test:pull": "bun test/test-pull.ts",
|
|
30
|
+
"test:enums": "bun test/test-enums.ts",
|
|
30
31
|
"test:typecheck": "bun test/test-typecheck.ts",
|
|
31
32
|
"test:drizzle-e2e": "bun test/test-drizzle-e2e.ts",
|
|
32
33
|
"typecheck": "tsc --noEmit",
|