postgresdk 0.19.0 → 0.19.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.
- package/README.md +1 -1
- package/dist/cli.js +59 -66
- package/dist/index.js +59 -66
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -594,7 +594,7 @@ const [order, updatedUser] = await sdk.$transaction([
|
|
|
594
594
|
// TypeScript infers: [SelectOrders, SelectUsers | null]
|
|
595
595
|
```
|
|
596
596
|
|
|
597
|
-
- `$create`, `$update`, `$
|
|
597
|
+
- `$create`, `$update`, `$softDelete`, `$hardDelete`, `$upsert` are **lazy builders** — nothing executes until `$transaction` is called
|
|
598
598
|
- All ops are Zod-validated **before** `BEGIN` is issued (fail-fast, no partial state)
|
|
599
599
|
- On any failure the transaction rolls back; an error is thrown with a `.failedAt` index
|
|
600
600
|
|
package/dist/cli.js
CHANGED
|
@@ -2823,7 +2823,7 @@ function emitZod(table, opts, enums) {
|
|
|
2823
2823
|
return `z.enum([${values}])`;
|
|
2824
2824
|
}
|
|
2825
2825
|
if (t === "uuid")
|
|
2826
|
-
return `z.string()`;
|
|
2826
|
+
return `z.string().uuid()`;
|
|
2827
2827
|
if (t === "bool" || t === "boolean")
|
|
2828
2828
|
return `z.boolean()`;
|
|
2829
2829
|
if (t === "int2" || t === "int4" || t === "int8") {
|
|
@@ -3662,6 +3662,20 @@ function emitClient(table, graph, opts, model) {
|
|
|
3662
3662
|
deleteMethodParts.push(buildDeleteMethod("hardDelete", hasSoftDelete));
|
|
3663
3663
|
const deleteMethodsCode = deleteMethodParts.join(`
|
|
3664
3664
|
|
|
3665
|
+
`);
|
|
3666
|
+
const txDeleteParts = [];
|
|
3667
|
+
if (hasSoftDelete)
|
|
3668
|
+
txDeleteParts.push(` /** Build a lazy soft-DELETE descriptor for use with sdk.$transaction([...]) */
|
|
3669
|
+
` + ` $softDelete(pk: ${pkType}): TxOp<Select${Type} | null> {
|
|
3670
|
+
` + ` return { _table: "${table.name}", _op: "softDelete", _pk: ${hasCompositePk ? "pk as Record<string, unknown>" : "pk"} };
|
|
3671
|
+
` + ` }`);
|
|
3672
|
+
if (exposeHard)
|
|
3673
|
+
txDeleteParts.push(` /** Build a lazy hard-DELETE descriptor for use with sdk.$transaction([...]) */
|
|
3674
|
+
` + ` $hardDelete(pk: ${pkType}): TxOp<Select${Type} | null> {
|
|
3675
|
+
` + ` return { _table: "${table.name}", _op: "hardDelete", _pk: ${hasCompositePk ? "pk as Record<string, unknown>" : "pk"} };
|
|
3676
|
+
` + ` }`);
|
|
3677
|
+
const txDeleteMethodsCode = txDeleteParts.join(`
|
|
3678
|
+
|
|
3665
3679
|
`);
|
|
3666
3680
|
return `/**
|
|
3667
3681
|
* AUTO-GENERATED FILE - DO NOT EDIT
|
|
@@ -4178,10 +4192,7 @@ ${deleteMethodsCode}
|
|
|
4178
4192
|
return { _table: "${table.name}", _op: "update", _pk: ${hasCompositePk ? "pk as Record<string, unknown>" : "pk"}, _data: data as Record<string, unknown> };
|
|
4179
4193
|
}
|
|
4180
4194
|
|
|
4181
|
-
|
|
4182
|
-
$delete(pk: ${pkType}): TxOp<Select${Type} | null> {
|
|
4183
|
-
return { _table: "${table.name}", _op: "delete", _pk: ${hasCompositePk ? "pk as Record<string, unknown>" : "pk"} };
|
|
4184
|
-
}
|
|
4195
|
+
${txDeleteMethodsCode}
|
|
4185
4196
|
|
|
4186
4197
|
/** Build a lazy UPSERT descriptor for use with sdk.$transaction([...]) */
|
|
4187
4198
|
$upsert(args: { where: Update${Type}; create: Insert${Type}; update: Update${Type} }): TxOp<Select${Type}> {
|
|
@@ -4535,13 +4546,13 @@ export abstract class BaseClient {
|
|
|
4535
4546
|
}
|
|
4536
4547
|
|
|
4537
4548
|
/**
|
|
4538
|
-
* Lazy operation descriptor returned by $create/$update/$
|
|
4549
|
+
* Lazy operation descriptor returned by $create/$update/$softDelete/$hardDelete/$upsert.
|
|
4539
4550
|
* \`__resultType\` is a phantom field — never assigned at runtime, exists only
|
|
4540
4551
|
* so TypeScript can infer the correct tuple element type inside \`$transaction\`.
|
|
4541
4552
|
*/
|
|
4542
4553
|
export type TxOp<T = unknown> = {
|
|
4543
4554
|
readonly _table: string;
|
|
4544
|
-
readonly _op: "create" | "update" | "
|
|
4555
|
+
readonly _op: "create" | "update" | "softDelete" | "hardDelete" | "upsert";
|
|
4545
4556
|
readonly _data?: Record<string, unknown>;
|
|
4546
4557
|
readonly _pk?: string | Record<string, unknown>;
|
|
4547
4558
|
/** @internal */
|
|
@@ -5619,11 +5630,16 @@ function emitHonoRouter(tables, hasAuth, useJsExtensions, pullToken, opts) {
|
|
|
5619
5630
|
return c.json({ error: \`Missing pk at index \${i}\`, failedAt: i }, 400);
|
|
5620
5631
|
}
|
|
5621
5632
|
validatedOps.push({ op: "update", table: item.table, pk: item.pk, data: parsed.data });
|
|
5622
|
-
} else if (item.op === "
|
|
5633
|
+
} else if (item.op === "softDelete") {
|
|
5623
5634
|
if (item.pk == null) {
|
|
5624
5635
|
return c.json({ error: \`Missing pk at index \${i}\`, failedAt: i }, 400);
|
|
5625
5636
|
}
|
|
5626
|
-
validatedOps.push({ op: "
|
|
5637
|
+
validatedOps.push({ op: "softDelete", table: item.table, pk: item.pk });
|
|
5638
|
+
} else if (item.op === "hardDelete") {
|
|
5639
|
+
if (item.pk == null) {
|
|
5640
|
+
return c.json({ error: \`Missing pk at index \${i}\`, failedAt: i }, 400);
|
|
5641
|
+
}
|
|
5642
|
+
validatedOps.push({ op: "hardDelete", table: item.table, pk: item.pk });
|
|
5627
5643
|
} else {
|
|
5628
5644
|
return c.json({ error: \`Unknown op "\${item?.op}" at index \${i}\`, failedAt: i }, 400);
|
|
5629
5645
|
}
|
|
@@ -5935,6 +5951,18 @@ const log = {
|
|
|
5935
5951
|
error: (...args: any[]) => console.error("[sdk]", ...args),
|
|
5936
5952
|
};
|
|
5937
5953
|
|
|
5954
|
+
/**
|
|
5955
|
+
* Checks if a Postgres error is a client input error (invalid syntax, out of range, etc.)
|
|
5956
|
+
* PG error class 22 = "data exception" — covers invalid input syntax for uuid, int, json, etc.
|
|
5957
|
+
* PG error code 23502 = "not_null_violation", 23505 = "unique_violation", 23503 = "foreign_key_violation"
|
|
5958
|
+
*/
|
|
5959
|
+
function pgErrorStatus(e: any): number {
|
|
5960
|
+
const code = e?.code;
|
|
5961
|
+
if (typeof code === "string" && code.startsWith("22")) return 400;
|
|
5962
|
+
if (code === "23502" || code === "23505" || code === "23503") return 409;
|
|
5963
|
+
return 500;
|
|
5964
|
+
}
|
|
5965
|
+
|
|
5938
5966
|
/**
|
|
5939
5967
|
* Builds SQL column list from select/exclude parameters
|
|
5940
5968
|
* @param select - Columns to include (mutually exclusive with exclude)
|
|
@@ -6035,22 +6063,13 @@ export async function createRecord(
|
|
|
6035
6063
|
|
|
6036
6064
|
return { data: parsedRows[0] ?? null, status: parsedRows[0] ? 201 : 500 };
|
|
6037
6065
|
} catch (e: any) {
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
const isJsonError = errorMsg.includes("invalid input syntax for type json");
|
|
6041
|
-
|
|
6042
|
-
if (isJsonError) {
|
|
6043
|
-
log.error(\`POST \${ctx.table} - Invalid JSON input detected!\`);
|
|
6044
|
-
log.error("Input data that caused error:", JSON.stringify(data, null, 2));
|
|
6045
|
-
log.error("PostgreSQL error:", errorMsg);
|
|
6046
|
-
} else {
|
|
6047
|
-
log.error(\`POST \${ctx.table} error:\`, e?.stack ?? e);
|
|
6048
|
-
}
|
|
6066
|
+
const status = pgErrorStatus(e);
|
|
6067
|
+
log.error(\`POST \${ctx.table} error:\`, e?.stack ?? e);
|
|
6049
6068
|
|
|
6050
6069
|
return {
|
|
6051
6070
|
error: e?.message ?? "Internal error",
|
|
6052
6071
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
6053
|
-
status
|
|
6072
|
+
status
|
|
6054
6073
|
};
|
|
6055
6074
|
}
|
|
6056
6075
|
}
|
|
@@ -6125,22 +6144,12 @@ export async function upsertRecord(
|
|
|
6125
6144
|
|
|
6126
6145
|
return { data: parsedRows[0], status: 200 };
|
|
6127
6146
|
} catch (e: any) {
|
|
6128
|
-
const
|
|
6129
|
-
|
|
6130
|
-
if (isJsonError) {
|
|
6131
|
-
log.error(\`UPSERT \${ctx.table} - Invalid JSON input detected!\`);
|
|
6132
|
-
log.error("Input args that caused error:", JSON.stringify(args, null, 2));
|
|
6133
|
-
log.error("Filtered update data (sent to DB):", JSON.stringify(Object.fromEntries(
|
|
6134
|
-
Object.entries(args.update).filter(([k]) => !ctx.pkColumns.includes(k))
|
|
6135
|
-
), null, 2));
|
|
6136
|
-
log.error("PostgreSQL error:", errorMsg);
|
|
6137
|
-
} else {
|
|
6138
|
-
log.error(\`UPSERT \${ctx.table} error:\`, e?.stack ?? e);
|
|
6139
|
-
}
|
|
6147
|
+
const status = pgErrorStatus(e);
|
|
6148
|
+
log.error(\`UPSERT \${ctx.table} error:\`, e?.stack ?? e);
|
|
6140
6149
|
return {
|
|
6141
6150
|
error: e?.message ?? "Internal error",
|
|
6142
6151
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
6143
|
-
status
|
|
6152
|
+
status
|
|
6144
6153
|
};
|
|
6145
6154
|
}
|
|
6146
6155
|
}
|
|
@@ -6173,11 +6182,12 @@ export async function getByPk(
|
|
|
6173
6182
|
|
|
6174
6183
|
return { data: parsedRows[0], status: 200 };
|
|
6175
6184
|
} catch (e: any) {
|
|
6185
|
+
const status = pgErrorStatus(e);
|
|
6176
6186
|
log.error(\`GET \${ctx.table} error:\`, e?.stack ?? e);
|
|
6177
|
-
return {
|
|
6178
|
-
error: e?.message ?? "Internal error",
|
|
6187
|
+
return {
|
|
6188
|
+
error: e?.message ?? "Internal error",
|
|
6179
6189
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
6180
|
-
status
|
|
6190
|
+
status
|
|
6181
6191
|
};
|
|
6182
6192
|
}
|
|
6183
6193
|
}
|
|
@@ -6726,22 +6736,13 @@ export async function listRecords(
|
|
|
6726
6736
|
log.debug(\`LIST \${ctx.table} result: \${rows.length} rows, \${total} total, hasMore=\${hasMore}\`);
|
|
6727
6737
|
return metadata;
|
|
6728
6738
|
} catch (e: any) {
|
|
6729
|
-
|
|
6730
|
-
|
|
6731
|
-
const isJsonError = errorMsg.includes("invalid input syntax for type json");
|
|
6732
|
-
|
|
6733
|
-
if (isJsonError) {
|
|
6734
|
-
log.error(\`LIST \${ctx.table} - Invalid JSON input detected in query!\`);
|
|
6735
|
-
log.error("WHERE clause:", JSON.stringify(params.where, null, 2));
|
|
6736
|
-
log.error("PostgreSQL error:", errorMsg);
|
|
6737
|
-
} else {
|
|
6738
|
-
log.error(\`LIST \${ctx.table} error:\`, e?.stack ?? e);
|
|
6739
|
-
}
|
|
6739
|
+
const status = pgErrorStatus(e);
|
|
6740
|
+
log.error(\`LIST \${ctx.table} error:\`, e?.stack ?? e);
|
|
6740
6741
|
|
|
6741
6742
|
return {
|
|
6742
6743
|
error: e?.message ?? "Internal error",
|
|
6743
6744
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
6744
|
-
status
|
|
6745
|
+
status
|
|
6745
6746
|
};
|
|
6746
6747
|
}
|
|
6747
6748
|
}
|
|
@@ -6793,25 +6794,13 @@ export async function updateRecord(
|
|
|
6793
6794
|
|
|
6794
6795
|
return { data: parsedRows[0], status: 200 };
|
|
6795
6796
|
} catch (e: any) {
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
const isJsonError = errorMsg.includes("invalid input syntax for type json");
|
|
6799
|
-
|
|
6800
|
-
if (isJsonError) {
|
|
6801
|
-
log.error(\`PATCH \${ctx.table} - Invalid JSON input detected!\`);
|
|
6802
|
-
log.error("Input data that caused error:", JSON.stringify(updateData, null, 2));
|
|
6803
|
-
log.error("Filtered data (sent to DB):", JSON.stringify(Object.fromEntries(
|
|
6804
|
-
Object.entries(updateData).filter(([k]) => !ctx.pkColumns.includes(k))
|
|
6805
|
-
), null, 2));
|
|
6806
|
-
log.error("PostgreSQL error:", errorMsg);
|
|
6807
|
-
} else {
|
|
6808
|
-
log.error(\`PATCH \${ctx.table} error:\`, e?.stack ?? e);
|
|
6809
|
-
}
|
|
6797
|
+
const status = pgErrorStatus(e);
|
|
6798
|
+
log.error(\`PATCH \${ctx.table} error:\`, e?.stack ?? e);
|
|
6810
6799
|
|
|
6811
6800
|
return {
|
|
6812
6801
|
error: e?.message ?? "Internal error",
|
|
6813
6802
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
6814
|
-
status
|
|
6803
|
+
status
|
|
6815
6804
|
};
|
|
6816
6805
|
}
|
|
6817
6806
|
}
|
|
@@ -6846,11 +6835,12 @@ export async function deleteRecord(
|
|
|
6846
6835
|
|
|
6847
6836
|
return { data: parsedRows[0], status: 200 };
|
|
6848
6837
|
} catch (e: any) {
|
|
6838
|
+
const status = pgErrorStatus(e);
|
|
6849
6839
|
log.error(\`DELETE \${ctx.table} error:\`, e?.stack ?? e);
|
|
6850
6840
|
return {
|
|
6851
6841
|
error: e?.message ?? "Internal error",
|
|
6852
6842
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
6853
|
-
status
|
|
6843
|
+
status
|
|
6854
6844
|
};
|
|
6855
6845
|
}
|
|
6856
6846
|
}
|
|
@@ -6873,7 +6863,8 @@ export interface TransactionTableMetadata {
|
|
|
6873
6863
|
export type TransactionOperation =
|
|
6874
6864
|
| { op: "create"; table: string; data: Record<string, unknown> }
|
|
6875
6865
|
| { op: "update"; table: string; pk: string | Record<string, unknown>; data: Record<string, unknown> }
|
|
6876
|
-
| { op: "
|
|
6866
|
+
| { op: "softDelete"; table: string; pk: string | Record<string, unknown> }
|
|
6867
|
+
| { op: "hardDelete"; table: string; pk: string | Record<string, unknown> }
|
|
6877
6868
|
| { op: "upsert"; table: string; data: { where: Record<string, unknown>; create: Record<string, unknown>; update: Record<string, unknown> } };
|
|
6878
6869
|
|
|
6879
6870
|
/**
|
|
@@ -6941,6 +6932,8 @@ export async function executeTransaction(
|
|
|
6941
6932
|
: [op.pk];
|
|
6942
6933
|
result = op.op === "update"
|
|
6943
6934
|
? await updateRecord(ctx, pkValues as string[], op.data)
|
|
6935
|
+
: op.op === "hardDelete"
|
|
6936
|
+
? await deleteRecord(ctx, pkValues as string[], { hard: true })
|
|
6944
6937
|
: await deleteRecord(ctx, pkValues as string[]);
|
|
6945
6938
|
}
|
|
6946
6939
|
|
package/dist/index.js
CHANGED
|
@@ -1863,7 +1863,7 @@ function emitZod(table, opts, enums) {
|
|
|
1863
1863
|
return `z.enum([${values}])`;
|
|
1864
1864
|
}
|
|
1865
1865
|
if (t === "uuid")
|
|
1866
|
-
return `z.string()`;
|
|
1866
|
+
return `z.string().uuid()`;
|
|
1867
1867
|
if (t === "bool" || t === "boolean")
|
|
1868
1868
|
return `z.boolean()`;
|
|
1869
1869
|
if (t === "int2" || t === "int4" || t === "int8") {
|
|
@@ -2702,6 +2702,20 @@ function emitClient(table, graph, opts, model) {
|
|
|
2702
2702
|
deleteMethodParts.push(buildDeleteMethod("hardDelete", hasSoftDelete));
|
|
2703
2703
|
const deleteMethodsCode = deleteMethodParts.join(`
|
|
2704
2704
|
|
|
2705
|
+
`);
|
|
2706
|
+
const txDeleteParts = [];
|
|
2707
|
+
if (hasSoftDelete)
|
|
2708
|
+
txDeleteParts.push(` /** Build a lazy soft-DELETE descriptor for use with sdk.$transaction([...]) */
|
|
2709
|
+
` + ` $softDelete(pk: ${pkType}): TxOp<Select${Type} | null> {
|
|
2710
|
+
` + ` return { _table: "${table.name}", _op: "softDelete", _pk: ${hasCompositePk ? "pk as Record<string, unknown>" : "pk"} };
|
|
2711
|
+
` + ` }`);
|
|
2712
|
+
if (exposeHard)
|
|
2713
|
+
txDeleteParts.push(` /** Build a lazy hard-DELETE descriptor for use with sdk.$transaction([...]) */
|
|
2714
|
+
` + ` $hardDelete(pk: ${pkType}): TxOp<Select${Type} | null> {
|
|
2715
|
+
` + ` return { _table: "${table.name}", _op: "hardDelete", _pk: ${hasCompositePk ? "pk as Record<string, unknown>" : "pk"} };
|
|
2716
|
+
` + ` }`);
|
|
2717
|
+
const txDeleteMethodsCode = txDeleteParts.join(`
|
|
2718
|
+
|
|
2705
2719
|
`);
|
|
2706
2720
|
return `/**
|
|
2707
2721
|
* AUTO-GENERATED FILE - DO NOT EDIT
|
|
@@ -3218,10 +3232,7 @@ ${deleteMethodsCode}
|
|
|
3218
3232
|
return { _table: "${table.name}", _op: "update", _pk: ${hasCompositePk ? "pk as Record<string, unknown>" : "pk"}, _data: data as Record<string, unknown> };
|
|
3219
3233
|
}
|
|
3220
3234
|
|
|
3221
|
-
|
|
3222
|
-
$delete(pk: ${pkType}): TxOp<Select${Type} | null> {
|
|
3223
|
-
return { _table: "${table.name}", _op: "delete", _pk: ${hasCompositePk ? "pk as Record<string, unknown>" : "pk"} };
|
|
3224
|
-
}
|
|
3235
|
+
${txDeleteMethodsCode}
|
|
3225
3236
|
|
|
3226
3237
|
/** Build a lazy UPSERT descriptor for use with sdk.$transaction([...]) */
|
|
3227
3238
|
$upsert(args: { where: Update${Type}; create: Insert${Type}; update: Update${Type} }): TxOp<Select${Type}> {
|
|
@@ -3575,13 +3586,13 @@ export abstract class BaseClient {
|
|
|
3575
3586
|
}
|
|
3576
3587
|
|
|
3577
3588
|
/**
|
|
3578
|
-
* Lazy operation descriptor returned by $create/$update/$
|
|
3589
|
+
* Lazy operation descriptor returned by $create/$update/$softDelete/$hardDelete/$upsert.
|
|
3579
3590
|
* \`__resultType\` is a phantom field — never assigned at runtime, exists only
|
|
3580
3591
|
* so TypeScript can infer the correct tuple element type inside \`$transaction\`.
|
|
3581
3592
|
*/
|
|
3582
3593
|
export type TxOp<T = unknown> = {
|
|
3583
3594
|
readonly _table: string;
|
|
3584
|
-
readonly _op: "create" | "update" | "
|
|
3595
|
+
readonly _op: "create" | "update" | "softDelete" | "hardDelete" | "upsert";
|
|
3585
3596
|
readonly _data?: Record<string, unknown>;
|
|
3586
3597
|
readonly _pk?: string | Record<string, unknown>;
|
|
3587
3598
|
/** @internal */
|
|
@@ -4659,11 +4670,16 @@ function emitHonoRouter(tables, hasAuth, useJsExtensions, pullToken, opts) {
|
|
|
4659
4670
|
return c.json({ error: \`Missing pk at index \${i}\`, failedAt: i }, 400);
|
|
4660
4671
|
}
|
|
4661
4672
|
validatedOps.push({ op: "update", table: item.table, pk: item.pk, data: parsed.data });
|
|
4662
|
-
} else if (item.op === "
|
|
4673
|
+
} else if (item.op === "softDelete") {
|
|
4663
4674
|
if (item.pk == null) {
|
|
4664
4675
|
return c.json({ error: \`Missing pk at index \${i}\`, failedAt: i }, 400);
|
|
4665
4676
|
}
|
|
4666
|
-
validatedOps.push({ op: "
|
|
4677
|
+
validatedOps.push({ op: "softDelete", table: item.table, pk: item.pk });
|
|
4678
|
+
} else if (item.op === "hardDelete") {
|
|
4679
|
+
if (item.pk == null) {
|
|
4680
|
+
return c.json({ error: \`Missing pk at index \${i}\`, failedAt: i }, 400);
|
|
4681
|
+
}
|
|
4682
|
+
validatedOps.push({ op: "hardDelete", table: item.table, pk: item.pk });
|
|
4667
4683
|
} else {
|
|
4668
4684
|
return c.json({ error: \`Unknown op "\${item?.op}" at index \${i}\`, failedAt: i }, 400);
|
|
4669
4685
|
}
|
|
@@ -4975,6 +4991,18 @@ const log = {
|
|
|
4975
4991
|
error: (...args: any[]) => console.error("[sdk]", ...args),
|
|
4976
4992
|
};
|
|
4977
4993
|
|
|
4994
|
+
/**
|
|
4995
|
+
* Checks if a Postgres error is a client input error (invalid syntax, out of range, etc.)
|
|
4996
|
+
* PG error class 22 = "data exception" — covers invalid input syntax for uuid, int, json, etc.
|
|
4997
|
+
* PG error code 23502 = "not_null_violation", 23505 = "unique_violation", 23503 = "foreign_key_violation"
|
|
4998
|
+
*/
|
|
4999
|
+
function pgErrorStatus(e: any): number {
|
|
5000
|
+
const code = e?.code;
|
|
5001
|
+
if (typeof code === "string" && code.startsWith("22")) return 400;
|
|
5002
|
+
if (code === "23502" || code === "23505" || code === "23503") return 409;
|
|
5003
|
+
return 500;
|
|
5004
|
+
}
|
|
5005
|
+
|
|
4978
5006
|
/**
|
|
4979
5007
|
* Builds SQL column list from select/exclude parameters
|
|
4980
5008
|
* @param select - Columns to include (mutually exclusive with exclude)
|
|
@@ -5075,22 +5103,13 @@ export async function createRecord(
|
|
|
5075
5103
|
|
|
5076
5104
|
return { data: parsedRows[0] ?? null, status: parsedRows[0] ? 201 : 500 };
|
|
5077
5105
|
} catch (e: any) {
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
const isJsonError = errorMsg.includes("invalid input syntax for type json");
|
|
5081
|
-
|
|
5082
|
-
if (isJsonError) {
|
|
5083
|
-
log.error(\`POST \${ctx.table} - Invalid JSON input detected!\`);
|
|
5084
|
-
log.error("Input data that caused error:", JSON.stringify(data, null, 2));
|
|
5085
|
-
log.error("PostgreSQL error:", errorMsg);
|
|
5086
|
-
} else {
|
|
5087
|
-
log.error(\`POST \${ctx.table} error:\`, e?.stack ?? e);
|
|
5088
|
-
}
|
|
5106
|
+
const status = pgErrorStatus(e);
|
|
5107
|
+
log.error(\`POST \${ctx.table} error:\`, e?.stack ?? e);
|
|
5089
5108
|
|
|
5090
5109
|
return {
|
|
5091
5110
|
error: e?.message ?? "Internal error",
|
|
5092
5111
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
5093
|
-
status
|
|
5112
|
+
status
|
|
5094
5113
|
};
|
|
5095
5114
|
}
|
|
5096
5115
|
}
|
|
@@ -5165,22 +5184,12 @@ export async function upsertRecord(
|
|
|
5165
5184
|
|
|
5166
5185
|
return { data: parsedRows[0], status: 200 };
|
|
5167
5186
|
} catch (e: any) {
|
|
5168
|
-
const
|
|
5169
|
-
|
|
5170
|
-
if (isJsonError) {
|
|
5171
|
-
log.error(\`UPSERT \${ctx.table} - Invalid JSON input detected!\`);
|
|
5172
|
-
log.error("Input args that caused error:", JSON.stringify(args, null, 2));
|
|
5173
|
-
log.error("Filtered update data (sent to DB):", JSON.stringify(Object.fromEntries(
|
|
5174
|
-
Object.entries(args.update).filter(([k]) => !ctx.pkColumns.includes(k))
|
|
5175
|
-
), null, 2));
|
|
5176
|
-
log.error("PostgreSQL error:", errorMsg);
|
|
5177
|
-
} else {
|
|
5178
|
-
log.error(\`UPSERT \${ctx.table} error:\`, e?.stack ?? e);
|
|
5179
|
-
}
|
|
5187
|
+
const status = pgErrorStatus(e);
|
|
5188
|
+
log.error(\`UPSERT \${ctx.table} error:\`, e?.stack ?? e);
|
|
5180
5189
|
return {
|
|
5181
5190
|
error: e?.message ?? "Internal error",
|
|
5182
5191
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
5183
|
-
status
|
|
5192
|
+
status
|
|
5184
5193
|
};
|
|
5185
5194
|
}
|
|
5186
5195
|
}
|
|
@@ -5213,11 +5222,12 @@ export async function getByPk(
|
|
|
5213
5222
|
|
|
5214
5223
|
return { data: parsedRows[0], status: 200 };
|
|
5215
5224
|
} catch (e: any) {
|
|
5225
|
+
const status = pgErrorStatus(e);
|
|
5216
5226
|
log.error(\`GET \${ctx.table} error:\`, e?.stack ?? e);
|
|
5217
|
-
return {
|
|
5218
|
-
error: e?.message ?? "Internal error",
|
|
5227
|
+
return {
|
|
5228
|
+
error: e?.message ?? "Internal error",
|
|
5219
5229
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
5220
|
-
status
|
|
5230
|
+
status
|
|
5221
5231
|
};
|
|
5222
5232
|
}
|
|
5223
5233
|
}
|
|
@@ -5766,22 +5776,13 @@ export async function listRecords(
|
|
|
5766
5776
|
log.debug(\`LIST \${ctx.table} result: \${rows.length} rows, \${total} total, hasMore=\${hasMore}\`);
|
|
5767
5777
|
return metadata;
|
|
5768
5778
|
} catch (e: any) {
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
const isJsonError = errorMsg.includes("invalid input syntax for type json");
|
|
5772
|
-
|
|
5773
|
-
if (isJsonError) {
|
|
5774
|
-
log.error(\`LIST \${ctx.table} - Invalid JSON input detected in query!\`);
|
|
5775
|
-
log.error("WHERE clause:", JSON.stringify(params.where, null, 2));
|
|
5776
|
-
log.error("PostgreSQL error:", errorMsg);
|
|
5777
|
-
} else {
|
|
5778
|
-
log.error(\`LIST \${ctx.table} error:\`, e?.stack ?? e);
|
|
5779
|
-
}
|
|
5779
|
+
const status = pgErrorStatus(e);
|
|
5780
|
+
log.error(\`LIST \${ctx.table} error:\`, e?.stack ?? e);
|
|
5780
5781
|
|
|
5781
5782
|
return {
|
|
5782
5783
|
error: e?.message ?? "Internal error",
|
|
5783
5784
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
5784
|
-
status
|
|
5785
|
+
status
|
|
5785
5786
|
};
|
|
5786
5787
|
}
|
|
5787
5788
|
}
|
|
@@ -5833,25 +5834,13 @@ export async function updateRecord(
|
|
|
5833
5834
|
|
|
5834
5835
|
return { data: parsedRows[0], status: 200 };
|
|
5835
5836
|
} catch (e: any) {
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
const isJsonError = errorMsg.includes("invalid input syntax for type json");
|
|
5839
|
-
|
|
5840
|
-
if (isJsonError) {
|
|
5841
|
-
log.error(\`PATCH \${ctx.table} - Invalid JSON input detected!\`);
|
|
5842
|
-
log.error("Input data that caused error:", JSON.stringify(updateData, null, 2));
|
|
5843
|
-
log.error("Filtered data (sent to DB):", JSON.stringify(Object.fromEntries(
|
|
5844
|
-
Object.entries(updateData).filter(([k]) => !ctx.pkColumns.includes(k))
|
|
5845
|
-
), null, 2));
|
|
5846
|
-
log.error("PostgreSQL error:", errorMsg);
|
|
5847
|
-
} else {
|
|
5848
|
-
log.error(\`PATCH \${ctx.table} error:\`, e?.stack ?? e);
|
|
5849
|
-
}
|
|
5837
|
+
const status = pgErrorStatus(e);
|
|
5838
|
+
log.error(\`PATCH \${ctx.table} error:\`, e?.stack ?? e);
|
|
5850
5839
|
|
|
5851
5840
|
return {
|
|
5852
5841
|
error: e?.message ?? "Internal error",
|
|
5853
5842
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
5854
|
-
status
|
|
5843
|
+
status
|
|
5855
5844
|
};
|
|
5856
5845
|
}
|
|
5857
5846
|
}
|
|
@@ -5886,11 +5875,12 @@ export async function deleteRecord(
|
|
|
5886
5875
|
|
|
5887
5876
|
return { data: parsedRows[0], status: 200 };
|
|
5888
5877
|
} catch (e: any) {
|
|
5878
|
+
const status = pgErrorStatus(e);
|
|
5889
5879
|
log.error(\`DELETE \${ctx.table} error:\`, e?.stack ?? e);
|
|
5890
5880
|
return {
|
|
5891
5881
|
error: e?.message ?? "Internal error",
|
|
5892
5882
|
...(DEBUG ? { stack: e?.stack } : {}),
|
|
5893
|
-
status
|
|
5883
|
+
status
|
|
5894
5884
|
};
|
|
5895
5885
|
}
|
|
5896
5886
|
}
|
|
@@ -5913,7 +5903,8 @@ export interface TransactionTableMetadata {
|
|
|
5913
5903
|
export type TransactionOperation =
|
|
5914
5904
|
| { op: "create"; table: string; data: Record<string, unknown> }
|
|
5915
5905
|
| { op: "update"; table: string; pk: string | Record<string, unknown>; data: Record<string, unknown> }
|
|
5916
|
-
| { op: "
|
|
5906
|
+
| { op: "softDelete"; table: string; pk: string | Record<string, unknown> }
|
|
5907
|
+
| { op: "hardDelete"; table: string; pk: string | Record<string, unknown> }
|
|
5917
5908
|
| { op: "upsert"; table: string; data: { where: Record<string, unknown>; create: Record<string, unknown>; update: Record<string, unknown> } };
|
|
5918
5909
|
|
|
5919
5910
|
/**
|
|
@@ -5981,6 +5972,8 @@ export async function executeTransaction(
|
|
|
5981
5972
|
: [op.pk];
|
|
5982
5973
|
result = op.op === "update"
|
|
5983
5974
|
? await updateRecord(ctx, pkValues as string[], op.data)
|
|
5975
|
+
: op.op === "hardDelete"
|
|
5976
|
+
? await deleteRecord(ctx, pkValues as string[], { hard: true })
|
|
5984
5977
|
: await deleteRecord(ctx, pkValues as string[]);
|
|
5985
5978
|
}
|
|
5986
5979
|
|