@objectstack/driver-sql 9.8.0 → 9.9.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/index.mjs CHANGED
@@ -7,6 +7,22 @@ import { createHash } from "crypto";
7
7
  var DEFAULT_ID_LENGTH = 16;
8
8
  var SEQUENCES_TABLE = "_objectstack_sequences";
9
9
  var GLOBAL_TENANT = "__global__";
10
+ var JSON_COLUMN_TYPES = /* @__PURE__ */ new Set([
11
+ "json",
12
+ "object",
13
+ "array",
14
+ "image",
15
+ "file",
16
+ "avatar",
17
+ "location",
18
+ "address",
19
+ "composite",
20
+ "multiselect",
21
+ "checkboxes",
22
+ "tags",
23
+ "repeater",
24
+ "vector"
25
+ ]);
10
26
  var SqlDriver = class {
11
27
  constructor(config) {
12
28
  // IDataDriver metadata
@@ -293,10 +309,8 @@ var SqlDriver = class {
293
309
  if (!Array.isArray(results)) {
294
310
  return [];
295
311
  }
296
- if (this.isSqlite) {
297
- for (const row of results) {
298
- this.formatOutput(object, row);
299
- }
312
+ for (const row of results) {
313
+ this.formatOutput(object, row);
300
314
  }
301
315
  return results;
302
316
  }
@@ -1125,6 +1139,30 @@ var SqlDriver = class {
1125
1139
  if (typeof t === "string") return t;
1126
1140
  return null;
1127
1141
  }
1142
+ /**
1143
+ * Collapse a `Field.date` value to a timezone-naive `YYYY-MM-DD`
1144
+ * calendar-day string (ADR-0053 Phase 1). A `Date` collapses to its UTC
1145
+ * calendar day; a string keeps its leading date and drops any time
1146
+ * component. Anything else (and `null`/`undefined`) passes through
1147
+ * unchanged. This is the single source of truth for date-only truncation,
1148
+ * shared by the filter (`coerceFilterValue`), write (`formatInput`) and
1149
+ * read (`formatOutput`) paths so all three agree on what a date *is*.
1150
+ */
1151
+ toDateOnly(value) {
1152
+ if (value == null) return value;
1153
+ if (value instanceof Date) {
1154
+ if (Number.isNaN(value.getTime())) return value;
1155
+ const y = value.getUTCFullYear();
1156
+ const m = String(value.getUTCMonth() + 1).padStart(2, "0");
1157
+ const d = String(value.getUTCDate()).padStart(2, "0");
1158
+ return `${y}-${m}-${d}`;
1159
+ }
1160
+ if (typeof value === "string") {
1161
+ const trimmed = value.trim();
1162
+ if (/^\d{4}-\d{2}-\d{2}/.test(trimmed)) return trimmed.slice(0, 10);
1163
+ }
1164
+ return value;
1165
+ }
1128
1166
  /**
1129
1167
  * Normalise a filter value for a single column so the comparison the
1130
1168
  * driver sends to SQLite matches the on-disk representation.
@@ -1166,17 +1204,7 @@ var SqlDriver = class {
1166
1204
  const ms = toMs(value);
1167
1205
  return ms == null ? value : ms;
1168
1206
  }
1169
- if (value instanceof Date) {
1170
- const y = value.getUTCFullYear();
1171
- const m = String(value.getUTCMonth() + 1).padStart(2, "0");
1172
- const d = String(value.getUTCDate()).padStart(2, "0");
1173
- return `${y}-${m}-${d}`;
1174
- }
1175
- if (typeof value === "string") {
1176
- const trimmed = value.trim();
1177
- if (/^\d{4}-\d{2}-\d{2}/.test(trimmed)) return trimmed.slice(0, 10);
1178
- }
1179
- return value;
1207
+ return this.toDateOnly(value);
1180
1208
  }
1181
1209
  applyFilters(builder, filters) {
1182
1210
  if (!filters) return;
@@ -1420,6 +1448,13 @@ var SqlDriver = class {
1420
1448
  case "file":
1421
1449
  case "avatar":
1422
1450
  case "location":
1451
+ case "address":
1452
+ case "composite":
1453
+ case "multiselect":
1454
+ case "checkboxes":
1455
+ case "tags":
1456
+ case "repeater":
1457
+ case "vector":
1423
1458
  col = table.json(name);
1424
1459
  break;
1425
1460
  case "lookup":
@@ -1523,7 +1558,7 @@ var SqlDriver = class {
1523
1558
  }
1524
1559
  }
1525
1560
  isJsonField(type, field) {
1526
- return ["json", "object", "array", "image", "file", "avatar", "location"].includes(type) || field.multiple;
1561
+ return JSON_COLUMN_TYPES.has(type) || !!field.multiple;
1527
1562
  }
1528
1563
  // ── SQLite serialisation ────────────────────────────────────────────────────
1529
1564
  formatInput(object, data) {
@@ -1542,16 +1577,42 @@ var SqlDriver = class {
1542
1577
  }
1543
1578
  }
1544
1579
  }
1580
+ const dateFields = this.dateFields[object];
1581
+ if (dateFields && dateFields.size > 0 && copy && typeof copy === "object") {
1582
+ for (const field of dateFields) {
1583
+ const v = copy[field];
1584
+ if (v == null) continue;
1585
+ const normalized = this.toDateOnly(v);
1586
+ if (normalized !== v) {
1587
+ if (!copied) {
1588
+ copy = { ...copy };
1589
+ copied = true;
1590
+ }
1591
+ copy[field] = normalized;
1592
+ }
1593
+ }
1594
+ }
1545
1595
  if (!this.isSqlite) return copy;
1546
1596
  const fields = this.jsonFields[object];
1547
- if (!fields || fields.length === 0) return copy;
1548
- if (!copied) {
1549
- copy = { ...copy };
1550
- copied = true;
1551
- }
1552
- for (const field of fields) {
1553
- if (copy[field] !== void 0 && typeof copy[field] === "object" && copy[field] !== null) {
1554
- copy[field] = JSON.stringify(copy[field]);
1597
+ if (fields && fields.length > 0) {
1598
+ if (!copied) {
1599
+ copy = { ...copy };
1600
+ copied = true;
1601
+ }
1602
+ for (const field of fields) {
1603
+ if (copy[field] !== void 0 && typeof copy[field] === "object" && copy[field] !== null) {
1604
+ copy[field] = JSON.stringify(copy[field]);
1605
+ }
1606
+ }
1607
+ }
1608
+ for (const key of Object.keys(copy)) {
1609
+ const v = copy[key];
1610
+ if (v !== null && typeof v === "object" && !(v instanceof Date) && !Buffer.isBuffer(v)) {
1611
+ if (!copied) {
1612
+ copy = { ...copy };
1613
+ copied = true;
1614
+ }
1615
+ copy[key] = JSON.stringify(v);
1555
1616
  }
1556
1617
  }
1557
1618
  return copy;
@@ -1579,6 +1640,15 @@ var SqlDriver = class {
1579
1640
  }
1580
1641
  }
1581
1642
  }
1643
+ const dateFields = this.dateFields[object];
1644
+ if (dateFields && dateFields.size > 0) {
1645
+ for (const field of dateFields) {
1646
+ const v = data[field];
1647
+ if (v == null) continue;
1648
+ const normalized = this.toDateOnly(v);
1649
+ if (normalized !== v) data[field] = normalized;
1650
+ }
1651
+ }
1582
1652
  return data;
1583
1653
  }
1584
1654
  // ── Introspection internals ─────────────────────────────────────────────────