@easy-cms/drizzle 0.5.0 → 0.6.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.ts +3 -0
- package/dist/index.js +85 -15
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -86,6 +86,9 @@ interface ChildModel {
|
|
|
86
86
|
readonly path: readonly string[];
|
|
87
87
|
readonly field: Field;
|
|
88
88
|
readonly table: TableModel;
|
|
89
|
+
/** Localized: rows carry `_locale`, and the data holds `{ [locale]: rows }`. */
|
|
90
|
+
readonly locales?: readonly string[];
|
|
91
|
+
readonly defaultLocale?: string;
|
|
89
92
|
}
|
|
90
93
|
interface TableModel {
|
|
91
94
|
readonly name: string;
|
package/dist/index.js
CHANGED
|
@@ -26,7 +26,12 @@ var columnPath = (column) => column.locale === void 0 ? column.path : [...column
|
|
|
26
26
|
function rowToData(model, row) {
|
|
27
27
|
const data = {};
|
|
28
28
|
for (const column of model.columns) setAt(data, columnPath(column), row[column.column] ?? null);
|
|
29
|
-
for (const child of model.children)
|
|
29
|
+
for (const child of model.children)
|
|
30
|
+
setAt(
|
|
31
|
+
data,
|
|
32
|
+
child.path,
|
|
33
|
+
child.locales ? Object.fromEntries(child.locales.map((locale) => [locale, []])) : []
|
|
34
|
+
);
|
|
30
35
|
return data;
|
|
31
36
|
}
|
|
32
37
|
function dataToRow(model, data) {
|
|
@@ -55,8 +60,12 @@ async function attachChildren(db, model, rows, docs) {
|
|
|
55
60
|
childRows.forEach((childRow, i) => {
|
|
56
61
|
const index = indexById.get(childRow._parent_id);
|
|
57
62
|
if (index === void 0) return;
|
|
58
|
-
const
|
|
59
|
-
|
|
63
|
+
const locale = child.locales ? String(childRow._locale) : void 0;
|
|
64
|
+
const path = locale === void 0 ? child.path : [...child.path, locale];
|
|
65
|
+
const list = getAt(docs[index], path);
|
|
66
|
+
if (!Array.isArray(list)) return;
|
|
67
|
+
const id = locale === void 0 ? childRow.id : String(childRow.id).replace(new RegExp(`:${locale}$`), "");
|
|
68
|
+
list.push(child.kind === "array" ? { id, ...childDocs?.[i] } : childRow.value);
|
|
60
69
|
});
|
|
61
70
|
}
|
|
62
71
|
}
|
|
@@ -77,20 +86,41 @@ function toDocument(row, data, drafts) {
|
|
|
77
86
|
async function insertChildren(db, model, parentId, data) {
|
|
78
87
|
for (const child of model.children) {
|
|
79
88
|
const value = getAt(data, child.path);
|
|
89
|
+
if (child.locales) {
|
|
90
|
+
if (!value || typeof value !== "object") continue;
|
|
91
|
+
for (const locale of child.locales) {
|
|
92
|
+
const items = value[locale];
|
|
93
|
+
if (Array.isArray(items) && items.length > 0)
|
|
94
|
+
await insertChild(db, child, parentId, items, locale);
|
|
95
|
+
}
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
80
98
|
if (!Array.isArray(value) || value.length === 0) continue;
|
|
81
99
|
await insertChild(db, child, parentId, value);
|
|
82
100
|
}
|
|
83
101
|
}
|
|
84
|
-
async function insertChild(db, child, parentId, items) {
|
|
102
|
+
async function insertChild(db, child, parentId, items, locale) {
|
|
103
|
+
const localeColumn = locale === void 0 ? {} : { _locale: locale };
|
|
85
104
|
if (child.kind === "values") {
|
|
86
|
-
const rows = items.map((value, i) => ({
|
|
105
|
+
const rows = items.map((value, i) => ({
|
|
106
|
+
_parent_id: parentId,
|
|
107
|
+
_order: i,
|
|
108
|
+
value,
|
|
109
|
+
...localeColumn
|
|
110
|
+
}));
|
|
87
111
|
for (const part of chunks(rows)) await db.insert(child.table.table).values(part);
|
|
88
112
|
return;
|
|
89
113
|
}
|
|
90
114
|
for (const [i, item] of items.entries()) {
|
|
91
115
|
const rowData = item;
|
|
92
|
-
const id = rowData.id
|
|
93
|
-
await db.insert(child.table.table).values({
|
|
116
|
+
const id = locale === void 0 ? rowData.id : `${rowData.id}:${locale}`;
|
|
117
|
+
await db.insert(child.table.table).values({
|
|
118
|
+
...dataToRow(child.table, rowData),
|
|
119
|
+
id,
|
|
120
|
+
_parent_id: parentId,
|
|
121
|
+
_order: i,
|
|
122
|
+
...localeColumn
|
|
123
|
+
});
|
|
94
124
|
await insertChildren(db, child.table, id, rowData);
|
|
95
125
|
}
|
|
96
126
|
}
|
|
@@ -413,13 +443,23 @@ function resolvePath(model, segments, drafts) {
|
|
|
413
443
|
continue;
|
|
414
444
|
}
|
|
415
445
|
const child = model.children.find((c) => c.path.join(".") === path.join("."));
|
|
446
|
+
if (child?.locales) {
|
|
447
|
+
const next = segments[i + 1];
|
|
448
|
+
const named = next !== void 0 && child.locales.includes(next);
|
|
449
|
+
return {
|
|
450
|
+
kind: "child",
|
|
451
|
+
child,
|
|
452
|
+
rest: segments.slice(i + (named ? 2 : 1)),
|
|
453
|
+
locale: named ? next : child.defaultLocale
|
|
454
|
+
};
|
|
455
|
+
}
|
|
416
456
|
if (child) return { kind: "child", child, rest: segments.slice(i + 1) };
|
|
417
457
|
const locale = field.localized ? segments[i + 1] : void 0;
|
|
418
458
|
const last = field.localized && locale !== void 0 ? i + 1 : i;
|
|
419
459
|
if (last < segments.length - 1) {
|
|
420
460
|
throw new QueryError(`Cannot query inside "${shown}" (${field.type} field)`);
|
|
421
461
|
}
|
|
422
|
-
if (field.type === "json" || field.type === "richText") {
|
|
462
|
+
if (field.type === "json" || field.type === "richText" || field.type === "blocks") {
|
|
423
463
|
throw new QueryError(`Cannot query "${shown}": ${field.type} fields are not queryable`);
|
|
424
464
|
}
|
|
425
465
|
const same = (c) => c.path.join(".") === path.join(".");
|
|
@@ -518,14 +558,15 @@ var WhereBuilder = class {
|
|
|
518
558
|
if (!OPERATORS.has(op)) throw new QueryError(`Unknown operator "${op}" on "${path}"`);
|
|
519
559
|
if (target.kind === "column")
|
|
520
560
|
return operatorSQL(this.dialect, target.column, target.field, op, value, path);
|
|
521
|
-
return this.child(model, target.child, target.rest, op, value, path);
|
|
561
|
+
return this.child(model, target.child, target.rest, op, value, path, target.locale);
|
|
522
562
|
});
|
|
523
563
|
return parts.length === 1 ? parts[0] : and(...parts);
|
|
524
564
|
}
|
|
525
565
|
/** Conditions on array rows or hasMany values become (NOT) EXISTS subqueries. */
|
|
526
|
-
child(parent, child, rest, op, value, path) {
|
|
566
|
+
child(parent, child, rest, op, value, path, locale) {
|
|
527
567
|
const table = child.table;
|
|
528
|
-
const
|
|
568
|
+
const parentLink = eq2(col2(table, "_parent_id"), col2(parent, "id"));
|
|
569
|
+
const link = locale === void 0 ? parentLink : and(parentLink, eq2(col2(table, "_locale"), locale));
|
|
529
570
|
const subquery = (condition) => exists(
|
|
530
571
|
this.db.select({ one: sql`1` }).from(table.table).where(condition ? and(link, condition) : link)
|
|
531
572
|
);
|
|
@@ -577,6 +618,8 @@ function columnKind(field) {
|
|
|
577
618
|
return "boolean";
|
|
578
619
|
case "json":
|
|
579
620
|
case "richText":
|
|
621
|
+
// Blocks are stored whole as JSON: rows of different kinds don't fit one child table.
|
|
622
|
+
case "blocks":
|
|
580
623
|
return "json";
|
|
581
624
|
case "upload":
|
|
582
625
|
case "relationship":
|
|
@@ -697,6 +740,14 @@ function buildTable(builder, name, kind, fields, options) {
|
|
|
697
740
|
);
|
|
698
741
|
add("_order", dialect.integer("_order").notNull(), "int!");
|
|
699
742
|
indexes.push({ column: "_parent_id", unique: false });
|
|
743
|
+
if (options.localized) {
|
|
744
|
+
add(
|
|
745
|
+
"_locale",
|
|
746
|
+
dialect.text("_locale").notNull().default(options.localized),
|
|
747
|
+
`locale:${options.localized}`
|
|
748
|
+
);
|
|
749
|
+
indexes.push({ column: "_locale", unique: false });
|
|
750
|
+
}
|
|
700
751
|
if (kind === "values" && options.valueField) {
|
|
701
752
|
const valueKind = columnKind(options.valueField);
|
|
702
753
|
add("value", makeColumn(dialect, "value", valueKind), valueKind);
|
|
@@ -710,17 +761,33 @@ function buildTable(builder, name, kind, fields, options) {
|
|
|
710
761
|
if (field.type === "group") {
|
|
711
762
|
walk(field.fields, fieldPath, false);
|
|
712
763
|
} else if (field.type === "array") {
|
|
764
|
+
const localization = field.localized ? builder.localization : null;
|
|
713
765
|
const child = buildTable(builder, `${name}__${base}`, "array", field.fields, {
|
|
714
|
-
parentIdKind: kind === "array" ? "text" : "integer"
|
|
766
|
+
parentIdKind: kind === "array" ? "text" : "integer",
|
|
767
|
+
...localization ? { localized: localization.defaultLocale } : {}
|
|
768
|
+
});
|
|
769
|
+
children.push({
|
|
770
|
+
kind: "array",
|
|
771
|
+
path: fieldPath,
|
|
772
|
+
field,
|
|
773
|
+
table: child,
|
|
774
|
+
...localeInfo(localization)
|
|
715
775
|
});
|
|
716
|
-
children.push({ kind: "array", path: fieldPath, field, table: child });
|
|
717
776
|
described.push([base, "array", child.name]);
|
|
718
777
|
} else if ((field.type === "select" || field.type === "relationship") && field.hasMany) {
|
|
778
|
+
const localization = field.localized ? builder.localization : null;
|
|
719
779
|
const child = buildTable(builder, `${name}__${base}`, "values", [], {
|
|
720
780
|
parentIdKind: kind === "array" ? "text" : "integer",
|
|
721
|
-
valueField: field
|
|
781
|
+
valueField: field,
|
|
782
|
+
...localization ? { localized: localization.defaultLocale } : {}
|
|
783
|
+
});
|
|
784
|
+
children.push({
|
|
785
|
+
kind: "values",
|
|
786
|
+
path: fieldPath,
|
|
787
|
+
field,
|
|
788
|
+
table: child,
|
|
789
|
+
...localeInfo(localization)
|
|
722
790
|
});
|
|
723
|
-
children.push({ kind: "values", path: fieldPath, field, table: child });
|
|
724
791
|
described.push([base, "values", child.name]);
|
|
725
792
|
} else {
|
|
726
793
|
const kindOfColumn = columnKind(field);
|
|
@@ -762,6 +829,9 @@ function buildTable(builder, name, kind, fields, options) {
|
|
|
762
829
|
const model = { name, kind, table, fields, columns: columnModels, children };
|
|
763
830
|
return options.valueField ? { ...model, valueField: options.valueField } : model;
|
|
764
831
|
}
|
|
832
|
+
function localeInfo(localization) {
|
|
833
|
+
return localization ? { locales: localization.locales, defaultLocale: localization.defaultLocale } : {};
|
|
834
|
+
}
|
|
765
835
|
|
|
766
836
|
// src/database.ts
|
|
767
837
|
var DEFAULT_TABLE_PREFIX = "ecms_";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@easy-cms/drizzle",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Shared Drizzle ORM layer for Easy CMS database adapters",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
"drizzle-orm": "0.45.3"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
|
-
"@easy-cms/core": "^0.
|
|
26
|
+
"@easy-cms/core": "^0.6.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@easy-cms/core": "^0.
|
|
29
|
+
"@easy-cms/core": "^0.6.0"
|
|
30
30
|
},
|
|
31
31
|
"publishConfig": {
|
|
32
32
|
"access": "public"
|