@objectstack/driver-sql 9.8.0 → 9.9.1
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.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
|
-
|
|
297
|
-
|
|
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
|
-
|
|
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
|
|
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 (
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
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 ─────────────────────────────────────────────────
|