@palbase/backend 27.0.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.
Files changed (52) hide show
  1. package/dist/bin/palbase-backend.cjs +165 -39
  2. package/dist/bin/palbase-backend.cjs.map +1 -1
  3. package/dist/bin/palbase-backend.js +4 -4
  4. package/dist/{chunk-GYK6QYS4.js → chunk-3TUJWHC2.js} +28 -3
  5. package/dist/chunk-3TUJWHC2.js.map +1 -0
  6. package/dist/{chunk-OO7R25AI.js → chunk-75YROPRZ.js} +118 -39
  7. package/dist/chunk-75YROPRZ.js.map +1 -0
  8. package/dist/{chunk-TS4U7NBD.js → chunk-IVZERLTM.js} +2 -2
  9. package/dist/{chunk-I3C4PFIW.js → chunk-RVP6BTEZ.js} +63 -6
  10. package/dist/chunk-RVP6BTEZ.js.map +1 -0
  11. package/dist/{chunk-DRZFQRJI.js → chunk-SNDXY565.js} +3 -2
  12. package/dist/chunk-SNDXY565.js.map +1 -0
  13. package/dist/db/index.cjs +30 -1
  14. package/dist/db/index.cjs.map +1 -1
  15. package/dist/db/index.d.cts +1 -1
  16. package/dist/db/index.d.ts +1 -1
  17. package/dist/db/index.js +3 -3
  18. package/dist/engine/index.cjs +175 -39
  19. package/dist/engine/index.cjs.map +1 -1
  20. package/dist/engine/index.d.cts +3 -3
  21. package/dist/engine/index.d.ts +3 -3
  22. package/dist/engine/index.js +11 -4
  23. package/dist/{index-VtToZmUm.d.cts → index-9C3JHxg-.d.cts} +112 -5
  24. package/dist/{index-NuzRCuxe.d.ts → index-BbvOoZFr.d.ts} +112 -5
  25. package/dist/{index-Bve7BBTL.d.cts → index-DtISj9QX.d.cts} +125 -22
  26. package/dist/{index-BrvvxSpn.d.ts → index-dTTLlHIn.d.ts} +125 -22
  27. package/dist/index.cjs +93 -4
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.cts +6 -22
  30. package/dist/index.d.ts +6 -22
  31. package/dist/index.js +10 -4
  32. package/dist/index.js.map +1 -1
  33. package/dist/openapi/index.d.cts +2 -2
  34. package/dist/openapi/index.d.ts +2 -2
  35. package/dist/{registry-B0eyOF9x.d.ts → registry-JQNIX-eA.d.ts} +1 -1
  36. package/dist/{registry-Bk9_rbNd.d.cts → registry-qIPM5BQe.d.cts} +1 -1
  37. package/dist/test/index.cjs +100 -6
  38. package/dist/test/index.cjs.map +1 -1
  39. package/dist/test/index.d.cts +1 -1
  40. package/dist/test/index.d.ts +1 -1
  41. package/dist/test/index.js +88 -6
  42. package/dist/test/index.js.map +1 -1
  43. package/docs/README.md +1 -1
  44. package/docs/database.md +103 -1
  45. package/docs/llms-full.txt +104 -2
  46. package/package.json +1 -1
  47. package/template/package.json +1 -1
  48. package/dist/chunk-DRZFQRJI.js.map +0 -1
  49. package/dist/chunk-GYK6QYS4.js.map +0 -1
  50. package/dist/chunk-I3C4PFIW.js.map +0 -1
  51. package/dist/chunk-OO7R25AI.js.map +0 -1
  52. /package/dist/{chunk-TS4U7NBD.js.map → chunk-IVZERLTM.js.map} +0 -0
