@rljson/db 0.0.10 → 0.0.12

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.js CHANGED
@@ -1,4 +1,4 @@
1
- import { timeId, createInsertHistoryTableCfg, Validate, BaseValidator, Route, isTimeId, getTimeIdTimestamp, createSliceIdsTableCfg, createLayerTableCfg, createCakeTableCfg, createHeadsTableCfg } from "@rljson/rljson";
1
+ import { timeId, Route, createInsertHistoryTableCfg, Validate, BaseValidator, treeFromObject, isTimeId, getTimeIdTimestamp, createSliceIdsTableCfg, createLayerTableCfg, createCakeTableCfg } from "@rljson/rljson";
2
2
  import { rmhsh, hsh, Hash, hip } from "@rljson/hash";
3
3
  import { equals, merge } from "@rljson/json";
4
4
  import { IoMem } from "@rljson/io";
@@ -184,7 +184,6 @@ class CakeController extends BaseController {
184
184
  this._refs = _refs;
185
185
  this._contentType = "cakes";
186
186
  }
187
- _table = null;
188
187
  _baseLayers = {};
189
188
  async init() {
190
189
  if (this._tableKey.endsWith("Cake") === false) {
@@ -192,9 +191,8 @@ class CakeController extends BaseController {
192
191
  `Table ${this._tableKey} is not supported by CakeController.`
193
192
  );
194
193
  }
195
- const rljson = await this._core.dumpTable(this._tableKey);
196
- this._table = rljson[this._tableKey];
197
- if (this._table._type !== "cakes") {
194
+ const contentType = await this._core.contentType(this._tableKey);
195
+ if (contentType !== "cakes") {
198
196
  throw new Error(`Table ${this._tableKey} is not of type cakes.`);
199
197
  }
200
198
  this._tableCfg = await this._core.tableCfg(this._tableKey);
@@ -207,21 +205,9 @@ class CakeController extends BaseController {
207
205
  }
208
206
  const baseCake = baseCakes[0];
209
207
  this._baseLayers = rmhsh(baseCake.layers);
210
- } else {
211
- const cake = this._table._data[0];
212
- if (!!cake) {
213
- this._refs = {
214
- sliceIdsTable: cake.sliceIdsTable,
215
- sliceIdsRow: cake.sliceIdsRow
216
- };
217
- this._baseLayers = rmhsh(cake.layers);
218
- }
219
208
  }
220
209
  }
221
210
  async getChildRefs(where, filter) {
222
- if (!this._table) {
223
- throw new Error(`Controller not initialized.`);
224
- }
225
211
  const childRefs = [];
226
212
  const { [this._tableKey]: table } = await this.get(where, filter);
227
213
  const cakes = table._data;
@@ -302,7 +288,7 @@ class ComponentController extends BaseController {
302
288
  "edits",
303
289
  "editHistory",
304
290
  "multiEdits",
305
- "head"
291
+ "insertHistory"
306
292
  ];
307
293
  _resolvedColumns = null;
308
294
  _refTableKeyToColumnKeyMap = null;
@@ -310,9 +296,8 @@ class ComponentController extends BaseController {
310
296
  if (!!this._refs && !this._refs.base) {
311
297
  throw new Error(`Refs are not required on ComponentController.`);
312
298
  }
313
- const rljson = await this._core.dumpTable(this._tableKey);
314
- const table = rljson[this._tableKey];
315
- if (this._allowedContentTypes.indexOf(table._type) === -1) {
299
+ const contentType = await this._core.contentType(this._tableKey);
300
+ if (this._allowedContentTypes.indexOf(contentType) === -1) {
316
301
  throw new Error(`Table ${this._tableKey} is not of type components.`);
317
302
  }
318
303
  this._tableCfg = await this._core.tableCfg(this._tableKey);
@@ -653,9 +638,8 @@ class SliceIdController extends BaseController {
653
638
  `Table ${this._tableKey} is not supported by SliceIdController.`
654
639
  );
655
640
  }
656
- const rljson = await this._core.dumpTable(this._tableKey);
657
- const table = rljson[this._tableKey];
658
- if (table._type !== "sliceIds") {
641
+ const contentType = await this._core.contentType(this._tableKey);
642
+ if (contentType !== "sliceIds") {
659
643
  throw new Error(`Table ${this._tableKey} is not of type sliceIds.`);
660
644
  }
661
645
  this._tableCfg = await this._core.tableCfg(this._tableKey);
@@ -666,13 +650,6 @@ class SliceIdController extends BaseController {
666
650
  if (SliceIds2.length === 0) {
667
651
  throw new Error(`Base sliceId ${this._refs.base} does not exist.`);
668
652
  }
669
- } else {
670
- const sliceId = table._data[0];
671
- if (!!sliceId) {
672
- this._refs = {
673
- base: sliceId.base
674
- };
675
- }
676
653
  }
677
654
  }
678
655
  async insert(command, value, origin, refs) {
@@ -771,9 +748,8 @@ class LayerController extends BaseController {
771
748
  `Table ${this._tableKey} is not supported by LayerController.`
772
749
  );
773
750
  }
774
- const rljson = await this._core.dumpTable(this._tableKey);
775
- const table = rljson[this._tableKey];
776
- if (table._type !== "layers") {
751
+ const contentType = await this._core.contentType(this._tableKey);
752
+ if (contentType !== "layers") {
777
753
  throw new Error(`Table ${this._tableKey} is not of type layers.`);
778
754
  }
779
755
  this._tableCfg = await this._core.tableCfg(this._tableKey);
@@ -792,15 +768,6 @@ class LayerController extends BaseController {
792
768
  componentsTable: baseLayer.componentsTable
793
769
  };
794
770
  }
795
- } else {
796
- const layer = table._data[0];
797
- if (!!layer) {
798
- this._refs = {
799
- sliceIdsTable: layer.sliceIdsTable,
800
- sliceIdsTableRow: layer.sliceIdsTableRow,
801
- componentsTable: layer.componentsTable
802
- };
803
- }
804
771
  }
805
772
  }
806
773
  async insert(command, value, origin, refs) {
@@ -963,6 +930,199 @@ class LayerController extends BaseController {
963
930
  return false;
964
931
  }
965
932
  }
