@milaboratories/pl-tree 1.4.34 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/dump.ts ADDED
@@ -0,0 +1,115 @@
1
+ import { ExtendedResourceData } from "./state"
2
+
3
+ export type ResourceStats = {
4
+ /** Number of resources of this type */
5
+ count: number,
6
+ /** Total number of bytes in the field names of all resources of this type */
7
+ fieldNameBytes: number,
8
+ /** Total number of fields in all resources of this type */
9
+ fieldsCount: number,
10
+ /** Total number of bytes in the data of all resources of this type */
11
+ dataBytes: number,
12
+ /** Total number of key-value records in all resources of this type */
13
+ kvCount: number,
14
+ /** Total number of bytes in the key-value records of all resources of this type */
15
+ kvBytes: number,
16
+ }
17
+
18
+ /**
19
+ * A map of resource type statistics, keyed by the resource type name and version.
20
+ *
21
+ * @type {Record<string, ResourceStats>}
22
+ */
23
+ export type TreeDumpStats = {
24
+ total: ResourceStats,
25
+ byResourceType: Record<`${string}/${string}`, ResourceStats>
26
+ }
27
+
28
+ /**
29
+ * Analyzes a collection of resources and generates statistics grouped by resource type.
30
+ *
31
+ * This function processes an array of ExtendedResourceData and calculates various metrics
32
+ * for each unique resource type, including:
33
+ * - Count of resources
34
+ * - Total bytes in field names
35
+ * - Total number of fields
36
+ * - Total bytes in resource data
37
+ * - Total number of key-value records
38
+ * - Total bytes in key-value records
39
+ *
40
+ * The statistics are organized by resource type using a key in the format "typeName/version".
41
+ *
42
+ * @param dumpStats - Array of ExtendedResourceData objects to analyze
43
+ * @returns A DumpStats object containing statistics for each resource type
44
+ * @example
45
+ * ```typescript
46
+ * const resources = [...]; // Array of ExtendedResourceData
47
+ * const stats = treeDumpStats(resources);
48
+ * // stats = {
49
+ * // "MyResource/1": {
50
+ * // count: 5,
51
+ * // fieldNameBytes: 150,
52
+ * // fieldsCount: 10,
53
+ * // dataBytes: 1024,
54
+ * // kvCount: 3,
55
+ * // kvBytes: 256
56
+ * // },
57
+ * // ...
58
+ * // }
59
+ * ```
60
+ */
61
+ export function treeDumpStats(dumpStats: ExtendedResourceData[]): TreeDumpStats {
62
+ const stats: TreeDumpStats = {
63
+ total: {
64
+ count: 0,
65
+ fieldNameBytes: 0,
66
+ fieldsCount: 0,
67
+ dataBytes: 0,
68
+ kvCount: 0,
69
+ kvBytes: 0
70
+ },
71
+ byResourceType: {}
72
+ };
73
+
74
+ for (const resource of dumpStats) {
75
+ const typeKey = `${resource.type.name}/${resource.type.version}` as const;
76
+ if (!stats.byResourceType[typeKey]) {
77
+ stats.byResourceType[typeKey] = {
78
+ count: 0,
79
+ fieldNameBytes: 0,
80
+ fieldsCount: 0,
81
+ dataBytes: 0,
82
+ kvCount: 0,
83
+ kvBytes: 0
84
+ };
85
+ }
86
+
87
+ const typeStats = stats.byResourceType[typeKey];
88
+ typeStats.count++;
89
+ stats.total.count++;
90
+
91
+ for (const field of resource.fields) {
92
+ typeStats.fieldNameBytes += field.name.length;
93
+ typeStats.fieldsCount++;
94
+ stats.total.fieldNameBytes += field.name.length;
95
+ stats.total.fieldsCount++;
96
+ }
97
+
98
+ if (resource.data) {
99
+ const dataLength = resource.data?.length ?? 0;
100
+ typeStats.dataBytes += dataLength;
101
+ stats.total.dataBytes += dataLength;
102
+ }
103
+
104
+ typeStats.kvCount += resource.kv.length;
105
+ stats.total.kvCount += resource.kv.length;
106
+
107
+ for (const kv of resource.kv) {
108
+ const kvLength = kv.key.length + kv.value.length;
109
+ typeStats.kvBytes += kvLength;
110
+ stats.total.kvBytes += kvLength;
111
+ }
112
+ }
113
+
114
+ return stats;
115
+ }
package/src/index.ts CHANGED
@@ -6,3 +6,4 @@ export * from './snapshot';
6
6
  export * from './synchronized_tree';
