@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.d.mts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +94 -24
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +94 -24
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -403,6 +403,16 @@ declare class SqlDriver implements IDataDriver {
|
|
|
403
403
|
* `initObjects`). Returns null when the builder is not table-scoped yet.
|
|
404
404
|
*/
|
|
405
405
|
protected tableNameForBuilder(builder: any): string | null;
|
|
406
|
+
/**
|
|
407
|
+
* Collapse a `Field.date` value to a timezone-naive `YYYY-MM-DD`
|
|
408
|
+
* calendar-day string (ADR-0053 Phase 1). A `Date` collapses to its UTC
|
|
409
|
+
* calendar day; a string keeps its leading date and drops any time
|
|
410
|
+
* component. Anything else (and `null`/`undefined`) passes through
|
|
411
|
+
* unchanged. This is the single source of truth for date-only truncation,
|
|
412
|
+
* shared by the filter (`coerceFilterValue`), write (`formatInput`) and
|
|
413
|
+
* read (`formatOutput`) paths so all three agree on what a date *is*.
|
|
414
|
+
*/
|
|
415
|
+
protected toDateOnly(value: any): any;
|
|
406
416
|
/**
|
|
407
417
|
* Normalise a filter value for a single column so the comparison the
|
|
408
418
|
* driver sends to SQLite matches the on-disk representation.
|
package/dist/index.d.ts
CHANGED
|
@@ -403,6 +403,16 @@ declare class SqlDriver implements IDataDriver {
|
|
|
403
403
|
* `initObjects`). Returns null when the builder is not table-scoped yet.
|
|
404
404
|
*/
|
|
405
405
|
protected tableNameForBuilder(builder: any): string | null;
|
|
406
|
+
/**
|
|
407
|
+
* Collapse a `Field.date` value to a timezone-naive `YYYY-MM-DD`
|
|
408
|
+
* calendar-day string (ADR-0053 Phase 1). A `Date` collapses to its UTC
|
|
409
|
+
* calendar day; a string keeps its leading date and drops any time
|
|
410
|
+
* component. Anything else (and `null`/`undefined`) passes through
|
|
411
|
+
* unchanged. This is the single source of truth for date-only truncation,
|
|
412
|
+
* shared by the filter (`coerceFilterValue`), write (`formatInput`) and
|
|
413
|
+
* read (`formatOutput`) paths so all three agree on what a date *is*.
|
|
414
|
+
*/
|
|
415
|
+
protected toDateOnly(value: any): any;
|
|
406
416
|
/**
|
|
407
417
|
* Normalise a filter value for a single column so the comparison the
|
|
408
418
|
* driver sends to SQLite matches the on-disk representation.
|
package/dist/index.js
CHANGED
|
@@ -44,6 +44,22 @@ var import_node_crypto = require("crypto");
|
|
|
44
44
|
var DEFAULT_ID_LENGTH = 16;
|
|
45
45
|
var SEQUENCES_TABLE = "_objectstack_sequences";
|
|
46
46
|
var GLOBAL_TENANT = "__global__";
|
|
47
|
+
var JSON_COLUMN_TYPES = /* @__PURE__ */ new Set([
|
|
48
|
+
"json",
|
|
49
|
+
"object",
|
|
50
|
+
"array",
|
|
51
|
+
"image",
|
|
52
|
+
"file",
|
|
53
|
+
"avatar",
|
|
54
|
+
"location",
|
|
55
|
+
"address",
|
|
56
|
+
"composite",
|
|
57
|
+
"multiselect",
|
|
58
|
+
"checkboxes",
|
|
59
|
+
"tags",
|
|
60
|
+
"repeater",
|
|
61
|
+
"vector"
|
|
62
|
+
]);
|
|
47
63
|
var SqlDriver = class {
|
|
48
64
|
constructor(config) {
|
|
49
65
|
// IDataDriver metadata
|
|
@@ -330,10 +346,8 @@ var SqlDriver = class {
|
|
|
330
346
|
if (!Array.isArray(results)) {
|
|
331
347
|
return [];
|
|
332
348
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
this.formatOutput(object, row);
|
|
336
|
-
}
|
|
349
|
+
for (const row of results) {
|
|
350
|
+
this.formatOutput(object, row);
|
|
337
351
|
}
|
|
338
352
|
return results;
|
|
339
353
|
}
|
|
@@ -1162,6 +1176,30 @@ var SqlDriver = class {
|
|
|
1162
1176
|
if (typeof t === "string") return t;
|
|
1163
1177
|
return null;
|
|
1164
1178
|
}
|
|
1179
|
+
/**
|
|
1180
|
+
* Collapse a `Field.date` value to a timezone-naive `YYYY-MM-DD`
|
|
1181
|
+
* calendar-day string (ADR-0053 Phase 1). A `Date` collapses to its UTC
|
|
1182
|
+
* calendar day; a string keeps its leading date and drops any time
|
|
1183
|
+
* component. Anything else (and `null`/`undefined`) passes through
|
|
1184
|
+
* unchanged. This is the single source of truth for date-only truncation,
|
|
1185
|
+
* shared by the filter (`coerceFilterValue`), write (`formatInput`) and
|
|
1186
|
+
* read (`formatOutput`) paths so all three agree on what a date *is*.
|
|
1187
|
+
*/
|
|
1188
|
+
toDateOnly(value) {
|
|
1189
|
+
if (value == null) return value;
|
|
1190
|
+
if (value instanceof Date) {
|
|
1191
|
+
if (Number.isNaN(value.getTime())) return value;
|
|
1192
|
+
const y = value.getUTCFullYear();
|
|
1193
|
+
const m = String(value.getUTCMonth() + 1).padStart(2, "0");
|
|
1194
|
+
const d = String(value.getUTCDate()).padStart(2, "0");
|
|
1195
|
+
return `${y}-${m}-${d}`;
|
|
1196
|
+
}
|
|
1197
|
+
if (typeof value === "string") {
|
|
1198
|
+
const trimmed = value.trim();
|
|
1199
|
+
if (/^\d{4}-\d{2}-\d{2}/.test(trimmed)) return trimmed.slice(0, 10);
|
|
1200
|
+
}
|
|
1201
|
+
return value;
|
|
1202
|
+
}
|
|
1165
1203
|
/**
|
|
1166
1204
|
* Normalise a filter value for a single column so the comparison the
|
|
1167
1205
|
* driver sends to SQLite matches the on-disk representation.
|
|
@@ -1203,17 +1241,7 @@ var SqlDriver = class {
|
|
|
1203
1241
|
const ms = toMs(value);
|
|
1204
1242
|
return ms == null ? value : ms;
|
|
1205
1243
|
}
|
|
1206
|
-
|
|
1207
|
-
const y = value.getUTCFullYear();
|
|
1208
|
-
const m = String(value.getUTCMonth() + 1).padStart(2, "0");
|
|
1209
|
-
const d = String(value.getUTCDate()).padStart(2, "0");
|
|
1210
|
-
return `${y}-${m}-${d}`;
|
|
1211
|
-
}
|
|
1212
|
-
if (typeof value === "string") {
|
|
1213
|
-
const trimmed = value.trim();
|
|
1214
|
-
if (/^\d{4}-\d{2}-\d{2}/.test(trimmed)) return trimmed.slice(0, 10);
|
|
1215
|
-
}
|
|
1216
|
-
return value;
|
|
1244
|
+
return this.toDateOnly(value);
|
|
1217
1245
|
}
|
|
1218
1246
|
applyFilters(builder, filters) {
|
|
1219
1247
|
if (!filters) return;
|
|
@@ -1457,6 +1485,13 @@ var SqlDriver = class {
|
|
|
1457
1485
|
case "file":
|
|
1458
1486
|
case "avatar":
|
|
1459
1487
|
case "location":
|
|
1488
|
+
case "address":
|
|
1489
|
+
case "composite":
|
|
1490
|
+
case "multiselect":
|
|
1491
|
+
case "checkboxes":
|
|
1492
|
+
case "tags":
|
|
1493
|
+
case "repeater":
|
|
1494
|
+
case "vector":
|
|
1460
1495
|
col = table.json(name);
|
|
1461
1496
|
break;
|
|
1462
1497
|
case "lookup":
|
|
@@ -1560,7 +1595,7 @@ var SqlDriver = class {
|
|
|
1560
1595
|
}
|
|
1561
1596
|
}
|
|
1562
1597
|
isJsonField(type, field) {
|
|
1563
|
-
return
|
|
1598
|
+
return JSON_COLUMN_TYPES.has(type) || !!field.multiple;
|
|
1564
1599
|
}
|
|
1565
1600
|
// ── SQLite serialisation ────────────────────────────────────────────────────
|
|
1566
1601
|
formatInput(object, data) {
|
|
@@ -1579,16 +1614,42 @@ var SqlDriver = class {
|
|
|
1579
1614
|
}
|
|
1580
1615
|
}
|
|
1581
1616
|
}
|
|
1617
|
+
const dateFields = this.dateFields[object];
|
|
1618
|
+
if (dateFields && dateFields.size > 0 && copy && typeof copy === "object") {
|
|
1619
|
+
for (const field of dateFields) {
|
|
1620
|
+
const v = copy[field];
|
|
1621
|
+
if (v == null) continue;
|
|
1622
|
+
const normalized = this.toDateOnly(v);
|
|
1623
|
+
if (normalized !== v) {
|
|
1624
|
+
if (!copied) {
|
|
1625
|
+
copy = { ...copy };
|
|
1626
|
+
copied = true;
|
|
1627
|
+
}
|
|
1628
|
+
copy[field] = normalized;
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1582
1632
|
if (!this.isSqlite) return copy;
|
|
1583
1633
|
const fields = this.jsonFields[object];
|
|
1584
|
-
if (
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1634
|
+
if (fields && fields.length > 0) {
|
|
1635
|
+
if (!copied) {
|
|
1636
|
+
copy = { ...copy };
|
|
1637
|
+
copied = true;
|
|
1638
|
+
}
|
|
1639
|
+
for (const field of fields) {
|
|
1640
|
+
if (copy[field] !== void 0 && typeof copy[field] === "object" && copy[field] !== null) {
|
|
1641
|
+
copy[field] = JSON.stringify(copy[field]);
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
for (const key of Object.keys(copy)) {
|
|
1646
|
+
const v = copy[key];
|
|
1647
|
+
if (v !== null && typeof v === "object" && !(v instanceof Date) && !Buffer.isBuffer(v)) {
|
|
1648
|
+
if (!copied) {
|
|
1649
|
+
copy = { ...copy };
|
|
1650
|
+
copied = true;
|
|
1651
|
+
}
|
|
1652
|
+
copy[key] = JSON.stringify(v);
|
|
1592
1653
|
}
|
|
1593
1654
|
}
|
|
1594
1655
|
return copy;
|
|
@@ -1616,6 +1677,15 @@ var SqlDriver = class {
|
|
|
1616
1677
|
}
|
|
1617
1678
|
}
|
|
1618
1679
|
}
|
|
1680
|
+
const dateFields = this.dateFields[object];
|
|
1681
|
+
if (dateFields && dateFields.size > 0) {
|
|
1682
|
+
for (const field of dateFields) {
|
|
1683
|
+
const v = data[field];
|
|
1684
|
+
if (v == null) continue;
|
|
1685
|
+
const normalized = this.toDateOnly(v);
|
|
1686
|
+
if (normalized !== v) data[field] = normalized;
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1619
1689
|
return data;
|
|
1620
1690
|
}
|
|
1621
1691
|
// ── Introspection internals ─────────────────────────────────────────────────
|