933
+ class TreeController extends BaseController {
934
+ constructor(_core, _tableKey) {
935
+ super(_core, _tableKey);
936
+ this._core = _core;
937
+ this._tableKey = _tableKey;
938
+ this._contentType = "trees";
939
+ }
940
+ async init() {
941
+ if (this._tableKey.endsWith("Tree") === false) {
942
+ throw new Error(
943
+ `Table ${this._tableKey} is not supported by TreeController.`
944
+ );
945
+ }
946
+ const contentType = await this._core.contentType(this._tableKey);
947
+ if (contentType !== "trees") {
948
+ throw new Error(`Table ${this._tableKey} is not of type trees.`);
949
+ }
950
+ this._tableCfg = await this._core.tableCfg(this._tableKey);
951
+ }
952
+ async insert(command, value, origin) {
953
+ if (!command.startsWith("add") && !command.startsWith("remove")) {
954
+ throw new Error(`Command ${command} is not supported by TreeController.`);
955
+ }
956
+ const rlJson = { [this._tableKey]: { _data: [value] } };
957
+ await this._core.import(rlJson);
958
+ const result = {
959
+ //Ref to component
960
+ [this._tableKey + "Ref"]: hsh(value)._hash,
961
+ //Data from edit
962
+ route: "",
963
+ origin,
964
+ //Unique id/timestamp
965
+ timeId: timeId()
966
+ };
967
+ return [result];
968
+ }
969
+ async get(where, filter, path) {
970
+ const {
971
+ [this._tableKey]: { _data: trees }
972
+ } = typeof where === "string" ? await this._getByHash(where, filter) : await this._getByWhere(where, filter);
973
+ if (trees.length === 0) {
974
+ return { [this._tableKey]: { _data: [], _type: "trees" } };
975
+ }
976
+ if (trees.length > 1) {
977
+ throw new Error(
978
+ `Multiple trees found for where clause. Please specify a more specific query.`
979
+ );
980
+ }
981
+ const treeRoute = Route.fromFlat(path || "");
982
+ const treeId = treeRoute.segments.length > 0 ? treeRoute.top.tableKey : null;
983
+ const tree = trees[0];
984
+ if (treeId && treeId !== tree.id) {
985
+ return { [this._tableKey]: { _data: [], _type: "trees" } };
986
+ }
987
+ const children = [];
988
+ for (const childRef of tree.children ?? []) {
989
+ const child = await this.get(
990
+ childRef,
991
+ void 0,
992
+ treeRoute.deeper().flat
993
+ );
994
+ const childData = child[this._tableKey]._data;
995
+ children.push(...childData);
996
+ }
997
+ return {
998
+ [this._tableKey]: {
999
+ _data: [...children, tree],
1000
+ _type: "trees"
1001
+ }
1002
+ };
1003
+ }
1004
+ async buildTreeFromTrees(trees) {
1005
+ if (trees.length === 0) {
1006
+ return {};
1007
+ }
1008
+ const treeMap = /* @__PURE__ */ new Map();
1009
+ for (const tree of trees) {
1010
+ treeMap.set(tree._hash, tree);
1011
+ }
1012
+ const buildObject = (tree) => {
1013
+ if (!tree.isParent || !tree.children || tree.children.length === 0) {
1014
+ return tree;
1015
+ }
1016
+ const result2 = {};
1017
+ for (const childHash of tree.children) {
1018
+ const childTree = treeMap.get(childHash);
1019
+ if (childTree && childTree.id) {
1020
+ result2[childTree.id] = buildObject(childTree);
1021
+ }
1022
+ }
1023
+ return result2;
1024
+ };
1025
+ const referencedHashes = /* @__PURE__ */ new Set();
1026
+ for (const tree of trees) {
1027
+ if (tree.children) {
1028
+ for (const childHash of tree.children) {
1029
+ referencedHashes.add(childHash);
1030
+ }
1031
+ }
1032
+ }
1033
+ const rootTrees = trees.filter(
1034
+ (tree) => !referencedHashes.has(tree._hash)
1035
+ );
1036
+ if (rootTrees.length === 0) {
1037
+ return {};
1038
+ }
1039
+ if (rootTrees.length === 1) {
1040
+ const rootTree = rootTrees[0];
1041
+ if (rootTree.id) {
1042
+ return { [rootTree.id]: buildObject(rootTree) };
1043
+ }
1044
+ return buildObject(rootTree);
1045
+ }
1046
+ const result = {};
1047
+ for (const rootTree of rootTrees) {
1048
+ if (rootTree.id) {
1049
+ result[rootTree.id] = buildObject(rootTree);
1050
+ }
1051
+ }
1052
+ return result;
1053
+ }
1054
+ async buildCellsFromTree(trees) {
1055
+ const cells = [];
1056
+ if (trees.length === 0) {
1057
+ return cells;
1058
+ }
1059
+ const treeMap = /* @__PURE__ */ new Map();
1060
+ const childToParentMap = /* @__PURE__ */ new Map();
1061
+ for (const tree of trees) {
1062
+ const treeHash = tree._hash;
1063
+ treeMap.set(treeHash, tree);
1064
+ if (tree.children) {
1065
+ for (const childHash of tree.children) {
1066
+ childToParentMap.set(childHash, treeHash);
1067
+ }
1068
+ }
1069
+ }
1070
+ const availableHashes = /* @__PURE__ */ new Set();
1071
+ for (const tree of trees) {
1072
+ availableHashes.add(tree._hash);
1073
+ }
1074
+ const leafNodes = trees.filter((tree) => {
1075
+ if (!tree.children || tree.children.length === 0) {
1076
+ return true;
1077
+ }
1078
+ const hasChildInTrees = tree.children.some(
1079
+ (childHash) => availableHashes.has(childHash)
1080
+ );
1081
+ return !hasChildInTrees;
1082
+ });
1083
+ for (const leaf of leafNodes) {
1084
+ const pathIds = [];
1085
+ let currentHash = leaf._hash;
1086
+ while (currentHash) {
1087
+ const current = treeMap.get(currentHash);
1088
+ if (!current) break;
1089
+ if (current.id) {
1090
+ pathIds.unshift(current.id);
1091
+ }
1092
+ const parentHash = childToParentMap.get(currentHash);
1093
+ if (!parentHash) break;
1094
+ currentHash = parentHash;
1095
+ }
1096
+ const routeStr = "/" + pathIds.join("/");
1097
+ const route = Route.fromFlat(routeStr);
1098
+ cells.push({
1099
+ route,
1100
+ value: leaf,
1101
+ row: leaf,
1102
+ path: [[this._tableKey, "_data", 0, ...pathIds]]
1103
+ });
1104
+ }
1105
+ return cells;
1106
+ }
1107
+ async getChildRefs(where, filter) {
1108
+ const childRefs = [];
1109
+ const { [this._tableKey]: table } = await this.get(where, filter);
1110
+ const trees = table._data;
1111
+ for (const tree of trees) {
1112
+ for (const treeChildRef of tree.children ?? []) {
1113
+ childRefs.push({
1114
+ tableKey: this._tableKey,
1115
+ ref: treeChildRef
1116
+ });
1117
+ }
1118
+ }
1119
+ return childRefs;
1120
+ }
1121
+ /* v8 ignore next -- @preserve */
1122
+ async filterRow() {
1123
+ return false;
1124
+ }
1125
+ }
966
1126
  const createController = async (type, core, tableKey, refs) => {
967
1127
  let ctrl;
968
1128
  switch (type) {
@@ -973,7 +1133,7 @@ const createController = async (type, core, tableKey, refs) => {
973
1133
  case "edits":
974
1134
  case "editHistory":
975
1135
  case "multiEdits":
976
- case "head":
1136
+ case "insertHistory":
977
1137
  ctrl = new ComponentController(core, tableKey, refs);
978
1138
  break;
979
1139
  case "cakes":
@@ -986,6 +1146,9 @@ const createController = async (type, core, tableKey, refs) => {
986
1146
  refs
987
1147
  );
988
1148
  break;
1149
+ case "trees":
1150
+ ctrl = new TreeController(core, tableKey);
1151
+ break;
989
1152
  default:
990
1153
  throw new Error(`Controller for type ${type} is not implemented yet.`);
991
1154
  }
@@ -1071,17 +1234,8 @@ class Core {
1071
1234
  }
1072
1235
  // ...........................................................................
1073
1236
  async tableCfg(table) {
1074
- const { [table]: dump } = await this._io.dumpTable({ table });
1075
- const tableCfgRef = dump._tableCfg;
1076
1237
  const tableCfgs = await this._io.rawTableCfgs();
1077
- let tableCfg;
1078
- if (!tableCfgRef) {
1079
- tableCfg = tableCfgs.find((tc) => tc.key === table);
1080
- } else {
1081
- tableCfg = tableCfgs.find(
1082
- (tc) => tc.key === table && tc._hash === tableCfgRef
1083
- );
1084
- }
1238
+ const tableCfg = tableCfgs.find((tc) => tc.key === table);
1085
1239
  return tableCfg;
1086
1240
  }
1087
1241
  // ...........................................................................
@@ -1101,7 +1255,7 @@ const inject = (tree, path, value) => {
1101
1255
  tree[segment] = value;
1102
1256
  delete tree["_hash"];
1103
1257
  } else {
1104
- if (!tree[segment]) {
1258
+ if (!tree[segment] || typeof tree[segment] !== "object") {
1105
1259
  tree[segment] = {};
1106
1260
  }
1107
1261
  tree = tree[segment];
@@ -2731,7 +2885,7 @@ class Db {
2731
2885
  * @returns An array of Rljson objects matching the route and filter
2732
2886
  * @throws {Error} If the route is not valid or if any controller cannot be created
2733
2887
  */
2734
- async get(route, where, filter, sliceIds) {
2888
+ async get(route, where, filter, sliceIds, options) {
2735
2889
  if (!route.isValid) throw new Error(`Route ${route.flat} is not valid.`);
2736
2890
  const isolatedRoute = await this.isolatePropertyKeyFromRoute(route);
2737
2891
  const controllers = await this.indexedControllers(isolatedRoute);
@@ -2740,7 +2894,9 @@ class Db {
2740
2894
  where,
2741
2895
  controllers,
2742
2896
  filter,
2743
- sliceIds
2897
+ sliceIds,
2898
+ void 0,
2899
+ options
2744
2900
  );
2745
2901
  const dataWithControllers = {
2746
2902
  ...data,
@@ -2758,20 +2914,30 @@ class Db {
2758
2914
  * @param controllers - The controllers to use for fetching data
2759
2915
  * @param filter - Optional filter to apply to the data at the current route segment
2760
2916
  * @param sliceIds - Optional slice IDs to filter the data at the current route segment
2917
+ * @param routeAccumulator - The accumulated route up to the current segment
2918
+ * @param options - Additional options for fetching data
2761
2919
  * @returns - An Rljson object matching the route and filters
2762
2920
  */
2763
- async _get(route, where, controllers, filter, sliceIds, routeAccumulator) {
2764
- const params = {
2765
- route: route.flat,
2766
- where,
2767
- filter,
2768
- sliceIds,
2769
- routeAccumulator: routeAccumulator ? routeAccumulator.flat : ""
2770
- };
2771
- const cacheHash = hsh(rmhsh(params))._hash;
2772
- const isCached = this._cache.has(cacheHash);
2773
- if (isCached) {
2774
- return this._cache.get(cacheHash);
2921
+ async _get(route, where, controllers, filter, sliceIds, routeAccumulator, options) {
2922
+ const opts = options ?? {};
2923
+ const routeHasRefs = route.flat != route.flatWithoutRefs;
2924
+ const hasFilter = filter !== void 0 && filter.length > 0;
2925
+ const cacheable = !!routeHasRefs || !!hasFilter;
2926
+ let cacheHash = "";
2927
+ if (cacheable) {
2928
+ const params = {
2929
+ route: route.flat,
2930
+ where,
2931
+ filter,
2932
+ sliceIds,
2933
+ routeAccumulator: routeAccumulator ? routeAccumulator.flat : "",
2934
+ options: opts
2935
+ };
2936
+ cacheHash = hsh(rmhsh(params))._hash;
2937
+ const isCached = this._cache.has(cacheHash);
2938
+ if (isCached) {
2939
+ return this._cache.get(cacheHash);
2940
+ }
2775
2941
  }
2776
2942
  const nodeTableKey = route.top.tableKey;
2777
2943
  const nodeRoute = route;
@@ -2789,12 +2955,59 @@ class Db {
2789
2955
  delete nodeWhere["_tableKey"];
2790
2956
  const {
2791
2957
  [nodeTableKey]: { _data: nodeRows, _type: nodeType, _hash: nodeHash }
2792
- } = await nodeController.get(nodeWhere);
2958
+ } = await nodeController.get(nodeWhere, void 0, route.propertyKey);
2793
2959
  const nodeColumnCfgs = nodeController.tableCfg().columns;
2960
+ const filterActive = filter && filter.length > 0;
2961
+ const sliceIdActive = nodeSliceIds && nodeSliceIds.length > 0;
2962
+ const filterMap = filterActive ? /* @__PURE__ */ new Map() : null;
2963
+ if (filterActive) {
2964
+ for (const f of filter) {
2965
+ if (f.tableKey === nodeTableKey) {
2966
+ if (!filterMap.has(f.ref)) {
2967
+ filterMap.set(f.ref, []);
2968
+ }
2969
+ filterMap.get(f.ref).push(f);
2970
+ }
2971
+ }
2972
+ }
2973
+ const sliceIdResolvePromises = /* @__PURE__ */ new Map();
2974
+ const nodeSliceIdSet = sliceIdActive ? new Set(nodeSliceIds) : null;
2975
+ if (sliceIdActive) {
2976
+ for (const nodeRow of nodeRows) {
2977
+ if (nodeType === "cakes") {
2978
+ const cake = nodeRow;
2979
+ const key = `${cake.sliceIdsTable}:${cake.sliceIdsRow}`;
2980
+ if (!sliceIdResolvePromises.has(key)) {
2981
+ sliceIdResolvePromises.set(
2982
+ key,
2983
+ this._resolveSliceIds(cake.sliceIdsTable, cake.sliceIdsRow)
2984
+ );
2985
+ }
2986
+ } else if (nodeType === "layers") {
2987
+ const layer = nodeRow;
2988
+ const key = `${layer.sliceIdsTable}:${layer.sliceIdsTableRow}`;
2989
+ if (!sliceIdResolvePromises.has(key)) {
2990
+ sliceIdResolvePromises.set(
2991
+ key,
2992
+ this._resolveSliceIds(
2993
+ layer.sliceIdsTable,
2994
+ layer.sliceIdsTableRow
2995
+ )
2996
+ );
2997
+ }
2998
+ }
2999
+ }
3000
+ }
3001
+ const resolvedSliceIds = /* @__PURE__ */ new Map();
3002
+ if (sliceIdResolvePromises.size > 0) {
3003
+ const entries = Array.from(sliceIdResolvePromises.entries());
3004
+ const results = await Promise.all(entries.map(([, p]) => p));
3005
+ entries.forEach(([key], idx) => {
3006
+ resolvedSliceIds.set(key, new Set(results[idx]));
3007
+ });
3008
+ }
2794
3009
  const nodeRowsFiltered = [];
2795
3010
  for (const nodeRow of nodeRows) {
2796
- const filterActive = filter && filter.length > 0;
2797
- const sliceIdActive = nodeSliceIds && nodeSliceIds.length > 0;
2798
3011
  if (!filterActive && !sliceIdActive) {
2799
3012
  nodeRowsFiltered.push(nodeRow);
2800
3013
  continue;
@@ -2802,12 +3015,10 @@ class Db {
2802
3015
  let filterResult = false;
2803
3016
  const filterProperties = [];
2804
3017
  if (filterActive) {
2805
- for (const f of filter) {
2806
- if (f.tableKey !== nodeTableKey) continue;
2807
- if (nodeRow._hash === f.ref) {
2808
- filterProperties.push(f);
2809
- filterResult = true;
2810
- }
3018
+ const rowFilters = filterMap.get(nodeRow._hash);
3019
+ if (rowFilters) {
3020
+ filterProperties.push(...rowFilters);
3021
+ filterResult = true;
2811
3022
  }
2812
3023
  } else {
2813
3024
  filterResult = true;
@@ -2817,36 +3028,36 @@ class Db {
2817
3028
  switch (nodeType) {
2818
3029
  case "cakes":
2819
3030
  const cake = nodeRow;
2820
- const cakeSliceIds = await this._resolveSliceIds(
2821
- cake.sliceIdsTable,
2822
- cake.sliceIdsRow
2823
- );
2824
- const cakeMatchesSliceIds = nodeSliceIds.filter(
2825
- (sId) => cakeSliceIds.includes(sId)
2826
- );
2827
- if (cakeMatchesSliceIds.length > 0) sliceIdResult = true;
3031
+ const cakeKey = `${cake.sliceIdsTable}:${cake.sliceIdsRow}`;
3032
+ const cakeSliceIdSet = resolvedSliceIds.get(cakeKey);
3033
+ for (const sId of nodeSliceIdSet) {
3034
+ if (cakeSliceIdSet.has(sId)) {
3035
+ sliceIdResult = true;
3036
+ break;
3037
+ }
3038
+ }
2828
3039
  break;
2829
3040
  case "layers":
2830
3041
  const layer = nodeRow;
2831
- const layerSliceIds = await this._resolveSliceIds(
2832
- layer.sliceIdsTable,
2833
- layer.sliceIdsTableRow
2834
- );
2835
- const layerMatchesSliceIds = nodeSliceIds.filter(
2836
- (sId) => layerSliceIds.includes(sId)
2837
- );
2838
- if (layerMatchesSliceIds.length > 0) sliceIdResult = true;
3042
+ const layerKey = `${layer.sliceIdsTable}:${layer.sliceIdsTableRow}`;
3043
+ const layerSliceIdSet = resolvedSliceIds.get(layerKey);
3044
+ for (const sId of nodeSliceIdSet) {
3045
+ if (layerSliceIdSet.has(sId)) {
3046
+ sliceIdResult = true;
3047
+ break;
3048
+ }
3049
+ }
2839
3050
  break;
2840
3051
  case "components":
2841
3052
  if (filterProperties.length > 0) {
2842
- const componentSliceIds = filterProperties.flatMap(
2843
- (f) => f.sliceIds
3053
+ const componentSliceIdSet = new Set(
3054
+ filterProperties.flatMap((f) => f.sliceIds)
2844
3055
  );
2845
- const componentMatchesSliceIds = nodeSliceIds.filter(
2846
- (sId) => componentSliceIds.includes(sId)
2847
- );
2848
- if (componentMatchesSliceIds.length > 0) {
2849
- sliceIdResult = true;
3056
+ for (const sId of nodeSliceIdSet) {
3057
+ if (componentSliceIdSet.has(sId)) {
3058
+ sliceIdResult = true;
3059
+ break;
3060
+ }
2850
3061
  }
2851
3062
  }
2852
3063
  break;
@@ -2867,47 +3078,68 @@ class Db {
2867
3078
  _hash: nodeHash
2868
3079
  }
2869
3080
  };
2870
- const nodeValue = node[nodeTableKey]._data.filter(
2871
- (v) => v !== void 0 && v !== null
2872
- );
2873
3081
  if (route.isRoot) {
3082
+ const baseRouteStr = (routeAccumulator ? routeAccumulator.flat : nodeTableKey) + (nodeHash ? `@${nodeHash}` : "");
2874
3083
  if (route.hasPropertyKey) {
2875
- const isolatedNode = this.isolatePropertyFromComponents(
2876
- node,
2877
- route.propertyKey
2878
- );
2879
- const result3 = {
2880
- rljson: isolatedNode,
2881
- tree: { [nodeTableKey]: node[nodeTableKey] },
2882
- cell: nodeValue.map(
3084
+ const isolatedNode = opts.skipRljson ? {} : this.isolatePropertyFromComponents(node, route.propertyKey);
3085
+ const routeWithProperty = opts.skipCell ? null : Route.fromFlat(
3086
+ baseRouteStr + `/${route.propertyKey}`
3087
+ ).toRouteWithProperty();
3088
+ let result3;
3089
+ if (nodeType === "trees") {
3090
+ const rljson3 = node;
3091
+ const tree3 = opts.skipTree ? {} : {
3092
+ [nodeTableKey]: {
3093
+ _data: [
3094
+ await nodeController.buildTreeFromTrees(nodeRows)
3095
+ ],
3096
+ _type: "trees"
3097
+ }
3098
+ };
3099
+ const cell3 = opts.skipCell ? [] : await nodeController.buildCellsFromTree(nodeRows);
3100
+ result3 = {
3101
+ rljson: rljson3,
3102
+ tree: tree3,
3103
+ cell: cell3
3104
+ };
3105
+ } else {
3106
+ const tree3 = opts.skipTree ? {} : { [nodeTableKey]: node[nodeTableKey] };
3107
+ const cell3 = opts.skipCell ? [] : nodeRowsFiltered.map(
2883
3108
  (v, idx) => ({
2884
3109
  value: v[route.propertyKey] ?? null,
2885
3110
  row: v,
2886
- route: Route.fromFlat(
2887
- (routeAccumulator ? routeAccumulator.flat : nodeTableKey) + (nodeHash ? `@${nodeHash}` : "") + `/${route.propertyKey}`
2888
- ).toRouteWithProperty(),
3111
+ route: routeWithProperty,
2889
3112
  path: [[nodeTableKey, "_data", idx, route.propertyKey]]
2890
3113
  })
2891
- )
2892
- };
3114
+ );
3115
+ result3 = {
3116
+ rljson: isolatedNode,
3117
+ tree: tree3,
3118
+ cell: cell3
3119
+ };
3120
+ }
2893
3121
  this._cache.set(cacheHash, result3);
2894
3122
  return result3;
2895
3123
  }
3124
+ const routeObj = opts.skipCell ? null : Route.fromFlat(baseRouteStr);
3125
+ const rljson2 = opts.skipRljson ? {} : node;
3126
+ const tree2 = opts.skipTree ? {} : { [nodeTableKey]: node[nodeTableKey] };
3127
+ const cell2 = opts.skipCell ? [] : nodeRowsFiltered.map(
3128
+ (v, idx) => ({
3129
+ value: v[route.propertyKey] ?? null,
3130
+ row: v,
3131
+ route: routeObj,
3132
+ path: [[nodeTableKey, "_data", idx]]
3133
+ })
3134
+ );
2896
3135
  const result2 = {
2897
- rljson: node,
2898
- tree: { [nodeTableKey]: node[nodeTableKey] },
2899
- cell: nodeValue.map(
2900
- (v, idx) => ({
2901
- value: v[route.propertyKey] ?? null,
2902
- row: v,
2903
- route: Route.fromFlat(
2904
- (routeAccumulator ? routeAccumulator.flat : nodeTableKey) + (nodeHash ? `@${nodeHash}` : "")
2905
- ),
2906
- path: [[nodeTableKey, "_data", idx]]
2907
- })
2908
- )
3136
+ rljson: rljson2,
3137
+ tree: tree2,
3138
+ cell: cell2
2909
3139
  };
2910
- this._cache.set(cacheHash, result2);
3140
+ if (cacheable) {
3141
+ this._cache.set(cacheHash, result2);
3142
+ }
2911
3143
  return result2;
2912
3144
  }
2913
3145
  const childrenRoute = route.deeper();
@@ -2916,12 +3148,20 @@ class Db {
2916
3148
  const childrenThroughProperty = childrenWhere?._through;
2917
3149
  const nodeChildrenArray = [];
2918
3150
  const nodeRowsMatchingChildrenRefs = /* @__PURE__ */ new Map();
3151
+ const columnReferenceMap = nodeType === "components" ? nodeColumnCfgs.filter((c) => c.ref?.tableKey === childrenTableKey).filter(
3152
+ (c) => c.ref && ["components", "cakes"].includes(c.ref.type)
3153
+ ).reduce((acc, curr) => {
3154
+ acc.set(curr.key, curr.ref.tableKey);
3155
+ return acc;
3156
+ }, /* @__PURE__ */ new Map()) : null;
3157
+ const childRefsPromises = nodeRowsFiltered.map(
3158
+ (nodeRow) => nodeController.getChildRefs(nodeRow._hash)
3159
+ );
3160
+ const allChildRefs = await Promise.all(childRefsPromises);
2919
3161
  for (let i = 0; i < nodeRowsFiltered.length; i++) {
2920
3162
  const nodeRow = nodeRowsFiltered[i];
2921
- const nodeRowObj = { ...{}, ...nodeRow };
2922
- const childrenRefs = await nodeController.getChildRefs(
2923
- nodeRow._hash
2924
- );
3163
+ const nodeRowHash = nodeRow._hash;
3164
+ const childrenRefs = allChildRefs[i];
2925
3165
  const childrenRefTypes = /* @__PURE__ */ new Map();
2926
3166
  const childrenRefSliceIds = /* @__PURE__ */ new Set();
2927
3167
  for (const cr of childrenRefs) {
@@ -2942,13 +3182,19 @@ class Db {
2942
3182
  }
2943
3183
  }
2944
3184
  }
2945
- if (childrenRefTypes.size > 1) {
3185
+ const childrenRefTypesSet = /* @__PURE__ */ new Set([
3186
+ ...childrenRefTypes.values()
3187
+ ]);
3188
+ if (childrenRefTypesSet.size > 1) {
2946
3189
  throw new Error(
2947
- `Db._get: Multiple reference types found for children of table ${nodeTableKey}.`
3190
+ `Db._get: Multiple reference types found for children of node table "${nodeTableKey}" and row "${nodeRowHash}". Found types: ${[
3191
+ ...childrenRefTypesSet
3192
+ ].join(", ")}.`
2948
3193
  );
2949
3194
  }
2950
- const cakeIsReferenced = childrenRefTypes.size === 1 && [...childrenRefTypes.values()][0] === "cakes";
2951
- const componentIsReferenced = childrenRefTypes.size === 1 && nodeType === "components" && [...childrenRefTypes.values()][0] === "components";
3195
+ const childrenRefType = childrenRefTypesSet.size > 0 ? [...childrenRefTypesSet][0] : null;
3196
+ const cakeIsReferenced = childrenRefTypes.size > 0 && childrenRefType === "cakes";
3197
+ const componentIsReferenced = childrenRefTypes.size > 0 && nodeType === "components" && childrenRefType === "components";
2952
3198
  const childrenSliceIds = cakeIsReferenced ? [...childrenRefSliceIds] : componentIsReferenced ? void 0 : nodeSliceIds;
2953
3199
  const {
2954
3200
  rljson: rowChildrenRljson,
@@ -2962,29 +3208,43 @@ class Db {
2962
3208
  childrenSliceIds,
2963
3209
  Route.fromFlat(
2964
3210
  (routeAccumulator ? routeAccumulator.flat : nodeTableKey) + (nodeHash ? `@${nodeHash}` : "") + "/" + childrenTableKey
2965
- )
3211
+ ),
3212
+ opts
2966
3213
  );
3214
+ if (!rowChildrenRljson[childrenTableKey] || rowChildrenRljson[childrenTableKey]._data.length === 0)
3215
+ continue;
3216
+ nodeChildrenArray.push(rowChildrenRljson);
3217
+ if (opts.skipTree && opts.skipCell) {
3218
+ nodeRowsMatchingChildrenRefs.set(nodeRowHash, {
3219
+ rljson: nodeRow,
3220
+ tree: {},
3221
+ cell: []
3222
+ });
3223
+ continue;
3224
+ }
3225
+ const nodeRowObj = { ...nodeRow };
2967
3226
  if (cakeIsReferenced) {
2968
3227
  const refKey = [...childrenRefTypes.keys()][0];
2969
3228
  nodeRowObj[refKey] = rowChildrenTree;
2970
3229
  }
2971
- if (rowChildrenRljson[childrenTableKey]._data.length === 0) continue;
2972
- nodeChildrenArray.push(rowChildrenRljson);
2973
3230
  if (childrenThroughProperty) {
2974
- const resolvedChildrenHashes = rowChildrenRljson[childrenTableKey]._data.map((rc) => rc._hash);
3231
+ const resolvedChildrenHashesSet = new Set(
3232
+ rowChildrenRljson[childrenTableKey]._data.map(
3233
+ (rc) => rc._hash
3234
+ )
3235
+ );
2975
3236
  for (const nr of nodeRowsFiltered) {
2976
- {
2977
- const throughHashesInRowCouldBeArray = nr[childrenThroughProperty];
2978
- const throughHashesInRow = Array.isArray(
2979
- throughHashesInRowCouldBeArray
2980
- ) ? throughHashesInRowCouldBeArray : [throughHashesInRowCouldBeArray];
2981
- for (const th of throughHashesInRow) {
2982
- if (resolvedChildrenHashes.includes(th)) {
2983
- nodeRowObj[childrenThroughProperty] = {
2984
- ...rowChildrenTree[childrenTableKey],
2985
- ...{ _tableKey: childrenTableKey }
2986
- };
2987
- }
3237
+ const throughHashesInRowCouldBeArray = nr[childrenThroughProperty];
3238
+ const throughHashesInRow = Array.isArray(
3239
+ throughHashesInRowCouldBeArray
3240
+ ) ? throughHashesInRowCouldBeArray : [throughHashesInRowCouldBeArray];
3241
+ for (const th of throughHashesInRow) {
3242
+ if (resolvedChildrenHashesSet.has(th)) {
3243
+ nodeRowObj[childrenThroughProperty] = {
3244
+ ...rowChildrenTree[childrenTableKey],
3245
+ _tableKey: childrenTableKey
3246
+ };
3247
+ break;
2988
3248
  }
2989
3249
  }
2990
3250
  }
@@ -2993,8 +3253,14 @@ class Db {
2993
3253
  const childrenRefsOfRow = childrenRefs.filter(
2994
3254
  (cr) => cr.tableKey == childrenTableKey
2995
3255
  );
3256
+ const resolvedChildrenHashSet = new Set(
3257
+ resolvedChildren.map((ch) => ch._hash)
3258
+ );
2996
3259
  const matchingChildrenRefs = childrenRefsOfRow.filter(
2997
- (cr) => !!resolvedChildren.find((ch) => cr.ref === ch._hash)
3260
+ (cr) => resolvedChildrenHashSet.has(cr.ref)
3261
+ );
3262
+ const matchingRefsMap = new Map(
3263
+ matchingChildrenRefs.map((cr) => [cr.ref, cr])
2998
3264
  );
2999
3265
  if (nodeType === "layers") {
3000
3266
  const compChildrenTrees = rowChildrenTree[childrenTableKey]._data;
@@ -3006,9 +3272,8 @@ class Db {
3006
3272
  };
3007
3273
  });
3008
3274
  const layerTreesAndPaths = components.map(({ tree: comp, path }) => {
3009
- const sliceIds2 = matchingChildrenRefs.find(
3010
- (cr) => cr.ref === comp._hash
3011
- )?.sliceIds;
3275
+ const matchedRef = matchingRefsMap.get(comp._hash);
3276
+ const sliceIds2 = matchedRef?.sliceIds;
3012
3277
  if (!sliceIds2 || sliceIds2.length === 0) {
3013
3278
  throw new Error(
3014
3279
  `Db._get: No sliceIds found for component ${comp._hash} of layer ${nodeRow._hash}.`
@@ -3020,99 +3285,90 @@ class Db {
3020
3285
  );
3021
3286
  }
3022
3287
  const sliceId = sliceIds2[0];
3023
- const pathsForSliceId = [
3024
- ...path.map((p) => p[0]).map((p) => {
3025
- const newPath = [...p];
3026
- newPath[2] = 0;
3027
- return ["add", sliceId, ...newPath];
3028
- })
3029
- ];
3288
+ const pathsForSliceId = path.map((p) => {
3289
+ const newPath = [...p[0]];
3290
+ newPath[2] = 0;
3291
+ return ["add", sliceId, ...newPath];
3292
+ });
3030
3293
  return {
3031
3294
  [sliceId]: {
3032
3295
  tree: {
3033
3296
  [childrenTableKey]: {
3034
- ...{ _data: [comp] },
3035
- ...{ _type: "components" }
3297
+ _data: [comp],
3298
+ _type: "components"
3036
3299
  }
3037
3300
  },
3038
3301
  path: pathsForSliceId
3039
3302
  }
3040
3303
  };
3041
3304
  });
3042
- const layer = layerTreesAndPaths.flatMap(
3043
- (ltap) => Object.entries(ltap).map(([sliceId, { tree }]) => ({
3044
- [sliceId]: tree
3045
- }))
3046
- ).reduce((a, b) => ({ ...a, ...b }), {});
3047
- const paths = layerTreesAndPaths.map(
3048
- (ltap) => Object.values(ltap)[0].path
3305
+ const layer = {};
3306
+ const paths = [];
3307
+ for (const ltap of layerTreesAndPaths) {
3308
+ for (const [sliceId, value] of Object.entries(ltap)) {
3309
+ layer[sliceId] = value.tree;
3310
+ if (!opts.skipCell) {
3311
+ paths.push(value.path);
3312
+ }
3313
+ }
3314
+ }
3315
+ const rljson2 = nodeRow;
3316
+ const tree2 = opts.skipTree ? {} : {
3317
+ ...nodeRowObj,
3318
+ add: { ...nodeRowObj.add, ...layer }
3319
+ };
3320
+ const cell2 = opts.skipCell ? [] : rowChildrenCell.map(
3321
+ (c, idx) => ({
3322
+ ...c,
3323
+ path: [paths.flat()[idx]]
3324
+ })
3049
3325
  );
3050
- nodeRowsMatchingChildrenRefs.set(nodeRow._hash, {
3051
- rljson: nodeRow,
3052
- tree: {
3053
- ...nodeRowObj,
3054
- add: { ...nodeRowObj.add, ...layer }
3055
- },
3056
- cell: rowChildrenCell.map(
3057
- (c, idx) => ({
3058
- ...c,
3059
- ...{
3060
- path: [paths.flat()[idx]]
3061
- }
3062
- })
3063
- )
3326
+ nodeRowsMatchingChildrenRefs.set(nodeRowHash, {
3327
+ rljson: rljson2,
3328
+ tree: tree2,
3329
+ cell: cell2
3064
3330
  });
3065
3331
  } else if (nodeType === "cakes") {
3066
- nodeRowsMatchingChildrenRefs.set(nodeRow._hash, {
3332
+ nodeRowsMatchingChildrenRefs.set(nodeRowHash, {
3067
3333
  rljson: nodeRow,
3068
- tree: {
3334
+ tree: opts.skipTree ? {} : {
3069
3335
  ...nodeRowObj,
3070
3336
  layers: { ...nodeRowObj.layers, ...rowChildrenTree }
3071
3337
  },
3072
- cell: rowChildrenCell.map((c) => ({
3338
+ cell: opts.skipCell ? [] : rowChildrenCell.map((c) => ({
3073
3339
  ...c,
3074
- ...{
3075
- path: c.path.map((p) => ["layers", ...p])
3076
- }
3340
+ path: c.path.map((p) => ["layers", ...p])
3077
3341
  }))
3078
3342
  });
3079
3343
  } else if (nodeType === "components") {
3080
3344
  if (rowChildrenTree && Object.keys(rowChildrenTree).length > 0) {
3081
- const columnReferenceMap = nodeColumnCfgs.filter(
3082
- (c) => c.ref && ["components", "cakes"].includes(c.ref.type)
3083
- ).reduce((acc, curr) => {
3084
- acc.set(curr.key, curr.ref.tableKey);
3085
- return acc;
3086
- }, /* @__PURE__ */ new Map());
3087
- const resolvedRefs = {};
3345
+ const resolvedProperties = {};
3346
+ const allCells = [];
3088
3347
  for (const [colKey, childTableKey] of columnReferenceMap) {
3089
- const tree = {
3090
- ...rowChildrenTree[childTableKey],
3091
- ...{ _tableKey: childTableKey }
3092
- };
3093
- const cell = rowChildrenCell.map((c) => ({
3094
- ...c,
3095
- ...{
3348
+ if (!opts.skipTree) {
3349
+ resolvedProperties[colKey] = {
3350
+ ...rowChildrenTree[childTableKey],
3351
+ _tableKey: childTableKey
3352
+ };
3353
+ }
3354
+ if (!opts.skipCell) {
3355
+ const cell2 = rowChildrenCell.map((c) => ({
3356
+ ...c,
3096
3357
  path: c.path.filter((p) => p[0] === childTableKey).map((p) => [colKey, ...p.slice(1)])
3097
- }
3098
- }));
3099
- resolvedRefs[colKey] = { tree, cell };
3358
+ }));
3359
+ allCells.push(...cell2);
3360
+ }
3100
3361
  }
3101
- const resolvedProperties = Object.entries(resolvedRefs).map(([colKey, { tree }]) => ({
3102
- [colKey]: tree
3103
- })).reduce((a, b) => ({ ...a, ...b }), {});
3104
- const resolvedTree = {
3105
- ...nodeRowObj,
3106
- ...resolvedProperties
3107
- };
3108
- const resolvedCell = Object.values(resolvedRefs).map((r) => r.cell).flat();
3109
- nodeRowsMatchingChildrenRefs.set(nodeRow._hash, {
3362
+ nodeRowsMatchingChildrenRefs.set(nodeRowHash, {
3110
3363
  rljson: nodeRow,
3111
- tree: resolvedTree,
3112
- cell: resolvedCell
3364
+ tree: opts.skipTree ? {} : {
3365
+ ...nodeRowObj,
3366
+ ...resolvedProperties
3367
+ },
3368
+ cell: allCells
3113
3369
  });
3114
3370
  } else {
3115
- nodeRowsMatchingChildrenRefs.set(nodeRow._hash, {
3371
+ nodeRowsMatchingChildrenRefs.set(nodeRowHash, {
3116
3372
  rljson: nodeRow,
3117
3373
  tree: { ...nodeRowObj },
3118
3374
  cell: rowChildrenCell
@@ -3124,43 +3380,46 @@ class Db {
3124
3380
  );
3125
3381
  }
3126
3382
  }
3127
- const nodeChildren = makeUnique(
3128
- merge(...nodeChildrenArray)
3129
- );
3383
+ const nodeChildren = opts.skipRljson ? {} : makeUnique(merge(...nodeChildrenArray));
3130
3384
  const matchedNodeRows = Array.from(nodeRowsMatchingChildrenRefs.values());
3131
- const result = {
3132
- rljson: {
3133
- ...node,
3134
- ...{
3135
- [nodeTableKey]: {
3136
- ...{
3137
- _data: matchedNodeRows.map((mr) => mr.rljson),
3138
- _type: nodeType
3139
- },
3140
- ...{
3141
- ...nodeHash ? { _hash: nodeHash } : {}
3142
- }
3143
- }
3144
- },
3145
- ...nodeChildren
3385
+ const rljson = opts.skipRljson ? {} : {
3386
+ ...node,
3387
+ [nodeTableKey]: {
3388
+ _data: matchedNodeRows.map((mr) => mr.rljson),
3389
+ _type: nodeType,
3390
+ ...nodeHash ? { _hash: nodeHash } : {}
3146
3391
  },
3147
- tree: {
3148
- [nodeTableKey]: {
3149
- ...{
3150
- _data: matchedNodeRows.map((mr) => mr.tree),
3151
- _type: nodeType
3152
- },
3153
- ...{
3154
- ...nodeHash ? { _hash: nodeHash } : {}
3155
- }
3392
+ ...nodeChildren
3393
+ };
3394
+ const tree = opts.skipTree ? {} : {
3395
+ [nodeTableKey]: {
3396
+ _data: matchedNodeRows.map((mr) => mr.tree),
3397
+ _type: nodeType,
3398
+ ...nodeHash ? { _hash: nodeHash } : {}
3399
+ }
3400
+ };
3401
+ const cell = opts.skipCell ? [] : (() => {
3402
+ let totalSize = 0;
3403
+ for (const mr of matchedNodeRows) {
3404
+ totalSize += mr.cell.length;
3405
+ }
3406
+ const cells = new Array(totalSize);
3407
+ let cellIdx = 0;
3408
+ for (let rowIdx = 0; rowIdx < matchedNodeRows.length; rowIdx++) {
3409
+ const mr = matchedNodeRows[rowIdx];
3410
+ for (const c of mr.cell) {
3411
+ cells[cellIdx++] = {
3412
+ ...c,
3413
+ path: c.path.map((p) => [nodeTableKey, "_data", rowIdx, ...p])
3414
+ };
3156
3415
  }
3157
- },
3158
- cell: matchedNodeRows.map(
3159
- (mr, idx) => mr.cell.map((c) => ({
3160
- ...c,
3161
- ...{ path: c.path.map((p) => [nodeTableKey, "_data", idx, ...p]) }
3162
- }))
3163
- ).flat()
3416
+ }
3417
+ return cells;
3418
+ })();
3419
+ const result = {
3420
+ rljson,
3421
+ tree,
3422
+ cell
3164
3423
  };
3165
3424
  this._cache.set(cacheHash, result);
3166
3425
  return result;
@@ -3192,7 +3451,13 @@ class Db {
3192
3451
  async join(columnSelection, cakeKey, cakeRef) {
3193
3452
  const {
3194
3453
  tree: { [cakeKey]: cakesTable }
3195
- } = await this.get(Route.fromFlat(`${cakeKey}@${cakeRef}`), {});
3454
+ } = await this.get(
3455
+ Route.fromFlat(`${cakeKey}@${cakeRef}`),
3456
+ {},
3457
+ void 0,
3458
+ void 0,
3459
+ { skipCell: true, skipRljson: true }
3460
+ );
3196
3461
  const cakes = cakesTable._data;
3197
3462
  if (cakes.length === 0) {
3198
3463
  throw new Error(
@@ -3266,7 +3531,10 @@ class Db {
3266
3531
  for (const [tableKey, controller] of Object.entries(controllers)) {
3267
3532
  runFns[tableKey] = controller.insert.bind(controller);
3268
3533
  }
3269
- return this._insert(route, tree, runFns, options);
3534
+ const insertHistoryRow = await this._insert(route, tree, runFns, options);
3535
+ if (!options?.skipHistory)
3536
+ await this._writeInsertHistory(route.top.tableKey, insertHistoryRow[0]);
3537
+ return insertHistoryRow;
3270
3538
  }
3271
3539
  // ...........................................................................
3272
3540
  /**
@@ -3292,7 +3560,7 @@ class Db {
3292
3560
  const previousHash = nodeSegment[nodeTableKey + "Ref"] ?? null;
3293
3561
  const previousTimeId = nodeSegment[nodeTableKey + "InsertHistoryRef"] ?? null;
3294
3562
  const previous = previousHash ? await this.getTimeIdsForRef(nodeTableKey, previousHash) : previousTimeId ? [previousTimeId] : [];
3295
- if (!nodeRoute.isRoot) {
3563
+ if (!nodeRoute.isRoot && nodeType != "trees") {
3296
3564
  const childRoute = nodeRoute.deeper(1);
3297
3565
  const childTableKey = childRoute.top.tableKey;
3298
3566
  if (nodeType === "cakes") {
@@ -3463,10 +3731,31 @@ class Db {
3463
3731
  );
3464
3732
  }
3465
3733
  }
3734
+ if (nodeType === "trees") {
3735
+ const treeObject = tree[nodeTableKey]._data[0];
3736
+ if (!treeObject) {
3737
+ throw new Error(
3738
+ `Db._insert: No tree data found for table "${nodeTableKey}" in route "${route.flat}".`
3739
+ );
3740
+ }
3741
+ const trees = treeFromObject(treeObject);
3742
+ const writePromises = trees.map(
3743
+ (tree2) => runFn("add", tree2, "db.insert")
3744
+ );
3745
+ const writeResults = await Promise.all(writePromises);
3746
+ const lastResult = writeResults[writeResults.length - 1];
3747
+ if (lastResult && lastResult.length > 0) {
3748
+ results.push(
3749
+ ...lastResult.map((r) => ({
3750
+ ...r,
3751
+ ...{ previous },
3752
+ ...{ route: route.flat }
3753
+ }))
3754
+ );
3755
+ }
3756
+ }
3466
3757
  }
3467
3758
  for (const result of results) {
3468
- if (!options?.skipHistory)
3469
- await this._writeInsertHistory(nodeTableKey, result);
3470
3759
  if (!options?.skipNotification)
3471
3760
  this.notify.notify(Route.fromFlat(result.route), result);
3472
3761
  }
@@ -3546,21 +3835,6 @@ class Db {
3546
3835
  });
3547
3836
  }
3548
3837
  // ...........................................................................
3549
- /**
3550
- * Add a head revision for a cake
3551
- * @param cakeKey - The cake table key
3552
- * @param cakeRef - The cake reference
3553
- */
3554
- async addHeadRevision(cakeKey, cakeRef) {
3555
- const cakeHeadKey = cakeKey + "Heads";
3556
- const cakeHeadController = await this.getController(cakeHeadKey);
3557
- return await cakeHeadController.insert("add", {
3558
- cakeRef,
3559
- timeId: timeId(),
3560
- _hash: ""
3561
- });
3562
- }
3563
- // ...........................................................................
3564
3838
  /**
3565
3839
  * Add a multiEdit
3566
3840
  * @param cakeKey - The cake table key
@@ -4141,9 +4415,6 @@ class MultiEditProcessor {
4141
4415
  }
4142
4416
  const inserted = inserteds[0];
4143
4417
  const writtenCakeRef = inserted[this._cakeKey + "Ref"];
4144
- if (!options?.skipHeadUpdate) {
4145
- await this._db.addHeadRevision(this._cakeKey, writtenCakeRef);
4146
- }
4147
4418
  if (!options?.skipSaveMultiEdit) {
4148
4419
  await this._db.addMultiEdit(this._cakeKey, this._multiEdit);
4149
4420
  }
@@ -4192,7 +4463,11 @@ class MultiEditProcessor {
4192
4463
  multiEdit.previous
4193
4464
  );
4194
4465
  const previousMultiEdit = previousMultiEdits[0];
4195
- return this._resolve(previousMultiEdit);
4466
+ const previousEditFromMultiEdit = previousMultiEdit.edit;
4467
+ const previousEdit = this._edits[this._edits.length - 2] ? this._edits[this._edits.length - 2]._hash : null;
4468
+ if (previousEdit !== previousEditFromMultiEdit) {
4469
+ return await this._resolve(previousMultiEdit);
4470
+ }
4196
4471
  }
4197
4472
  }
4198
4473
  //...........................................................................
@@ -4329,6 +4604,14 @@ class MultiEditProcessor {
4329
4604
  }
4330
4605
  return this._join;
4331
4606
  }
4607
+ //...........................................................................
4608
+ /**
4609
+ * Get the list of Edits applied in this MultiEditProcessor
4610
+ * @returns Array of Edits
4611
+ */
4612
+ get edits() {
4613
+ return this._edits;
4614
+ }
4332
4615
  }
4333
4616
  class MultiEditManager {
4334
4617
  constructor(_cakeKey, _db) {
@@ -5293,27 +5576,6 @@ const staticExample = () => {
5293
5576
  }
5294
5577
  ]
5295
5578
  });
5296
- const carCakeHeadTableCfg = hip(
5297
- createHeadsTableCfg("carCake")
5298
- );
5299
- const carCakeHeads = hip({
5300
- _tableCfg: carCakeHeadTableCfg._hash,
5301
- _type: "head",
5302
- _data: [
5303
- {
5304
- timeId: "1764756756311:jkCG",
5305
- cakeRef: carCake._data[0]._hash
5306
- },
5307
- {
5308
- timeId: "1764756756312:1AGV",
5309
- cakeRef: carCake._data[1]._hash
5310
- },
5311
- {
5312
- timeId: "1764756756312:g8nh",
5313
- cakeRef: carCake._data[2]._hash
5314
- }
5315
- ]
5316
- });
5317
5579
  const seriesSliceIdTableCfg = hip(
5318
5580
  createSliceIdsTableCfg("seriesSliceId")
5319
5581
  );
@@ -5670,27 +5932,6 @@ const staticExample = () => {
5670
5932
  }
5671
5933
  ]
5672
5934
  });
5673
- const seriesCakeHeadTableCfg = hip(
5674
- createHeadsTableCfg("seriesCake")
5675
- );
5676
- const seriesCakeHeads = hip({
5677
- _tableCfg: seriesCakeHeadTableCfg._hash,
5678
- _type: "head",
5679
- _data: [
5680
- {
5681
- timeId: "1764756756315:L14y",
5682
- cakeRef: seriesCake._data[0]._hash
5683
- },
5684
- {
5685
- timeId: "1764756756315:xCXT",
5686
- cakeRef: seriesCake._data[1]._hash
5687
- },
5688
- {
5689
- timeId: "1764756756315:fZwA",
5690
- cakeRef: seriesCake._data[2]._hash
5691
- }
5692
- ]
5693
- });
5694
5935
  const catalogSliceIdTableCfg = hip(
5695
5936
  createSliceIdsTableCfg("catalogSliceId")
5696
5937
  );
@@ -5792,19 +6033,6 @@ const staticExample = () => {
5792
6033
  }
5793
6034
  ]
5794
6035
  });
5795
- const catalogCakeHeadTableCfg = hip(
5796
- createHeadsTableCfg("catalogCake")
5797
- );
5798
- const catalogCakeHeads = hip({
5799
- _tableCfg: catalogCakeHeadTableCfg._hash,
5800
- _type: "head",
5801
- _data: [
5802
- {
5803
- timeId: "1764756756317:5UTy",
5804
- cakeRef: catalogCake._data[0]._hash
5805
- }
5806
- ]
5807
- });
5808
6036
  const tableCfgs = {
5809
6037
  _data: [
5810
6038
  carSliceIdTableCfg,
@@ -5816,19 +6044,16 @@ const staticExample = () => {
5816
6044
  carTechnicalLayerTableCfg,
5817
6045
  carColorLayerTableCfg,
5818
6046
  carCakeTableCfg,
5819
- carCakeHeadTableCfg,
5820
6047
  seriesSliceIdTableCfg,
5821
6048
  seriesGeneralTableCfg,
5822
6049
  seriesCarsTableCfg,
5823
6050
  seriesGeneralLayerTableCfg,
5824
6051
  seriesCarsLayerTableCfg,
5825
6052
  seriesCakeTableCfg,
5826
- seriesCakeHeadTableCfg,
5827
6053
  catalogSliceIdTableCfg,
5828
6054
  catalogSeriesTableCfg,
5829
6055
  catalogSeriesLayerTableCfg,
5830
- catalogCakeTableCfg,
5831
- catalogCakeHeadTableCfg
6056
+ catalogCakeTableCfg
5832
6057
  ]
5833
6058
  };
5834
6059
  const staticExample2 = {
@@ -5841,19 +6066,16 @@ const staticExample = () => {
5841
6066
  carTechnicalLayer,
5842
6067
  carColorLayer,
5843
6068
  carCake,
5844
- carCakeHeads,
5845
6069
  seriesSliceId,
5846
6070
  seriesGeneral,
5847
6071
  seriesCars,
5848
6072
  seriesGeneralLayer,
5849
6073
  seriesCarsLayer,
5850
6074
  seriesCake,
5851
- seriesCakeHeads,
5852
6075
  catalogSliceId,
5853
6076
  catalogSeries,
5854
6077
  catalogSeriesLayer,
5855
6078
  catalogCake,
5856
- catalogCakeHeads,
5857
6079
  tableCfgs
5858
6080
  };
5859
6081
  return staticExample2;