@atscript/db-sql-tools 0.1.83 → 0.1.85

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/index.cjs CHANGED
@@ -318,8 +318,19 @@ function buildSelect(dialect, table, where, controls) {
318
318
  }
319
319
  /**
320
320
  * Builds an UPDATE ... SET ... WHERE statement with optional LIMIT.
321
+ *
322
+ * Optimistic concurrency control (OCC) hooks:
323
+ * - `versionColumn` — when supplied, the builder appends
324
+ * `<col> = <col> + 1` to the SET list. The bump is **mandatory** whenever
325
+ * `versionColumn` is set, regardless of whether `expectedVersion` is
326
+ * supplied. If the version column doesn't auto-increment on every write,
327
+ * OCC silently degrades to no protection.
328
+ * - `expectedVersion` — when supplied, the builder appends
329
+ * `AND <col> = ?` to the WHERE clause and pushes the value. Requires
330
+ * `versionColumn` (CAS targets that column); supplying `expectedVersion`
331
+ * without `versionColumn` is a programmer error and throws.
321
332
  */
322
- function buildUpdate(dialect, table, data, where, limit, ops) {
333
+ function buildUpdate(dialect, table, data, where, limit, ops, versionColumn, expectedVersion) {
323
334
  const setClauses = [];
324
335
  const params = [];
325
336
  for (const [key, value] of Object.entries(data)) {
@@ -336,11 +347,26 @@ function buildUpdate(dialect, table, data, where, limit, ops) {
336
347
  setClauses.push(`${col} = ${col} * ?`);
337
348
  params.push(ops.mul[key]);
338
349
  }
339
- let sql = `UPDATE ${dialect.quoteTable(table)} SET ${setClauses.join(", ")} WHERE ${where.sql}`;
350
+ if (expectedVersion !== void 0 && versionColumn === void 0) throw new Error("buildUpdate: expectedVersion requires versionColumn");
351
+ let whereSql = where.sql;
352
+ const whereParams = [];
353
+ if (versionColumn !== void 0) {
354
+ const vcol = dialect.quoteIdentifier(versionColumn);
355
+ setClauses.push(`${vcol} = ${vcol} + 1`);
356
+ if (expectedVersion !== void 0) {
357
+ whereSql += ` AND ${vcol} = ?`;
358
+ whereParams.push(expectedVersion);
359
+ }
360
+ }
361
+ let sql = `UPDATE ${dialect.quoteTable(table)} SET ${setClauses.join(", ")} WHERE ${whereSql}`;
340
362
  if (limit !== void 0) sql += ` LIMIT ${limit}`;
341
363
  return finalizeParams(dialect, {
342
364
  sql,
343
- params: [...params, ...where.params]
365
+ params: [
366
+ ...params,
367
+ ...where.params,
368
+ ...whereParams
369
+ ]
344
370
  });
345
371
  }
346
372
  /**
package/dist/index.d.cts CHANGED
@@ -53,8 +53,19 @@ declare function buildInsert(dialect: SqlDialect, table: string, data: Record<st
53
53
  declare function buildSelect(dialect: SqlDialect, table: string, where: TSqlFragment, controls?: DbControls): TSqlFragment;
54
54
  /**
55
55
  * Builds an UPDATE ... SET ... WHERE statement with optional LIMIT.
56
+ *
57
+ * Optimistic concurrency control (OCC) hooks:
58
+ * - `versionColumn` — when supplied, the builder appends
59
+ * `<col> = <col> + 1` to the SET list. The bump is **mandatory** whenever
60
+ * `versionColumn` is set, regardless of whether `expectedVersion` is
61
+ * supplied. If the version column doesn't auto-increment on every write,
62
+ * OCC silently degrades to no protection.
63
+ * - `expectedVersion` — when supplied, the builder appends
64
+ * `AND <col> = ?` to the WHERE clause and pushes the value. Requires
65
+ * `versionColumn` (CAS targets that column); supplying `expectedVersion`
66
+ * without `versionColumn` is a programmer error and throws.
56
67
  */
57
- declare function buildUpdate(dialect: SqlDialect, table: string, data: Record<string, unknown>, where: TSqlFragment, limit?: number, ops?: TFieldOps): TSqlFragment;
68
+ declare function buildUpdate(dialect: SqlDialect, table: string, data: Record<string, unknown>, where: TSqlFragment, limit?: number, ops?: TFieldOps, versionColumn?: string, expectedVersion?: number): TSqlFragment;
58
69
  /**
59
70
  * Builds a DELETE ... WHERE statement with optional LIMIT.
60
71
  */
package/dist/index.d.mts CHANGED
@@ -53,8 +53,19 @@ declare function buildInsert(dialect: SqlDialect, table: string, data: Record<st
53
53
  declare function buildSelect(dialect: SqlDialect, table: string, where: TSqlFragment, controls?: DbControls): TSqlFragment;
54
54
  /**
55
55
  * Builds an UPDATE ... SET ... WHERE statement with optional LIMIT.
56
+ *
57
+ * Optimistic concurrency control (OCC) hooks:
58
+ * - `versionColumn` — when supplied, the builder appends
59
+ * `<col> = <col> + 1` to the SET list. The bump is **mandatory** whenever
60
+ * `versionColumn` is set, regardless of whether `expectedVersion` is
61
+ * supplied. If the version column doesn't auto-increment on every write,
62
+ * OCC silently degrades to no protection.
63
+ * - `expectedVersion` — when supplied, the builder appends
64
+ * `AND <col> = ?` to the WHERE clause and pushes the value. Requires
65
+ * `versionColumn` (CAS targets that column); supplying `expectedVersion`
66
+ * without `versionColumn` is a programmer error and throws.
56
67
  */
57
- declare function buildUpdate(dialect: SqlDialect, table: string, data: Record<string, unknown>, where: TSqlFragment, limit?: number, ops?: TFieldOps): TSqlFragment;
68
+ declare function buildUpdate(dialect: SqlDialect, table: string, data: Record<string, unknown>, where: TSqlFragment, limit?: number, ops?: TFieldOps, versionColumn?: string, expectedVersion?: number): TSqlFragment;
58
69
  /**
59
70
  * Builds a DELETE ... WHERE statement with optional LIMIT.
60
71
  */
package/dist/index.mjs CHANGED
@@ -317,8 +317,19 @@ function buildSelect(dialect, table, where, controls) {
317
317
  }
318
318
  /**
319
319
  * Builds an UPDATE ... SET ... WHERE statement with optional LIMIT.
320
+ *
321
+ * Optimistic concurrency control (OCC) hooks:
322
+ * - `versionColumn` — when supplied, the builder appends
323
+ * `<col> = <col> + 1` to the SET list. The bump is **mandatory** whenever
324
+ * `versionColumn` is set, regardless of whether `expectedVersion` is
325
+ * supplied. If the version column doesn't auto-increment on every write,
326
+ * OCC silently degrades to no protection.
327
+ * - `expectedVersion` — when supplied, the builder appends
328
+ * `AND <col> = ?` to the WHERE clause and pushes the value. Requires
329
+ * `versionColumn` (CAS targets that column); supplying `expectedVersion`
330
+ * without `versionColumn` is a programmer error and throws.
320
331
  */
321
- function buildUpdate(dialect, table, data, where, limit, ops) {
332
+ function buildUpdate(dialect, table, data, where, limit, ops, versionColumn, expectedVersion) {
322
333
  const setClauses = [];
323
334
  const params = [];
324
335
  for (const [key, value] of Object.entries(data)) {
@@ -335,11 +346,26 @@ function buildUpdate(dialect, table, data, where, limit, ops) {
335
346
  setClauses.push(`${col} = ${col} * ?`);
336
347
  params.push(ops.mul[key]);
337
348
  }
338
- let sql = `UPDATE ${dialect.quoteTable(table)} SET ${setClauses.join(", ")} WHERE ${where.sql}`;
349
+ if (expectedVersion !== void 0 && versionColumn === void 0) throw new Error("buildUpdate: expectedVersion requires versionColumn");
350
+ let whereSql = where.sql;
351
+ const whereParams = [];
352
+ if (versionColumn !== void 0) {
353
+ const vcol = dialect.quoteIdentifier(versionColumn);
354
+ setClauses.push(`${vcol} = ${vcol} + 1`);
355
+ if (expectedVersion !== void 0) {
356
+ whereSql += ` AND ${vcol} = ?`;
357
+ whereParams.push(expectedVersion);
358
+ }
359
+ }
360
+ let sql = `UPDATE ${dialect.quoteTable(table)} SET ${setClauses.join(", ")} WHERE ${whereSql}`;
339
361
  if (limit !== void 0) sql += ` LIMIT ${limit}`;
340
362
  return finalizeParams(dialect, {
341
363
  sql,
342
- params: [...params, ...where.params]
364
+ params: [
365
+ ...params,
366
+ ...where.params,
367
+ ...whereParams
368
+ ]
343
369
  });
344
370
  }
345
371
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/db-sql-tools",
3
- "version": "0.1.83",
3
+ "version": "0.1.85",
4
4
  "description": "Shared SQL builder utilities for @atscript database adapters.",
5
5
  "keywords": [
6
6
  "atscript",
@@ -42,7 +42,7 @@
42
42
  },
43
43
  "peerDependencies": {
44
44
  "@uniqu/core": "^0.1.6",
45
- "@atscript/db": "^0.1.83"
45
+ "@atscript/db": "^0.1.85"
46
46
  },
47
47
  "scripts": {
48
48
  "build": "vp pack",