7
7
  export * from './value_and_error';
8
8
  export * from './value_or_error';
9
+ export * from './dump';
package/src/state.ts CHANGED
@@ -45,6 +45,17 @@ class PlTreeField implements FieldData {
45
45
  /** Last version of resource this field was observed, used to garbage collect fields in tree patching procedure */
46
46
  public resourceVersion: number
47
47
  ) {}
48
+
49
+ get state(): FieldData {
50
+ return {
51
+ name: this.name,
52
+ type: this.type,
53
+ status: this.status,
54
+ value: this.value,
55
+ error: this.error,
56
+ valueIsFinal: this.valueIsFinal
57
+ };
58
+ }
48
59
  }
49
60
 
50
61
  const InitialResourceVersion = 0;
@@ -306,10 +317,10 @@ export class PlTreeResource implements ResourceDataWithFinalState {
306
317
 
307
318
  verifyReadyState() {
308
319
  if (this.resourceReady && !this.inputsLocked)
309
- throw new Error(`ready without input or output lock: ${stringifyWithResourceId(this.state)}`);
320
+ throw new Error(`ready without input or output lock: ${stringifyWithResourceId(this.basicState)}`);
310
321
  }
311
322
 
312
- get state(): BasicResourceData {
323
+ get basicState(): BasicResourceData {
313
324
  return {
314
325
  id: this.id,
315
326
  kind: this.kind,
@@ -324,6 +335,14 @@ export class PlTreeResource implements ResourceDataWithFinalState {
324
335
  };
325
336
  }
326
337
 
338
+ get extendedState(): ExtendedResourceData {
339
+ return {
340
+ ...this.basicState,
341
+ fields: this.fields,
342
+ kv: Array.from(this.kv.entries()).map(([key, value]) => ({ key, value }))
343
+ };
344
+ }
345
+
327
346
  /** Called when {@link FinalResourceDataPredicate} returns true for the state. */
328
347
  markFinal() {
329
348
  if (this._finalState) return;
@@ -399,7 +418,7 @@ export class PlTreeState {
399
418
  for (const rd of resourceData) {
400
419
  let resource = this.resources.get(rd.id);
401
420
 
402
- const statBeforeMutation = resource?.state;
421
+ const statBeforeMutation = resource?.basicState;
403
422
  const unexpectedTransitionError = (reason: string): never => {
404
423
  const { fields, ...rdWithoutFields } = rd;
405
424
  this.invalidateTree();
@@ -718,4 +737,8 @@ export class PlTreeState {
718
737
  res.markAllChanged();
719
738
  });
720
739
  }
740
+
741
+ public dumpState(): ExtendedResourceData[] {
742
+ return Array.from(this.resources.values()).map((res) => res.extendedState);
743
+ }
721
744
  }
@@ -7,7 +7,7 @@ import {
7
7
  ResourceId,
8
8
  TxOps
9
9
  } from '@milaboratories/pl-client';
10
- import { PlTreeState, TreeStateUpdateError } from './state';
10
+ import { ExtendedResourceData, PlTreeState, TreeStateUpdateError } from './state';
11
11
  import {
12
12
  constructTreeLoadingRequest,
13
13
  initialTreeLoadingStat,
@@ -198,6 +198,14 @@ export class SynchronizedTreeState {
198
198
  this.currentLoop = undefined;
199
199
  }
200
200
 
201
+ /**
202
+ * Dumps the current state of the tree.
203
+ * @returns An array of ExtendedResourceData objects representing the current state of the tree.
204
+ */
205
+ public dumpState(): ExtendedResourceData[] {
206
+ return this.state.dumpState();
207
+ }
208
+
201
209
  /**
202
210
  * Terminates the internal loop, and permanently destoys all internal state, so
203
211
  * all computables using this state will resolve to errors.