@palbase/backend 24.0.0 → 24.0.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.
@@ -1374,11 +1374,17 @@ function offsetClause(offset, limit) {
1374
1374
  }
1375
1375
  function compileWhere(table, colSet, where, add, caller = "search") {
1376
1376
  const parts = [];
1377
+ const transforms = transformsOf(currentSchema, table);
1378
+ const bindFor = (col) => {
1379
+ const t = transforms.get(col);
1380
+ return t?.toDb === void 0 ? add : (v) => add(v === null || v === void 0 ? v : t.toDb(v));
1381
+ };
1377
1382
  for (const [col, cond] of Object.entries(where)) {
1378
1383
  if (colSet !== null && !colSet.has(col)) {
1379
1384
  throw new Error(`${caller}(${table}): where kolonu "${col}" tabloda yok (FR-016)`);
1380
1385
  }
1381
1386
  const q = `t.${quoteIdent(col)}`;
1387
+ const bind = bindFor(col);
1382
1388
  if (cond !== null && typeof cond === "object" && !Array.isArray(cond)) {
1383
1389
  for (const [op, v] of Object.entries(cond)) {
1384
1390
  if (op === "in") {
@@ -1387,15 +1393,15 @@ function compileWhere(table, colSet, where, add, caller = "search") {
1387
1393
  parts.push("false");
1388
1394
  continue;
1389
1395
  }
1390
- parts.push(`${q} IN (${v.map((x) => add(x)).join(", ")})`);
1396
+ parts.push(`${q} IN (${v.map((x) => bind(x)).join(", ")})`);
1391
1397
  } else if (op in WHERE_OPS) {
1392
- parts.push(`${q} ${WHERE_OPS[op]} ${add(v)}`);
1398
+ parts.push(`${q} ${WHERE_OPS[op]} ${bind(v)}`);
1393
1399
  } else {
1394
1400
  throw new Error(`${caller}(${table}): where.${col} bilinmeyen operat\xF6r "${op}" (gt/gte/lt/lte/neq/in)`);
1395
1401
  }
1396
1402
  }
1397
1403
  } else {
1398
- parts.push(`${q} = ${add(cond)}`);
1404
+ parts.push(`${q} = ${bind(cond)}`);
1399
1405
  }
1400
1406
  }
1401
1407
  return parts.length === 0 ? "" : ` AND ${parts.join(" AND ")}`;
@@ -1594,10 +1600,9 @@ function createOps(tx) {
1594
1600
  */
1595
1601
  async updateMany(table, where, set) {
1596
1602
  const cols = Object.keys(set);
1597
- if (cols.length === 0) return [];
1598
- if (Object.keys(where).length === 0) {
1603
+ if (cols.length === 0) {
1599
1604
  throw new Error(
1600
- `updateMany(${table}): bo\u015F filtre T\xDCM sat\u0131rlar\u0131 g\xFCncellerdi \u2014 bir filtre verin, ya da her sat\u0131ra uyan bir ko\u015Ful yaz\u0131n`
1605
+ `updateMany(${table}): nothing to set. An update with no columns is not a no-op worth pretending happened \u2014 pass the columns to write.`
1601
1606
  );
1602
1607
  }
1603
1608
  const params = [];
@@ -1608,6 +1613,7 @@ function createOps(tx) {
1608
1613
  const assignments = cols.map((c) => `${quoteIdent(c)} = ${add(asBindParams(table, [c], set)[0])}`).join(", ");
1609
1614
  const known = schemaColumns(table);
1610
1615
  const whereSql = compileWhere(table, known, where, add, "updateMany");
1616
+ assertHasPredicate(whereSql, "updateMany", table);
1611
1617
  const sql = `UPDATE ${quoteIdent(table)} AS t SET ${assignments} WHERE true${whereSql} RETURNING *`;
1612
1618
  return asTableRows(table, await (await at()).unsafe(sql, params));
1613
1619
  },
@@ -1617,11 +1623,6 @@ function createOps(tx) {
1617
1623
  * {@link updateMany} — and here the accident is worse.
1618
1624
  */
1619
1625
  async deleteMany(table, where) {
1620
- if (Object.keys(where).length === 0) {
1621
- throw new Error(
1622
- `deleteMany(${table}): bo\u015F filtre T\xDCM sat\u0131rlar\u0131 silerdi \u2014 bir filtre verin, ya da her sat\u0131ra uyan bir ko\u015Ful yaz\u0131n`
1623
- );
1624
- }
1625
1626
  const params = [];
1626
1627
  const add = (v) => {
1627
1628
  params.push(v);
@@ -1629,6 +1630,7 @@ function createOps(tx) {
1629
1630
  };
1630
1631
  const known = schemaColumns(table);
1631
1632
  const whereSql = compileWhere(table, known, where, add, "deleteMany");
1633
+ assertHasPredicate(whereSql, "deleteMany", table);
1632
1634
  const sql = `DELETE FROM ${quoteIdent(table)} AS t WHERE true${whereSql} RETURNING 1`;
1633
1635
  const rows = await (await at()).unsafe(sql, params);
1634
1636
  return rows.length;
@@ -2179,6 +2181,12 @@ function isAbortedTransaction(e) {
2179
2181
  const message = String(e?.message ?? "");
2180
2182
  return sqlstateOf(e) === "25P02" || /current transaction is aborted/i.test(message);
2181
2183
  }
2184
+ function assertHasPredicate(whereSql, op, table) {
2185
+ if (whereSql.trim().length > 0) return;
2186
+ throw new Error(
2187
+ `${op}(${table}): the filter compiled to no condition, so this would have written EVERY row. An empty filter \u2014 or an operator object with no operators in it, like { col: {} } \u2014 is refused. Name a condition.`
2188
+ );
2189
+ }
2182
2190
  function sqlstateOf(e) {
2183
2191
  const err = e;
2184
2192
  const isState = (v) => typeof v === "string" && /^[0-9A-Z]{5}$/.test(v);
@@ -2287,7 +2295,7 @@ function isRef(v) {
2287
2295
  function isExpr(v) {
2288
2296
  return typeof v === "object" && v !== null && "$expr" in v;
2289
2297
  }
2290
- function renderValue(value, column, args, results, vectorCols) {
2298
+ function renderValue(value, column, args, results, vectorCols, transforms) {
2291
2299
  if (isRef(value)) {
2292
2300
  const source = results[value.$ref.op];
2293
2301
  const row = source?.rows[0];
@@ -2296,15 +2304,15 @@ function renderValue(value, column, args, results, vectorCols) {
2296
2304
  error_code: "tx_ref_unresolved"
2297
2305
  });
2298
2306
  }
2299
- return bindMaybeVector(args, column, vectorCols, row[value.$ref.field]);
2307
+ return bindMaybeVector(args, column, vectorCols, row[value.$ref.field], transforms);
2300
2308
  }
2301
2309
  if (isExpr(value)) {
2302
2310
  const fn = value.$expr;
2303
2311
  if (fn.fn === "now") return "now()";
2304
2312
  const operator = fn.fn === "inc" ? "+" : "-";
2305
- return `${quoteIdent(column)} ${operator} ${bindMaybeVector(args, column, vectorCols, fn.by)}`;
2313
+ return `${quoteIdent(column)} ${operator} ${bindMaybeVector(args, column, vectorCols, fn.by, transforms)}`;
2306
2314
  }
2307
- return bindMaybeVector(args, column, vectorCols, value);
2315
+ return bindMaybeVector(args, column, vectorCols, value, transforms);
2308
2316
  }
2309
2317
  function renderWhere(where, args, results) {
2310
2318
  const cols = Object.keys(where ?? {});
@@ -2316,21 +2324,26 @@ function renderWhere(where, args, results) {
2316
2324
  });
2317
2325
  return ` WHERE ${terms.join(" AND ")}`;
2318
2326
  }
2319
- function bindMaybeVector(args, column, vectorCols, value) {
2327
+ function bindMaybeVector(args, column, vectorCols, value, transforms) {
2320
2328
  if (column !== void 0 && vectorCols?.has(column) && Array.isArray(value)) {
2321
2329
  return args.bind(toVectorLiteral(value));
2322
2330
  }
2331
+ const t = column !== void 0 ? transforms?.get(column) : void 0;
2332
+ if (t?.toDb !== void 0 && value !== null && value !== void 0) {
2333
+ return args.bind(t.toDb(value));
2334
+ }
2323
2335
  return args.bind(value);
2324
2336
  }
2325
2337
  async function runPlanOp(sp, op, results) {
2326
2338
  const opVectorCols = vectorColumnsOf(currentSchema, op.table);
2339
+ const opTransforms = transformsOf(currentSchema, op.table);
2327
2340
  const args = new Args();
2328
2341
  const table = quoteIdent(op.table);
2329
2342
  let sql;
2330
2343
  switch (op.op) {
2331
2344
  case "insert": {
2332
2345
  const cols = Object.keys(op.values ?? {});
2333
- const rendered = cols.map((c) => renderValue(op.values[c], c, args, results, opVectorCols));
2346
+ const rendered = cols.map((c) => renderValue(op.values[c], c, args, results, opVectorCols, opTransforms));
2334
2347
  sql = cols.length ? `INSERT INTO ${table} (${cols.map(quoteIdent).join(", ")}) VALUES (${rendered.join(", ")}) RETURNING *` : `INSERT INTO ${table} DEFAULT VALUES RETURNING *`;
2335
2348
  break;
2336
2349
  }
@@ -2343,7 +2356,7 @@ async function runPlanOp(sp, op, results) {
2343
2356
  });
2344
2357
  }
2345
2358
  const rendered = cols.map(
2346
- (c) => renderValue(op.values[c], c, args, results, opVectorCols)
2359
+ (c) => renderValue(op.values[c], c, args, results, opVectorCols, opTransforms)
2347
2360
  );
2348
2361
  sql = `INSERT INTO ${table} (${cols.map(quoteIdent).join(", ")}) VALUES (${rendered.join(", ")}) ${onConflictTail(cols, conflict, "update")} RETURNING *`;
2349
2362
  break;
@@ -2353,7 +2366,7 @@ async function runPlanOp(sp, op, results) {
2353
2366
  if (rows.length === 0 || !rows[0]) return [];
2354
2367
  const cols = Object.keys(rows[0]);
2355
2368
  const tuples = rows.map(
2356
- (r) => `(${cols.map((c) => renderValue(r[c], c, args, results, opVectorCols)).join(", ")})`
2369
+ (r) => `(${cols.map((c) => renderValue(r[c], c, args, results, opVectorCols, opTransforms)).join(", ")})`
2357
2370
  );
2358
2371
  const conflictCols = op.onConflict ?? [];
2359
2372
  const tail = op.action !== void 0 && conflictCols.length > 0 ? ` ${onConflictTail(cols, conflictCols, op.action)}` : "";
@@ -2364,7 +2377,7 @@ async function runPlanOp(sp, op, results) {
2364
2377
  const cols = Object.keys(op.set ?? {});
2365
2378
  if (cols.length === 0) throw new Error(`update ${op.table}: nothing to set`);
2366
2379
  const assignments = cols.map(
2367
- (c) => `${quoteIdent(c)} = ${renderValue(op.set[c], c, args, results, opVectorCols)}`
2380
+ (c) => `${quoteIdent(c)} = ${renderValue(op.set[c], c, args, results, opVectorCols, opTransforms)}`
2368
2381
  );
2369
2382
  sql = `UPDATE ${table} SET ${assignments.join(", ")}${renderWhere(op.where, args, results)} RETURNING *`;
2370
2383
  break;