@palbase/backend 27.1.0 → 28.0.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.
- package/dist/bin/palbase-backend.cjs +133 -38
- package/dist/bin/palbase-backend.cjs.map +1 -1
- package/dist/bin/palbase-backend.js +4 -4
- package/dist/{chunk-JVZQCC77.js → chunk-3TUJWHC2.js} +8 -3
- package/dist/chunk-3TUJWHC2.js.map +1 -0
- package/dist/{chunk-EB3TUX5J.js → chunk-75YROPRZ.js} +102 -38
- package/dist/chunk-75YROPRZ.js.map +1 -0
- package/dist/{chunk-XABHGMUT.js → chunk-IVZERLTM.js} +2 -2
- package/dist/{chunk-BQN723PL.js → chunk-RVP6BTEZ.js} +63 -6
- package/dist/chunk-RVP6BTEZ.js.map +1 -0
- package/dist/{chunk-OZKSM3JW.js → chunk-SNDXY565.js} +3 -2
- package/dist/chunk-SNDXY565.js.map +1 -0
- package/dist/db/index.cjs +4 -1
- package/dist/db/index.cjs.map +1 -1
- package/dist/db/index.d.cts +1 -1
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.js +3 -3
- package/dist/engine/index.cjs +143 -38
- package/dist/engine/index.cjs.map +1 -1
- package/dist/engine/index.d.cts +3 -3
- package/dist/engine/index.d.ts +3 -3
- package/dist/engine/index.js +11 -4
- package/dist/{index-H-0qv5d4.d.cts → index-9C3JHxg-.d.cts} +112 -5
- package/dist/{index-CAKOgAlP.d.ts → index-BbvOoZFr.d.ts} +112 -5
- package/dist/{index-CgE4sVhg.d.cts → index-DtISj9QX.d.cts} +94 -11
- package/dist/{index-V7QRh1wg.d.ts → index-dTTLlHIn.d.ts} +94 -11
- package/dist/index.cjs +67 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -22
- package/dist/index.d.ts +6 -22
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/dist/openapi/index.d.cts +2 -2
- package/dist/openapi/index.d.ts +2 -2
- package/dist/{registry-4EI8aaFs.d.ts → registry-JQNIX-eA.d.ts} +1 -1
- package/dist/{registry-DHsPDY0_.d.cts → registry-qIPM5BQe.d.cts} +1 -1
- package/dist/test/index.cjs +73 -6
- package/dist/test/index.cjs.map +1 -1
- package/dist/test/index.d.cts +1 -1
- package/dist/test/index.d.ts +1 -1
- package/dist/test/index.js +70 -6
- package/dist/test/index.js.map +1 -1
- package/docs/README.md +1 -1
- package/docs/database.md +69 -1
- package/docs/llms-full.txt +70 -2
- package/package.json +1 -1
- package/template/package.json +1 -1
- package/dist/chunk-BQN723PL.js.map +0 -1
- package/dist/chunk-EB3TUX5J.js.map +0 -1
- package/dist/chunk-JVZQCC77.js.map +0 -1
- package/dist/chunk-OZKSM3JW.js.map +0 -1
- /package/dist/{chunk-XABHGMUT.js.map → chunk-IVZERLTM.js.map} +0 -0
|
@@ -83,8 +83,11 @@ __name(isColumnExpr, "isColumnExpr");
|
|
|
83
83
|
function assertNoExpressionHandles(caller, table, cols, data) {
|
|
84
84
|
for (const c of cols) {
|
|
85
85
|
const v = data[c];
|
|
86
|
+
if (isNowExpr(v)) {
|
|
87
|
+
throw new Error(`${caller}(${table}): "${c}" now() ald\u0131 \u2014 bu yolda de\u011Fer beklenir. Sat\u0131r EKLEN\u0130RKEN sunucu saatini yazman\u0131n yolu kolonu defaultNow() ile bildirmek (varsay\u0131lan kolonun yan\u0131nda durur, her \xE7a\u011Fr\u0131da tekrarlanmaz); var olan bir sat\u0131r\u0131 damgalamak i\xE7in updateMany({ where, set: { ${c}: now() } }) ya da $transaction i\xE7inde tx.public.${table}.updateWhere(where, { ${c}: now() }).`);
|
|
88
|
+
}
|
|
86
89
|
if (isColumnExpr(v)) {
|
|
87
|
-
throw new Error(`${caller}(${table}): "${c}" bir ifade tutama\u011F\u0131 ald\u0131 (increment()/decrement()
|
|
90
|
+
throw new Error(`${caller}(${table}): "${c}" bir ifade tutama\u011F\u0131 ald\u0131 (increment()/decrement()). Bu yolda de\u011Fer beklenir. Saya\xE7 art\u0131\u015F\u0131 i\xE7in updateMany({ where, set: { ${c}: increment(n) } }) ya da $transaction i\xE7inde tx.public.${table}.updateWhere(where, { ${c}: increment(n) }) kullan\u0131n.`);
|
|
88
91
|
}
|
|
89
92
|
if (isColRef(v)) {
|
|
90
93
|
throw new Error(`${caller}(${table}): "${c}" bir col() ald\u0131. Kolon referans\u0131 yaln\u0131z F\u0130LTREDE durabilir; bir kolonun de\u011Ferini ba\u015Fka bir kolona yazmak i\xE7in $query kullan\u0131n.`);
|
|
@@ -376,7 +379,9 @@ function encodeMap(map, allowColumnExpr) {
|
|
|
376
379
|
const out = {};
|
|
377
380
|
for (const key of Object.keys(map).sort()) {
|
|
378
381
|
const value = map[key];
|
|
379
|
-
if (value === void 0)
|
|
382
|
+
if (value === void 0) {
|
|
383
|
+
throw new TxPlanError(`${key} de\u011Feri undefined \u2014 bu bir yazma de\u011Feri de\u011Fil. Anahtar duruyor ama de\u011Feri yok, yani kolon sessizce YAZILMAZDI (istek g\xF6vdesinden gelen bir alan\u0131n eksik olmas\u0131 bu \u015Fekilde g\xF6r\xFCn\xFCr). Kolon varsay\u0131lan\u0131n\u0131 istiyorsan\u0131z anahtar\u0131 hi\xE7 koymay\u0131n; NULL yazmak istiyorsan\u0131z a\xE7\u0131k\xE7a null yaz\u0131n.`);
|
|
384
|
+
}
|
|
380
385
|
out[key] = encodeValue(value, key, allowColumnExpr);
|
|
381
386
|
}
|
|
382
387
|
return out;
|
|
@@ -904,6 +909,10 @@ function makeTableProxy(ops, prefix) {
|
|
|
904
909
|
const name = `${prefix}${prop}`;
|
|
905
910
|
return {
|
|
906
911
|
insert: /* @__PURE__ */ __name((data) => ops().insert(name, data), "insert"),
|
|
912
|
+
// DÖRDÜNCÜ FİİL, aynı gerekçeyle: tip söz veriyor, ops katmanı
|
|
913
|
+
// uyguluyor, ve bir handler'ın gerçekten dokunduğu yer BURASI.
|
|
914
|
+
// `runtime-table-verbs` kapısı bunu adıyla saydı.
|
|
915
|
+
insertMany: /* @__PURE__ */ __name((rows, opts) => ops().insertMany(name, rows, opts), "insertMany"),
|
|
907
916
|
update: /* @__PURE__ */ __name((q) => ops().update(name, q.where.id, q.set), "update"),
|
|
908
917
|
delete: /* @__PURE__ */ __name((id) => ops().delete(name, id), "delete"),
|
|
909
918
|
findById: /* @__PURE__ */ __name((id) => ops().findById(name, id), "findById"),
|
|
@@ -960,6 +969,7 @@ function makeTypedSurface(raw) {
|
|
|
960
969
|
$claim: /* @__PURE__ */ __name((table, unique, extra) => reco.claim(table, unique, extra), "$claim"),
|
|
961
970
|
$lockRows: /* @__PURE__ */ __name((table, ids) => reco.lockRows(table, ids), "$lockRows"),
|
|
962
971
|
$advisoryXactLock: /* @__PURE__ */ __name((key) => reco.advisoryXactLock(key), "$advisoryXactLock"),
|
|
972
|
+
$insertMany: /* @__PURE__ */ __name((table, rows, opts) => raw.insertMany(table, rows, opts), "$insertMany"),
|
|
963
973
|
$supersede: /* @__PURE__ */ __name((table, id, row) => raw.supersede(table, id, row), "$supersede")
|
|
964
974
|
};
|
|
965
975
|
const base = Object.assign(ops, {
|
|
@@ -1149,6 +1159,20 @@ ${detail}`);
|
|
|
1149
1159
|
}
|
|
1150
1160
|
__name(loadConfig, "loadConfig");
|
|
1151
1161
|
|
|
1162
|
+
// src/refusals.ts
|
|
1163
|
+
var DECLARATION_REFUSAL = /* @__PURE__ */ Symbol.for("palbase.backend.declarationRefusal");
|
|
1164
|
+
var DeclarationRefused = class extends Error {
|
|
1165
|
+
static {
|
|
1166
|
+
__name(this, "DeclarationRefused");
|
|
1167
|
+
}
|
|
1168
|
+
/** @see DECLARATION_REFUSAL — realm-safe, unlike `instanceof`. */
|
|
1169
|
+
[DECLARATION_REFUSAL] = true;
|
|
1170
|
+
constructor(message) {
|
|
1171
|
+
super(message);
|
|
1172
|
+
this.name = "DeclarationRefused";
|
|
1173
|
+
}
|
|
1174
|
+
};
|
|
1175
|
+
|
|
1152
1176
|
// src/engine/auth.ts
|
|
1153
1177
|
function b64urlToBytes(s) {
|
|
1154
1178
|
const pad = s.replace(/-/g, "+").replace(/_/g, "/");
|
|
@@ -1471,12 +1495,12 @@ function buildRelations(schemas) {
|
|
|
1471
1495
|
const held = names.get(name);
|
|
1472
1496
|
if (held !== void 0) {
|
|
1473
1497
|
if (held.def.owns === true && origin.def.owns === true) {
|
|
1474
|
-
throw new
|
|
1498
|
+
throw new DeclarationRefused(`table "${tableKey}" declares TWO owner columns (${held.column}, ${origin.column}) \u2014 a table has at most ONE ownedByUser(). If the other column only POINTS at a user, declare it userRef({ onDelete: \u2026 }) instead.`);
|
|
1475
1499
|
}
|
|
1476
1500
|
const heldFix = renameCall(held);
|
|
1477
1501
|
const originFix = renameCall(origin);
|
|
1478
1502
|
const remedy = heldFix === originFix ? `rename one of them: ${heldFix}` : `rename one of them \u2014 "${held.table}.${held.column}": ${heldFix}; "${origin.table}.${origin.column}": ${originFix}`;
|
|
1479
|
-
throw new
|
|
1503
|
+
throw new DeclarationRefused(`table "${tableKey}": ${describeOrigin(held)} and ${describeOrigin(origin)} both resolve to the relation name "${name}" \u2014 ${remedy}.`);
|
|
1480
1504
|
}
|
|
1481
1505
|
names.set(name, origin);
|
|
1482
1506
|
out.get(tableKey)?.push(edge);
|
|
@@ -2054,7 +2078,7 @@ function compileWhereBare(table, colSet, where, add, caller = "search", alias =
|
|
|
2054
2078
|
const rel = rels.find((r) => r.name === relName);
|
|
2055
2079
|
if (rel === void 0) {
|
|
2056
2080
|
const known = rels.map((r) => r.name).sort();
|
|
2057
|
-
throw new Error(`${caller}(${table}): has.${relName} diye bir ili\u015Fki yok
|
|
2081
|
+
throw new Error(`${caller}(${table}): has.${relName} diye bir ili\u015Fki yok` + (known.length > 0 ? ` (bilinenler: ${known.join(", ")}). \u0130li\u015Fkiler yabanc\u0131 anahtarlardan T\xDCRET\u0130L\u0130R; ad\u0131n\u0131 de\u011Fi\u015Ftirmek i\xE7in references(..., { as, reverseAs }).` : `. Bu tablo H\u0130\xC7 yabanc\u0131 anahtar bildirmiyor, ve ili\u015Fkiler onlardan T\xDCRET\u0130L\u0130R. Var olan bir veritaban\u0131ndan introspect edilmi\u015F \u015Femalarda bu s\u0131k olur: kolon \`text()\`/\`uuid()\` olarak durur, \`references(() => <tablo>.<kolon>)\` yoktur. Bildirdi\u011Finiz anda ili\u015Fki iki tarafta da adland\u0131r\u0131l\u0131r \u2014 ama bu CANLI veritaban\u0131na giden bir k\u0131s\u0131tt\u0131r ve mevcut yetim sat\u0131rlar onu d\xFC\u015F\xFCr\xFCr; \xF6nce onlar\u0131 say\u0131n.`));
|
|
2058
2082
|
}
|
|
2059
2083
|
const ourCol = rel.kind === "many" ? primaryKeyOf(table) : rel.via;
|
|
2060
2084
|
const theirCol = rel.kind === "many" ? rel.via : primaryKeyOf(rel.to);
|
|
@@ -2234,6 +2258,37 @@ async function embedQuery(embed, text) {
|
|
|
2234
2258
|
}
|
|
2235
2259
|
}
|
|
2236
2260
|
__name(embedQuery, "embedQuery");
|
|
2261
|
+
function buildSetAssignments(table, cols, set, add, caller) {
|
|
2262
|
+
return cols.map((c) => {
|
|
2263
|
+
const expr = columnExprOf(set[c]);
|
|
2264
|
+
if (expr !== null && expr.fn === "now") {
|
|
2265
|
+
return `${quoteIdent(c)} = now()`;
|
|
2266
|
+
}
|
|
2267
|
+
if (expr !== null) {
|
|
2268
|
+
const operator = expr.fn === "inc" ? "+" : "-";
|
|
2269
|
+
const t = transformsOf(currentSchema, table).get(c);
|
|
2270
|
+
const amount = t?.toDb === void 0 || expr.by === null || expr.by === void 0 ? expr.by : t.toDb(expr.by);
|
|
2271
|
+
return `${quoteIdent(c)} = ${quoteIdent(c)} ${operator} ${add(amount)}`;
|
|
2272
|
+
}
|
|
2273
|
+
return `${quoteIdent(c)} = ${add(asBindParams(table, [
|
|
2274
|
+
c
|
|
2275
|
+
], set, caller)[0])}`;
|
|
2276
|
+
}).join(", ");
|
|
2277
|
+
}
|
|
2278
|
+
__name(buildSetAssignments, "buildSetAssignments");
|
|
2279
|
+
function buildValueTuple(table, cols, data, add, caller) {
|
|
2280
|
+
return cols.map((c) => {
|
|
2281
|
+
const expr = columnExprOf(data[c]);
|
|
2282
|
+
if (expr !== null && expr.fn === "now") return "now()";
|
|
2283
|
+
if (expr !== null) {
|
|
2284
|
+
throw new Error(`${caller}(${table}): "${c}" ${expr.fn === "inc" ? "increment()" : "decrement()"} ald\u0131 \u2014 sat\u0131r HEN\xDCZ YOK, yani "kolonun \u015Fu anki de\u011Feri" diye bir \u015Fey yok. Ba\u015Flang\u0131\xE7 de\u011Ferini yaz\u0131n; art\u0131rmak i\xE7in sat\u0131r olu\u015Ftuktan sonra updateMany({ where, set: { ${c}: ${expr.fn === "inc" ? "increment" : "decrement"}(n) } }).`);
|
|
2285
|
+
}
|
|
2286
|
+
return add(asBindParams(table, [
|
|
2287
|
+
c
|
|
2288
|
+
], data, caller)[0]);
|
|
2289
|
+
}).join(", ");
|
|
2290
|
+
}
|
|
2291
|
+
__name(buildValueTuple, "buildValueTuple");
|
|
2237
2292
|
function createOps(tx) {
|
|
2238
2293
|
const at = /* @__PURE__ */ __name(() => resolveTx(tx), "at");
|
|
2239
2294
|
const ops = {
|
|
@@ -2247,9 +2302,11 @@ function createOps(tx) {
|
|
|
2247
2302
|
async insert(table, data) {
|
|
2248
2303
|
const cols = Object.keys(data);
|
|
2249
2304
|
if (cols.length === 0) throw new Error(`insert into ${table}: no columns given`);
|
|
2250
|
-
const
|
|
2251
|
-
const
|
|
2252
|
-
const
|
|
2305
|
+
const params = [];
|
|
2306
|
+
const add = /* @__PURE__ */ __name((v) => `$${params.push(v)}`, "add");
|
|
2307
|
+
const tuple = buildValueTuple(table, cols, data, add, "insert");
|
|
2308
|
+
const sql = `INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${tuple}) RETURNING *`;
|
|
2309
|
+
const rows = await (await at()).unsafe(sql, params);
|
|
2253
2310
|
const inserted = rows[0];
|
|
2254
2311
|
if (!inserted) {
|
|
2255
2312
|
throw new Error(`insert into ${table} returned no row \u2014 the write was rejected (an RLS policy, most likely).`);
|
|
@@ -2257,6 +2314,41 @@ function createOps(tx) {
|
|
|
2257
2314
|
return asTableRow(table, inserted);
|
|
2258
2315
|
},
|
|
2259
2316
|
/**
|
|
2317
|
+
* Çok satırı TEK statement'la ekle.
|
|
2318
|
+
*
|
|
2319
|
+
* Motor bunu zaten yapıyordu ve yalnız PLAN yolundan erişilebiliyordu
|
|
2320
|
+
* (`tx.public.x.insertMany`). Dışarıda tek kapı `insert(row)` olduğu için
|
|
2321
|
+
* "şu 200 satırı yaz" ya 200 gidiş-dönüş ya da ham SQL oluyordu — ölçüldü:
|
|
2322
|
+
* bir müşteri projesinde bir seed rutini satırları tek tek siliyor
|
|
2323
|
+
* (`deleteMany` VARKEN) ve tek tek ekliyor.
|
|
2324
|
+
*
|
|
2325
|
+
* SATIRLARIN ANAHTAR KÜMESİ AYNI OLMAK ZORUNDA. Kolon listesi tek bir
|
|
2326
|
+
* statement'ta paylaşıldığı için ilk satırdan türer; farklı anahtar taşıyan
|
|
2327
|
+
* bir satırın fazla kolonu SESSİZCE YAZILMAZDI. Eksik kolon için `null`
|
|
2328
|
+
* yazın ya da varsayılanı istiyorsanız o satırları ayrı çağrıda ekleyin.
|
|
2329
|
+
*/
|
|
2330
|
+
async insertMany(table, rows, opts) {
|
|
2331
|
+
if (rows.length === 0) return [];
|
|
2332
|
+
const first = rows[0];
|
|
2333
|
+
const cols = Object.keys(first);
|
|
2334
|
+
if (cols.length === 0) throw new Error(`insertMany into ${table}: no columns given`);
|
|
2335
|
+
for (let i = 1; i < rows.length; i++) {
|
|
2336
|
+
const keys = Object.keys(rows[i]);
|
|
2337
|
+
const missing = cols.filter((c) => !(c in rows[i]));
|
|
2338
|
+
const extra = keys.filter((k) => !cols.includes(k));
|
|
2339
|
+
if (missing.length > 0 || extra.length > 0) {
|
|
2340
|
+
throw new Error(`insertMany(${table}): ${i}. sat\u0131r\u0131n kolonlar\u0131 ilk sat\u0131rla ayn\u0131 de\u011Fil` + (missing.length > 0 ? ` (eksik: ${missing.join(", ")})` : "") + (extra.length > 0 ? ` (fazla: ${extra.join(", ")})` : "") + `. Tek statement kolon listesini PAYLA\u015EIR, yani fazla kolon sessizce yaz\u0131lmaz ve eksik kolon yanl\u0131\u015F s\xFCtuna kayar. Eksikler i\xE7in null yaz\u0131n, ya da farkl\u0131 \u015Fekilli sat\u0131rlar\u0131 ayr\u0131 \xE7a\u011Fr\u0131larda ekleyin.`);
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
const params = [];
|
|
2344
|
+
const add = /* @__PURE__ */ __name((v) => `$${params.push(v)}`, "add");
|
|
2345
|
+
const tuples = rows.map((r) => `(${buildValueTuple(table, cols, r, add, "insertMany")})`);
|
|
2346
|
+
const tail = opts !== void 0 && opts.onConflict.length > 0 ? ` ${onConflictTail(cols, opts.onConflict, opts.action ?? "ignore")}` : "";
|
|
2347
|
+
const sql = `INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(", ")}) VALUES ${tuples.join(", ")}${tail} RETURNING *`;
|
|
2348
|
+
const out = await (await at()).unsafe(sql, params);
|
|
2349
|
+
return out.map((r) => asTableRow(table, r));
|
|
2350
|
+
},
|
|
2351
|
+
/**
|
|
2260
2352
|
* Bir ADI kilitle — satırı değil (FR-054).
|
|
2261
2353
|
*
|
|
2262
2354
|
* "Aynı anda tek bir fatura kapanışı koşsun" gibi, kilitlenecek satırı
|
|
@@ -2342,8 +2434,10 @@ function createOps(tx) {
|
|
|
2342
2434
|
const live = await at();
|
|
2343
2435
|
try {
|
|
2344
2436
|
return await live.savepoint(async (sp) => {
|
|
2345
|
-
const
|
|
2346
|
-
const
|
|
2437
|
+
const params = [];
|
|
2438
|
+
const add = /* @__PURE__ */ __name((v) => `$${params.push(v)}`, "add");
|
|
2439
|
+
const tuple = buildValueTuple(table, cols, data, add, "claim");
|
|
2440
|
+
const rows = await sp.unsafe(`INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${tuple}) RETURNING *`, params);
|
|
2347
2441
|
if (!rows[0]) {
|
|
2348
2442
|
throw new Error(`claim(${table}): INSERT sat\u0131r d\xF6nd\xFCrmedi \u2014 yazma reddedildi (b\xFCy\xFCk olas\u0131l\u0131kla bir RLS policy'si).`);
|
|
2349
2443
|
}
|
|
@@ -2394,10 +2488,11 @@ function createOps(tx) {
|
|
|
2394
2488
|
const cols = Object.keys(data);
|
|
2395
2489
|
if (cols.length === 0) throw new Error(`upsert into ${table}: no columns given`);
|
|
2396
2490
|
if (searchConfigFor(table)?.validity) {
|
|
2397
|
-
const
|
|
2491
|
+
const bindData = [];
|
|
2492
|
+
const addPut = /* @__PURE__ */ __name((v) => `$${bindData.push(v)}`, "addPut");
|
|
2493
|
+
const ph = buildValueTuple(table, cols, data, addPut, "put");
|
|
2398
2494
|
const insertSql = `INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${ph}) ON CONFLICT (${conflict.map(quoteIdent).join(", ")}) WHERE "valid_to" IS NULL DO NOTHING RETURNING *`;
|
|
2399
2495
|
const live = await at();
|
|
2400
|
-
const bindData = asBindParams(table, cols, data, "put");
|
|
2401
2496
|
const first = await live.unsafe(insertSql, bindData);
|
|
2402
2497
|
if (first[0]) return asTableRow(table, first[0]);
|
|
2403
2498
|
const condSql = conflict.map((c, i) => `${quoteIdent(c)} = $${i + 1}`).join(" AND ");
|
|
@@ -2422,12 +2517,14 @@ function createOps(tx) {
|
|
|
2422
2517
|
]);
|
|
2423
2518
|
return asTableRow(table, second[0]);
|
|
2424
2519
|
}
|
|
2425
|
-
const
|
|
2520
|
+
const params = [];
|
|
2521
|
+
const add = /* @__PURE__ */ __name((v) => `$${params.push(v)}`, "add");
|
|
2522
|
+
const placeholders = buildValueTuple(table, cols, data, add, "put");
|
|
2426
2523
|
const conflictSet = new Set(conflict);
|
|
2427
2524
|
const assignments = cols.filter((c) => !conflictSet.has(c)).map((c) => `${quoteIdent(c)} = EXCLUDED.${quoteIdent(c)}`);
|
|
2428
2525
|
const action = assignments.length ? `DO UPDATE SET ${assignments.join(", ")}` : `DO UPDATE SET ${quoteIdent(conflict[0])} = EXCLUDED.${quoteIdent(conflict[0])}`;
|
|
2429
2526
|
const sql = `INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${placeholders}) ON CONFLICT (${conflict.map(quoteIdent).join(", ")}) ${action} RETURNING *`;
|
|
2430
|
-
const rows = await (await at()).unsafe(sql,
|
|
2527
|
+
const rows = await (await at()).unsafe(sql, params);
|
|
2431
2528
|
const row = rows[0];
|
|
2432
2529
|
if (!row) {
|
|
2433
2530
|
throw new Error(`upsert into ${table} returned no row \u2014 the write was rejected (an RLS policy, most likely).`);
|
|
@@ -2438,12 +2535,14 @@ function createOps(tx) {
|
|
|
2438
2535
|
assertNotAppendOnly("update", table);
|
|
2439
2536
|
const cols = Object.keys(data);
|
|
2440
2537
|
if (cols.length === 0) return ops.findById(table, id);
|
|
2441
|
-
const
|
|
2442
|
-
const
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2538
|
+
const params = [];
|
|
2539
|
+
const add = /* @__PURE__ */ __name((v) => {
|
|
2540
|
+
params.push(v);
|
|
2541
|
+
return `$${params.length}`;
|
|
2542
|
+
}, "add");
|
|
2543
|
+
const assignments = buildSetAssignments(table, cols, data, add, "update");
|
|
2544
|
+
const sql = `UPDATE ${quoteTable(table)} SET ${assignments} WHERE id = ${add(id)} RETURNING *`;
|
|
2545
|
+
const rows = await (await at()).unsafe(sql, params);
|
|
2447
2546
|
return rows[0] ? asTableRow(table, rows[0]) : null;
|
|
2448
2547
|
},
|
|
2449
2548
|
async delete(table, id) {
|
|
@@ -2489,21 +2588,7 @@ function createOps(tx) {
|
|
|
2489
2588
|
params.push(v);
|
|
2490
2589
|
return `$${params.length}`;
|
|
2491
2590
|
}, "add");
|
|
2492
|
-
const assignments =
|
|
2493
|
-
const expr = columnExprOf(set[c]);
|
|
2494
|
-
if (expr !== null && expr.fn === "now") {
|
|
2495
|
-
return `${quoteIdent(c)} = now()`;
|
|
2496
|
-
}
|
|
2497
|
-
if (expr !== null) {
|
|
2498
|
-
const operator = expr.fn === "inc" ? "+" : "-";
|
|
2499
|
-
const t = transformsOf(currentSchema, table).get(c);
|
|
2500
|
-
const amount = t?.toDb === void 0 || expr.by === null || expr.by === void 0 ? expr.by : t.toDb(expr.by);
|
|
2501
|
-
return `${quoteIdent(c)} = ${quoteIdent(c)} ${operator} ${add(amount)}`;
|
|
2502
|
-
}
|
|
2503
|
-
return `${quoteIdent(c)} = ${add(asBindParams(table, [
|
|
2504
|
-
c
|
|
2505
|
-
], set, "updateMany")[0])}`;
|
|
2506
|
-
}).join(", ");
|
|
2591
|
+
const assignments = buildSetAssignments(table, cols, set, add, "updateMany");
|
|
2507
2592
|
const whereSql = compileWhere(table, known, where, add, "updateMany");
|
|
2508
2593
|
assertHasPredicate(whereSql, "updateMany", table);
|
|
2509
2594
|
const pk = primaryKeyOf(table);
|
|
@@ -2961,8 +3046,10 @@ function createOps(tx) {
|
|
|
2961
3046
|
[cfg.pk]: newId
|
|
2962
3047
|
};
|
|
2963
3048
|
const cols = Object.keys(data);
|
|
2964
|
-
const
|
|
2965
|
-
const
|
|
3049
|
+
const params = [];
|
|
3050
|
+
const add = /* @__PURE__ */ __name((v) => `$${params.push(v)}`, "add");
|
|
3051
|
+
const tuple = buildValueTuple(table, cols, data, add, "supersede");
|
|
3052
|
+
const rows = await sp.unsafe(`INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${tuple}) RETURNING *`, params);
|
|
2966
3053
|
if (!rows[0]) {
|
|
2967
3054
|
throw new Error(`supersede(${table}): INSERT sat\u0131r d\xF6nd\xFCrmedi \u2014 yazma reddedildi (b\xFCy\xFCk olas\u0131l\u0131kla bir RLS policy'si)`);
|
|
2968
3055
|
}
|
|
@@ -3918,6 +4005,14 @@ var DiError = class extends Error {
|
|
|
3918
4005
|
path;
|
|
3919
4006
|
at;
|
|
3920
4007
|
fixes;
|
|
4008
|
+
/**
|
|
4009
|
+
* EVERY `DiKind` IS A FACT ABOUT THE AUTHOR'S DECLARATIONS — an unresolvable
|
|
4010
|
+
* dependency, a cycle, a class no module owns. Not one of them is something
|
|
4011
|
+
* the environment could change, so restarting re-reads the same bytes and
|
|
4012
|
+
* fails identically. The cure is a new artifact, and the tag is how the
|
|
4013
|
+
* runtime learns that without matching on wording.
|
|
4014
|
+
*/
|
|
4015
|
+
[DECLARATION_REFUSAL] = true;
|
|
3921
4016
|
constructor(kind, path, at, detail, fixes) {
|
|
3922
4017
|
super(`
|
|
3923
4018
|
Kind: ${kind}
|
|
@@ -4333,7 +4428,7 @@ async function createApp(opts) {
|
|
|
4333
4428
|
assertNoOrphanEntryPoints(controllers, container.owned);
|
|
4334
4429
|
const routes = buildRouteTable(controllers, liveContainer);
|
|
4335
4430
|
if (routes.length === 0) {
|
|
4336
|
-
throw new
|
|
4431
|
+
throw new DeclarationRefused("boot refused: zero endpoints collected \u2014 nothing would answer.");
|
|
4337
4432
|
}
|
|
4338
4433
|
const sql = opts.sql ?? await defaultSqlDriver(config);
|
|
4339
4434
|
await sql.unsafe("select 1");
|