@rljson/db 0.0.7 → 0.0.8
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/db.d.ts +27 -40
- package/dist/db.js +1209 -675
- package/package.json +11 -11
- package/dist/cars-example.d.ts +0 -41
package/dist/db.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import { equals, merge } from "@rljson/json";
|
|
2
|
-
import { timeId, createInsertHistoryTableCfg, Validate, BaseValidator, Route, validateInsert, isTimeId } from "@rljson/rljson";
|
|
3
|
-
import { traverse } from "object-traversal";
|
|
4
1
|
import { rmhsh, hsh, Hash, hip } from "@rljson/hash";
|
|
2
|
+
import { equals, merge } from "@rljson/json";
|
|
3
|
+
import { timeId, createInsertHistoryTableCfg, Validate, BaseValidator, Route, isTimeId } from "@rljson/rljson";
|
|
5
4
|
import { IoMem } from "@rljson/io";
|
|
5
|
+
import { traverse } from "object-traversal";
|
|
6
6
|
import { compileExpression } from "filtrex";
|
|
7
7
|
class BaseController {
|
|
8
8
|
constructor(_core, _tableKey) {
|
|
9
9
|
this._core = _core;
|
|
10
10
|
this._tableKey = _tableKey;
|
|
11
11
|
}
|
|
12
|
+
_contentType;
|
|
13
|
+
_tableCfg;
|
|
12
14
|
// ...........................................................................
|
|
13
15
|
/**
|
|
14
16
|
* Retrieves the current state of the table.
|
|
@@ -67,6 +69,28 @@ class BaseController {
|
|
|
67
69
|
});
|
|
68
70
|
return rows;
|
|
69
71
|
}
|
|
72
|
+
// ...........................................................................
|
|
73
|
+
/**
|
|
74
|
+
* Gets the content type of the controller.
|
|
75
|
+
* @returns The content type managed by the controller.
|
|
76
|
+
*/
|
|
77
|
+
/* v8 ignore next -- @preserve */
|
|
78
|
+
contentType() {
|
|
79
|
+
return this._contentType ?? "components";
|
|
80
|
+
}
|
|
81
|
+
// ...........................................................................
|
|
82
|
+
/**
|
|
83
|
+
* Gets the table configuration of the controller.
|
|
84
|
+
* @returns The table configuration managed by the controller.
|
|
85
|
+
*/
|
|
86
|
+
tableCfg() {
|
|
87
|
+
if (!this._tableCfg) {
|
|
88
|
+
throw new Error(
|
|
89
|
+
`TableCfg for controller ${this._tableKey} is not initialized.`
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
return this._tableCfg;
|
|
93
|
+
}
|
|
70
94
|
}
|
|
71
95
|
class CakeController extends BaseController {
|
|
72
96
|
constructor(_core, _tableKey, _refs) {
|
|
@@ -74,6 +98,7 @@ class CakeController extends BaseController {
|
|
|
74
98
|
this._core = _core;
|
|
75
99
|
this._tableKey = _tableKey;
|
|
76
100
|
this._refs = _refs;
|
|
101
|
+
this._contentType = "cakes";
|
|
77
102
|
}
|
|
78
103
|
_table = null;
|
|
79
104
|
_baseLayers = {};
|
|
@@ -88,7 +113,8 @@ class CakeController extends BaseController {
|
|
|
88
113
|
if (this._table._type !== "cakes") {
|
|
89
114
|
throw new Error(`Table ${this._tableKey} is not of type cakes.`);
|
|
90
115
|
}
|
|
91
|
-
|
|
116
|
+
this._tableCfg = await this._core.tableCfg(this._tableKey);
|
|
117
|
+
if (this._refs && this._refs.base && this._refs.base !== void 0 && this._refs.base.length > 0) {
|
|
92
118
|
const {
|
|
93
119
|
[this._tableKey]: { _data: baseCakes }
|
|
94
120
|
} = await this._core.readRow(this._tableKey, this._refs.base);
|
|
@@ -99,11 +125,13 @@ class CakeController extends BaseController {
|
|
|
99
125
|
this._baseLayers = rmhsh(baseCake.layers);
|
|
100
126
|
} else {
|
|
101
127
|
const cake = this._table._data[0];
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
128
|
+
if (!!cake) {
|
|
129
|
+
this._refs = {
|
|
130
|
+
sliceIdsTable: cake.sliceIdsTable,
|
|
131
|
+
sliceIdsRow: cake.sliceIdsRow
|
|
132
|
+
};
|
|
133
|
+
this._baseLayers = rmhsh(cake.layers);
|
|
134
|
+
}
|
|
107
135
|
}
|
|
108
136
|
}
|
|
109
137
|
async getChildRefs(where, filter) {
|
|
@@ -131,7 +159,7 @@ class CakeController extends BaseController {
|
|
|
131
159
|
if (this._refs?.base) delete this._refs.base;
|
|
132
160
|
const normalizedValue = {};
|
|
133
161
|
for (const [layerTable, layerRef] of Object.entries(
|
|
134
|
-
value
|
|
162
|
+
value.layers
|
|
135
163
|
)) {
|
|
136
164
|
if (Array.isArray(layerRef) && layerRef.length > 1) {
|
|
137
165
|
throw new Error(
|
|
@@ -141,6 +169,7 @@ class CakeController extends BaseController {
|
|
|
141
169
|
normalizedValue[layerTable] = Array.isArray(layerRef) ? layerRef[0] : layerRef;
|
|
142
170
|
}
|
|
143
171
|
const cake = {
|
|
172
|
+
...value,
|
|
144
173
|
layers: { ...this._baseLayers, ...normalizedValue },
|
|
145
174
|
...refs || this._refs
|
|
146
175
|
};
|
|
@@ -166,7 +195,7 @@ class CakeController extends BaseController {
|
|
|
166
195
|
return Promise.resolve({});
|
|
167
196
|
}
|
|
168
197
|
}
|
|
169
|
-
filterRow(row, key, value) {
|
|
198
|
+
async filterRow(row, key, value) {
|
|
170
199
|
const cake = row;
|
|
171
200
|
for (const [layerKey, layerRef] of Object.entries(cake.layers)) {
|
|
172
201
|
if (layerKey === key && layerRef === value) {
|
|
@@ -182,8 +211,14 @@ class ComponentController extends BaseController {
|
|
|
182
211
|
this._core = _core;
|
|
183
212
|
this._tableKey = _tableKey;
|
|
184
213
|
this._refs = _refs;
|
|
214
|
+
this._contentType = "components";
|
|
185
215
|
}
|
|
186
|
-
|
|
216
|
+
_allowedContentTypes = [
|
|
217
|
+
"components",
|
|
218
|
+
"edits",
|
|
219
|
+
"editHistory",
|
|
220
|
+
"multiEdits"
|
|
221
|
+
];
|
|
187
222
|
_resolvedColumns = null;
|
|
188
223
|
_refTableKeyToColumnKeyMap = null;
|
|
189
224
|
async init() {
|
|
@@ -192,7 +227,7 @@ class ComponentController extends BaseController {
|
|
|
192
227
|
}
|
|
193
228
|
const rljson = await this._core.dumpTable(this._tableKey);
|
|
194
229
|
const table = rljson[this._tableKey];
|
|
195
|
-
if (table._type
|
|
230
|
+
if (this._allowedContentTypes.indexOf(table._type) === -1) {
|
|
196
231
|
throw new Error(`Table ${this._tableKey} is not of type components.`);
|
|
197
232
|
}
|
|
198
233
|
this._tableCfg = await this._core.tableCfg(this._tableKey);
|
|
@@ -210,38 +245,12 @@ class ComponentController extends BaseController {
|
|
|
210
245
|
if (!!refs) {
|
|
211
246
|
throw new Error(`Refs are not supported on ComponentController.`);
|
|
212
247
|
}
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const ref = possibleRef._ref;
|
|
220
|
-
const val = possibleRef._value;
|
|
221
|
-
if (!referencedValues.has(ref))
|
|
222
|
-
referencedValues.set(ref, { [k]: val });
|
|
223
|
-
else {
|
|
224
|
-
const existing = referencedValues.get(ref);
|
|
225
|
-
referencedValues.set(ref, { ...{ [k]: val }, ...existing });
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
if (referencedValues.size > 0) {
|
|
232
|
-
for (const refValue of referencedValues.values()) {
|
|
233
|
-
values.push({ ...value, ...refValue });
|
|
234
|
-
}
|
|
235
|
-
} else {
|
|
236
|
-
values.push(value);
|
|
237
|
-
}
|
|
238
|
-
const components = values;
|
|
239
|
-
const results = [];
|
|
240
|
-
for (const component of components) {
|
|
241
|
-
delete component._somethingToInsert;
|
|
242
|
-
const rlJson = { [this._tableKey]: { _data: [component] } };
|
|
243
|
-
await this._core.import(rlJson);
|
|
244
|
-
const result = {
|
|
248
|
+
const component = value;
|
|
249
|
+
delete component._somethingToInsert;
|
|
250
|
+
const rlJson = { [this._tableKey]: { _data: [component] } };
|
|
251
|
+
await this._core.import(rlJson);
|
|
252
|
+
return [
|
|
253
|
+
{
|
|
245
254
|
//Ref to component
|
|
246
255
|
[this._tableKey + "Ref"]: hsh(component)._hash,
|
|
247
256
|
//Data from edit
|
|
@@ -249,10 +258,8 @@ class ComponentController extends BaseController {
|
|
|
249
258
|
origin,
|
|
250
259
|
//Unique id/timestamp
|
|
251
260
|
timeId: timeId()
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
}
|
|
255
|
-
return results;
|
|
261
|
+
}
|
|
262
|
+
];
|
|
256
263
|
}
|
|
257
264
|
// ...........................................................................
|
|
258
265
|
/**
|
|
@@ -287,6 +294,20 @@ class ComponentController extends BaseController {
|
|
|
287
294
|
columnKey: propertyKey,
|
|
288
295
|
ref: refItem
|
|
289
296
|
});
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
if (typeof refItem === "object" && refItem !== null) {
|
|
300
|
+
const cakeReference = refItem;
|
|
301
|
+
childRefs.set(
|
|
302
|
+
`${childRefTableKey}|${propertyKey}|${cakeReference.ref}|${cakeReference.sliceIds?.join(",")}`,
|
|
303
|
+
{
|
|
304
|
+
tableKey: childRefTableKey,
|
|
305
|
+
columnKey: propertyKey,
|
|
306
|
+
ref: cakeReference.ref,
|
|
307
|
+
sliceIds: cakeReference.sliceIds
|
|
308
|
+
}
|
|
309
|
+
);
|
|
310
|
+
continue;
|
|
290
311
|
}
|
|
291
312
|
}
|
|
292
313
|
continue;
|
|
@@ -319,7 +340,7 @@ class ComponentController extends BaseController {
|
|
|
319
340
|
const column = Object.keys(refWhere)[0];
|
|
320
341
|
const refValue = refWhere[column];
|
|
321
342
|
for (const row of tableData) {
|
|
322
|
-
if (this.filterRow(row, column, refValue)) {
|
|
343
|
+
if (await this.filterRow(row, column, refValue)) {
|
|
323
344
|
consolidatedRows.set(row._hash, row);
|
|
324
345
|
}
|
|
325
346
|
}
|
|
@@ -518,7 +539,7 @@ class ComponentController extends BaseController {
|
|
|
518
539
|
return this._core.readRows(table, where);
|
|
519
540
|
}
|
|
520
541
|
}
|
|
521
|
-
filterRow(row, key, value) {
|
|
542
|
+
async filterRow(row, key, value) {
|
|
522
543
|
for (const [propertyKey, propertyValue] of Object.entries(row)) {
|
|
523
544
|
if (propertyKey === key && equals(propertyValue, value)) {
|
|
524
545
|
return true;
|
|
@@ -533,12 +554,131 @@ class ComponentController extends BaseController {
|
|
|
533
554
|
return false;
|
|
534
555
|
}
|
|
535
556
|
}
|
|
557
|
+
class SliceIdController extends BaseController {
|
|
558
|
+
constructor(_core, _tableKey, _refs) {
|
|
559
|
+
super(_core, _tableKey);
|
|
560
|
+
this._core = _core;
|
|
561
|
+
this._tableKey = _tableKey;
|
|
562
|
+
this._refs = _refs;
|
|
563
|
+
this._contentType = "sliceIds";
|
|
564
|
+
}
|
|
565
|
+
async init() {
|
|
566
|
+
if (this._tableKey.endsWith("SliceId") === false) {
|
|
567
|
+
throw new Error(
|
|
568
|
+
`Table ${this._tableKey} is not supported by SliceIdController.`
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
const rljson = await this._core.dumpTable(this._tableKey);
|
|
572
|
+
const table = rljson[this._tableKey];
|
|
573
|
+
if (table._type !== "sliceIds") {
|
|
574
|
+
throw new Error(`Table ${this._tableKey} is not of type sliceIds.`);
|
|
575
|
+
}
|
|
576
|
+
this._tableCfg = await this._core.tableCfg(this._tableKey);
|
|
577
|
+
if (this._refs && this._refs.base) {
|
|
578
|
+
const {
|
|
579
|
+
[this._tableKey]: { _data: SliceIds2 }
|
|
580
|
+
} = await this._core.readRow(this._tableKey, this._refs.base);
|
|
581
|
+
if (SliceIds2.length === 0) {
|
|
582
|
+
throw new Error(`Base sliceId ${this._refs.base} does not exist.`);
|
|
583
|
+
}
|
|
584
|
+
} else {
|
|
585
|
+
const sliceId = table._data[0];
|
|
586
|
+
if (!!sliceId) {
|
|
587
|
+
this._refs = {
|
|
588
|
+
base: sliceId.base
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
async insert(command, value, origin, refs) {
|
|
594
|
+
if (!command.startsWith("add") && !command.startsWith("remove")) {
|
|
595
|
+
throw new Error(
|
|
596
|
+
`Command ${command} is not supported by SliceIdController.`
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
const sliceIds = command.startsWith("add") === true ? {
|
|
600
|
+
add: value,
|
|
601
|
+
...refs || this._refs
|
|
602
|
+
} : {
|
|
603
|
+
add: [],
|
|
604
|
+
remove: value,
|
|
605
|
+
...refs || this._refs
|
|
606
|
+
};
|
|
607
|
+
const rlJson = { [this._tableKey]: { _data: [sliceIds] } };
|
|
608
|
+
await this._core.import(rlJson);
|
|
609
|
+
const result = {
|
|
610
|
+
//Ref to component
|
|
611
|
+
[this._tableKey + "Ref"]: hsh(sliceIds)._hash,
|
|
612
|
+
//Data from edit
|
|
613
|
+
route: "",
|
|
614
|
+
origin,
|
|
615
|
+
//Unique id/timestamp
|
|
616
|
+
timeId: timeId()
|
|
617
|
+
};
|
|
618
|
+
return [result];
|
|
619
|
+
}
|
|
620
|
+
async get(where, filter) {
|
|
621
|
+
if (typeof where === "string") {
|
|
622
|
+
return this._getByHash(where, filter);
|
|
623
|
+
} else {
|
|
624
|
+
return this._getByWhere(where, filter);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
async resolveBaseSliceIds(sliceIds) {
|
|
628
|
+
const add = /* @__PURE__ */ new Set();
|
|
629
|
+
const remove = /* @__PURE__ */ new Set();
|
|
630
|
+
if (!!sliceIds.base) {
|
|
631
|
+
const baseSliceIds = await this.get(sliceIds.base);
|
|
632
|
+
if (!baseSliceIds[this._tableKey]?._data?.[0]) {
|
|
633
|
+
throw new Error(`Base sliceIds ${sliceIds.base} does not exist.`);
|
|
634
|
+
}
|
|
635
|
+
if (baseSliceIds[this._tableKey]._data.length > 1) {
|
|
636
|
+
throw new Error(
|
|
637
|
+
`Base sliceIds ${sliceIds.base} has more than one entry.`
|
|
638
|
+
);
|
|
639
|
+
}
|
|
640
|
+
const baseSliceId = baseSliceIds[this._tableKey]._data[0];
|
|
641
|
+
const resolvedBaseSliceIds = await this.resolveBaseSliceIds(baseSliceId);
|
|
642
|
+
for (const sliceId of resolvedBaseSliceIds.add) {
|
|
643
|
+
add.add(sliceId);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
for (const sliceId of sliceIds.add) {
|
|
647
|
+
add.add(sliceId);
|
|
648
|
+
}
|
|
649
|
+
if (!!sliceIds.remove)
|
|
650
|
+
for (const sliceId of sliceIds.remove) {
|
|
651
|
+
remove.add(sliceId);
|
|
652
|
+
}
|
|
653
|
+
for (const sliceId of remove.values()) {
|
|
654
|
+
if (add.has(sliceId)) {
|
|
655
|
+
add.delete(sliceId);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
return { add: Array.from(add) };
|
|
659
|
+
}
|
|
660
|
+
/* v8 ignore next -- @preserve */
|
|
661
|
+
async getChildRefs() {
|
|
662
|
+
return [];
|
|
663
|
+
}
|
|
664
|
+
async filterRow(row, _, value) {
|
|
665
|
+
const sliceIds = row;
|
|
666
|
+
const sliceId = value;
|
|
667
|
+
for (const sId of Object.values(sliceIds.add)) {
|
|
668
|
+
if (sliceId === sId) {
|
|
669
|
+
return true;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
return false;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
536
675
|
class LayerController extends BaseController {
|
|
537
676
|
constructor(_core, _tableKey, _refs) {
|
|
538
677
|
super(_core, _tableKey);
|
|
539
678
|
this._core = _core;
|
|
540
679
|
this._tableKey = _tableKey;
|
|
541
680
|
this._refs = _refs;
|
|
681
|
+
this._contentType = "layers";
|
|
542
682
|
}
|
|
543
683
|
async init() {
|
|
544
684
|
if (this._tableKey.endsWith("Layer") === false) {
|
|
@@ -551,6 +691,7 @@ class LayerController extends BaseController {
|
|
|
551
691
|
if (table._type !== "layers") {
|
|
552
692
|
throw new Error(`Table ${this._tableKey} is not of type layers.`);
|
|
553
693
|
}
|
|
694
|
+
this._tableCfg = await this._core.tableCfg(this._tableKey);
|
|
554
695
|
if (this._refs && this._refs.base) {
|
|
555
696
|
const {
|
|
556
697
|
[this._tableKey]: { _data: baseLayers }
|
|
@@ -568,11 +709,13 @@ class LayerController extends BaseController {
|
|
|
568
709
|
}
|
|
569
710
|
} else {
|
|
570
711
|
const layer = table._data[0];
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
712
|
+
if (!!layer) {
|
|
713
|
+
this._refs = {
|
|
714
|
+
sliceIdsTable: layer.sliceIdsTable,
|
|
715
|
+
sliceIdsTableRow: layer.sliceIdsTableRow,
|
|
716
|
+
componentsTable: layer.componentsTable
|
|
717
|
+
};
|
|
718
|
+
}
|
|
576
719
|
}
|
|
577
720
|
}
|
|
578
721
|
async insert(command, value, origin, refs) {
|
|
@@ -581,10 +724,9 @@ class LayerController extends BaseController {
|
|
|
581
724
|
`Command ${command} is not supported by LayerController.`
|
|
582
725
|
);
|
|
583
726
|
}
|
|
727
|
+
const isAdd = command.startsWith("add");
|
|
584
728
|
const normalizedValue = {};
|
|
585
|
-
for (const [sliceId, compRef] of Object.entries(
|
|
586
|
-
value
|
|
587
|
-
)) {
|
|
729
|
+
for (const [sliceId, compRef] of isAdd ? Object.entries(value.add) : Object.entries(value.remove)) {
|
|
588
730
|
if (Array.isArray(compRef) && compRef.length > 1) {
|
|
589
731
|
throw new Error(
|
|
590
732
|
`LayerController insert: Component ref for slice ${sliceId} cannot be an array of size > 1. No 1:n relations supported.`
|
|
@@ -592,13 +734,20 @@ class LayerController extends BaseController {
|
|
|
592
734
|
}
|
|
593
735
|
normalizedValue[sliceId] = Array.isArray(compRef) ? compRef[0] : compRef;
|
|
594
736
|
}
|
|
595
|
-
const layer =
|
|
596
|
-
|
|
597
|
-
...
|
|
737
|
+
const layer = isAdd ? {
|
|
738
|
+
...value,
|
|
739
|
+
...{
|
|
740
|
+
add: normalizedValue,
|
|
741
|
+
remove: {}
|
|
742
|
+
},
|
|
743
|
+
...refs
|
|
598
744
|
} : {
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
745
|
+
...value,
|
|
746
|
+
...{
|
|
747
|
+
remove: normalizedValue,
|
|
748
|
+
add: {}
|
|
749
|
+
},
|
|
750
|
+
...refs
|
|
602
751
|
};
|
|
603
752
|
const rlJson = { [this._tableKey]: { _data: [layer] } };
|
|
604
753
|
await this._core.import(rlJson);
|
|
@@ -620,25 +769,108 @@ class LayerController extends BaseController {
|
|
|
620
769
|
return this._getByWhere(where, filter);
|
|
621
770
|
}
|
|
622
771
|
}
|
|
772
|
+
async resolveBaseLayer(layer) {
|
|
773
|
+
const add = /* @__PURE__ */ new Map();
|
|
774
|
+
const sliceIds = /* @__PURE__ */ new Set();
|
|
775
|
+
if (!!layer.base) {
|
|
776
|
+
const baseLayer = await this.get(layer.base);
|
|
777
|
+
if (!baseLayer[this._tableKey]?._data?.[0]) {
|
|
778
|
+
throw new Error(`Base layer ${layer.base} does not exist.`);
|
|
779
|
+
}
|
|
780
|
+
if (baseLayer[this._tableKey]._data.length > 1) {
|
|
781
|
+
throw new Error(
|
|
782
|
+
`Base layer ${layer.base} resolving not possible. Not unique.`
|
|
783
|
+
);
|
|
784
|
+
}
|
|
785
|
+
const baseLayerData = rmhsh(baseLayer[this._tableKey]._data[0]);
|
|
786
|
+
const baseLayerResolved = await this.resolveBaseLayer(baseLayerData);
|
|
787
|
+
for (const [sliceId, compRef] of Object.entries(baseLayerResolved.add)) {
|
|
788
|
+
if (sliceId.startsWith("_")) continue;
|
|
789
|
+
add.set(sliceId, compRef);
|
|
790
|
+
}
|
|
791
|
+
for (const sliceId of baseLayerResolved.sliceIds) {
|
|
792
|
+
sliceIds.add(sliceId);
|
|
793
|
+
}
|
|
794
|
+
const baseLayerSliceIdsTable = baseLayerData.sliceIdsTable;
|
|
795
|
+
const baseLayerSliceIdsRow = baseLayerData.sliceIdsTableRow;
|
|
796
|
+
const {
|
|
797
|
+
[baseLayerSliceIdsTable]: { _data: baseLayerSliceIds }
|
|
798
|
+
} = await this._core.readRow(
|
|
799
|
+
baseLayerSliceIdsTable,
|
|
800
|
+
baseLayerSliceIdsRow
|
|
801
|
+
);
|
|
802
|
+
for (const sIds of baseLayerSliceIds) {
|
|
803
|
+
const sliceIdController = new SliceIdController(
|
|
804
|
+
this._core,
|
|
805
|
+
baseLayerSliceIdsTable
|
|
806
|
+
);
|
|
807
|
+
const resolvedSliceIds = await sliceIdController.resolveBaseSliceIds(
|
|
808
|
+
sIds
|
|
809
|
+
);
|
|
810
|
+
for (const sId of resolvedSliceIds.add) {
|
|
811
|
+
if (sId.startsWith("_")) continue;
|
|
812
|
+
sliceIds.add(sId);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
const {
|
|
817
|
+
[layer.sliceIdsTable]: { _data: layerSliceIds }
|
|
818
|
+
} = await this._core.readRow(layer.sliceIdsTable, layer.sliceIdsTableRow);
|
|
819
|
+
if (!layerSliceIds || layerSliceIds.length === 0) {
|
|
820
|
+
throw new Error(
|
|
821
|
+
`Layer sliceIds ${layer.sliceIdsTableRow} does not exist.`
|
|
822
|
+
);
|
|
823
|
+
}
|
|
824
|
+
if (layerSliceIds.length > 1) {
|
|
825
|
+
throw new Error(
|
|
826
|
+
`Layer sliceIds ${layer.sliceIdsTableRow} has more than one entry.`
|
|
827
|
+
);
|
|
828
|
+
}
|
|
829
|
+
const layerSliceId = layerSliceIds[0];
|
|
830
|
+
for (const sId of layerSliceId.add) {
|
|
831
|
+
if (sId.startsWith("_")) continue;
|
|
832
|
+
sliceIds.add(sId);
|
|
833
|
+
}
|
|
834
|
+
if (!!layerSliceId.remove)
|
|
835
|
+
for (const sId of Object.keys(layerSliceId.remove)) {
|
|
836
|
+
if (sliceIds.has(sId)) {
|
|
837
|
+
sliceIds.delete(sId);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
for (const [sliceId, compRef] of Object.entries(layer.add)) {
|
|
841
|
+
if (sliceId.startsWith("_")) continue;
|
|
842
|
+
add.set(sliceId, compRef);
|
|
843
|
+
}
|
|
844
|
+
if (!!layer.remove)
|
|
845
|
+
for (const sliceId of Object.keys(layer.remove)) {
|
|
846
|
+
if (add.has(sliceId)) {
|
|
847
|
+
add.delete(sliceId);
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
return { add: Object.fromEntries(add), sliceIds: Array.from(sliceIds) };
|
|
851
|
+
}
|
|
623
852
|
async getChildRefs(where, filter) {
|
|
624
853
|
const { [this._tableKey]: table } = await this.get(where, filter);
|
|
625
854
|
const childRefs = [];
|
|
626
855
|
for (const row of table._data) {
|
|
627
856
|
const layer = row;
|
|
628
|
-
|
|
857
|
+
const resolvedLayer = await this.resolveBaseLayer(layer);
|
|
858
|
+
for (const [sliceId, ref] of Object.entries(resolvedLayer.add)) {
|
|
629
859
|
if (sliceId.startsWith("_")) continue;
|
|
630
860
|
childRefs.push({
|
|
631
861
|
tableKey: layer.componentsTable,
|
|
632
|
-
ref
|
|
862
|
+
ref,
|
|
863
|
+
sliceIds: [sliceId]
|
|
633
864
|
});
|
|
634
865
|
}
|
|
635
866
|
}
|
|
636
867
|
return childRefs;
|
|
637
868
|
}
|
|
638
|
-
filterRow(row, _, value) {
|
|
869
|
+
async filterRow(row, _, value) {
|
|
639
870
|
const layer = row;
|
|
640
871
|
const compRef = value;
|
|
641
|
-
|
|
872
|
+
const resolvedLayer = await this.resolveBaseLayer(layer);
|
|
873
|
+
for (const componentRef of Object.values(resolvedLayer.add)) {
|
|
642
874
|
if (componentRef === compRef) {
|
|
643
875
|
return true;
|
|
644
876
|
}
|
|
@@ -653,11 +885,21 @@ const createController = async (type, core, tableKey, refs) => {
|
|
|
653
885
|
ctrl = new LayerController(core, tableKey, refs);
|
|
654
886
|
break;
|
|
655
887
|
case "components":
|
|
888
|
+
case "edits":
|
|
889
|
+
case "editHistory":
|
|
890
|
+
case "multiEdits":
|
|
656
891
|
ctrl = new ComponentController(core, tableKey, refs);
|
|
657
892
|
break;
|
|
658
893
|
case "cakes":
|
|
659
894
|
ctrl = new CakeController(core, tableKey, refs);
|
|
660
895
|
break;
|
|
896
|
+
case "sliceIds":
|
|
897
|
+
ctrl = new SliceIdController(
|
|
898
|
+
core,
|
|
899
|
+
tableKey,
|
|
900
|
+
refs
|
|
901
|
+
);
|
|
902
|
+
break;
|
|
661
903
|
default:
|
|
662
904
|
throw new Error(`Controller for type ${type} is not implemented yet.`);
|
|
663
905
|
}
|
|
@@ -721,7 +963,7 @@ class Core {
|
|
|
721
963
|
const validate = new Validate();
|
|
722
964
|
validate.addValidator(new BaseValidator());
|
|
723
965
|
const result = await validate.run(data);
|
|
724
|
-
if ((result.hasErrors || result.base && result.base.hasErrors) && !result.base.refsNotFound) {
|
|
966
|
+
if ((result.hasErrors || result.base && result.base.hasErrors) && !result.base.refsNotFound && !result.base.layerBasesNotFound) {
|
|
725
967
|
throw new Error(
|
|
726
968
|
"The imported rljson data is not valid:\n" + JSON.stringify(result, null, 2)
|
|
727
969
|
);
|
|
@@ -767,6 +1009,152 @@ class Core {
|
|
|
767
1009
|
return this._io.readRows({ table, where });
|
|
768
1010
|
}
|
|
769
1011
|
}
|
|
1012
|
+
const inject = (tree, path, value) => {
|
|
1013
|
+
for (let i = 0; i < path.length; i++) {
|
|
1014
|
+
const segment = path[i];
|
|
1015
|
+
if (i === path.length - 1) {
|
|
1016
|
+
tree[segment] = value;
|
|
1017
|
+
delete tree["_hash"];
|
|
1018
|
+
} else {
|
|
1019
|
+
if (!tree[segment]) {
|
|
1020
|
+
tree[segment] = {};
|
|
1021
|
+
}
|
|
1022
|
+
tree = tree[segment];
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
};
|
|
1026
|
+
const isolate = (tree, path, preservedKeys = []) => {
|
|
1027
|
+
if (path.length === 0) {
|
|
1028
|
+
return Array.isArray(tree) ? [] : {};
|
|
1029
|
+
}
|
|
1030
|
+
if (tree == null) {
|
|
1031
|
+
return null;
|
|
1032
|
+
}
|
|
1033
|
+
const [currentKey, ...remainingPath] = path;
|
|
1034
|
+
const result = Array.isArray(tree) ? [] : {};
|
|
1035
|
+
if (!Array.isArray(tree)) {
|
|
1036
|
+
for (const key in tree) {
|
|
1037
|
+
if (typeof key === "string" && key.startsWith("_") || preservedKeys.includes(key)) {
|
|
1038
|
+
result[key] = tree[key];
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
if (!(currentKey in tree)) {
|
|
1043
|
+
return result;
|
|
1044
|
+
}
|
|
1045
|
+
const currentValue = tree[currentKey];
|
|
1046
|
+
if (remainingPath.length === 0) {
|
|
1047
|
+
if (Array.isArray(result)) {
|
|
1048
|
+
result[currentKey] = currentValue;
|
|
1049
|
+
} else {
|
|
1050
|
+
result[currentKey] = currentValue;
|
|
1051
|
+
}
|
|
1052
|
+
} else {
|
|
1053
|
+
const isolatedChild = isolate(currentValue, remainingPath, preservedKeys);
|
|
1054
|
+
const hasContent = Array.isArray(isolatedChild) ? isolatedChild.length > 0 : Object.keys(isolatedChild).length > 0;
|
|
1055
|
+
if (hasContent || isolatedChild === null) {
|
|
1056
|
+
if (Array.isArray(result)) {
|
|
1057
|
+
result[currentKey] = isolatedChild;
|
|
1058
|
+
} else {
|
|
1059
|
+
result[currentKey] = isolatedChild;
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
return result;
|
|
1064
|
+
};
|
|
1065
|
+
const mergeTrees = (trees) => {
|
|
1066
|
+
if (!trees || trees.length === 0) {
|
|
1067
|
+
return {};
|
|
1068
|
+
}
|
|
1069
|
+
let result = {};
|
|
1070
|
+
for (const { tree } of trees) {
|
|
1071
|
+
if (tree != null) {
|
|
1072
|
+
result = mergeStructures(result, tree);
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
const pathValues = [];
|
|
1076
|
+
for (const { tree, path } of trees) {
|
|
1077
|
+
if (tree == null) continue;
|
|
1078
|
+
let current = tree;
|
|
1079
|
+
let pathExists = true;
|
|
1080
|
+
for (const key of path) {
|
|
1081
|
+
if (current == null || !(key in current)) {
|
|
1082
|
+
pathExists = false;
|
|
1083
|
+
break;
|
|
1084
|
+
}
|
|
1085
|
+
current = current[key];
|
|
1086
|
+
}
|
|
1087
|
+
if (pathExists && current != null) {
|
|
1088
|
+
pathValues.push({ path, value: current });
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
const pathGroups = /* @__PURE__ */ new Map();
|
|
1092
|
+
for (const { path, value } of pathValues) {
|
|
1093
|
+
const pathKey = JSON.stringify(path);
|
|
1094
|
+
if (!pathGroups.has(pathKey)) {
|
|
1095
|
+
pathGroups.set(pathKey, []);
|
|
1096
|
+
}
|
|
1097
|
+
pathGroups.get(pathKey).push(value);
|
|
1098
|
+
}
|
|
1099
|
+
for (const [pathKey, values] of pathGroups) {
|
|
1100
|
+
const path = JSON.parse(pathKey);
|
|
1101
|
+
let mergedValue = void 0;
|
|
1102
|
+
for (const value of values) {
|
|
1103
|
+
if (value == null) continue;
|
|
1104
|
+
if (mergedValue === void 0) {
|
|
1105
|
+
mergedValue = value;
|
|
1106
|
+
continue;
|
|
1107
|
+
}
|
|
1108
|
+
if (Array.isArray(mergedValue) && Array.isArray(value)) {
|
|
1109
|
+
mergedValue = [...mergedValue, ...value];
|
|
1110
|
+
} else if (!Array.isArray(mergedValue) && !Array.isArray(value)) {
|
|
1111
|
+
mergedValue = {
|
|
1112
|
+
...mergedValue,
|
|
1113
|
+
...value
|
|
1114
|
+
};
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
let current = result;
|
|
1118
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
1119
|
+
const key = path[i];
|
|
1120
|
+
if (current == null || !(key in current)) {
|
|
1121
|
+
current[key] = typeof path[i + 1] === "number" ? [] : {};
|
|
1122
|
+
}
|
|
1123
|
+
current = current[key];
|
|
1124
|
+
}
|
|
1125
|
+
if (path.length > 0) {
|
|
1126
|
+
current[path[path.length - 1]] = mergedValue;
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
return result;
|
|
1130
|
+
};
|
|
1131
|
+
function mergeStructures(target, source) {
|
|
1132
|
+
if (source == null) return target;
|
|
1133
|
+
if (target == null) return source;
|
|
1134
|
+
if (Array.isArray(target) && Array.isArray(source)) {
|
|
1135
|
+
const result = [...target];
|
|
1136
|
+
for (let i = 0; i < source.length; i++) {
|
|
1137
|
+
if (result[i] === void 0) {
|
|
1138
|
+
result[i] = source[i];
|
|
1139
|
+
} else {
|
|
1140
|
+
result[i] = mergeStructures(result[i], source[i]);
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
return result;
|
|
1144
|
+
}
|
|
1145
|
+
if (typeof target === "object" && typeof source === "object" && !Array.isArray(target) && !Array.isArray(source) && target !== null && source !== null) {
|
|
1146
|
+
const result = { ...target };
|
|
1147
|
+
for (const key in source) {
|
|
1148
|
+
if (key in result) {
|
|
1149
|
+
result[key] = mergeStructures(result[key], source[key]);
|
|
1150
|
+
} else {
|
|
1151
|
+
result[key] = source[key];
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
return result;
|
|
1155
|
+
}
|
|
1156
|
+
return source;
|
|
1157
|
+
}
|
|
770
1158
|
class ColumnSelection {
|
|
771
1159
|
constructor(columns) {
|
|
772
1160
|
this._throwOnWrongAlias(columns);
|
|
@@ -1113,6 +1501,19 @@ class ColumnSelection {
|
|
|
1113
1501
|
}
|
|
1114
1502
|
]);
|
|
1115
1503
|
}
|
|
1504
|
+
static exampleCarsDeeplyNestedColumnSelection() {
|
|
1505
|
+
return new ColumnSelection([
|
|
1506
|
+
{
|
|
1507
|
+
key: "brand",
|
|
1508
|
+
route: "catalogCake/catalogSeriesLayer/catalogSeries/seriesCake/seriesCarsLayer/seriesCars/carCake/carGeneralLayer/carGeneral/brand",
|
|
1509
|
+
alias: "brand",
|
|
1510
|
+
titleLong: "Car Brand",
|
|
1511
|
+
titleShort: "Brand",
|
|
1512
|
+
type: "string",
|
|
1513
|
+
_hash: ""
|
|
1514
|
+
}
|
|
1515
|
+
]);
|
|
1516
|
+
}
|
|
1116
1517
|
static exampleCarsColumnSelectionOnlySomeColumns() {
|
|
1117
1518
|
return new ColumnSelection([
|
|
1118
1519
|
{
|
|
@@ -1638,23 +2039,8 @@ class RowFilterProcessor {
|
|
|
1638
2039
|
return remainingIndices;
|
|
1639
2040
|
}
|
|
1640
2041
|
for (const i of remainingIndices) {
|
|
1641
|
-
const
|
|
1642
|
-
|
|
1643
|
-
for (const v of cellValue) {
|
|
1644
|
-
if (typeof v === "object" && v !== null && v.hasOwnProperty("_value")) {
|
|
1645
|
-
const matchValue = v._value;
|
|
1646
|
-
if (filter.matches(matchValue)) {
|
|
1647
|
-
result.push(i);
|
|
1648
|
-
break;
|
|
1649
|
-
}
|
|
1650
|
-
} else {
|
|
1651
|
-
if (filter.matches(v)) {
|
|
1652
|
-
result.push(i);
|
|
1653
|
-
break;
|
|
1654
|
-
}
|
|
1655
|
-
}
|
|
1656
|
-
}
|
|
1657
|
-
} else {
|
|
2042
|
+
const cellValues = join.value(i, columnIndex);
|
|
2043
|
+
for (const cellValue of cellValues) {
|
|
1658
2044
|
if (filter.matches(cellValue)) {
|
|
1659
2045
|
result.push(i);
|
|
1660
2046
|
}
|
|
@@ -1695,9 +2081,11 @@ class RowFilterProcessor {
|
|
|
1695
2081
|
if (applyTo[r]) {
|
|
1696
2082
|
continue;
|
|
1697
2083
|
}
|
|
1698
|
-
const
|
|
1699
|
-
|
|
1700
|
-
|
|
2084
|
+
const cellValues = join.value(r, columnIndex);
|
|
2085
|
+
for (const cellValue of cellValues) {
|
|
2086
|
+
if (filter.matches(cellValue)) {
|
|
2087
|
+
applyTo[r] = true;
|
|
2088
|
+
}
|
|
1701
2089
|
}
|
|
1702
2090
|
}
|
|
1703
2091
|
}
|
|
@@ -1717,14 +2105,22 @@ ${availableRoutes.map((a) => `- ${a}`).join("\n")}`
|
|
|
1717
2105
|
}
|
|
1718
2106
|
}
|
|
1719
2107
|
}
|
|
2108
|
+
const joinPreserveKeys = [
|
|
2109
|
+
"sliceIdsTable",
|
|
2110
|
+
"sliceIdsRow",
|
|
2111
|
+
/*'base',*/
|
|
2112
|
+
"sliceIdsTable",
|
|
2113
|
+
"sliceIdsTableRow",
|
|
2114
|
+
"componentsTable"
|
|
2115
|
+
];
|
|
1720
2116
|
class Join {
|
|
1721
|
-
constructor(baseRows, _baseColumnSelection, _objectMap) {
|
|
1722
|
-
this._baseColumnSelection = _baseColumnSelection;
|
|
1723
|
-
this._objectMap = _objectMap;
|
|
1724
|
-
this._base = this._hashedRows(baseRows);
|
|
1725
|
-
}
|
|
1726
2117
|
_base = {};
|
|
2118
|
+
_baseColumnSelection;
|
|
1727
2119
|
_processes = [];
|
|
2120
|
+
constructor(rows, columnSelection) {
|
|
2121
|
+
this._base = this._hashedRows(rows);
|
|
2122
|
+
this._baseColumnSelection = columnSelection;
|
|
2123
|
+
}
|
|
1728
2124
|
// ...........................................................................
|
|
1729
2125
|
/**
|
|
1730
2126
|
* Applies a filter to the join and returns the filtered view
|
|
@@ -1753,14 +2149,62 @@ class Join {
|
|
|
1753
2149
|
const data = {};
|
|
1754
2150
|
for (const [sliceId, joinRowH] of Object.entries(this.data)) {
|
|
1755
2151
|
const cols = [...joinRowH.columns];
|
|
2152
|
+
const insertCols = [];
|
|
1756
2153
|
for (const col of cols) {
|
|
1757
|
-
|
|
1758
|
-
col
|
|
1759
|
-
|
|
2154
|
+
const insertCol = {
|
|
2155
|
+
...col
|
|
2156
|
+
//inserts: col.inserts ? [...col.inserts] : [],
|
|
2157
|
+
};
|
|
2158
|
+
if (Route.fromFlat(setValue.route).equalsWithoutRefs(col.route)) {
|
|
2159
|
+
for (const cell of col.value.cell) {
|
|
2160
|
+
if (cell.path.length === 0) {
|
|
2161
|
+
throw new Error(
|
|
2162
|
+
`Join: Error while applying SetValue: Cannot set value for column without paths. Route: ${setValue.route.toString()}.`
|
|
2163
|
+
);
|
|
2164
|
+
}
|
|
2165
|
+
if (cell.path.length > 1) {
|
|
2166
|
+
throw new Error(
|
|
2167
|
+
`Join: Error while applying SetValue: Cannot set value for multiple paths in one cell. Found paths: [${cell.path.join(", ")}] for route: ${setValue.route.toString()}.`
|
|
2168
|
+
);
|
|
2169
|
+
}
|
|
2170
|
+
const cellInsertTree = isolate(
|
|
2171
|
+
{ ...col.value.tree },
|
|
2172
|
+
cell.path[0],
|
|
2173
|
+
joinPreserveKeys
|
|
2174
|
+
);
|
|
2175
|
+
inject(cellInsertTree, cell.path[0], setValue.value);
|
|
2176
|
+
const propertyKey = cell.path[0].slice(-1)[0];
|
|
2177
|
+
const insert = {
|
|
2178
|
+
cell: [
|
|
2179
|
+
{
|
|
2180
|
+
...cell,
|
|
2181
|
+
...{ value: setValue.value },
|
|
2182
|
+
...{
|
|
2183
|
+
row: {
|
|
2184
|
+
...cell.row,
|
|
2185
|
+
...{ [propertyKey]: setValue.value }
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
],
|
|
2190
|
+
tree: cellInsertTree,
|
|
2191
|
+
rljson: col.value.rljson
|
|
2192
|
+
};
|
|
2193
|
+
if (insert) {
|
|
2194
|
+
if (insertCol.inserts) insertCol.inserts.push(insert);
|
|
2195
|
+
else insertCol.inserts = [insert];
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
insertCols.push(insertCol);
|
|
1760
2200
|
}
|
|
1761
2201
|
data[sliceId] = {
|
|
1762
|
-
rowHash: Hash.default.calcHash(
|
|
1763
|
-
|
|
2202
|
+
rowHash: Hash.default.calcHash(
|
|
2203
|
+
insertCols.map(
|
|
2204
|
+
(col) => col.value.cell.flatMap((c) => c.value)
|
|
2205
|
+
)
|
|
2206
|
+
),
|
|
2207
|
+
columns: insertCols
|
|
1764
2208
|
};
|
|
1765
2209
|
}
|
|
1766
2210
|
const process = {
|
|
@@ -1803,15 +2247,15 @@ class Join {
|
|
|
1803
2247
|
const data = {};
|
|
1804
2248
|
for (let i2 = 0; i2 < this.rowCount; i2++) {
|
|
1805
2249
|
const [sliceId, row] = Object.entries(this.data)[i2];
|
|
1806
|
-
const
|
|
2250
|
+
const cols = [];
|
|
1807
2251
|
for (let j = 0; j < masterColumnIndices.length; j++) {
|
|
1808
|
-
|
|
2252
|
+
cols.push(row.columns[masterColumnIndices[j]]);
|
|
1809
2253
|
}
|
|
1810
2254
|
data[sliceId] = {
|
|
1811
2255
|
rowHash: Hash.default.calcHash(
|
|
1812
|
-
|
|
2256
|
+
cols.map((col) => col.value.cell.flatMap((c) => c.value))
|
|
1813
2257
|
),
|
|
1814
|
-
columns:
|
|
2258
|
+
columns: cols
|
|
1815
2259
|
};
|
|
1816
2260
|
}
|
|
1817
2261
|
const process = {
|
|
@@ -1850,30 +2294,51 @@ class Join {
|
|
|
1850
2294
|
* Returns insert Object of the join
|
|
1851
2295
|
*/
|
|
1852
2296
|
insert() {
|
|
1853
|
-
const
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
const
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
2297
|
+
const inserts = [];
|
|
2298
|
+
for (let i = 0; i < this.columnCount; i++) {
|
|
2299
|
+
const colInserts = [];
|
|
2300
|
+
for (const row of Object.values(this.data)) {
|
|
2301
|
+
const col = row.columns[i];
|
|
2302
|
+
if (col.inserts && col.inserts.length > 0) {
|
|
2303
|
+
for (const insert of col.inserts) {
|
|
2304
|
+
for (const cell of insert.cell) {
|
|
2305
|
+
const tree = insert.tree;
|
|
2306
|
+
const path = cell.path;
|
|
2307
|
+
inject(tree, path[0].slice(0, -1), cell.row);
|
|
2308
|
+
colInserts.push({
|
|
2309
|
+
route: col.route,
|
|
2310
|
+
tree,
|
|
2311
|
+
path: path[0]
|
|
2312
|
+
});
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
if (colInserts.length === 0) continue;
|
|
2318
|
+
const routes = colInserts.map((ins) => ins.route.flat);
|
|
2319
|
+
const uniqueRoute = Array.from(new Set(routes));
|
|
2320
|
+
if (uniqueRoute.length > 1) {
|
|
2321
|
+
throw new Error(
|
|
2322
|
+
`Join: Error while generating insert: Multiple different routes found in inserts: ${uniqueRoute.map((r) => r.toString()).join(", ")}. Cannot generate single insert object.`
|
|
1862
2323
|
);
|
|
1863
|
-
const mergedValue = merge(existingValue, cakeInsert.value);
|
|
1864
|
-
cakeInsertsMergedOfLayerRoutes.set(cakeInsertRoute, mergedValue);
|
|
1865
2324
|
}
|
|
2325
|
+
const merged = mergeTrees(
|
|
2326
|
+
colInserts.map((ins) => ({
|
|
2327
|
+
tree: ins.tree,
|
|
2328
|
+
path: ins.path.slice(0, -1)
|
|
2329
|
+
}))
|
|
2330
|
+
);
|
|
2331
|
+
traverse(merged, ({ parent, key, value }) => {
|
|
2332
|
+
if (key == "_data" && Array.isArray(value) && value.length > 0) {
|
|
2333
|
+
parent[key] = value.filter((v) => !!v);
|
|
2334
|
+
}
|
|
2335
|
+
});
|
|
2336
|
+
inserts.push({
|
|
2337
|
+
route: Route.fromFlat(uniqueRoute[0]).toRouteWithProperty(),
|
|
2338
|
+
tree: merged
|
|
2339
|
+
});
|
|
1866
2340
|
}
|
|
1867
|
-
|
|
1868
|
-
for (const [route, value] of cakeInsertsMergedOfLayerRoutes) {
|
|
1869
|
-
const insert = {
|
|
1870
|
-
command: "add",
|
|
1871
|
-
route,
|
|
1872
|
-
value
|
|
1873
|
-
};
|
|
1874
|
-
results.push(insert);
|
|
1875
|
-
}
|
|
1876
|
-
return results;
|
|
2341
|
+
return inserts;
|
|
1877
2342
|
}
|
|
1878
2343
|
// ...........................................................................
|
|
1879
2344
|
/**
|
|
@@ -2020,7 +2485,11 @@ class Join {
|
|
|
2020
2485
|
const dataColRoute = dataCol.route;
|
|
2021
2486
|
return colInfoRoute.equalsWithoutRefs(dataColRoute);
|
|
2022
2487
|
});
|
|
2023
|
-
|
|
2488
|
+
const insertValue = joinCol && joinCol.inserts ? joinCol.inserts.flatMap(
|
|
2489
|
+
(con) => con.cell.flatMap((c) => c.value)
|
|
2490
|
+
) ?? null : null;
|
|
2491
|
+
const baseValue = joinCol && joinCol.value.cell ? joinCol.value.cell.flatMap((c) => c.value) ?? null : null;
|
|
2492
|
+
row.push(insertValue ?? baseValue);
|
|
2024
2493
|
}
|
|
2025
2494
|
result.push(row);
|
|
2026
2495
|
}
|
|
@@ -2029,184 +2498,26 @@ class Join {
|
|
|
2029
2498
|
static empty() {
|
|
2030
2499
|
return new Join({}, ColumnSelection.empty());
|
|
2031
2500
|
}
|
|
2032
|
-
//#############################################################
|
|
2033
|
-
// ############# Private Methods ##############################
|
|
2034
|
-
//#############################################################
|
|
2035
2501
|
// ...........................................................................
|
|
2036
2502
|
/**
|
|
2037
|
-
*
|
|
2038
|
-
*
|
|
2039
|
-
* @
|
|
2503
|
+
* Hashes the given join rows. If insert value is present, it is used for hashing.
|
|
2504
|
+
*
|
|
2505
|
+
* @param rows The join rows to hash
|
|
2506
|
+
* @returns The hashed join rows
|
|
2040
2507
|
*/
|
|
2041
|
-
|
|
2042
|
-
const
|
|
2043
|
-
const
|
|
2044
|
-
for (const
|
|
2045
|
-
const
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
const cakeInsertObject = {};
|
|
2051
|
-
for (const [layerRoute, layerInsertObj] of Object.entries(
|
|
2052
|
-
layerInsertObject
|
|
2053
|
-
)) {
|
|
2054
|
-
cakeInsertObject[cakeRoute.root.tableKey] = {
|
|
2055
|
-
route: layerInsertObj.route,
|
|
2056
|
-
value: {
|
|
2057
|
-
[layerRoute]: layerInsertObj.value
|
|
2058
|
-
}
|
|
2059
|
-
};
|
|
2060
|
-
}
|
|
2061
|
-
cakeInsertObjects.push(cakeInsertObject);
|
|
2062
|
-
}
|
|
2063
|
-
}
|
|
2064
|
-
return cakeInsertObjects;
|
|
2065
|
-
}
|
|
2066
|
-
// ...........................................................................
|
|
2067
|
-
/**
|
|
2068
|
-
* Wraps component insert objects into layer insert objects
|
|
2069
|
-
* @param sliceId - The slice id
|
|
2070
|
-
* @param componentInsertObjects - The component insert objects
|
|
2071
|
-
* @returns
|
|
2072
|
-
*/
|
|
2073
|
-
_insertLayerObjects(sliceId, insertRow) {
|
|
2074
|
-
const layerRoutes = this.layerRoutes;
|
|
2075
|
-
const layerInsertObjects = [];
|
|
2076
|
-
const insertComponentObjects = this._insertComponentObjects(
|
|
2077
|
-
sliceId,
|
|
2078
|
-
insertRow
|
|
2079
|
-
);
|
|
2080
|
-
for (const layerRoute of layerRoutes) {
|
|
2081
|
-
for (const [compRouteFlat, compInsertObj] of Object.entries(
|
|
2082
|
-
insertComponentObjects
|
|
2083
|
-
)) {
|
|
2084
|
-
if (!compInsertObj._somethingToInsert) continue;
|
|
2085
|
-
const compRoute = Route.fromFlat(compRouteFlat);
|
|
2086
|
-
if (layerRoute.includes(compRoute)) {
|
|
2087
|
-
const layerInsertObj = {};
|
|
2088
|
-
layerInsertObj[layerRoute.root.tableKey] = {
|
|
2089
|
-
route: Route.fromFlat(compRouteFlat),
|
|
2090
|
-
value: {
|
|
2091
|
-
[sliceId]: compInsertObj
|
|
2092
|
-
}
|
|
2093
|
-
};
|
|
2094
|
-
layerInsertObjects.push(layerInsertObj);
|
|
2095
|
-
} else {
|
|
2096
|
-
continue;
|
|
2097
|
-
}
|
|
2098
|
-
}
|
|
2099
|
-
}
|
|
2100
|
-
return layerInsertObjects;
|
|
2101
|
-
}
|
|
2102
|
-
// ...........................................................................
|
|
2103
|
-
/**
|
|
2104
|
-
* Merges columns into component insert objects
|
|
2105
|
-
* @param insertColumns - The columns to merge
|
|
2106
|
-
* @returns
|
|
2107
|
-
*/
|
|
2108
|
-
_insertComponentObjects(sliceId, insertColumns) {
|
|
2109
|
-
const columns = this._mergeInsertRow(sliceId, insertColumns);
|
|
2110
|
-
return this._denormalizeComponentInserts(columns, this._objectMap || {});
|
|
2111
|
-
}
|
|
2112
|
-
_denormalizeComponentInserts(columns, objectMap, refTableKey) {
|
|
2113
|
-
const result = {};
|
|
2114
|
-
for (const [propertyKey, propertyValue] of Object.entries(objectMap)) {
|
|
2115
|
-
if (typeof propertyValue === "object") {
|
|
2116
|
-
const refObjectMap = {};
|
|
2117
|
-
const refTableKey2 = propertyValue._tableKey;
|
|
2118
|
-
for (const [refKey, refValue] of Object.entries(
|
|
2119
|
-
propertyValue
|
|
2120
|
-
)) {
|
|
2121
|
-
if (refKey === "_tableKey") continue;
|
|
2122
|
-
refObjectMap[refTableKey2 + "/" + refKey] = refValue;
|
|
2123
|
-
}
|
|
2124
|
-
const refInsert = this._denormalizeComponentInserts(
|
|
2125
|
-
columns,
|
|
2126
|
-
refObjectMap,
|
|
2127
|
-
refTableKey2
|
|
2128
|
-
);
|
|
2129
|
-
for (const [refRoute, refObject] of Object.entries(refInsert)) {
|
|
2130
|
-
const insertObj = { [propertyKey]: refObject };
|
|
2131
|
-
result[refRoute] = {
|
|
2132
|
-
...result[refRoute],
|
|
2133
|
-
...insertObj,
|
|
2134
|
-
...{
|
|
2135
|
-
_somethingToInsert: result[refRoute]._somethingToInsert || refObject._somethingToInsert
|
|
2136
|
-
}
|
|
2137
|
-
};
|
|
2138
|
-
}
|
|
2139
|
-
} else {
|
|
2140
|
-
let compKey = Route.fromFlat(propertyValue).upper().flat;
|
|
2141
|
-
compKey = refTableKey ? compKey.replace(`/${refTableKey}`, "") : compKey;
|
|
2142
|
-
const refPropertyKey = refTableKey ? propertyKey.replace(`${refTableKey}/`, "") : propertyKey;
|
|
2143
|
-
if (!result[compKey]) result[compKey] = {};
|
|
2144
|
-
if (refTableKey && !result[compKey]._tableKey)
|
|
2145
|
-
result[compKey]._tableKey = refTableKey;
|
|
2146
|
-
const propValue = columns.find((col) => {
|
|
2147
|
-
return col.route.propertyKey === propertyKey;
|
|
2148
|
-
});
|
|
2149
|
-
if (!propValue) {
|
|
2150
|
-
throw new Error(
|
|
2151
|
-
`Join._denormalizeComponentInserts: Could not find column value for property key "${propertyKey}".`
|
|
2152
|
-
);
|
|
2153
|
-
}
|
|
2154
|
-
const somethingToInsert = !!propValue.insert;
|
|
2155
|
-
result[compKey] = {
|
|
2156
|
-
...result[compKey],
|
|
2157
|
-
[refPropertyKey]: propValue.insert ?? propValue.value,
|
|
2158
|
-
...{
|
|
2159
|
-
_somethingToInsert: result[compKey]._somethingToInsert || somethingToInsert
|
|
2160
|
-
}
|
|
2161
|
-
};
|
|
2162
|
-
}
|
|
2163
|
-
}
|
|
2164
|
-
return result;
|
|
2165
|
-
}
|
|
2166
|
-
// ...........................................................................
|
|
2167
|
-
/**
|
|
2168
|
-
* Merges the insert values into the base row
|
|
2169
|
-
* @param sliceId - The slice id
|
|
2170
|
-
* @param insertRow - The insert row
|
|
2171
|
-
* @returns The merged join row
|
|
2172
|
-
*/
|
|
2173
|
-
_mergeInsertRow(sliceId, insertRow) {
|
|
2174
|
-
const baseColumns = this._base[sliceId].columns;
|
|
2175
|
-
const mergedRow = [];
|
|
2176
|
-
for (const baseCol of baseColumns) {
|
|
2177
|
-
const insertCol = insertRow.find(
|
|
2178
|
-
(col) => col.route.equalsWithoutRefs(baseCol.route)
|
|
2179
|
-
);
|
|
2180
|
-
if (insertCol) {
|
|
2181
|
-
mergedRow.push({
|
|
2182
|
-
route: baseCol.route,
|
|
2183
|
-
value: baseCol.value,
|
|
2184
|
-
insert: insertCol.insert
|
|
2185
|
-
});
|
|
2186
|
-
} else {
|
|
2187
|
-
mergedRow.push(baseCol);
|
|
2188
|
-
}
|
|
2189
|
-
}
|
|
2190
|
-
return mergedRow;
|
|
2191
|
-
}
|
|
2192
|
-
// ...........................................................................
|
|
2193
|
-
/**
|
|
2194
|
-
* Hashes the given join rows. If insert value is present, it is used for hashing.
|
|
2195
|
-
*
|
|
2196
|
-
* @param rows The join rows to hash
|
|
2197
|
-
* @returns The hashed join rows
|
|
2198
|
-
*/
|
|
2199
|
-
_hashedRows(rows) {
|
|
2200
|
-
const sliceIds = Object.keys(rows);
|
|
2201
|
-
const hashedRows = {};
|
|
2202
|
-
for (const sliceId of sliceIds) {
|
|
2203
|
-
const columns = rows[sliceId];
|
|
2204
|
-
const rowHash = Hash.default.calcHash(
|
|
2205
|
-
columns.map((col) => col.insert ?? col.value)
|
|
2508
|
+
_hashedRows(rows) {
|
|
2509
|
+
const sliceIds = Object.keys(rows);
|
|
2510
|
+
const hashedRows = {};
|
|
2511
|
+
for (const sliceId of sliceIds) {
|
|
2512
|
+
const cols = rows[sliceId];
|
|
2513
|
+
const rowHash = Hash.default.calcHash(
|
|
2514
|
+
cols.map(
|
|
2515
|
+
(col) => col.inserts?.flatMap((con) => con.cell.flatMap((c) => c.value)) ?? col.value.cell ? col.value.cell.flatMap((c) => c.value) : []
|
|
2516
|
+
)
|
|
2206
2517
|
);
|
|
2207
2518
|
hashedRows[sliceId] = {
|
|
2208
2519
|
rowHash,
|
|
2209
|
-
columns
|
|
2520
|
+
columns: cols
|
|
2210
2521
|
};
|
|
2211
2522
|
}
|
|
2212
2523
|
return hashedRows;
|
|
@@ -2276,6 +2587,25 @@ class Notify {
|
|
|
2276
2587
|
return this._callbacks.get(route.flat) || [];
|
|
2277
2588
|
}
|
|
2278
2589
|
}
|
|
2590
|
+
const makeUniqueArrayByHash = (arr) => {
|
|
2591
|
+
const seen = /* @__PURE__ */ new Map();
|
|
2592
|
+
const result = [];
|
|
2593
|
+
for (const item of arr) {
|
|
2594
|
+
if (!seen.has(item._hash)) {
|
|
2595
|
+
seen.set(item._hash, item);
|
|
2596
|
+
result.push(item);
|
|
2597
|
+
}
|
|
2598
|
+
}
|
|
2599
|
+
return result;
|
|
2600
|
+
};
|
|
2601
|
+
const makeUnique = (rljson) => {
|
|
2602
|
+
traverse(rljson, ({ parent, key, value }) => {
|
|
2603
|
+
if (key == "_data" && Array.isArray(value)) {
|
|
2604
|
+
parent[key] = makeUniqueArrayByHash(value);
|
|
2605
|
+
}
|
|
2606
|
+
});
|
|
2607
|
+
return rljson;
|
|
2608
|
+
};
|
|
2279
2609
|
class Db {
|
|
2280
2610
|
/**
|
|
2281
2611
|
* Constructor
|
|
@@ -2300,22 +2630,27 @@ class Db {
|
|
|
2300
2630
|
* Get data from a route with optional filtering
|
|
2301
2631
|
* @param route - The route to get data from
|
|
2302
2632
|
* @param where - Optional filter to apply to the data
|
|
2633
|
+
* @param filter - Optional filter to apply to child entries in related tables
|
|
2634
|
+
* @param sliceIds - Optional slice IDs to filter the data
|
|
2303
2635
|
* @returns An array of Rljson objects matching the route and filter
|
|
2304
2636
|
* @throws {Error} If the route is not valid or if any controller cannot be created
|
|
2305
2637
|
*/
|
|
2306
|
-
async get(route, where) {
|
|
2638
|
+
async get(route, where, filter, sliceIds) {
|
|
2307
2639
|
if (!route.isValid) throw new Error(`Route ${route.flat} is not valid.`);
|
|
2308
2640
|
const isolatedRoute = await this.isolatePropertyKeyFromRoute(route);
|
|
2309
|
-
const
|
|
2310
|
-
const
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2641
|
+
const controllers = await this.indexedControllers(isolatedRoute);
|
|
2642
|
+
const data = await this._get(
|
|
2643
|
+
isolatedRoute,
|
|
2644
|
+
where,
|
|
2645
|
+
controllers,
|
|
2646
|
+
filter,
|
|
2647
|
+
sliceIds
|
|
2648
|
+
);
|
|
2649
|
+
const dataWithControllers = {
|
|
2650
|
+
...data,
|
|
2651
|
+
...{ controllers }
|
|
2652
|
+
};
|
|
2653
|
+
return dataWithControllers;
|
|
2319
2654
|
}
|
|
2320
2655
|
// ...........................................................................
|
|
2321
2656
|
/**
|
|
@@ -2326,37 +2661,108 @@ class Db {
|
|
|
2326
2661
|
* @param where - The recursive filtering key/value pairs to apply to the data
|
|
2327
2662
|
* @param controllers - The controllers to use for fetching data
|
|
2328
2663
|
* @param filter - Optional filter to apply to the data at the current route segment
|
|
2664
|
+
* @param sliceIds - Optional slice IDs to filter the data at the current route segment
|
|
2329
2665
|
* @returns - An Rljson object matching the route and filters
|
|
2330
2666
|
*/
|
|
2331
|
-
async _get(route, where, controllers, filter) {
|
|
2667
|
+
async _get(route, where, controllers, filter, sliceIds, routeAccumulator) {
|
|
2668
|
+
const params = {
|
|
2669
|
+
route: route.flat,
|
|
2670
|
+
where,
|
|
2671
|
+
filter,
|
|
2672
|
+
sliceIds,
|
|
2673
|
+
routeAccumulator: routeAccumulator ? routeAccumulator.flat : ""
|
|
2674
|
+
};
|
|
2675
|
+
const cacheHash = hsh(rmhsh(params))._hash;
|
|
2676
|
+
const isCached = this._cache.has(cacheHash);
|
|
2677
|
+
if (isCached) {
|
|
2678
|
+
return this._cache.get(cacheHash);
|
|
2679
|
+
}
|
|
2332
2680
|
const nodeTableKey = route.top.tableKey;
|
|
2333
2681
|
const nodeRoute = route;
|
|
2334
2682
|
const nodeRouteRef = await this._getReferenceOfRouteSegment(nodeRoute.top);
|
|
2335
2683
|
const nodeController = controllers[nodeTableKey];
|
|
2684
|
+
const nodeSliceIds = nodeRoute.top.sliceIds ?? sliceIds;
|
|
2336
2685
|
let nodeWhere = typeof where === "object" ? { ...where } : where;
|
|
2337
2686
|
if (!route.isRoot && typeof nodeWhere === "object") {
|
|
2338
2687
|
delete nodeWhere[nodeRoute.deeper().top.tableKey];
|
|
2339
2688
|
}
|
|
2340
2689
|
nodeWhere = nodeWhere ? typeof nodeWhere === "string" ? { _hash: nodeWhere } : nodeWhere : {};
|
|
2341
2690
|
if (nodeRouteRef && nodeRouteRef.length > 0)
|
|
2342
|
-
nodeWhere = {
|
|
2691
|
+
nodeWhere = { _hash: nodeRouteRef };
|
|
2343
2692
|
delete nodeWhere["_through"];
|
|
2344
2693
|
delete nodeWhere["_tableKey"];
|
|
2345
2694
|
const {
|
|
2346
2695
|
[nodeTableKey]: { _data: nodeRows, _type: nodeType, _hash: nodeHash }
|
|
2347
2696
|
} = await nodeController.get(nodeWhere);
|
|
2697
|
+
const nodeColumnCfgs = nodeController.tableCfg().columns;
|
|
2348
2698
|
const nodeRowsFiltered = [];
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2699
|
+
for (const nodeRow of nodeRows) {
|
|
2700
|
+
const filterActive = filter && filter.length > 0;
|
|
2701
|
+
const sliceIdActive = nodeSliceIds && nodeSliceIds.length > 0;
|
|
2702
|
+
if (!filterActive && !sliceIdActive) {
|
|
2703
|
+
nodeRowsFiltered.push(nodeRow);
|
|
2704
|
+
continue;
|
|
2705
|
+
}
|
|
2706
|
+
let filterResult = false;
|
|
2707
|
+
const filterProperties = [];
|
|
2708
|
+
if (filterActive) {
|
|
2709
|
+
for (const f of filter) {
|
|
2710
|
+
if (f.tableKey !== nodeTableKey) continue;
|
|
2353
2711
|
if (nodeRow._hash === f.ref) {
|
|
2354
|
-
|
|
2712
|
+
filterProperties.push(f);
|
|
2713
|
+
filterResult = true;
|
|
2355
2714
|
}
|
|
2356
2715
|
}
|
|
2716
|
+
} else {
|
|
2717
|
+
filterResult = true;
|
|
2718
|
+
}
|
|
2719
|
+
let sliceIdResult = false;
|
|
2720
|
+
if (sliceIdActive) {
|
|
2721
|
+
switch (nodeType) {
|
|
2722
|
+
case "cakes":
|
|
2723
|
+
const cake = nodeRow;
|
|
2724
|
+
const cakeSliceIds = await this._resolveSliceIds(
|
|
2725
|
+
cake.sliceIdsTable,
|
|
2726
|
+
cake.sliceIdsRow
|
|
2727
|
+
);
|
|
2728
|
+
const cakeMatchesSliceIds = nodeSliceIds.filter(
|
|
2729
|
+
(sId) => cakeSliceIds.includes(sId)
|
|
2730
|
+
);
|
|
2731
|
+
if (cakeMatchesSliceIds.length > 0) sliceIdResult = true;
|
|
2732
|
+
break;
|
|
2733
|
+
case "layers":
|
|
2734
|
+
const layer = nodeRow;
|
|
2735
|
+
const layerSliceIds = await this._resolveSliceIds(
|
|
2736
|
+
layer.sliceIdsTable,
|
|
2737
|
+
layer.sliceIdsTableRow
|
|
2738
|
+
);
|
|
2739
|
+
const layerMatchesSliceIds = nodeSliceIds.filter(
|
|
2740
|
+
(sId) => layerSliceIds.includes(sId)
|
|
2741
|
+
);
|
|
2742
|
+
if (layerMatchesSliceIds.length > 0) sliceIdResult = true;
|
|
2743
|
+
break;
|
|
2744
|
+
case "components":
|
|
2745
|
+
if (filterProperties.length > 0) {
|
|
2746
|
+
const componentSliceIds = filterProperties.flatMap(
|
|
2747
|
+
(f) => f.sliceIds
|
|
2748
|
+
);
|
|
2749
|
+
const componentMatchesSliceIds = nodeSliceIds.filter(
|
|
2750
|
+
(sId) => componentSliceIds.includes(sId)
|
|
2751
|
+
);
|
|
2752
|
+
if (componentMatchesSliceIds.length > 0) {
|
|
2753
|
+
sliceIdResult = true;
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2756
|
+
break;
|
|
2757
|
+
/* v8 ignore next -- @preserve */
|
|
2758
|
+
default:
|
|
2759
|
+
sliceIdResult = true;
|
|
2760
|
+
break;
|
|
2761
|
+
}
|
|
2762
|
+
} else {
|
|
2763
|
+
sliceIdResult = true;
|
|
2357
2764
|
}
|
|
2358
|
-
|
|
2359
|
-
nodeRowsFiltered.push(...nodeRows);
|
|
2765
|
+
if (filterResult && sliceIdResult) nodeRowsFiltered.push(nodeRow);
|
|
2360
2766
|
}
|
|
2361
2767
|
const node = {
|
|
2362
2768
|
[nodeTableKey]: {
|
|
@@ -2365,11 +2771,48 @@ class Db {
|
|
|
2365
2771
|
_hash: nodeHash
|
|
2366
2772
|
}
|
|
2367
2773
|
};
|
|
2774
|
+
const nodeValue = node[nodeTableKey]._data.filter(
|
|
2775
|
+
(v) => v !== void 0 && v !== null
|
|
2776
|
+
);
|
|
2368
2777
|
if (route.isRoot) {
|
|
2369
2778
|
if (route.hasPropertyKey) {
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2779
|
+
const isolatedNode = this.isolatePropertyFromComponents(
|
|
2780
|
+
node,
|
|
2781
|
+
route.propertyKey
|
|
2782
|
+
);
|
|
2783
|
+
const result3 = {
|
|
2784
|
+
rljson: isolatedNode,
|
|
2785
|
+
tree: { [nodeTableKey]: node[nodeTableKey] },
|
|
2786
|
+
cell: nodeValue.map(
|
|
2787
|
+
(v, idx) => ({
|
|
2788
|
+
value: v[route.propertyKey] ?? null,
|
|
2789
|
+
row: v,
|
|
2790
|
+
route: Route.fromFlat(
|
|
2791
|
+
(routeAccumulator ? routeAccumulator.flat : nodeTableKey) + (nodeHash ? `@${nodeHash}` : "") + `/${route.propertyKey}`
|
|
2792
|
+
).toRouteWithProperty(),
|
|
2793
|
+
path: [[nodeTableKey, "_data", idx, route.propertyKey]]
|
|
2794
|
+
})
|
|
2795
|
+
)
|
|
2796
|
+
};
|
|
2797
|
+
this._cache.set(cacheHash, result3);
|
|
2798
|
+
return result3;
|
|
2799
|
+
}
|
|
2800
|
+
const result2 = {
|
|
2801
|
+
rljson: node,
|
|
2802
|
+
tree: { [nodeTableKey]: node[nodeTableKey] },
|
|
2803
|
+
cell: nodeValue.map(
|
|
2804
|
+
(v, idx) => ({
|
|
2805
|
+
value: v[route.propertyKey] ?? null,
|
|
2806
|
+
row: v,
|
|
2807
|
+
route: Route.fromFlat(
|
|
2808
|
+
(routeAccumulator ? routeAccumulator.flat : nodeTableKey) + (nodeHash ? `@${nodeHash}` : "")
|
|
2809
|
+
),
|
|
2810
|
+
path: [[nodeTableKey, "_data", idx]]
|
|
2811
|
+
})
|
|
2812
|
+
)
|
|
2813
|
+
};
|
|
2814
|
+
this._cache.set(cacheHash, result2);
|
|
2815
|
+
return result2;
|
|
2373
2816
|
}
|
|
2374
2817
|
const childrenRoute = route.deeper();
|
|
2375
2818
|
const childrenTableKey = childrenRoute.top.tableKey;
|
|
@@ -2379,21 +2822,60 @@ class Db {
|
|
|
2379
2822
|
const nodeRowsMatchingChildrenRefs = /* @__PURE__ */ new Map();
|
|
2380
2823
|
for (let i = 0; i < nodeRowsFiltered.length; i++) {
|
|
2381
2824
|
const nodeRow = nodeRowsFiltered[i];
|
|
2825
|
+
const nodeRowObj = { ...{}, ...nodeRow };
|
|
2382
2826
|
const childrenRefs = await nodeController.getChildRefs(
|
|
2383
2827
|
nodeRow._hash
|
|
2384
2828
|
);
|
|
2385
|
-
const
|
|
2829
|
+
const childrenRefTypes = /* @__PURE__ */ new Map();
|
|
2830
|
+
const childrenRefSliceIds = /* @__PURE__ */ new Set();
|
|
2831
|
+
for (const cr of childrenRefs) {
|
|
2832
|
+
if (!!cr.columnKey) {
|
|
2833
|
+
const childrenRefColumnCfg = nodeColumnCfgs.find(
|
|
2834
|
+
(c) => c.key === cr.columnKey
|
|
2835
|
+
);
|
|
2836
|
+
if (childrenRefColumnCfg) {
|
|
2837
|
+
childrenRefTypes.set(
|
|
2838
|
+
childrenRefColumnCfg.key,
|
|
2839
|
+
childrenRefColumnCfg.ref?.type ?? ""
|
|
2840
|
+
);
|
|
2841
|
+
}
|
|
2842
|
+
if (cr.sliceIds && cr.sliceIds.length > 0) {
|
|
2843
|
+
for (const sId of cr.sliceIds) {
|
|
2844
|
+
childrenRefSliceIds.add(sId);
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
}
|
|
2848
|
+
}
|
|
2849
|
+
if (childrenRefTypes.size > 1) {
|
|
2850
|
+
throw new Error(
|
|
2851
|
+
`Db._get: Multiple reference types found for children of table ${nodeTableKey}.`
|
|
2852
|
+
);
|
|
2853
|
+
}
|
|
2854
|
+
const cakeIsReferenced = childrenRefTypes.size === 1 && [...childrenRefTypes.values()][0] === "cakes";
|
|
2855
|
+
const componentIsReferenced = childrenRefTypes.size === 1 && nodeType === "components" && [...childrenRefTypes.values()][0] === "components";
|
|
2856
|
+
const childrenSliceIds = cakeIsReferenced ? [...childrenRefSliceIds] : componentIsReferenced ? void 0 : nodeSliceIds;
|
|
2857
|
+
const {
|
|
2858
|
+
rljson: rowChildrenRljson,
|
|
2859
|
+
tree: rowChildrenTree,
|
|
2860
|
+
cell: rowChildrenCell
|
|
2861
|
+
} = await this._get(
|
|
2386
2862
|
childrenRoute,
|
|
2387
2863
|
childrenWhere,
|
|
2388
2864
|
controllers,
|
|
2389
|
-
childrenRefs
|
|
2865
|
+
childrenRefs,
|
|
2866
|
+
childrenSliceIds,
|
|
2867
|
+
Route.fromFlat(
|
|
2868
|
+
(routeAccumulator ? routeAccumulator.flat : nodeTableKey) + (nodeHash ? `@${nodeHash}` : "") + "/" + childrenTableKey
|
|
2869
|
+
)
|
|
2390
2870
|
);
|
|
2391
|
-
if (
|
|
2392
|
-
|
|
2871
|
+
if (cakeIsReferenced) {
|
|
2872
|
+
const refKey = [...childrenRefTypes.keys()][0];
|
|
2873
|
+
nodeRowObj[refKey] = rowChildrenTree;
|
|
2874
|
+
}
|
|
2875
|
+
if (rowChildrenRljson[childrenTableKey]._data.length === 0) continue;
|
|
2876
|
+
nodeChildrenArray.push(rowChildrenRljson);
|
|
2393
2877
|
if (childrenThroughProperty) {
|
|
2394
|
-
const
|
|
2395
|
-
(rc) => rc._hash
|
|
2396
|
-
);
|
|
2878
|
+
const resolvedChildrenHashes = rowChildrenRljson[childrenTableKey]._data.map((rc) => rc._hash);
|
|
2397
2879
|
for (const nr of nodeRowsFiltered) {
|
|
2398
2880
|
{
|
|
2399
2881
|
const throughHashesInRowCouldBeArray = nr[childrenThroughProperty];
|
|
@@ -2401,30 +2883,191 @@ class Db {
|
|
|
2401
2883
|
throughHashesInRowCouldBeArray
|
|
2402
2884
|
) ? throughHashesInRowCouldBeArray : [throughHashesInRowCouldBeArray];
|
|
2403
2885
|
for (const th of throughHashesInRow) {
|
|
2404
|
-
if (
|
|
2405
|
-
|
|
2886
|
+
if (resolvedChildrenHashes.includes(th)) {
|
|
2887
|
+
nodeRowObj[childrenThroughProperty] = {
|
|
2888
|
+
...rowChildrenTree[childrenTableKey],
|
|
2889
|
+
...{ _tableKey: childrenTableKey }
|
|
2890
|
+
};
|
|
2406
2891
|
}
|
|
2407
2892
|
}
|
|
2408
2893
|
}
|
|
2409
2894
|
}
|
|
2410
2895
|
}
|
|
2896
|
+
const resolvedChildren = rowChildrenRljson[childrenTableKey]._data;
|
|
2897
|
+
const childrenRefsOfRow = childrenRefs.filter(
|
|
2898
|
+
(cr) => cr.tableKey == childrenTableKey
|
|
2899
|
+
);
|
|
2900
|
+
const matchingChildrenRefs = childrenRefsOfRow.filter(
|
|
2901
|
+
(cr) => !!resolvedChildren.find((ch) => cr.ref === ch._hash)
|
|
2902
|
+
);
|
|
2903
|
+
if (nodeType === "layers") {
|
|
2904
|
+
const compChildrenTrees = rowChildrenTree[childrenTableKey]._data;
|
|
2905
|
+
const compChildrenPaths = rowChildrenCell.map((c) => c.path);
|
|
2906
|
+
const components = compChildrenTrees.map((c, idx) => {
|
|
2907
|
+
return {
|
|
2908
|
+
tree: c,
|
|
2909
|
+
path: compChildrenPaths.filter((p) => p[0][2] == idx)
|
|
2910
|
+
};
|
|
2911
|
+
});
|
|
2912
|
+
const layerTreesAndPaths = components.map(({ tree: comp, path }) => {
|
|
2913
|
+
const sliceIds2 = matchingChildrenRefs.find(
|
|
2914
|
+
(cr) => cr.ref === comp._hash
|
|
2915
|
+
)?.sliceIds;
|
|
2916
|
+
if (!sliceIds2 || sliceIds2.length === 0) {
|
|
2917
|
+
throw new Error(
|
|
2918
|
+
`Db._get: No sliceIds found for component ${comp._hash} of layer ${nodeRow._hash}.`
|
|
2919
|
+
);
|
|
2920
|
+
}
|
|
2921
|
+
if (sliceIds2.length > 1) {
|
|
2922
|
+
throw new Error(
|
|
2923
|
+
`Db._get: Multiple sliceIds found for component ${comp._hash} of layer ${nodeRow._hash}.`
|
|
2924
|
+
);
|
|
2925
|
+
}
|
|
2926
|
+
const sliceId = sliceIds2[0];
|
|
2927
|
+
const pathsForSliceId = [
|
|
2928
|
+
...path.map((p) => p[0]).map((p) => {
|
|
2929
|
+
const newPath = [...p];
|
|
2930
|
+
newPath[2] = 0;
|
|
2931
|
+
return ["add", sliceId, ...newPath];
|
|
2932
|
+
})
|
|
2933
|
+
];
|
|
2934
|
+
return {
|
|
2935
|
+
[sliceId]: {
|
|
2936
|
+
tree: {
|
|
2937
|
+
[childrenTableKey]: {
|
|
2938
|
+
...{ _data: [comp] },
|
|
2939
|
+
...{ _type: "components" }
|
|
2940
|
+
}
|
|
2941
|
+
},
|
|
2942
|
+
path: pathsForSliceId
|
|
2943
|
+
}
|
|
2944
|
+
};
|
|
2945
|
+
});
|
|
2946
|
+
const layer = layerTreesAndPaths.flatMap(
|
|
2947
|
+
(ltap) => Object.entries(ltap).map(([sliceId, { tree }]) => ({
|
|
2948
|
+
[sliceId]: tree
|
|
2949
|
+
}))
|
|
2950
|
+
).reduce((a, b) => ({ ...a, ...b }), {});
|
|
2951
|
+
const paths = layerTreesAndPaths.map(
|
|
2952
|
+
(ltap) => Object.values(ltap)[0].path
|
|
2953
|
+
);
|
|
2954
|
+
nodeRowsMatchingChildrenRefs.set(nodeRow._hash, {
|
|
2955
|
+
rljson: nodeRow,
|
|
2956
|
+
tree: {
|
|
2957
|
+
...nodeRowObj,
|
|
2958
|
+
add: { ...nodeRowObj.add, ...layer }
|
|
2959
|
+
},
|
|
2960
|
+
cell: rowChildrenCell.map(
|
|
2961
|
+
(c, idx) => ({
|
|
2962
|
+
...c,
|
|
2963
|
+
...{
|
|
2964
|
+
path: [paths.flat()[idx]]
|
|
2965
|
+
}
|
|
2966
|
+
})
|
|
2967
|
+
)
|
|
2968
|
+
});
|
|
2969
|
+
} else if (nodeType === "cakes") {
|
|
2970
|
+
nodeRowsMatchingChildrenRefs.set(nodeRow._hash, {
|
|
2971
|
+
rljson: nodeRow,
|
|
2972
|
+
tree: {
|
|
2973
|
+
...nodeRowObj,
|
|
2974
|
+
layers: { ...nodeRowObj.layers, ...rowChildrenTree }
|
|
2975
|
+
},
|
|
2976
|
+
cell: rowChildrenCell.map((c) => ({
|
|
2977
|
+
...c,
|
|
2978
|
+
...{
|
|
2979
|
+
path: c.path.map((p) => ["layers", ...p])
|
|
2980
|
+
}
|
|
2981
|
+
}))
|
|
2982
|
+
});
|
|
2983
|
+
} else if (nodeType === "components") {
|
|
2984
|
+
if (rowChildrenTree && Object.keys(rowChildrenTree).length > 0) {
|
|
2985
|
+
const columnReferenceMap = nodeColumnCfgs.filter(
|
|
2986
|
+
(c) => c.ref && ["components", "cakes"].includes(c.ref.type)
|
|
2987
|
+
).reduce((acc, curr) => {
|
|
2988
|
+
acc.set(curr.key, curr.ref.tableKey);
|
|
2989
|
+
return acc;
|
|
2990
|
+
}, /* @__PURE__ */ new Map());
|
|
2991
|
+
const resolvedRefs = {};
|
|
2992
|
+
for (const [colKey, childTableKey] of columnReferenceMap) {
|
|
2993
|
+
const tree = {
|
|
2994
|
+
...rowChildrenTree[childTableKey],
|
|
2995
|
+
...{ _tableKey: childTableKey }
|
|
2996
|
+
};
|
|
2997
|
+
const cell = rowChildrenCell.map((c) => ({
|
|
2998
|
+
...c,
|
|
2999
|
+
...{
|
|
3000
|
+
path: c.path.filter((p) => p[0] === childTableKey).map((p) => [colKey, ...p.slice(1)])
|
|
3001
|
+
}
|
|
3002
|
+
}));
|
|
3003
|
+
resolvedRefs[colKey] = { tree, cell };
|
|
3004
|
+
}
|
|
3005
|
+
const resolvedProperties = Object.entries(resolvedRefs).map(([colKey, { tree }]) => ({
|
|
3006
|
+
[colKey]: tree
|
|
3007
|
+
})).reduce((a, b) => ({ ...a, ...b }), {});
|
|
3008
|
+
const resolvedTree = {
|
|
3009
|
+
...nodeRowObj,
|
|
3010
|
+
...resolvedProperties
|
|
3011
|
+
};
|
|
3012
|
+
const resolvedCell = Object.values(resolvedRefs).map((r) => r.cell).flat();
|
|
3013
|
+
nodeRowsMatchingChildrenRefs.set(nodeRow._hash, {
|
|
3014
|
+
rljson: nodeRow,
|
|
3015
|
+
tree: resolvedTree,
|
|
3016
|
+
cell: resolvedCell
|
|
3017
|
+
});
|
|
3018
|
+
} else {
|
|
3019
|
+
nodeRowsMatchingChildrenRefs.set(nodeRow._hash, {
|
|
3020
|
+
rljson: nodeRow,
|
|
3021
|
+
tree: { ...nodeRowObj },
|
|
3022
|
+
cell: rowChildrenCell
|
|
3023
|
+
});
|
|
3024
|
+
}
|
|
3025
|
+
} else {
|
|
3026
|
+
throw new Error(
|
|
3027
|
+
`Db._get: Unsupported node type ${nodeType} for getting children.`
|
|
3028
|
+
);
|
|
3029
|
+
}
|
|
2411
3030
|
}
|
|
2412
|
-
const nodeChildren =
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
3031
|
+
const nodeChildren = makeUnique(
|
|
3032
|
+
merge(...nodeChildrenArray)
|
|
3033
|
+
);
|
|
3034
|
+
const matchedNodeRows = Array.from(nodeRowsMatchingChildrenRefs.values());
|
|
3035
|
+
const result = {
|
|
3036
|
+
rljson: {
|
|
2416
3037
|
...node,
|
|
2417
3038
|
...{
|
|
2418
3039
|
[nodeTableKey]: {
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
3040
|
+
...{
|
|
3041
|
+
_data: matchedNodeRows.map((mr) => mr.rljson),
|
|
3042
|
+
_type: nodeType
|
|
3043
|
+
},
|
|
3044
|
+
...{
|
|
3045
|
+
...nodeHash ? { _hash: nodeHash } : {}
|
|
3046
|
+
}
|
|
2422
3047
|
}
|
|
2423
3048
|
},
|
|
2424
3049
|
...nodeChildren
|
|
2425
|
-
}
|
|
2426
|
-
|
|
2427
|
-
|
|
3050
|
+
},
|
|
3051
|
+
tree: {
|
|
3052
|
+
[nodeTableKey]: {
|
|
3053
|
+
...{
|
|
3054
|
+
_data: matchedNodeRows.map((mr) => mr.tree),
|
|
3055
|
+
_type: nodeType
|
|
3056
|
+
},
|
|
3057
|
+
...{
|
|
3058
|
+
...nodeHash ? { _hash: nodeHash } : {}
|
|
3059
|
+
}
|
|
3060
|
+
}
|
|
3061
|
+
},
|
|
3062
|
+
cell: matchedNodeRows.map(
|
|
3063
|
+
(mr, idx) => mr.cell.map((c) => ({
|
|
3064
|
+
...c,
|
|
3065
|
+
...{ path: c.path.map((p) => [nodeTableKey, "_data", idx, ...p]) }
|
|
3066
|
+
}))
|
|
3067
|
+
).flat()
|
|
3068
|
+
};
|
|
3069
|
+
this._cache.set(cacheHash, result);
|
|
3070
|
+
return result;
|
|
2428
3071
|
}
|
|
2429
3072
|
// ...........................................................................
|
|
2430
3073
|
/**
|
|
@@ -2451,234 +3094,66 @@ class Db {
|
|
|
2451
3094
|
* @param rljson - The Rljson to join data for
|
|
2452
3095
|
*/
|
|
2453
3096
|
async join(columnSelection, cakeKey, cakeRef) {
|
|
2454
|
-
const
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
3097
|
+
const {
|
|
3098
|
+
tree: { [cakeKey]: cakesTable }
|
|
3099
|
+
} = await this.get(Route.fromFlat(`${cakeKey}@${cakeRef}`), {});
|
|
3100
|
+
const cakes = cakesTable._data;
|
|
3101
|
+
if (cakes.length === 0) {
|
|
2458
3102
|
throw new Error(
|
|
2459
3103
|
`Db.join: Cake with ref "${cakeRef}" not found in cake table "${cakeKey}".`
|
|
2460
3104
|
);
|
|
2461
3105
|
}
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
const layersTable = data[layerKey];
|
|
2466
|
-
const layer = layersTable._data.find(
|
|
2467
|
-
(l) => l._hash === cake.layers[layerKey]
|
|
3106
|
+
if (cakes.length > 1) {
|
|
3107
|
+
throw new Error(
|
|
3108
|
+
`Db.join: Multiple cakes with ref "${cakeRef}" found in cake table "${cakeKey}".`
|
|
2468
3109
|
);
|
|
2469
|
-
layers.set(layerKey, layer);
|
|
2470
|
-
}
|
|
2471
|
-
const components = /* @__PURE__ */ new Map();
|
|
2472
|
-
for (const [tableKey, table] of Object.entries(data)) {
|
|
2473
|
-
if (table._type !== "components") continue;
|
|
2474
|
-
components.set(tableKey, table);
|
|
2475
|
-
}
|
|
2476
|
-
const mergedSliceIds = /* @__PURE__ */ new Set();
|
|
2477
|
-
for (const layer of layers.values()) {
|
|
2478
|
-
const sliceIdsTable = layer.sliceIdsTable;
|
|
2479
|
-
const sliceIdsTableRow = layer.sliceIdsTableRow;
|
|
2480
|
-
const {
|
|
2481
|
-
[sliceIdsTable]: { _data: sliceIds }
|
|
2482
|
-
} = await this.core.readRows(sliceIdsTable, { _hash: sliceIdsTableRow });
|
|
2483
|
-
for (const sid of sliceIds) {
|
|
2484
|
-
for (const s of sid.add) {
|
|
2485
|
-
mergedSliceIds.add(s);
|
|
2486
|
-
}
|
|
2487
|
-
}
|
|
2488
3110
|
}
|
|
2489
|
-
const
|
|
2490
|
-
const
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
)
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
for (const [layerKey, layer] of layers.entries()) {
|
|
2507
|
-
const layerRef = layer._hash;
|
|
2508
|
-
const componentKey = layer.componentsTable;
|
|
2509
|
-
const componentRef = layer.add[sliceId];
|
|
2510
|
-
const componentsTable = data[componentKey];
|
|
2511
|
-
const rowComponentProperties = componentsTable._data.find(
|
|
2512
|
-
(r) => r._hash === componentRef
|
|
2513
|
-
);
|
|
2514
|
-
const resolvedProperties = this._resolveComponentProperties(
|
|
2515
|
-
rowComponentProperties,
|
|
2516
|
-
objectMap,
|
|
2517
|
-
data
|
|
2518
|
-
);
|
|
2519
|
-
const joinColumns = [];
|
|
2520
|
-
for (const [
|
|
2521
|
-
resolvedPropertyKey,
|
|
2522
|
-
resolvedPropertyValue
|
|
2523
|
-
] of Object.entries(resolvedProperties)) {
|
|
2524
|
-
const propertyRoute = cakeKey + "/" + layerKey + "/" + componentKey + "/" + resolvedPropertyKey;
|
|
2525
|
-
const propertyColumnInfo = columnInfos.get(componentKey).find((cI) => cI.route === propertyRoute);
|
|
2526
|
-
if (!!propertyColumnInfo) {
|
|
2527
|
-
const joinColumnRoute = Route.fromFlat(
|
|
2528
|
-
`${cakeKey}@${cakeRef}/${layerKey}@${layerRef}/${componentKey}@${componentRef}`
|
|
2529
|
-
);
|
|
2530
|
-
joinColumnRoute.propertyKey = resolvedPropertyKey;
|
|
2531
|
-
joinColumnInfos.set(resolvedPropertyKey, {
|
|
2532
|
-
...propertyColumnInfo,
|
|
2533
|
-
key: resolvedPropertyKey,
|
|
2534
|
-
route: joinColumnRoute.flatWithoutRefs.slice(1)
|
|
2535
|
-
});
|
|
2536
|
-
joinColumns.push({
|
|
2537
|
-
route: joinColumnRoute,
|
|
2538
|
-
value: resolvedPropertyValue ?? null,
|
|
2539
|
-
insert: null
|
|
2540
|
-
});
|
|
2541
|
-
}
|
|
2542
|
-
}
|
|
2543
|
-
sliceIdRow.push(...joinColumns);
|
|
2544
|
-
}
|
|
2545
|
-
rowMap.set(sliceId, sliceIdRow);
|
|
2546
|
-
}
|
|
2547
|
-
const joinRows = {};
|
|
2548
|
-
for (const [sliceId, joinColumns] of rowMap.entries()) {
|
|
2549
|
-
Object.assign(joinRows, {
|
|
2550
|
-
[sliceId]: joinColumns
|
|
2551
|
-
});
|
|
2552
|
-
}
|
|
2553
|
-
return new Join(
|
|
2554
|
-
joinRows,
|
|
2555
|
-
new ColumnSelection(Array.from(joinColumnInfos.values())),
|
|
2556
|
-
objectMap
|
|
2557
|
-
).select(columnSelection);
|
|
2558
|
-
}
|
|
2559
|
-
_resolveComponentProperties(componentData, objectMapOrRoute, baseData) {
|
|
2560
|
-
let result = {};
|
|
2561
|
-
for (const [propertyKey, propertyObjectMap] of Object.entries(
|
|
2562
|
-
objectMapOrRoute
|
|
2563
|
-
)) {
|
|
2564
|
-
if (propertyKey === "_tableKey") continue;
|
|
2565
|
-
if (typeof propertyObjectMap === "object") {
|
|
2566
|
-
const refs = Array.isArray(componentData[propertyKey]) ? componentData[propertyKey] : [componentData[propertyKey]];
|
|
2567
|
-
const refTableKey = propertyObjectMap["_tableKey"];
|
|
2568
|
-
const refCompTable = baseData[refTableKey];
|
|
2569
|
-
if (!refCompTable) continue;
|
|
2570
|
-
const prefixedResolvedRefCompData = {};
|
|
2571
|
-
for (const ref of refs) {
|
|
2572
|
-
const refCompData = refCompTable._data.find((r) => r._hash === ref);
|
|
2573
|
-
if (refCompData) {
|
|
2574
|
-
const resolvedRefCompData = this._resolveComponentProperties(
|
|
2575
|
-
refCompData,
|
|
2576
|
-
propertyObjectMap,
|
|
2577
|
-
baseData
|
|
2578
|
-
);
|
|
2579
|
-
for (const [refPropKey, value] of Object.entries(
|
|
2580
|
-
resolvedRefCompData
|
|
2581
|
-
)) {
|
|
2582
|
-
if (!prefixedResolvedRefCompData[`${refTableKey}/${refPropKey}`]) {
|
|
2583
|
-
prefixedResolvedRefCompData[`${refTableKey}/${refPropKey}`] = [];
|
|
2584
|
-
}
|
|
2585
|
-
prefixedResolvedRefCompData[`${refTableKey}/${refPropKey}`].push({
|
|
2586
|
-
_ref: ref,
|
|
2587
|
-
_value: value
|
|
2588
|
-
});
|
|
2589
|
-
}
|
|
2590
|
-
}
|
|
2591
|
-
result = {
|
|
2592
|
-
...result,
|
|
2593
|
-
...prefixedResolvedRefCompData
|
|
2594
|
-
};
|
|
2595
|
-
}
|
|
2596
|
-
}
|
|
2597
|
-
result = {
|
|
2598
|
-
...result,
|
|
2599
|
-
...{ [propertyKey]: componentData[propertyKey] }
|
|
2600
|
-
};
|
|
2601
|
-
}
|
|
2602
|
-
return result;
|
|
2603
|
-
}
|
|
2604
|
-
// ...........................................................................
|
|
2605
|
-
/**
|
|
2606
|
-
* Resolve a component's columns, including referenced components
|
|
2607
|
-
*
|
|
2608
|
-
* @param baseRoute - The base route for the component
|
|
2609
|
-
* @param componentKey - The component's table key
|
|
2610
|
-
* @returns - The resolved column configurations, column infos, and object map
|
|
2611
|
-
*/
|
|
2612
|
-
async _resolveComponent(baseRoute, componentKey) {
|
|
2613
|
-
const { columns: colCfgs } = await this.core.tableCfg(componentKey);
|
|
2614
|
-
const objectMap = {};
|
|
2615
|
-
const columnCfgs = [];
|
|
2616
|
-
const columnInfos = [];
|
|
2617
|
-
for (let i = 0; i < colCfgs.length; i++) {
|
|
2618
|
-
if (colCfgs[i].key === "_hash") continue;
|
|
2619
|
-
const colCfg = colCfgs[i];
|
|
2620
|
-
if (colCfg.ref) {
|
|
2621
|
-
const columnCfgsAndInfosForRef = await this._resolveComponent(
|
|
2622
|
-
baseRoute + `/${componentKey}`,
|
|
2623
|
-
colCfg.ref.tableKey
|
|
3111
|
+
const cake = cakes[0];
|
|
3112
|
+
const sliceIds = await this._resolveSliceIds(
|
|
3113
|
+
cake.sliceIdsTable,
|
|
3114
|
+
cake.sliceIdsRow
|
|
3115
|
+
);
|
|
3116
|
+
const rows = {};
|
|
3117
|
+
for (const sliceId of sliceIds) {
|
|
3118
|
+
const row = [];
|
|
3119
|
+
for (const columnInfo of columnSelection.columns) {
|
|
3120
|
+
const columnRoute = Route.fromFlat(
|
|
3121
|
+
columnInfo.route
|
|
3122
|
+
).toRouteWithProperty();
|
|
3123
|
+
const columnContainer = await this.get(
|
|
3124
|
+
columnRoute,
|
|
3125
|
+
cakeRef,
|
|
3126
|
+
void 0,
|
|
3127
|
+
[sliceId]
|
|
2624
3128
|
);
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
3129
|
+
const column = {
|
|
3130
|
+
route: columnRoute,
|
|
3131
|
+
value: columnContainer,
|
|
3132
|
+
inserts: null
|
|
2628
3133
|
};
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
key: colCfg.ref.tableKey + "/" + cc.key
|
|
2633
|
-
})
|
|
2634
|
-
);
|
|
2635
|
-
const columnInfosForRef = columnCfgsAndInfosForRef.columnInfos.map(
|
|
2636
|
-
(cc) => ({
|
|
2637
|
-
...cc,
|
|
2638
|
-
key: colCfg.ref.tableKey + "/" + cc.key
|
|
2639
|
-
})
|
|
2640
|
-
);
|
|
2641
|
-
columnCfgs.push(...columnCfgsForRef);
|
|
2642
|
-
columnInfos.push(...columnInfosForRef);
|
|
2643
|
-
}
|
|
2644
|
-
const columnRoute = Route.fromFlat(
|
|
2645
|
-
baseRoute.length > 0 ? `${baseRoute}/${componentKey}/${colCfg.key}` : `/${componentKey}/${colCfg.key}`
|
|
2646
|
-
).flat.slice(1);
|
|
2647
|
-
if (!objectMap[colCfg.key]) objectMap[colCfg.key] = columnRoute;
|
|
2648
|
-
columnCfgs.push(colCfg);
|
|
2649
|
-
columnInfos.push({
|
|
2650
|
-
...colCfg,
|
|
2651
|
-
alias: `${colCfg.key}`,
|
|
2652
|
-
route: columnRoute,
|
|
2653
|
-
titleShort: colCfg.key,
|
|
2654
|
-
titleLong: colCfg.key
|
|
2655
|
-
});
|
|
3134
|
+
row.push(column);
|
|
3135
|
+
}
|
|
3136
|
+
rows[sliceId] = row;
|
|
2656
3137
|
}
|
|
2657
|
-
return
|
|
3138
|
+
return new Join(rows, columnSelection);
|
|
2658
3139
|
}
|
|
2659
3140
|
// ...........................................................................
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
const
|
|
2669
|
-
|
|
2670
|
-
);
|
|
2671
|
-
uniqueComponentRoutes.add(
|
|
2672
|
-
isolatedComponentRoute.toRouteWithoutProperty().flat
|
|
3141
|
+
async _resolveSliceIds(sliceIdTable, sliceIdRow) {
|
|
3142
|
+
const sliceIdController = new SliceIdController(this.core, sliceIdTable);
|
|
3143
|
+
sliceIdController.init();
|
|
3144
|
+
const resolvedSliceIds = /* @__PURE__ */ new Set();
|
|
3145
|
+
const {
|
|
3146
|
+
[sliceIdTable]: { _data: sliceIds }
|
|
3147
|
+
} = await sliceIdController.get(sliceIdRow);
|
|
3148
|
+
for (const sliceId of sliceIds) {
|
|
3149
|
+
const baseSliceIds = await sliceIdController.resolveBaseSliceIds(
|
|
3150
|
+
sliceId
|
|
2673
3151
|
);
|
|
3152
|
+
for (const sId of baseSliceIds.add) {
|
|
3153
|
+
resolvedSliceIds.add(sId);
|
|
3154
|
+
}
|
|
2674
3155
|
}
|
|
2675
|
-
|
|
2676
|
-
for (const compRouteFlat of uniqueComponentRoutes) {
|
|
2677
|
-
const uniqueComponentRoute = Route.fromFlat(compRouteFlat);
|
|
2678
|
-
const componentData = await this.get(uniqueComponentRoute, {});
|
|
2679
|
-
Object.assign(data, componentData);
|
|
2680
|
-
}
|
|
2681
|
-
return data;
|
|
3156
|
+
return Array.from(resolvedSliceIds);
|
|
2682
3157
|
}
|
|
2683
3158
|
// ...........................................................................
|
|
2684
3159
|
/**
|
|
@@ -2687,17 +3162,15 @@ class Db {
|
|
|
2687
3162
|
* @returns The result of the Insert as an InsertHistoryRow
|
|
2688
3163
|
* @throws {Error} If the Insert is not valid or if any controller cannot be created
|
|
2689
3164
|
*/
|
|
2690
|
-
async insert(
|
|
2691
|
-
const
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
${JSON.stringify(errors, null, 2)}`
|
|
2698
|
-
);
|
|
3165
|
+
async insert(route, tree, options) {
|
|
3166
|
+
const controllers = await this.indexedControllers(
|
|
3167
|
+
Route.fromFlat(route.flatWithoutRefs)
|
|
3168
|
+
);
|
|
3169
|
+
const runFns = {};
|
|
3170
|
+
for (const [tableKey, controller] of Object.entries(controllers)) {
|
|
3171
|
+
runFns[tableKey] = controller.insert.bind(controller);
|
|
2699
3172
|
}
|
|
2700
|
-
return this._insert(
|
|
3173
|
+
return this._insert(route, tree, runFns, options);
|
|
2701
3174
|
}
|
|
2702
3175
|
// ...........................................................................
|
|
2703
3176
|
/**
|
|
@@ -2708,87 +3181,190 @@ ${JSON.stringify(errors, null, 2)}`
|
|
|
2708
3181
|
* @returns The result of the Insert
|
|
2709
3182
|
* @throws {Error} If the route is not valid or if any controller cannot be created
|
|
2710
3183
|
*/
|
|
2711
|
-
async _insert(
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
const
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
if (Route.segmentHasDefaultRef(segment)) {
|
|
2723
|
-
const timeIds = await this.getTimeIdsForRef(
|
|
2724
|
-
tableKey,
|
|
2725
|
-
Route.segmentRef(segment)
|
|
2726
|
-
);
|
|
2727
|
-
previous = [...previous, ...timeIds];
|
|
2728
|
-
}
|
|
3184
|
+
async _insert(route, tree, runFns, options) {
|
|
3185
|
+
const results = [];
|
|
3186
|
+
const nodeRoute = route;
|
|
3187
|
+
const nodeSegment = nodeRoute.segment(0);
|
|
3188
|
+
const nodeTableKey = nodeSegment.tableKey;
|
|
3189
|
+
const nodeTree = tree[nodeTableKey];
|
|
3190
|
+
const nodeType = nodeTree._type;
|
|
3191
|
+
if (nodeTree._data.length === 0) {
|
|
3192
|
+
throw new Error(
|
|
3193
|
+
`Db._insert: No data found for table "${nodeTableKey}" in route "${route.flat}".`
|
|
3194
|
+
);
|
|
2729
3195
|
}
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
3196
|
+
const previousHash = nodeSegment[nodeTableKey + "Ref"] ?? null;
|
|
3197
|
+
const previousTimeId = nodeSegment[nodeTableKey + "InsertHistoryRef"] ?? null;
|
|
3198
|
+
const previous = previousHash ? await this.getTimeIdsForRef(nodeTableKey, previousHash) : previousTimeId ? [previousTimeId] : [];
|
|
3199
|
+
if (!nodeRoute.isRoot) {
|
|
3200
|
+
const childRoute = nodeRoute.deeper(1);
|
|
3201
|
+
const childTableKey = childRoute.top.tableKey;
|
|
3202
|
+
if (nodeType === "cakes") {
|
|
3203
|
+
const cakes = nodeTree._data;
|
|
3204
|
+
if (cakes.length > 1) ;
|
|
3205
|
+
const cake = cakes[0];
|
|
3206
|
+
const childTree = cake.layers[childTableKey];
|
|
2737
3207
|
const childResults = await this._insert(
|
|
2738
|
-
childInsert,
|
|
2739
3208
|
childRoute,
|
|
3209
|
+
{ [childTableKey]: childTree },
|
|
2740
3210
|
runFns
|
|
2741
3211
|
);
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
3212
|
+
if (childResults.length > 1) {
|
|
3213
|
+
throw new Error(
|
|
3214
|
+
`Db._insert: Multiple inserts returned for child table "${childTableKey}" when inserting into cake table "${nodeTableKey}". Only single child inserts are supported.`
|
|
3215
|
+
);
|
|
3216
|
+
}
|
|
3217
|
+
const childResult = childResults[0];
|
|
3218
|
+
const insertValue = {
|
|
3219
|
+
...cake,
|
|
3220
|
+
...{
|
|
3221
|
+
layers: {
|
|
3222
|
+
...cake.layers,
|
|
3223
|
+
...{
|
|
3224
|
+
[childTableKey]: childResult[childTableKey + "Ref"]
|
|
3225
|
+
}
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
};
|
|
3229
|
+
const runFn = runFns[nodeTableKey];
|
|
3230
|
+
const result = await runFn("add", rmhsh(insertValue), "db.insert");
|
|
3231
|
+
results.push(
|
|
3232
|
+
...result.map((r) => ({
|
|
3233
|
+
...r,
|
|
3234
|
+
...{ previous },
|
|
3235
|
+
...{ route: route.flat }
|
|
3236
|
+
}))
|
|
2745
3237
|
);
|
|
2746
|
-
childRefs[k] = childRefArray;
|
|
2747
3238
|
}
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
{
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
3239
|
+
if (nodeType === "layers") {
|
|
3240
|
+
const layers = nodeTree._data;
|
|
3241
|
+
for (const layer of layers) {
|
|
3242
|
+
const layerInsert = {};
|
|
3243
|
+
for (const [sliceId, componentTree] of Object.entries(layer.add)) {
|
|
3244
|
+
if (sliceId === "_hash") continue;
|
|
3245
|
+
const writtenComponents = await this._insert(
|
|
3246
|
+
childRoute,
|
|
3247
|
+
componentTree,
|
|
3248
|
+
runFns
|
|
3249
|
+
);
|
|
3250
|
+
if (writtenComponents.length > 1) {
|
|
3251
|
+
throw new Error(
|
|
3252
|
+
`Db._insert: Multiple components written for layer "${layer._hash}" and sliceId "${sliceId}" is currently not supported.`
|
|
3253
|
+
);
|
|
3254
|
+
}
|
|
3255
|
+
const writtenComponent = writtenComponents[0];
|
|
3256
|
+
if (!writtenComponent || !writtenComponent[childTableKey + "Ref"]) {
|
|
3257
|
+
throw new Error(
|
|
3258
|
+
`Db._insert: No component reference returned for layer "${layer._hash}" and sliceId "${sliceId}".`
|
|
3259
|
+
);
|
|
3260
|
+
}
|
|
3261
|
+
layerInsert[sliceId] = writtenComponent[childTableKey + "Ref"];
|
|
3262
|
+
}
|
|
3263
|
+
const runFn = runFns[nodeTableKey];
|
|
3264
|
+
const result = await runFn(
|
|
3265
|
+
"add",
|
|
3266
|
+
rmhsh({
|
|
3267
|
+
...layer,
|
|
3268
|
+
...{ add: layerInsert }
|
|
3269
|
+
}),
|
|
3270
|
+
"db.insert"
|
|
3271
|
+
);
|
|
3272
|
+
results.push(
|
|
3273
|
+
...result.map((r) => ({
|
|
3274
|
+
...r,
|
|
3275
|
+
...{ previous },
|
|
3276
|
+
...{ route: route.flat }
|
|
3277
|
+
}))
|
|
3278
|
+
);
|
|
3279
|
+
}
|
|
3280
|
+
}
|
|
3281
|
+
if (["components", "edits", "multiEdits"].includes(
|
|
3282
|
+
nodeType
|
|
3283
|
+
)) {
|
|
3284
|
+
const runFn = runFns[nodeTableKey];
|
|
3285
|
+
const components = nodeTree._data;
|
|
3286
|
+
for (const component of components) {
|
|
3287
|
+
const resolvedComponent = { ...component };
|
|
3288
|
+
for (const [property, value] of Object.entries(component)) {
|
|
3289
|
+
if (value.hasOwnProperty("_tableKey") && value._tableKey === childTableKey) {
|
|
3290
|
+
const writtenReferences = await this._insert(
|
|
3291
|
+
childRoute,
|
|
3292
|
+
{ [childTableKey]: value },
|
|
3293
|
+
runFns
|
|
3294
|
+
);
|
|
3295
|
+
resolvedComponent[property] = writtenReferences.map(
|
|
3296
|
+
(wr) => wr[childTableKey + "Ref"]
|
|
3297
|
+
);
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
3300
|
+
const result = await runFn(
|
|
3301
|
+
"add",
|
|
3302
|
+
rmhsh(resolvedComponent),
|
|
3303
|
+
"db.insert"
|
|
3304
|
+
);
|
|
3305
|
+
results.push(
|
|
3306
|
+
...result.map((r) => ({
|
|
3307
|
+
...r,
|
|
3308
|
+
...{ previous },
|
|
3309
|
+
...{ route: route.flat }
|
|
3310
|
+
}))
|
|
3311
|
+
);
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
2759
3314
|
} else {
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
3315
|
+
const runFn = runFns[nodeTableKey];
|
|
3316
|
+
if (["components", "edits", "multiEdits"].includes(
|
|
3317
|
+
nodeType
|
|
3318
|
+
)) {
|
|
3319
|
+
const components = rmhsh(
|
|
3320
|
+
tree[nodeTableKey]
|
|
3321
|
+
);
|
|
3322
|
+
for (const component of components._data) {
|
|
3323
|
+
if (!component) continue;
|
|
3324
|
+
delete component._tableKey;
|
|
3325
|
+
delete component._type;
|
|
3326
|
+
const result = await runFn("add", component, "db.insert");
|
|
3327
|
+
results.push(
|
|
3328
|
+
...result.map((r) => ({
|
|
3329
|
+
...r,
|
|
3330
|
+
...{ previous },
|
|
3331
|
+
...{ route: route.flat }
|
|
3332
|
+
}))
|
|
3333
|
+
);
|
|
3334
|
+
}
|
|
3335
|
+
}
|
|
3336
|
+
if (nodeType === "layers") {
|
|
3337
|
+
const layers = rmhsh(tree[nodeTableKey]);
|
|
3338
|
+
for (const layer of layers._data) {
|
|
3339
|
+
const result = await runFn("add", layer, "db.insert");
|
|
3340
|
+
results.push(
|
|
3341
|
+
...result.map((r) => ({
|
|
3342
|
+
...r,
|
|
3343
|
+
...{ previous },
|
|
3344
|
+
...{ route: route.flat }
|
|
3345
|
+
}))
|
|
3346
|
+
);
|
|
3347
|
+
}
|
|
3348
|
+
}
|
|
3349
|
+
if (nodeType === "cakes") {
|
|
3350
|
+
const cakes = rmhsh(tree[nodeTableKey]);
|
|
3351
|
+
for (const cake of cakes._data) {
|
|
3352
|
+
const result = await runFn("add", cake, "db.insert");
|
|
3353
|
+
results.push(
|
|
3354
|
+
...result.map((r) => ({
|
|
3355
|
+
...r,
|
|
3356
|
+
...{ previous },
|
|
3357
|
+
...{ route: route.flat }
|
|
3358
|
+
}))
|
|
3359
|
+
);
|
|
2778
3360
|
}
|
|
2779
3361
|
}
|
|
2780
|
-
results = [
|
|
2781
|
-
...(await runFn(insert.command, insertValue, insert.origin)).map(
|
|
2782
|
-
(r) => ({ ...r, previous })
|
|
2783
|
-
)
|
|
2784
|
-
];
|
|
2785
3362
|
}
|
|
2786
3363
|
for (const result of results) {
|
|
2787
|
-
result.route = insert.route;
|
|
2788
3364
|
if (!options?.skipHistory)
|
|
2789
|
-
await this._writeInsertHistory(
|
|
3365
|
+
await this._writeInsertHistory(nodeTableKey, result);
|
|
2790
3366
|
if (!options?.skipNotification)
|
|
2791
|
-
this.notify.notify(Route.fromFlat(
|
|
3367
|
+
this.notify.notify(Route.fromFlat(result.route), result);
|
|
2792
3368
|
}
|
|
2793
3369
|
return results;
|
|
2794
3370
|
}
|
|
@@ -2811,48 +3387,6 @@ ${JSON.stringify(errors, null, 2)}`
|
|
|
2811
3387
|
this.notify.unregister(route, callback);
|
|
2812
3388
|
}
|
|
2813
3389
|
// ...........................................................................
|
|
2814
|
-
/**
|
|
2815
|
-
* Resolves an Insert by returning the run functions of all controllers involved in the Insert's route
|
|
2816
|
-
* @param Insert - The Insert to resolve
|
|
2817
|
-
* @returns A record of controller run functions, keyed by table name
|
|
2818
|
-
* @throws {Error} If the route is not valid or if any controller cannot be created
|
|
2819
|
-
*/
|
|
2820
|
-
async _resolveInsert(Insert2) {
|
|
2821
|
-
const controllers = await this._indexedControllers(
|
|
2822
|
-
Route.fromFlat(Insert2.route)
|
|
2823
|
-
);
|
|
2824
|
-
const referencedComponentTableKeys = /* @__PURE__ */ new Set();
|
|
2825
|
-
traverse(Insert2.value, ({ key, parent }) => {
|
|
2826
|
-
if (key == "_tableKey")
|
|
2827
|
-
referencedComponentTableKeys.add(parent[key]);
|
|
2828
|
-
});
|
|
2829
|
-
for (const tableKey of referencedComponentTableKeys) {
|
|
2830
|
-
controllers[tableKey] ??= await this.getController(tableKey);
|
|
2831
|
-
}
|
|
2832
|
-
const runFns = {};
|
|
2833
|
-
for (const tableKey of Object.keys(controllers)) {
|
|
2834
|
-
runFns[tableKey] = controllers[tableKey].insert.bind(
|
|
2835
|
-
controllers[tableKey]
|
|
2836
|
-
);
|
|
2837
|
-
}
|
|
2838
|
-
return runFns;
|
|
2839
|
-
}
|
|
2840
|
-
// ...........................................................................
|
|
2841
|
-
/**
|
|
2842
|
-
* Returns the keys of child refs in a value based on a route
|
|
2843
|
-
* @param value - The value to check
|
|
2844
|
-
* @returns An array of keys of child refs in the value
|
|
2845
|
-
*/
|
|
2846
|
-
_childKeys(value) {
|
|
2847
|
-
const keys = Object.keys(value);
|
|
2848
|
-
const childKeys = [];
|
|
2849
|
-
for (const k of keys) {
|
|
2850
|
-
if (typeof value[k] !== "object") continue;
|
|
2851
|
-
childKeys.push(k);
|
|
2852
|
-
}
|
|
2853
|
-
return childKeys;
|
|
2854
|
-
}
|
|
2855
|
-
// ...........................................................................
|
|
2856
3390
|
/**
|
|
2857
3391
|
* Get a controller for a specific table
|
|
2858
3392
|
* @param tableKey - The key of the table to get the controller for
|
|
@@ -2869,7 +3403,7 @@ ${JSON.stringify(errors, null, 2)}`
|
|
|
2869
3403
|
return createController(contentType, this.core, tableKey, refs);
|
|
2870
3404
|
}
|
|
2871
3405
|
// ...........................................................................
|
|
2872
|
-
async
|
|
3406
|
+
async indexedControllers(route) {
|
|
2873
3407
|
const controllers = {};
|
|
2874
3408
|
const isolatedRoute = await this.isolatePropertyKeyFromRoute(route);
|
|
2875
3409
|
for (let i = 0; i < isolatedRoute.segments.length; i++) {
|