@@ -29,9 +29,11 @@ __name(brandOf, "brandOf");
29
29
  function looksLikeUnbrandedRef(v) {
30
30
  if (typeof v !== "object" || v === null) return null;
31
31
  if (brandOf(v) !== void 0) return null;
32
+ if (isColumnExpr(v)) return null;
32
33
  const o = v;
33
34
  if (typeof o.$col === "string") return "col";
34
35
  if (o.$sql !== void 0 && typeof o.$sql === "object" && o.$sql !== null) return "sql";
36
+ if (o.$expr !== void 0 && typeof o.$expr === "object" && o.$expr !== null) return "expr";
35
37
  return null;
36
38
  }
37
39
  __name(looksLikeUnbrandedRef, "looksLikeUnbrandedRef");
@@ -58,6 +60,16 @@ function isSqlFragment(v) {
58
60
  }
59
61
  __name(isSqlFragment, "isSqlFragment");
60
62
  var TX_EXPR = /* @__PURE__ */ Symbol.for("palbase.tx.expr");
63
+ function isNowExpr(v) {
64
+ if (!isColumnExpr(v)) return false;
65
+ try {
66
+ const e = v[TX_EXPR];
67
+ return typeof e === "object" && e !== null && e.fn === "now";
68
+ } catch {
69
+ return false;
70
+ }
71
+ }
72
+ __name(isNowExpr, "isNowExpr");
61
73
  function isColumnExpr(v) {
62
74
  if (typeof v !== "object" && typeof v !== "function") return false;
63
75
  if (v === null) return false;
@@ -71,8 +83,11 @@ __name(isColumnExpr, "isColumnExpr");
71
83
  function assertNoExpressionHandles(caller, table, cols, data) {
72
84
  for (const c of cols) {
73
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
+ }
74
89
  if (isColumnExpr(v)) {
75
- throw new Error(`${caller}(${table}): "${c}" bir ifade tutama\u011F\u0131 ald\u0131 (increment()/decrement()/now()). Bu yolda de\u011Fer beklenir. Saya\xE7 art\u0131\u015F\u0131 i\xE7in updateMany(where, { ${c}: increment(n) }) ya da $transaction i\xE7inde tx.tables.${table}.updateWhere(where, { ${c}: increment(n) }) kullan\u0131n.`);
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.`);
76
91
  }
77
92
  if (isColRef(v)) {
78
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.`);
@@ -140,6 +155,7 @@ function assertUsableFilter(caller, table, where) {
140
155
  }
141
156
  if (cond === null || typeof cond !== "object" || Array.isArray(cond)) continue;
142
157
  if (isColRef(cond)) continue;
158
+ if (isNowExpr(cond)) continue;
143
159
  const entries = Object.entries(cond);
144
160
  if (entries.length === 0) {
145
161
  throw new Error(`${caller}(${table}): where.${col} bo\u015F bir operat\xF6r nesnesi ({}) \u2014 hi\xE7bir ko\u015Ful \xFCretmez, yani bu alan filtreden sessizce D\xDC\u015EERD\u0130. Ko\u015Ful kurulmayacaksa anahtar\u0131 filtreye hi\xE7 koymay\u0131n (D-21).`);
@@ -281,6 +297,11 @@ function encodeValue(value, column, allowColumnExpr) {
281
297
  field: ref.field
282
298
  }
283
299
  }, "ref");
300
+ if (isNowExpr(value)) return {
301
+ $expr: {
302
+ fn: "now"
303
+ }
304
+ };
284
305
  const expr = exprOf(value);
285
306
  if (expr) {
286
307
  if (expr.fn !== "now" && !allowColumnExpr) {
@@ -358,7 +379,9 @@ function encodeMap(map, allowColumnExpr) {
358
379
  const out = {};
359
380
  for (const key of Object.keys(map).sort()) {
360
381
  const value = map[key];
361
- if (value === void 0) continue;
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
+ }
362
385
  out[key] = encodeValue(value, key, allowColumnExpr);
363
386
  }
364
387
  return out;
@@ -886,6 +909,10 @@ function makeTableProxy(ops, prefix) {
886
909
  const name = `${prefix}${prop}`;
887
910
  return {
888
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"),
889
916
  update: /* @__PURE__ */ __name((q) => ops().update(name, q.where.id, q.set), "update"),
890
917
  delete: /* @__PURE__ */ __name((id) => ops().delete(name, id), "delete"),
891
918
  findById: /* @__PURE__ */ __name((id) => ops().findById(name, id), "findById"),
@@ -942,6 +969,7 @@ function makeTypedSurface(raw) {
942
969
  $claim: /* @__PURE__ */ __name((table, unique, extra) => reco.claim(table, unique, extra), "$claim"),
943
970
  $lockRows: /* @__PURE__ */ __name((table, ids) => reco.lockRows(table, ids), "$lockRows"),
944
971
  $advisoryXactLock: /* @__PURE__ */ __name((key) => reco.advisoryXactLock(key), "$advisoryXactLock"),
972
+ $insertMany: /* @__PURE__ */ __name((table, rows, opts) => raw.insertMany(table, rows, opts), "$insertMany"),
945
973
  $supersede: /* @__PURE__ */ __name((table, id, row) => raw.supersede(table, id, row), "$supersede")
946
974
  };
947
975
  const base = Object.assign(ops, {
@@ -1131,6 +1159,20 @@ ${detail}`);
1131
1159
  }
1132
1160
  __name(loadConfig, "loadConfig");
1133
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
+
1134
1176
  // src/engine/auth.ts
1135
1177
  function b64urlToBytes(s) {
1136
1178
  const pad = s.replace(/-/g, "+").replace(/_/g, "/");
@@ -1453,12 +1495,12 @@ function buildRelations(schemas) {
1453
1495
  const held = names.get(name);
1454
1496
  if (held !== void 0) {
1455
1497
  if (held.def.owns === true && origin.def.owns === true) {
1456
- throw new Error(`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.`);
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.`);
1457
1499
  }
1458
1500
  const heldFix = renameCall(held);
1459
1501
  const originFix = renameCall(origin);
1460
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}`;
1461
- throw new Error(`table "${tableKey}": ${describeOrigin(held)} and ${describeOrigin(origin)} both resolve to the relation name "${name}" \u2014 ${remedy}.`);
1503
+ throw new DeclarationRefused(`table "${tableKey}": ${describeOrigin(held)} and ${describeOrigin(origin)} both resolve to the relation name "${name}" \u2014 ${remedy}.`);
1462
1504
  }
1463
1505
  names.set(name, origin);
1464
1506
  out.get(tableKey)?.push(edge);
@@ -2036,7 +2078,7 @@ function compileWhereBare(table, colSet, where, add, caller = "search", alias =
2036
2078
  const rel = rels.find((r) => r.name === relName);
2037
2079
  if (rel === void 0) {
2038
2080
  const known = rels.map((r) => r.name).sort();
2039
- throw new Error(`${caller}(${table}): has.${relName} diye bir ili\u015Fki yok${known.length > 0 ? ` (bilinenler: ${known.join(", ")})` : " \u2014 bu tablonun hi\xE7 ili\u015Fkisi yok"}. \u0130li\u015Fkiler yabanc\u0131 anahtarlardan T\xDCRET\u0130L\u0130R; ad\u0131n\u0131 de\u011Fi\u015Ftirmek i\xE7in references(..., { as, reverseAs }).`);
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.`));
2040
2082
  }
2041
2083
  const ourCol = rel.kind === "many" ? primaryKeyOf(table) : rel.via;
2042
2084
  const theirCol = rel.kind === "many" ? rel.via : primaryKeyOf(rel.to);
@@ -2063,6 +2105,10 @@ function compileWhereBare(table, colSet, where, add, caller = "search", alias =
2063
2105
  parts.push(`${q} = ${colRefSql(table, colSet, cond, caller, alias)}`);
2064
2106
  continue;
2065
2107
  }
2108
+ if (isNowExpr(cond)) {
2109
+ parts.push(`${q} = now()`);
2110
+ continue;
2111
+ }
2066
2112
  if (cond !== null && typeof cond === "object" && !Array.isArray(cond)) {
2067
2113
  for (const [op, v] of Object.entries(cond)) {
2068
2114
  if (op === "contains" || op === "icontains" || op === "startsWith" || op === "endsWith") {
@@ -2091,6 +2137,13 @@ function compileWhereBare(table, colSet, where, add, caller = "search", alias =
2091
2137
  continue;
2092
2138
  }
2093
2139
  parts.push(`${q} IN (${v.map((x) => bind(x)).join(", ")})`);
2140
+ } else if (isNowExpr(v)) {
2141
+ if (!(op in WHERE_OPS)) {
2142
+ throw new Error(`${caller}(${table}): where.${col}.${op} now() ile kullan\u0131lamaz \u2014 e\u015Fitlik i\xE7in \xE7\u0131plak bi\xE7imi kullan\u0131n: { ${col}: now() }`);
2143
+ }
2144
+ parts.push(`${q} ${WHERE_OPS[op]} now()`);
2145
+ } else if (isColumnExpr(v)) {
2146
+ throw new Error(`${caller}(${table}): where.${col}.${op} bir YAZMA ifadesi ald\u0131 (increment/decrement) \u2014 kar\u015F\u0131la\u015Ft\u0131rma de\u011Feri de\u011Fil. Sunucu saati i\xE7in now() kullan\u0131n; say\u0131sal bir e\u015Fik i\xE7in de\u011Feri yaz\u0131n.`);
2094
2147
  } else if (isColRef(v)) {
2095
2148
  if (!(op in WHERE_OPS)) {
2096
2149
  throw new Error(`${caller}(${table}): where.${col}.${op} col() ile kullan\u0131lamaz \u2014 e\u015Fitlik i\xE7in \xE7\u0131plak bi\xE7imi kullan\u0131n: { ${col}: col("\u2026") }`);
@@ -2098,7 +2151,9 @@ function compileWhereBare(table, colSet, where, add, caller = "search", alias =
2098
2151
  parts.push(`${q} ${WHERE_OPS[op]} ${colRefSql(table, colSet, v, caller, alias)}`);
2099
2152
  } else if (looksLikeUnbrandedRef(v) !== null) {
2100
2153
  const kind = looksLikeUnbrandedRef(v);
2101
- throw new Error(`${caller}(${table}): where.${col}.${op} bir ${kind === "col" ? "col()" : "sqlFragment"} TAKL\u0130D\u0130 ald\u0131 \u2014 bu nesne bu s\xFCre\xE7te ${kind === "col" ? "col()" : "sqlFragment"} ile \xFCretilmemi\u015F. \u0130stek g\xF6vdesinden gelen bir filtre i\u015Faret\xE7i TA\u015EIYAMAZ; kolon kar\u015F\u0131la\u015Ft\u0131rmas\u0131n\u0131 kendi kodunuzda ${kind === "col" ? 'col("kolon_ad\u0131")' : "sqlFragment`\u2026`"} ile kurun.`);
2154
+ const made = kind === "col" ? "col()" : kind === "sql" ? "sqlFragment" : "now()";
2155
+ const how = kind === "col" ? 'col("kolon_ad\u0131")' : kind === "sql" ? "sqlFragment`\u2026`" : "now()";
2156
+ throw new Error(`${caller}(${table}): where.${col}.${op} bir ${made} TAKL\u0130D\u0130 ald\u0131 \u2014 bu nesne bu s\xFCre\xE7te ${made} ile \xFCretilmemi\u015F. \u0130stek g\xF6vdesinden gelen bir filtre i\u015Faret\xE7i TA\u015EIYAMAZ; ko\u015Fulu kendi kodunuzda ${how} ile kurun.`);
2102
2157
  } else if (op in WHERE_OPS) {
2103
2158
  if (v === null && op === "neq") {
2104
2159
  parts.push(`${q} IS NOT NULL`);
@@ -2203,6 +2258,37 @@ async function embedQuery(embed, text) {
2203
2258
  }
2204
2259
  }
2205
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");
2206
2292
  function createOps(tx) {
2207
2293
  const at = /* @__PURE__ */ __name(() => resolveTx(tx), "at");
2208
2294
  const ops = {
@@ -2216,9 +2302,11 @@ function createOps(tx) {
2216
2302
  async insert(table, data) {
2217
2303
  const cols = Object.keys(data);
2218
2304
  if (cols.length === 0) throw new Error(`insert into ${table}: no columns given`);
2219
- const placeholders = cols.map((_, i) => `$${i + 1}`).join(", ");
2220
- const sql = `INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${placeholders}) RETURNING *`;
2221
- const rows = await (await at()).unsafe(sql, asBindParams(table, cols, data, "insert"));
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);
2222
2310
  const inserted = rows[0];
2223
2311
  if (!inserted) {
2224
2312
  throw new Error(`insert into ${table} returned no row \u2014 the write was rejected (an RLS policy, most likely).`);
@@ -2226,6 +2314,41 @@ function createOps(tx) {
2226
2314
  return asTableRow(table, inserted);
2227
2315
  },
2228
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
+ /**
2229
2352
  * Bir ADI kilitle — satırı değil (FR-054).
2230
2353
  *
2231
2354
  * "Aynı anda tek bir fatura kapanışı koşsun" gibi, kilitlenecek satırı
@@ -2311,8 +2434,10 @@ function createOps(tx) {
2311
2434
  const live = await at();
2312
2435
  try {
2313
2436
  return await live.savepoint(async (sp) => {
2314
- const placeholders = cols.map((_, i) => `$${i + 1}`).join(", ");
2315
- const rows = await sp.unsafe(`INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${placeholders}) RETURNING *`, asBindParams(table, cols, data, "claim"));
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);
2316
2441
  if (!rows[0]) {
2317
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).`);
2318
2443
  }
@@ -2363,10 +2488,11 @@ function createOps(tx) {
2363
2488
  const cols = Object.keys(data);
2364
2489
  if (cols.length === 0) throw new Error(`upsert into ${table}: no columns given`);
2365
2490
  if (searchConfigFor(table)?.validity) {
2366
- const ph = cols.map((_, i) => `$${i + 1}`).join(", ");
2491
+ const bindData = [];
2492
+ const addPut = /* @__PURE__ */ __name((v) => `$${bindData.push(v)}`, "addPut");
2493
+ const ph = buildValueTuple(table, cols, data, addPut, "put");
2367
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 *`;
2368
2495
  const live = await at();
2369
- const bindData = asBindParams(table, cols, data, "put");
2370
2496
  const first = await live.unsafe(insertSql, bindData);
2371
2497
  if (first[0]) return asTableRow(table, first[0]);
2372
2498
  const condSql = conflict.map((c, i) => `${quoteIdent(c)} = $${i + 1}`).join(" AND ");
@@ -2391,12 +2517,14 @@ function createOps(tx) {
2391
2517
  ]);
2392
2518
  return asTableRow(table, second[0]);
2393
2519
  }
2394
- const placeholders = cols.map((_, i) => `$${i + 1}`).join(", ");
2520
+ const params = [];
2521
+ const add = /* @__PURE__ */ __name((v) => `$${params.push(v)}`, "add");
2522
+ const placeholders = buildValueTuple(table, cols, data, add, "put");
2395
2523
  const conflictSet = new Set(conflict);
2396
2524
  const assignments = cols.filter((c) => !conflictSet.has(c)).map((c) => `${quoteIdent(c)} = EXCLUDED.${quoteIdent(c)}`);
2397
2525
  const action = assignments.length ? `DO UPDATE SET ${assignments.join(", ")}` : `DO UPDATE SET ${quoteIdent(conflict[0])} = EXCLUDED.${quoteIdent(conflict[0])}`;
2398
2526
  const sql = `INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${placeholders}) ON CONFLICT (${conflict.map(quoteIdent).join(", ")}) ${action} RETURNING *`;
2399
- const rows = await (await at()).unsafe(sql, asBindParams(table, cols, data, "put"));
2527
+ const rows = await (await at()).unsafe(sql, params);
2400
2528
  const row = rows[0];
2401
2529
  if (!row) {
2402
2530
  throw new Error(`upsert into ${table} returned no row \u2014 the write was rejected (an RLS policy, most likely).`);
@@ -2407,12 +2535,14 @@ function createOps(tx) {
2407
2535
  assertNotAppendOnly("update", table);
2408
2536
  const cols = Object.keys(data);
2409
2537
  if (cols.length === 0) return ops.findById(table, id);
2410
- const assignments = cols.map((c, i) => `${quoteIdent(c)} = $${i + 1}`).join(", ");
2411
- const sql = `UPDATE ${quoteTable(table)} SET ${assignments} WHERE id = $${cols.length + 1} RETURNING *`;
2412
- const rows = await (await at()).unsafe(sql, [
2413
- ...asBindParams(table, cols, data, "update"),
2414
- id
2415
- ]);
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);
2416
2546
  return rows[0] ? asTableRow(table, rows[0]) : null;
2417
2547
  },
2418
2548
  async delete(table, id) {
@@ -2458,21 +2588,7 @@ function createOps(tx) {
2458
2588
  params.push(v);
2459
2589
  return `$${params.length}`;
2460
2590
  }, "add");
2461
- const assignments = cols.map((c) => {
2462
- const expr = columnExprOf(set[c]);
2463
- if (expr !== null && expr.fn === "now") {
2464
- return `${quoteIdent(c)} = now()`;
2465
- }
2466
- if (expr !== null) {
2467
- const operator = expr.fn === "inc" ? "+" : "-";
2468
- const t = transformsOf(currentSchema, table).get(c);
2469
- const amount = t?.toDb === void 0 || expr.by === null || expr.by === void 0 ? expr.by : t.toDb(expr.by);
2470
- return `${quoteIdent(c)} = ${quoteIdent(c)} ${operator} ${add(amount)}`;
2471
- }
2472
- return `${quoteIdent(c)} = ${add(asBindParams(table, [
2473
- c
2474
- ], set, "updateMany")[0])}`;
2475
- }).join(", ");
2591
+ const assignments = buildSetAssignments(table, cols, set, add, "updateMany");
2476
2592
  const whereSql = compileWhere(table, known, where, add, "updateMany");
2477
2593
  assertHasPredicate(whereSql, "updateMany", table);
2478
2594
  const pk = primaryKeyOf(table);
@@ -2930,8 +3046,10 @@ function createOps(tx) {
2930
3046
  [cfg.pk]: newId
2931
3047
  };
2932
3048
  const cols = Object.keys(data);
2933
- const placeholders = cols.map((_, i) => `$${i + 1}`).join(", ");
2934
- const rows = await sp.unsafe(`INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${placeholders}) RETURNING *`, asBindParams(table, cols, data, "supersede"));
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);
2935
3053
  if (!rows[0]) {
2936
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)`);
2937
3055
  }
@@ -3887,6 +4005,14 @@ var DiError = class extends Error {
3887
4005
  path;
3888
4006
  at;
3889
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;
3890
4016
  constructor(kind, path, at, detail, fixes) {
3891
4017
  super(`
3892
4018
  Kind: ${kind}
@@ -4302,7 +4428,7 @@ async function createApp(opts) {
4302
4428
  assertNoOrphanEntryPoints(controllers, container.owned);
4303
4429
  const routes = buildRouteTable(controllers, liveContainer);
4304
4430
  if (routes.length === 0) {
4305
- throw new BootRefused([], "boot refused: zero endpoints collected \u2014 nothing would answer.");
4431
+ throw new DeclarationRefused("boot refused: zero endpoints collected \u2014 nothing would answer.");
4306
4432
  }
4307
4433
  const sql = opts.sql ?? await defaultSqlDriver(config);
4308
4434
  await sql.unsafe("select 1");