@xh/hoist 75.0.0-SNAPSHOT.1754329446115 → 75.0.0-SNAPSHOT.1754347635253

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.
@@ -7,17 +7,20 @@
7
7
 
8
8
  import {PlainObject, Some} from '@xh/hoist/core';
9
9
  import {BucketSpec} from '@xh/hoist/data/cube/BucketSpec';
10
+ import {ViewRowData} from '@xh/hoist/data/cube/ViewRowData';
10
11
  import {compact, isEmpty, reduce} from 'lodash';
11
12
  import {View} from '../View';
12
13
  import {RowUpdate} from './RowUpdate';
13
14
 
14
15
  /**
15
- * Base class for a view row.
16
+ * Base class for a row within a dataset produced by a Cube / View.
17
+ *
18
+ * This is an internal data structure - {@link ViewRowData} is the public row-level data API.
16
19
  */
17
20
  export abstract class BaseRow {
18
21
  readonly view: View = null;
19
22
  readonly id: string = null;
20
- readonly data: PlainObject;
23
+ readonly data: ViewRowData;
21
24
 
22
25
  // readonly, but set by subclasses
23
26
  parent: BaseRow = null;
@@ -38,37 +41,48 @@ export abstract class BaseRow {
38
41
  constructor(view: View, id: string) {
39
42
  this.view = view;
40
43
  this.id = id;
41
- this.data = {id, _meta: this};
44
+ this.data = new ViewRowData(id);
42
45
  }
43
46
 
44
47
  //-----------------------
45
48
  // For all rows types
46
49
  //------------------------
47
50
  noteBucketed(bucketSpec: BucketSpec, bucketVal: any) {
48
- this.data.buckets = this.data.buckets ?? {};
49
- this.data.buckets[bucketSpec.name] = bucketVal;
51
+ this.data.cubeBuckets ??= {};
52
+ this.data.cubeBuckets[bucketSpec.name] = bucketVal;
50
53
  this.children?.forEach(it => it.noteBucketed(bucketSpec, bucketVal));
51
54
  }
52
55
 
53
56
  // Determine what should be exposed as the actual children in the
54
57
  // row data. This where we lock, skip degenerate rows, etc.
55
- getVisibleDatas(): Some<PlainObject> {
56
- let {view, data, isLeaf} = this;
57
-
58
- // 1) Get visible children nodes recursively
59
- let dataChildren = this.getVisibleChildrenDatas();
58
+ getVisibleDatas(): Some<ViewRowData> {
59
+ const {view, data, isLeaf} = this,
60
+ {query} = view,
61
+ {omitRedundantNodes, provideLeaves, includeLeaves} = query;
62
+
63
+ // 1) Get children nodes recursively
64
+ let dataChildren = this.getChildrenDatas();
65
+
66
+ // End hierarchy at cube leaves, if so configured. But be sure to hold on to them if needed
67
+ if (dataChildren && !includeLeaves && dataChildren[0]?.isCubeLeaf) {
68
+ if (provideLeaves) {
69
+ data._cubeLeafChildren = dataChildren;
70
+ }
71
+ dataChildren = null;
72
+ }
60
73
 
61
74
  // 2) If omitting ourselves, we are done, return visible children.
62
- if (!isLeaf && view.query.omitFn?.(this as any)) return dataChildren;
75
+ if (!isLeaf && query.omitFn?.(this as any)) return dataChildren;
63
76
 
64
77
  // 3) Otherwise, we can attach this data to the children data and return.
65
78
 
66
79
  // 3a) Before attaching examine that we don't have a chain of redundant nodes
67
80
  // (not sure if loop needed -- are these redundant relations transitive?)
68
- if (view.query.omitRedundantNodes) {
81
+ if (omitRedundantNodes) {
82
+ const rowCache = view._rowCache;
69
83
  while (dataChildren?.length === 1) {
70
- const childRow = dataChildren[0]._meta;
71
- if (this.isRedundantChild(this, childRow)) {
84
+ const childRow = rowCache.get(dataChildren[0].id);
85
+ if (childRow && this.isRedundantChild(this, childRow)) {
72
86
  dataChildren = childRow.data.children;
73
87
  } else {
74
88
  break;
@@ -76,20 +90,16 @@ export abstract class BaseRow {
76
90
  }
77
91
  }
78
92
 
93
+ // Wire up visible data children and leaves, as needed.
79
94
  data.children = dataChildren;
80
95
  return data;
81
96
  }
82
97
 
83
- private getVisibleChildrenDatas(): PlainObject[] {
98
+ private getChildrenDatas(): ViewRowData[] {
84
99
  let {children, view} = this;
85
100
 
86
101
  if (!children) return null;
87
102
 
88
- // Skip all leaves from the data if the query is not configured to include leaves and
89
- if (!view.query.includeLeaves && children[0]?.isLeaf) {
90
- return null;
91
- }
92
-
93
103
  // Skip all children in a locked node
94
104
  if (view.query.lockFn?.(this as any)) {
95
105
  this.locked = true;
@@ -11,7 +11,11 @@ import {BucketSpec} from '../BucketSpec';
11
11
  import {View} from '../View';
12
12
 
13
13
  /**
14
- * Object used by views to gather bucket rows.
14
+ * Row within a dataset produced by a Cube / View representing aggregated data on a dimension that
15
+ * has been further grouped into a dynamic child "bucket" - a subset of the dimension-level
16
+ * {@link AggregateRow} produced as per a specified {@link Query.bucketSpecFn}.
17
+ *
18
+ * This is an internal data structure - {@link ViewRowData} is the public row-level data API.
15
19
  */
16
20
  export class BucketRow extends BaseRow {
17
21
  override get isBucket() {
@@ -13,15 +13,16 @@ import {BaseRow} from './BaseRow';
13
13
  import {RowUpdate} from './RowUpdate';
14
14
 
15
15
  /**
16
- * Represents a leaf row returned by a {@link View} or call to {@link Cube.executeQuery}.
17
- *
18
- * These rows are 1-1 with the source records loaded into the Cube's internal store - i.e. they are
19
- * not computed aggregates - although the data they contain is a shallow copy of the original and
16
+ * Row within a dataset produced by a Cube or View representing leaf-level data. These rows have a
17
+ * 1-1 relationship with the source records loaded into the Cube's internal store - i.e. they are
18
+ * not computed aggregates, although the data they contain is a shallow copy of the original and
20
19
  * limited to the fields requested by the View / Query that produced them.
20
+ *
21
+ * This is an internal data structure - {@link ViewRowData} is the public row-level data API.
21
22
  */
22
23
  export class LeafRow extends BaseRow {
23
24
  /**
24
- * Id of the StoreRecord within the Cube that was used to construct this leaf row.
25
+ * ID of the `StoreRecord` within the Cube that was used to construct this leaf row.
25
26
  * Useful if you need to update this leaf's data via {@link Cube.updateDataAsync}.
26
27
  */
27
28
  readonly cubeRecordId: StoreRecordId;
@@ -34,7 +35,8 @@ export class LeafRow extends BaseRow {
34
35
  super(view, id);
35
36
 
36
37
  this.cubeRecordId = rawRecord.id;
37
- this.data.cubeLabel = rawRecord.id;
38
+ this.data.cubeLabel = rawRecord.id.toString();
39
+ this.data.cubeDimension = null;
38
40
 
39
41
  view.fields.forEach(({name}) => {
40
42
  this.data[name] = rawRecord.data[name];
package/data/index.ts CHANGED
@@ -36,6 +36,7 @@ export * from './cube/Cube';
36
36
  export * from './cube/CubeField';
37
37
  export * from './cube/Query';
38
38
  export * from './cube/View';
39
+ export * from './cube/ViewRowData';
39
40
 
40
41
  export * from './validation/constraints';
41
42
  export * from './validation/Rule';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xh/hoist",
3
- "version": "75.0.0-SNAPSHOT.1754329446115",
3
+ "version": "75.0.0-SNAPSHOT.1754347635253",
4
4
  "description": "Hoist add-on for building and deploying React Applications.",
5
5
  "repository": "github:xh/hoist-react",
6
6
  "homepage": "https://xh.io",