postgresdk 0.19.1 → 0.19.3
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/dist/cli.js +63 -65
- package/dist/index.js +63 -65
- package/dist/rel-classify.d.ts +2 -0
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -583,7 +583,8 @@ function buildReturnType(baseTable, path, isMany, targets, graph) {
|
|
|
583
583
|
continue;
|
|
584
584
|
const targetType = `Select${pascal(target)}`;
|
|
585
585
|
if (i === 0) {
|
|
586
|
-
|
|
586
|
+
const edgeNull = !isMany[i] && graph[baseTable]?.[key]?.nullable ? " | null" : "";
|
|
587
|
+
parts.push(`${key}: ${isMany[i] ? `${targetType}[]` : `${targetType}${edgeNull}`}`);
|
|
587
588
|
} else {
|
|
588
589
|
let nestedType = targetType;
|
|
589
590
|
for (let j = i;j < path.length; j++) {
|
|
@@ -593,13 +594,26 @@ function buildReturnType(baseTable, path, isMany, targets, graph) {
|
|
|
593
594
|
if (!nestedKey || !nestedTarget)
|
|
594
595
|
continue;
|
|
595
596
|
const nestedTargetType = `Select${pascal(nestedTarget)}`;
|
|
596
|
-
|
|
597
|
+
const nestedSource = targets[j - 1];
|
|
598
|
+
const nestedNull = !isMany[j] && graph[nestedSource]?.[nestedKey]?.nullable ? " | null" : "";
|
|
599
|
+
nestedType = `${nestedType} & { ${nestedKey}: ${isMany[j] ? `${nestedTargetType}[]` : `${nestedTargetType}${nestedNull}`} }`;
|
|
597
600
|
}
|
|
598
601
|
}
|
|
599
602
|
const prevKey = path[i - 1];
|
|
600
603
|
const prevTarget = targets[i - 1];
|
|
601
604
|
if (prevKey && prevTarget) {
|
|
602
|
-
|
|
605
|
+
const prevSource = i - 1 === 0 ? baseTable : targets[i - 2];
|
|
606
|
+
const innerNull = !isMany[i] && graph[prevTarget]?.[key]?.nullable ? " | null" : "";
|
|
607
|
+
const prevNullable = !isMany[i - 1] && graph[prevSource]?.[prevKey]?.nullable;
|
|
608
|
+
const inner = isMany[i] ? `${targetType}[]` : `${targetType}${innerNull}`;
|
|
609
|
+
const composite = `Select${pascal(prevTarget)} & { ${key}: ${inner} }`;
|
|
610
|
+
if (isMany[i - 1]) {
|
|
611
|
+
parts[parts.length - 1] = `${prevKey}: (${composite})[]`;
|
|
612
|
+
} else if (prevNullable) {
|
|
613
|
+
parts[parts.length - 1] = `${prevKey}: (${composite}) | null`;
|
|
614
|
+
} else {
|
|
615
|
+
parts[parts.length - 1] = `${prevKey}: ${composite}`;
|
|
616
|
+
}
|
|
603
617
|
}
|
|
604
618
|
break;
|
|
605
619
|
}
|
|
@@ -689,8 +703,10 @@ function generateIncludeMethods(table, graph, opts, allTables) {
|
|
|
689
703
|
}
|
|
690
704
|
const combinedPath = [key1, key2];
|
|
691
705
|
const combinedSuffix = `With${pascal(key1)}And${pascal(key2)}`;
|
|
692
|
-
const
|
|
693
|
-
const
|
|
706
|
+
const null1 = edge1.kind === "one" && edge1.nullable ? " | null" : "";
|
|
707
|
+
const null2 = edge2.kind === "one" && edge2.nullable ? " | null" : "";
|
|
708
|
+
const type1 = `${key1}: ${edge1.kind === "many" ? `Select${pascal(edge1.target)}[]` : `Select${pascal(edge1.target)}${null1}`}`;
|
|
709
|
+
const type2 = `${key2}: ${edge2.kind === "many" ? `Select${pascal(edge2.target)}[]` : `Select${pascal(edge2.target)}${null2}`}`;
|
|
694
710
|
const combinedBaseType = `Select${pascal(baseTableName)} & { ${type1}; ${type2} }`;
|
|
695
711
|
const combinedTypeName = `Select${pascal(baseTableName)}${combinedSuffix}`;
|
|
696
712
|
methods.push({
|
|
@@ -2639,7 +2655,14 @@ function buildGraph(model) {
|
|
|
2639
2655
|
const upKey = singular(parent.name);
|
|
2640
2656
|
const downKey = plural(child.name);
|
|
2641
2657
|
if (!(upKey in childNode)) {
|
|
2642
|
-
|
|
2658
|
+
const fkNullable = fk.from.some((colName) => child.columns.find((c) => c.name === colName)?.nullable);
|
|
2659
|
+
childNode[upKey] = {
|
|
2660
|
+
from: child.name,
|
|
2661
|
+
key: upKey,
|
|
2662
|
+
kind: "one",
|
|
2663
|
+
target: parent.name,
|
|
2664
|
+
...fkNullable && { nullable: true }
|
|
2665
|
+
};
|
|
2643
2666
|
}
|
|
2644
2667
|
if (!(downKey in parentNode)) {
|
|
2645
2668
|
parentNode[downKey] = { from: parent.name, key: downKey, kind: "many", target: child.name };
|
|
@@ -2757,10 +2780,11 @@ function emitIncludeResolver(graph, useJsExtensions) {
|
|
|
2757
2780
|
: Select${targetType}[]
|
|
2758
2781
|
)`;
|
|
2759
2782
|
} else {
|
|
2783
|
+
const nullSuffix = edge.nullable ? " | null" : "";
|
|
2760
2784
|
out += `(
|
|
2761
2785
|
TInclude[K] extends { include: infer U extends ${targetType}IncludeSpec }
|
|
2762
|
-
? ${targetType}WithIncludes<U
|
|
2763
|
-
: Select${targetType}
|
|
2786
|
+
? ${targetType}WithIncludes<U>${nullSuffix}
|
|
2787
|
+
: Select${targetType}${nullSuffix}
|
|
2764
2788
|
)`;
|
|
2765
2789
|
}
|
|
2766
2790
|
out += ` :${isLast ? `
|
|
@@ -2823,7 +2847,7 @@ function emitZod(table, opts, enums) {
|
|
|
2823
2847
|
return `z.enum([${values}])`;
|
|
2824
2848
|
}
|
|
2825
2849
|
if (t === "uuid")
|
|
2826
|
-
return `z.string()`;
|
|
2850
|
+
return `z.string().uuid()`;
|
|
2827
2851
|
if (t === "bool" || t === "boolean")
|
|
2828
2852
|
return `z.boolean()`;
|
|
2829
2853
|
if (t === "int2" || t === "int4" || t === "int8") {
|
|
@@ -5951,6 +5975,18 @@ const log = {
|
|
|
5951
5975
|
error: (...args: any[]) => console.error("[sdk]", ...args),
|
|
5952
5976
|
};
|
|
5953
5977
|
|
|
5978
|
+
/**
|
|
5979
|
+
* Checks if a Postgres error is a client input error (invalid syntax, out of range, etc.)
|
|
5980
|
+
* PG error class 22 = "data exception" — covers invalid input syntax for uuid, int, json, etc.
|
|
5981
|
+
* PG error code 23502 = "not_null_violation", 23505 = "unique_violation", 23503 = "foreign_key_violation"
|
|
5982
|
+
*/
|
|
5983
|
+
function pgErrorStatus(e: any): number {
|
|
5984
|
+
const code = e?.code;
|
|
5985
|
+
if (typeof code === "string" && code.startsWith("22")) return 400;
|
|
5986
|
+
if (code === "23502" || code === "23505" || code === "23503") return 409;
|
|
5987
|
+
return 500;
|
|
5988
|
+
}
|
|
5989
|
+
|
|
5954
5990
|
/**
|
|
5955
5991
|
* Builds SQL column list from select/exclude parameters
|
|
5956
5992
|
* @param select - Columns to include (mutually exclusive with exclude)
|
|
@@ -6051,22 +6087,13 @@ export async function createRecord(
|
|
|
6051
6087
|
|
|
6052
6088
|
return { data: parsedRows[0] ?? null, status: parsedRows[0] ? 201 : 500 };
|
|
6053
6089
|
} catch (e: any) {
|
|
6054
|
-
|
|
6055
|
-
|
|
6056
|
-
const isJsonError = errorMsg.includes("invalid input syntax for type json");
|
|
6057
|
-
|
|
6058
|
-
if (isJsonError) {
|
|
6059
|
-
log.error(\`POST \${ctx.table} - Invalid JSON input detected!\`);
|
|
6060
|
-
log.error("Input data that caused error:", JSON.stringify(data, null, 2));
|
|
6061
|
-
log.error("PostgreSQL error:", errorMsg);
|
|
6062
|
-
} else {
|
|
6063
|
-
log.error(\`POST \${ctx.table} error:\`, e?.stack ?? e);
|
|
6064
|
-
}
|
|
6090
|
+
const status = pgErrorStatus(e);
|
|
6091
|
+
log.error(\`POST \${ctx.table} error:\`, e?.stack ?? e);
|
|
6065
6092
|
|
|
6066
6093
|
return {
|
|
6067
6094
|
error: e?.message ?? "Internal error",
|
|
6068
6095
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
6069
|
-
status
|
|
6096
|
+
status
|
|
6070
6097
|
};
|
|
6071
6098
|
}
|
|
6072
6099
|
}
|
|
@@ -6141,22 +6168,12 @@ export async function upsertRecord(
|
|
|
6141
6168
|
|
|
6142
6169
|
return { data: parsedRows[0], status: 200 };
|
|
6143
6170
|
} catch (e: any) {
|
|
6144
|
-
const
|
|
6145
|
-
|
|
6146
|
-
if (isJsonError) {
|
|
6147
|
-
log.error(\`UPSERT \${ctx.table} - Invalid JSON input detected!\`);
|
|
6148
|
-
log.error("Input args that caused error:", JSON.stringify(args, null, 2));
|
|
6149
|
-
log.error("Filtered update data (sent to DB):", JSON.stringify(Object.fromEntries(
|
|
6150
|
-
Object.entries(args.update).filter(([k]) => !ctx.pkColumns.includes(k))
|
|
6151
|
-
), null, 2));
|
|
6152
|
-
log.error("PostgreSQL error:", errorMsg);
|
|
6153
|
-
} else {
|
|
6154
|
-
log.error(\`UPSERT \${ctx.table} error:\`, e?.stack ?? e);
|
|
6155
|
-
}
|
|
6171
|
+
const status = pgErrorStatus(e);
|
|
6172
|
+
log.error(\`UPSERT \${ctx.table} error:\`, e?.stack ?? e);
|
|
6156
6173
|
return {
|
|
6157
6174
|
error: e?.message ?? "Internal error",
|
|
6158
6175
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
6159
|
-
status
|
|
6176
|
+
status
|
|
6160
6177
|
};
|
|
6161
6178
|
}
|
|
6162
6179
|
}
|
|
@@ -6189,11 +6206,12 @@ export async function getByPk(
|
|
|
6189
6206
|
|
|
6190
6207
|
return { data: parsedRows[0], status: 200 };
|
|
6191
6208
|
} catch (e: any) {
|
|
6209
|
+
const status = pgErrorStatus(e);
|
|
6192
6210
|
log.error(\`GET \${ctx.table} error:\`, e?.stack ?? e);
|
|
6193
|
-
return {
|
|
6194
|
-
error: e?.message ?? "Internal error",
|
|
6211
|
+
return {
|
|
6212
|
+
error: e?.message ?? "Internal error",
|
|
6195
6213
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
6196
|
-
status
|
|
6214
|
+
status
|
|
6197
6215
|
};
|
|
6198
6216
|
}
|
|
6199
6217
|
}
|
|
@@ -6742,22 +6760,13 @@ export async function listRecords(
|
|
|
6742
6760
|
log.debug(\`LIST \${ctx.table} result: \${rows.length} rows, \${total} total, hasMore=\${hasMore}\`);
|
|
6743
6761
|
return metadata;
|
|
6744
6762
|
} catch (e: any) {
|
|
6745
|
-
|
|
6746
|
-
|
|
6747
|
-
const isJsonError = errorMsg.includes("invalid input syntax for type json");
|
|
6748
|
-
|
|
6749
|
-
if (isJsonError) {
|
|
6750
|
-
log.error(\`LIST \${ctx.table} - Invalid JSON input detected in query!\`);
|
|
6751
|
-
log.error("WHERE clause:", JSON.stringify(params.where, null, 2));
|
|
6752
|
-
log.error("PostgreSQL error:", errorMsg);
|
|
6753
|
-
} else {
|
|
6754
|
-
log.error(\`LIST \${ctx.table} error:\`, e?.stack ?? e);
|
|
6755
|
-
}
|
|
6763
|
+
const status = pgErrorStatus(e);
|
|
6764
|
+
log.error(\`LIST \${ctx.table} error:\`, e?.stack ?? e);
|
|
6756
6765
|
|
|
6757
6766
|
return {
|
|
6758
6767
|
error: e?.message ?? "Internal error",
|
|
6759
6768
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
6760
|
-
status
|
|
6769
|
+
status
|
|
6761
6770
|
};
|
|
6762
6771
|
}
|
|
6763
6772
|
}
|
|
@@ -6809,25 +6818,13 @@ export async function updateRecord(
|
|
|
6809
6818
|
|
|
6810
6819
|
return { data: parsedRows[0], status: 200 };
|
|
6811
6820
|
} catch (e: any) {
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
const isJsonError = errorMsg.includes("invalid input syntax for type json");
|
|
6815
|
-
|
|
6816
|
-
if (isJsonError) {
|
|
6817
|
-
log.error(\`PATCH \${ctx.table} - Invalid JSON input detected!\`);
|
|
6818
|
-
log.error("Input data that caused error:", JSON.stringify(updateData, null, 2));
|
|
6819
|
-
log.error("Filtered data (sent to DB):", JSON.stringify(Object.fromEntries(
|
|
6820
|
-
Object.entries(updateData).filter(([k]) => !ctx.pkColumns.includes(k))
|
|
6821
|
-
), null, 2));
|
|
6822
|
-
log.error("PostgreSQL error:", errorMsg);
|
|
6823
|
-
} else {
|
|
6824
|
-
log.error(\`PATCH \${ctx.table} error:\`, e?.stack ?? e);
|
|
6825
|
-
}
|
|
6821
|
+
const status = pgErrorStatus(e);
|
|
6822
|
+
log.error(\`PATCH \${ctx.table} error:\`, e?.stack ?? e);
|
|
6826
6823
|
|
|
6827
6824
|
return {
|
|
6828
6825
|
error: e?.message ?? "Internal error",
|
|
6829
6826
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
6830
|
-
status
|
|
6827
|
+
status
|
|
6831
6828
|
};
|
|
6832
6829
|
}
|
|
6833
6830
|
}
|
|
@@ -6862,11 +6859,12 @@ export async function deleteRecord(
|
|
|
6862
6859
|
|
|
6863
6860
|
return { data: parsedRows[0], status: 200 };
|
|
6864
6861
|
} catch (e: any) {
|
|
6862
|
+
const status = pgErrorStatus(e);
|
|
6865
6863
|
log.error(\`DELETE \${ctx.table} error:\`, e?.stack ?? e);
|
|
6866
6864
|
return {
|
|
6867
6865
|
error: e?.message ?? "Internal error",
|
|
6868
6866
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
6869
|
-
status
|
|
6867
|
+
status
|
|
6870
6868
|
};
|
|
6871
6869
|
}
|
|
6872
6870
|
}
|
package/dist/index.js
CHANGED
|
@@ -582,7 +582,8 @@ function buildReturnType(baseTable, path, isMany, targets, graph) {
|
|
|
582
582
|
continue;
|
|
583
583
|
const targetType = `Select${pascal(target)}`;
|
|
584
584
|
if (i === 0) {
|
|
585
|
-
|
|
585
|
+
const edgeNull = !isMany[i] && graph[baseTable]?.[key]?.nullable ? " | null" : "";
|
|
586
|
+
parts.push(`${key}: ${isMany[i] ? `${targetType}[]` : `${targetType}${edgeNull}`}`);
|
|
586
587
|
} else {
|
|
587
588
|
let nestedType = targetType;
|
|
588
589
|
for (let j = i;j < path.length; j++) {
|
|
@@ -592,13 +593,26 @@ function buildReturnType(baseTable, path, isMany, targets, graph) {
|
|
|
592
593
|
if (!nestedKey || !nestedTarget)
|
|
593
594
|
continue;
|
|
594
595
|
const nestedTargetType = `Select${pascal(nestedTarget)}`;
|
|
595
|
-
|
|
596
|
+
const nestedSource = targets[j - 1];
|
|
597
|
+
const nestedNull = !isMany[j] && graph[nestedSource]?.[nestedKey]?.nullable ? " | null" : "";
|
|
598
|
+
nestedType = `${nestedType} & { ${nestedKey}: ${isMany[j] ? `${nestedTargetType}[]` : `${nestedTargetType}${nestedNull}`} }`;
|
|
596
599
|
}
|
|
597
600
|
}
|
|
598
601
|
const prevKey = path[i - 1];
|
|
599
602
|
const prevTarget = targets[i - 1];
|
|
600
603
|
if (prevKey && prevTarget) {
|
|
601
|
-
|
|
604
|
+
const prevSource = i - 1 === 0 ? baseTable : targets[i - 2];
|
|
605
|
+
const innerNull = !isMany[i] && graph[prevTarget]?.[key]?.nullable ? " | null" : "";
|
|
606
|
+
const prevNullable = !isMany[i - 1] && graph[prevSource]?.[prevKey]?.nullable;
|
|
607
|
+
const inner = isMany[i] ? `${targetType}[]` : `${targetType}${innerNull}`;
|
|
608
|
+
const composite = `Select${pascal(prevTarget)} & { ${key}: ${inner} }`;
|
|
609
|
+
if (isMany[i - 1]) {
|
|
610
|
+
parts[parts.length - 1] = `${prevKey}: (${composite})[]`;
|
|
611
|
+
} else if (prevNullable) {
|
|
612
|
+
parts[parts.length - 1] = `${prevKey}: (${composite}) | null`;
|
|
613
|
+
} else {
|
|
614
|
+
parts[parts.length - 1] = `${prevKey}: ${composite}`;
|
|
615
|
+
}
|
|
602
616
|
}
|
|
603
617
|
break;
|
|
604
618
|
}
|
|
@@ -688,8 +702,10 @@ function generateIncludeMethods(table, graph, opts, allTables) {
|
|
|
688
702
|
}
|
|
689
703
|
const combinedPath = [key1, key2];
|
|
690
704
|
const combinedSuffix = `With${pascal(key1)}And${pascal(key2)}`;
|
|
691
|
-
const
|
|
692
|
-
const
|
|
705
|
+
const null1 = edge1.kind === "one" && edge1.nullable ? " | null" : "";
|
|
706
|
+
const null2 = edge2.kind === "one" && edge2.nullable ? " | null" : "";
|
|
707
|
+
const type1 = `${key1}: ${edge1.kind === "many" ? `Select${pascal(edge1.target)}[]` : `Select${pascal(edge1.target)}${null1}`}`;
|
|
708
|
+
const type2 = `${key2}: ${edge2.kind === "many" ? `Select${pascal(edge2.target)}[]` : `Select${pascal(edge2.target)}${null2}`}`;
|
|
693
709
|
const combinedBaseType = `Select${pascal(baseTableName)} & { ${type1}; ${type2} }`;
|
|
694
710
|
const combinedTypeName = `Select${pascal(baseTableName)}${combinedSuffix}`;
|
|
695
711
|
methods.push({
|
|
@@ -1679,7 +1695,14 @@ function buildGraph(model) {
|
|
|
1679
1695
|
const upKey = singular(parent.name);
|
|
1680
1696
|
const downKey = plural(child.name);
|
|
1681
1697
|
if (!(upKey in childNode)) {
|
|
1682
|
-
|
|
1698
|
+
const fkNullable = fk.from.some((colName) => child.columns.find((c) => c.name === colName)?.nullable);
|
|
1699
|
+
childNode[upKey] = {
|
|
1700
|
+
from: child.name,
|
|
1701
|
+
key: upKey,
|
|
1702
|
+
kind: "one",
|
|
1703
|
+
target: parent.name,
|
|
1704
|
+
...fkNullable && { nullable: true }
|
|
1705
|
+
};
|
|
1683
1706
|
}
|
|
1684
1707
|
if (!(downKey in parentNode)) {
|
|
1685
1708
|
parentNode[downKey] = { from: parent.name, key: downKey, kind: "many", target: child.name };
|
|
@@ -1797,10 +1820,11 @@ function emitIncludeResolver(graph, useJsExtensions) {
|
|
|
1797
1820
|
: Select${targetType}[]
|
|
1798
1821
|
)`;
|
|
1799
1822
|
} else {
|
|
1823
|
+
const nullSuffix = edge.nullable ? " | null" : "";
|
|
1800
1824
|
out += `(
|
|
1801
1825
|
TInclude[K] extends { include: infer U extends ${targetType}IncludeSpec }
|
|
1802
|
-
? ${targetType}WithIncludes<U
|
|
1803
|
-
: Select${targetType}
|
|
1826
|
+
? ${targetType}WithIncludes<U>${nullSuffix}
|
|
1827
|
+
: Select${targetType}${nullSuffix}
|
|
1804
1828
|
)`;
|
|
1805
1829
|
}
|
|
1806
1830
|
out += ` :${isLast ? `
|
|
@@ -1863,7 +1887,7 @@ function emitZod(table, opts, enums) {
|
|
|
1863
1887
|
return `z.enum([${values}])`;
|
|
1864
1888
|
}
|
|
1865
1889
|
if (t === "uuid")
|
|
1866
|
-
return `z.string()`;
|
|
1890
|
+
return `z.string().uuid()`;
|
|
1867
1891
|
if (t === "bool" || t === "boolean")
|
|
1868
1892
|
return `z.boolean()`;
|
|
1869
1893
|
if (t === "int2" || t === "int4" || t === "int8") {
|
|
@@ -4991,6 +5015,18 @@ const log = {
|
|
|
4991
5015
|
error: (...args: any[]) => console.error("[sdk]", ...args),
|
|
4992
5016
|
};
|
|
4993
5017
|
|
|
5018
|
+
/**
|
|
5019
|
+
* Checks if a Postgres error is a client input error (invalid syntax, out of range, etc.)
|
|
5020
|
+
* PG error class 22 = "data exception" — covers invalid input syntax for uuid, int, json, etc.
|
|
5021
|
+
* PG error code 23502 = "not_null_violation", 23505 = "unique_violation", 23503 = "foreign_key_violation"
|
|
5022
|
+
*/
|
|
5023
|
+
function pgErrorStatus(e: any): number {
|
|
5024
|
+
const code = e?.code;
|
|
5025
|
+
if (typeof code === "string" && code.startsWith("22")) return 400;
|
|
5026
|
+
if (code === "23502" || code === "23505" || code === "23503") return 409;
|
|
5027
|
+
return 500;
|
|
5028
|
+
}
|
|
5029
|
+
|
|
4994
5030
|
/**
|
|
4995
5031
|
* Builds SQL column list from select/exclude parameters
|
|
4996
5032
|
* @param select - Columns to include (mutually exclusive with exclude)
|
|
@@ -5091,22 +5127,13 @@ export async function createRecord(
|
|
|
5091
5127
|
|
|
5092
5128
|
return { data: parsedRows[0] ?? null, status: parsedRows[0] ? 201 : 500 };
|
|
5093
5129
|
} catch (e: any) {
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
const isJsonError = errorMsg.includes("invalid input syntax for type json");
|
|
5097
|
-
|
|
5098
|
-
if (isJsonError) {
|
|
5099
|
-
log.error(\`POST \${ctx.table} - Invalid JSON input detected!\`);
|
|
5100
|
-
log.error("Input data that caused error:", JSON.stringify(data, null, 2));
|
|
5101
|
-
log.error("PostgreSQL error:", errorMsg);
|
|
5102
|
-
} else {
|
|
5103
|
-
log.error(\`POST \${ctx.table} error:\`, e?.stack ?? e);
|
|
5104
|
-
}
|
|
5130
|
+
const status = pgErrorStatus(e);
|
|
5131
|
+
log.error(\`POST \${ctx.table} error:\`, e?.stack ?? e);
|
|
5105
5132
|
|
|
5106
5133
|
return {
|
|
5107
5134
|
error: e?.message ?? "Internal error",
|
|
5108
5135
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
5109
|
-
status
|
|
5136
|
+
status
|
|
5110
5137
|
};
|
|
5111
5138
|
}
|
|
5112
5139
|
}
|
|
@@ -5181,22 +5208,12 @@ export async function upsertRecord(
|
|
|
5181
5208
|
|
|
5182
5209
|
return { data: parsedRows[0], status: 200 };
|
|
5183
5210
|
} catch (e: any) {
|
|
5184
|
-
const
|
|
5185
|
-
|
|
5186
|
-
if (isJsonError) {
|
|
5187
|
-
log.error(\`UPSERT \${ctx.table} - Invalid JSON input detected!\`);
|
|
5188
|
-
log.error("Input args that caused error:", JSON.stringify(args, null, 2));
|
|
5189
|
-
log.error("Filtered update data (sent to DB):", JSON.stringify(Object.fromEntries(
|
|
5190
|
-
Object.entries(args.update).filter(([k]) => !ctx.pkColumns.includes(k))
|
|
5191
|
-
), null, 2));
|
|
5192
|
-
log.error("PostgreSQL error:", errorMsg);
|
|
5193
|
-
} else {
|
|
5194
|
-
log.error(\`UPSERT \${ctx.table} error:\`, e?.stack ?? e);
|
|
5195
|
-
}
|
|
5211
|
+
const status = pgErrorStatus(e);
|
|
5212
|
+
log.error(\`UPSERT \${ctx.table} error:\`, e?.stack ?? e);
|
|
5196
5213
|
return {
|
|
5197
5214
|
error: e?.message ?? "Internal error",
|
|
5198
5215
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
5199
|
-
status
|
|
5216
|
+
status
|
|
5200
5217
|
};
|
|
5201
5218
|
}
|
|
5202
5219
|
}
|
|
@@ -5229,11 +5246,12 @@ export async function getByPk(
|
|
|
5229
5246
|
|
|
5230
5247
|
return { data: parsedRows[0], status: 200 };
|
|
5231
5248
|
} catch (e: any) {
|
|
5249
|
+
const status = pgErrorStatus(e);
|
|
5232
5250
|
log.error(\`GET \${ctx.table} error:\`, e?.stack ?? e);
|
|
5233
|
-
return {
|
|
5234
|
-
error: e?.message ?? "Internal error",
|
|
5251
|
+
return {
|
|
5252
|
+
error: e?.message ?? "Internal error",
|
|
5235
5253
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
5236
|
-
status
|
|
5254
|
+
status
|
|
5237
5255
|
};
|
|
5238
5256
|
}
|
|
5239
5257
|
}
|
|
@@ -5782,22 +5800,13 @@ export async function listRecords(
|
|
|
5782
5800
|
log.debug(\`LIST \${ctx.table} result: \${rows.length} rows, \${total} total, hasMore=\${hasMore}\`);
|
|
5783
5801
|
return metadata;
|
|
5784
5802
|
} catch (e: any) {
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
const isJsonError = errorMsg.includes("invalid input syntax for type json");
|
|
5788
|
-
|
|
5789
|
-
if (isJsonError) {
|
|
5790
|
-
log.error(\`LIST \${ctx.table} - Invalid JSON input detected in query!\`);
|
|
5791
|
-
log.error("WHERE clause:", JSON.stringify(params.where, null, 2));
|
|
5792
|
-
log.error("PostgreSQL error:", errorMsg);
|
|
5793
|
-
} else {
|
|
5794
|
-
log.error(\`LIST \${ctx.table} error:\`, e?.stack ?? e);
|
|
5795
|
-
}
|
|
5803
|
+
const status = pgErrorStatus(e);
|
|
5804
|
+
log.error(\`LIST \${ctx.table} error:\`, e?.stack ?? e);
|
|
5796
5805
|
|
|
5797
5806
|
return {
|
|
5798
5807
|
error: e?.message ?? "Internal error",
|
|
5799
5808
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
5800
|
-
status
|
|
5809
|
+
status
|
|
5801
5810
|
};
|
|
5802
5811
|
}
|
|
5803
5812
|
}
|
|
@@ -5849,25 +5858,13 @@ export async function updateRecord(
|
|
|
5849
5858
|
|
|
5850
5859
|
return { data: parsedRows[0], status: 200 };
|
|
5851
5860
|
} catch (e: any) {
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
const isJsonError = errorMsg.includes("invalid input syntax for type json");
|
|
5855
|
-
|
|
5856
|
-
if (isJsonError) {
|
|
5857
|
-
log.error(\`PATCH \${ctx.table} - Invalid JSON input detected!\`);
|
|
5858
|
-
log.error("Input data that caused error:", JSON.stringify(updateData, null, 2));
|
|
5859
|
-
log.error("Filtered data (sent to DB):", JSON.stringify(Object.fromEntries(
|
|
5860
|
-
Object.entries(updateData).filter(([k]) => !ctx.pkColumns.includes(k))
|
|
5861
|
-
), null, 2));
|
|
5862
|
-
log.error("PostgreSQL error:", errorMsg);
|
|
5863
|
-
} else {
|
|
5864
|
-
log.error(\`PATCH \${ctx.table} error:\`, e?.stack ?? e);
|
|
5865
|
-
}
|
|
5861
|
+
const status = pgErrorStatus(e);
|
|
5862
|
+
log.error(\`PATCH \${ctx.table} error:\`, e?.stack ?? e);
|
|
5866
5863
|
|
|
5867
5864
|
return {
|
|
5868
5865
|
error: e?.message ?? "Internal error",
|
|
5869
5866
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
5870
|
-
status
|
|
5867
|
+
status
|
|
5871
5868
|
};
|
|
5872
5869
|
}
|
|
5873
5870
|
}
|
|
@@ -5902,11 +5899,12 @@ export async function deleteRecord(
|
|
|
5902
5899
|
|
|
5903
5900
|
return { data: parsedRows[0], status: 200 };
|
|
5904
5901
|
} catch (e: any) {
|
|
5902
|
+
const status = pgErrorStatus(e);
|
|
5905
5903
|
log.error(\`DELETE \${ctx.table} error:\`, e?.stack ?? e);
|
|
5906
5904
|
return {
|
|
5907
5905
|
error: e?.message ?? "Internal error",
|
|
5908
5906
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
5909
|
-
status
|
|
5907
|
+
status
|
|
5910
5908
|
};
|
|
5911
5909
|
}
|
|
5912
5910
|
}
|
package/dist/rel-classify.d.ts
CHANGED
|
@@ -5,6 +5,8 @@ export type Edge = {
|
|
|
5
5
|
kind: "one" | "many";
|
|
6
6
|
target: string;
|
|
7
7
|
via?: string;
|
|
8
|
+
/** True when the FK column(s) are nullable (belongs-to may return null). */
|
|
9
|
+
nullable?: boolean;
|
|
8
10
|
};
|
|
9
11
|
export type Graph = Record<string, Record<string, Edge>>;
|
|
10
12
|
export declare function buildGraph(model: Model): Graph;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "postgresdk",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.3",
|
|
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:write-files && 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 && bun test test/test-jsonb-array-serialization.test.ts && bun test test/test-trigram-search.test.ts && bun test test/test-soft-delete-config.test.ts && bun test test/test-soft-delete-include-loader.test.ts && bun test test/test-soft-delete-nested-include.test.ts && bun test test/test-transaction.test.ts",
|
|
25
|
+
"test": "bun test:write-files && 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 && bun test test/test-jsonb-array-serialization.test.ts && bun test test/test-trigram-search.test.ts && bun test test/test-soft-delete-config.test.ts && bun test test/test-soft-delete-include-loader.test.ts && bun test test/test-soft-delete-nested-include.test.ts && bun test test/test-transaction.test.ts && bun test test/test-nullable-belongs-to.test.ts",
|
|
26
26
|
"test:write-files": "bun test/test-write-files-if-changed.ts",
|
|
27
27
|
"test:init": "bun test/test-init.ts",
|
|
28
28
|
"test:gen": "bun test/test-gen.ts",
|