industrial-model 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -28,6 +28,14 @@ var CogniteSdkAdapter = class {
28
28
  nextCursor: response.nextCursor
29
29
  };
30
30
  }
31
+ async aggregateInstances(request) {
32
+ const response = await this.client.instances.aggregate(
33
+ request
34
+ );
35
+ return {
36
+ items: response.items
37
+ };
38
+ }
31
39
  };
32
40
 
33
41
  // src/constants.ts
@@ -36,6 +44,8 @@ var EDGE_MARKER = "<EdgeMarker>";
36
44
  var MAX_LIMIT = 1e4;
37
45
  var DEFAULT_LIMIT = 1e3;
38
46
  var MAX_DEPENDENCY_DEPTH = 3;
47
+ var AGGREGATE_LIMIT = 1e3;
48
+ var MAX_GROUP_BY = 5;
39
49
 
40
50
  // src/mappers/utils.ts
41
51
  var NODE_PROPERTIES = /* @__PURE__ */ new Set([
@@ -77,135 +87,32 @@ function buildSelect(source, properties) {
77
87
  if (properties.length === 0) return {};
78
88
  return { sources: [{ source, properties }] };
79
89
  }
80
-
81
- // src/mappers/filter-mapper.ts
82
- var LEAF_OPS = /* @__PURE__ */ new Set([
83
- "eq",
84
- "in",
85
- "gt",
86
- "gte",
87
- "lt",
88
- "lte",
89
- "exists",
90
- "prefix",
91
- "containsAny",
92
- "containsAll"
90
+ var GROUPABLE_PROPERTY_TYPES = /* @__PURE__ */ new Set([
91
+ "text",
92
+ "direct",
93
+ "int32",
94
+ "int64",
95
+ "float32",
96
+ "float64",
97
+ "boolean",
98
+ "enum"
93
99
  ]);
94
- function isLeafFilter(value) {
95
- return Object.keys(value).some((k) => LEAF_OPS.has(k));
100
+ var NUMERIC_PROPERTY_TYPES = /* @__PURE__ */ new Set(["int32", "int64", "float32", "float64"]);
101
+ function isGroupableProperty(property) {
102
+ if (!isViewPropertyDefinition(property)) return false;
103
+ if (property.type.list === true) return false;
104
+ const type = property.type.type;
105
+ return type != null && GROUPABLE_PROPERTY_TYPES.has(type);
96
106
  }
97
- var FilterMapper = class {
98
- constructor(viewMapper) {
99
- this.viewMapper = viewMapper;
100
- }
101
- async map(input, rootView) {
102
- const result = [];
103
- for (const [key, value] of Object.entries(input)) {
104
- if (value == null) continue;
105
- if (key === "AND") {
106
- const clauses = Array.isArray(value) ? value : [value];
107
- const inner = await Promise.all(clauses.map((c) => this.whereInputToSingle(c, rootView)));
108
- result.push({ and: inner });
109
- } else if (key === "OR") {
110
- const clauses = value;
111
- const branches = await Promise.all(
112
- clauses.map((c) => this.whereInputToSingle(c, rootView))
113
- );
114
- result.push({ or: branches });
115
- } else if (key === "NOT") {
116
- const clauses = Array.isArray(value) ? value : [value];
117
- const [firstClause, ...restClauses] = clauses;
118
- const combined = restClauses.length === 0 && firstClause !== void 0 ? firstClause : { AND: clauses };
119
- result.push({ not: await this.whereInputToSingle(combined, rootView) });
120
- } else {
121
- const filterValue = value;
122
- const property = getPropertyRef(key, rootView);
123
- if (isLeafFilter(filterValue)) {
124
- result.push(...this.leafToFilterDefs(property, filterValue));
125
- } else {
126
- const targetView = await this.getNestedTargetView(key, rootView);
127
- const innerFilter = await this.whereInputToSingle(filterValue, targetView);
128
- result.push({ nested: { scope: property, filter: innerFilter } });
129
- }
130
- }
131
- }
132
- return result;
133
- }
134
- async whereInputToSingle(input, rootView) {
135
- const filters = await this.map(input, rootView);
136
- const [firstFilter, ...restFilters] = filters;
137
- if (restFilters.length === 0 && firstFilter !== void 0) {
138
- return firstFilter;
139
- }
140
- return { and: filters };
141
- }
142
- leafToFilterDefs(property, filter) {
143
- const result = [];
144
- if ("eq" in filter && filter.eq !== void 0) {
145
- result.push({
146
- equals: { property, value: this.coerceValue(filter.eq) }
147
- });
148
- }
149
- if ("in" in filter && filter.in !== void 0) {
150
- result.push({
151
- in: { property, values: this.coerceValue(filter.in) }
152
- });
153
- }
154
- if ("gt" in filter && filter.gt !== void 0) {
155
- result.push({ range: { property, gt: this.coerceValue(filter.gt) } });
156
- }
157
- if ("gte" in filter && filter.gte !== void 0) {
158
- result.push({ range: { property, gte: this.coerceValue(filter.gte) } });
159
- }
160
- if ("lt" in filter && filter.lt !== void 0) {
161
- result.push({ range: { property, lt: this.coerceValue(filter.lt) } });
162
- }
163
- if ("lte" in filter && filter.lte !== void 0) {
164
- result.push({ range: { property, lte: this.coerceValue(filter.lte) } });
165
- }
166
- if ("exists" in filter) {
167
- if (filter.exists === true) {
168
- result.push({ exists: { property } });
169
- } else if (filter.exists === false) {
170
- result.push({ not: { exists: { property } } });
171
- }
172
- }
173
- if ("prefix" in filter && filter.prefix !== void 0) {
174
- result.push({ prefix: { property, value: this.coerceValue(filter.prefix) } });
175
- }
176
- if ("containsAll" in filter && filter.containsAll !== void 0) {
177
- result.push({
178
- containsAll: {
179
- property,
180
- values: this.coerceValue(filter.containsAll)
181
- }
182
- });
183
- }
184
- if ("containsAny" in filter && filter.containsAny !== void 0) {
185
- result.push({
186
- containsAny: {
187
- property,
188
- values: this.coerceValue(filter.containsAny)
189
- }
190
- });
191
- }
192
- return result;
193
- }
194
- async getNestedTargetView(property, rootView) {
195
- const viewProp = rootView.properties[property];
196
- if (!viewProp || !isViewPropertyDefinition(viewProp)) {
197
- throw new Error(`Property "${property}" is not a mapped property`);
198
- }
199
- const source = getDirectRelationSource(viewProp);
200
- if (!source) throw new Error(`Property "${property}" has no relation source`);
201
- return this.viewMapper.getView(source.externalId);
202
- }
203
- coerceValue(value) {
204
- if (value instanceof Date) return value.toISOString();
205
- if (Array.isArray(value)) return value.map((v) => this.coerceValue(v));
206
- return value;
207
- }
208
- };
107
+ function isNumericProperty(property) {
108
+ const type = property.type.type;
109
+ return type != null && NUMERIC_PROPERTY_TYPES.has(type);
110
+ }
111
+ function getSelectedGroupByKeys(groupBy) {
112
+ return Object.entries(groupBy).filter((entry) => entry[1] === true).map(([key]) => key);
113
+ }
114
+
115
+ // src/validation.ts
209
116
  var nodeIdSchema = zod.z.object({
210
117
  space: zod.z.string().min(1),
211
118
  externalId: zod.z.string().min(1)
@@ -285,7 +192,7 @@ var leafOps = /* @__PURE__ */ new Set([
285
192
  function isRecord(value) {
286
193
  return value != null && typeof value === "object" && !Array.isArray(value);
287
194
  }
288
- function isLeafFilter2(value) {
195
+ function isLeafFilter(value) {
289
196
  return Object.keys(value).some((key) => leafOps.has(key));
290
197
  }
291
198
  function issuePath(path) {
@@ -405,7 +312,7 @@ var QueryValidator = class {
405
312
  errors.push(...await this.validateSelect(options.select, rootView, ["select"]));
406
313
  }
407
314
  if (options.filters !== void 0) {
408
- errors.push(...await this.validateFilters(options.filters, rootView, ["filters"]));
315
+ errors.push(...await this.validateWhereInput(options.filters, rootView, ["filters"]));
409
316
  }
410
317
  if (options.sort !== void 0) {
411
318
  errors.push(...this.validateSort(options.sort, rootView, ["sort"]));
@@ -465,6 +372,9 @@ ${errors.map((error) => `- ${error}`).join("\n")}`);
465
372
  }
466
373
  return errors;
467
374
  }
375
+ async validateWhereInput(filters, view, path) {
376
+ return this.validateFilters(filters, view, path);
377
+ }
468
378
  async validateFilters(filters, view, path) {
469
379
  const shape = {
470
380
  AND: zod.z.union([recordSchema, zod.z.array(recordSchema)]).optional(),
@@ -508,7 +418,7 @@ ${errors.map((error) => `- ${error}`).join("\n")}`);
508
418
  if (!property) continue;
509
419
  if (isViewPropertyDefinition(property)) {
510
420
  const target2 = getDirectRelationSource(property);
511
- if (target2 != null && !isLeafFilter2(value)) {
421
+ if (target2 != null && !isLeafFilter(value)) {
512
422
  const targetView = await this.viewMapper.getView(target2.externalId);
513
423
  errors.push(...await this.validateFilters(value, targetView, [...path, name]));
514
424
  } else {
@@ -546,6 +456,351 @@ ${errors.map((error) => `- ${error}`).join("\n")}`);
546
456
  }
547
457
  };
548
458
 
459
+ // src/mappers/aggregate-validator.ts
460
+ var NODE_COUNT_PROPERTIES = /* @__PURE__ */ new Set(["externalId", "space"]);
461
+ function issuePath2(path) {
462
+ return path.length === 0 ? "aggregate" : path.map(String).join(".");
463
+ }
464
+ function formatZodIssues2(error, path) {
465
+ return error.issues.map((issue) => `${issuePath2([...path, ...issue.path])}: ${issue.message}`);
466
+ }
467
+ function isEmptyObject(value) {
468
+ return value != null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 0;
469
+ }
470
+ var AggregateValidator = class {
471
+ constructor(viewMapper) {
472
+ this.queryValidator = new QueryValidator(viewMapper);
473
+ }
474
+ async validate(options, rootView) {
475
+ const errors = [];
476
+ errors.push(...this.validateOptionsShape(options, rootView));
477
+ const selectedGroupBy = options.groupBy ? getSelectedGroupByKeys(options.groupBy) : [];
478
+ if (selectedGroupBy.length === 0 && options.aggregate === void 0) {
479
+ errors.push("aggregate: either groupBy or aggregate must be provided");
480
+ }
481
+ if (options.filters !== void 0) {
482
+ errors.push(
483
+ ...await this.queryValidator.validateWhereInput(options.filters, rootView, ["filters"])
484
+ );
485
+ }
486
+ if (options.groupBy !== void 0) {
487
+ errors.push(...this.validateGroupBy(options.groupBy, rootView, ["groupBy"]));
488
+ }
489
+ if (options.aggregate !== void 0) {
490
+ errors.push(
491
+ ...this.validateAggregate(
492
+ options.aggregate,
493
+ rootView,
494
+ ["aggregate"]
495
+ )
496
+ );
497
+ }
498
+ if (errors.length > 0) {
499
+ throw new Error(
500
+ `Invalid aggregate options:
501
+ ${errors.map((error) => `- ${error}`).join("\n")}`
502
+ );
503
+ }
504
+ }
505
+ validateOptionsShape(options, rootView) {
506
+ const schema = zod.z.object({
507
+ viewExternalId: zod.z.literal(rootView.externalId),
508
+ filters: zod.z.unknown().optional(),
509
+ groupBy: zod.z.unknown().optional(),
510
+ aggregate: zod.z.unknown().optional()
511
+ }).strict();
512
+ const result = schema.safeParse(options);
513
+ return result.success ? [] : formatZodIssues2(result.error, []);
514
+ }
515
+ validateGroupBy(groupBy, view, path) {
516
+ const shape = {};
517
+ for (const [name, property] of Object.entries(view.properties)) {
518
+ if (isGroupableProperty(property)) {
519
+ shape[name] = zod.z.literal(true).optional();
520
+ }
521
+ }
522
+ const result = zod.z.object(shape).strict().safeParse(groupBy);
523
+ if (!result.success) {
524
+ return formatZodIssues2(result.error, path);
525
+ }
526
+ const selected = getSelectedGroupByKeys(groupBy);
527
+ const errors = [];
528
+ if (selected.length === 0) {
529
+ errors.push(`${issuePath2(path)}: at least one property must be set to true`);
530
+ }
531
+ if (selected.length > MAX_GROUP_BY) {
532
+ errors.push(`${issuePath2(path)}: at most ${MAX_GROUP_BY} properties can be grouped`);
533
+ }
534
+ for (const name of selected) {
535
+ const property = view.properties[name];
536
+ if (!property || !isGroupableProperty(property)) {
537
+ errors.push(`${issuePath2([...path, name])}: property "${name}" cannot be used in groupBy`);
538
+ }
539
+ }
540
+ return errors;
541
+ }
542
+ validateAggregate(aggregate, view, path) {
543
+ if ("count" in aggregate) {
544
+ const property2 = aggregate.count;
545
+ if (isEmptyObject(property2)) {
546
+ return [];
547
+ }
548
+ if (typeof property2 === "string") {
549
+ if (NODE_COUNT_PROPERTIES.has(property2)) {
550
+ return [];
551
+ }
552
+ const viewProperty = view.properties[property2];
553
+ if (!viewProperty || !isGroupableProperty(viewProperty)) {
554
+ return [`${issuePath2([...path, "count"])}: property "${property2}" cannot be counted`];
555
+ }
556
+ return [];
557
+ }
558
+ return [`${issuePath2([...path, "count"])}: invalid count property`];
559
+ }
560
+ let propertyName;
561
+ let numericOp = null;
562
+ if ("avg" in aggregate) {
563
+ numericOp = "avg";
564
+ propertyName = aggregate.avg;
565
+ } else if ("min" in aggregate) {
566
+ numericOp = "min";
567
+ propertyName = aggregate.min;
568
+ } else if ("max" in aggregate) {
569
+ numericOp = "max";
570
+ propertyName = aggregate.max;
571
+ } else if ("sum" in aggregate) {
572
+ numericOp = "sum";
573
+ propertyName = aggregate.sum;
574
+ }
575
+ if (numericOp == null) {
576
+ return [`${issuePath2(path)}: unknown aggregate operation`];
577
+ }
578
+ if (typeof propertyName !== "string") {
579
+ return [`${issuePath2(path)}: aggregate property must be a string`];
580
+ }
581
+ const property = view.properties[propertyName];
582
+ if (!property || !isViewPropertyDefinition(property) || !isNumericProperty(property)) {
583
+ return [
584
+ `${issuePath2([...path, numericOp])}: property "${propertyName}" must be a numeric view property`
585
+ ];
586
+ }
587
+ if (getDirectRelationSource(property) != null) {
588
+ return [
589
+ `${issuePath2([...path, numericOp])}: property "${propertyName}" is a relation and cannot be aggregated`
590
+ ];
591
+ }
592
+ return [];
593
+ }
594
+ };
595
+
596
+ // src/mappers/filter-mapper.ts
597
+ var LEAF_OPS = /* @__PURE__ */ new Set([
598
+ "eq",
599
+ "in",
600
+ "gt",
601
+ "gte",
602
+ "lt",
603
+ "lte",
604
+ "exists",
605
+ "prefix",
606
+ "containsAny",
607
+ "containsAll"
608
+ ]);
609
+ function isLeafFilter2(value) {
610
+ return Object.keys(value).some((k) => LEAF_OPS.has(k));
611
+ }
612
+ var FilterMapper = class {
613
+ constructor(viewMapper) {
614
+ this.viewMapper = viewMapper;
615
+ }
616
+ async map(input, rootView) {
617
+ const result = [];
618
+ for (const [key, value] of Object.entries(input)) {
619
+ if (value == null) continue;
620
+ if (key === "AND") {
621
+ const clauses = Array.isArray(value) ? value : [value];
622
+ const inner = await Promise.all(clauses.map((c) => this.whereInputToSingle(c, rootView)));
623
+ result.push({ and: inner });
624
+ } else if (key === "OR") {
625
+ const clauses = value;
626
+ const branches = await Promise.all(
627
+ clauses.map((c) => this.whereInputToSingle(c, rootView))
628
+ );
629
+ result.push({ or: branches });
630
+ } else if (key === "NOT") {
631
+ const clauses = Array.isArray(value) ? value : [value];
632
+ const [firstClause, ...restClauses] = clauses;
633
+ const combined = restClauses.length === 0 && firstClause !== void 0 ? firstClause : { AND: clauses };
634
+ result.push({ not: await this.whereInputToSingle(combined, rootView) });
635
+ } else {
636
+ const filterValue = value;
637
+ const property = getPropertyRef(key, rootView);
638
+ if (isLeafFilter2(filterValue)) {
639
+ result.push(...this.leafToFilterDefs(property, filterValue));
640
+ } else {
641
+ const targetView = await this.getNestedTargetView(key, rootView);
642
+ const innerFilter = await this.whereInputToSingle(filterValue, targetView);
643
+ result.push({ nested: { scope: property, filter: innerFilter } });
644
+ }
645
+ }
646
+ }
647
+ return result;
648
+ }
649
+ async whereInputToSingle(input, rootView) {
650
+ const filters = await this.map(input, rootView);
651
+ const [firstFilter, ...restFilters] = filters;
652
+ if (restFilters.length === 0 && firstFilter !== void 0) {
653
+ return firstFilter;
654
+ }
655
+ return { and: filters };
656
+ }
657
+ leafToFilterDefs(property, filter) {
658
+ const result = [];
659
+ if ("eq" in filter && filter.eq !== void 0) {
660
+ result.push({
661
+ equals: { property, value: this.coerceValue(filter.eq) }
662
+ });
663
+ }
664
+ if ("in" in filter && filter.in !== void 0) {
665
+ result.push({
666
+ in: { property, values: this.coerceValue(filter.in) }
667
+ });
668
+ }
669
+ if ("gt" in filter && filter.gt !== void 0) {
670
+ result.push({ range: { property, gt: this.coerceValue(filter.gt) } });
671
+ }
672
+ if ("gte" in filter && filter.gte !== void 0) {
673
+ result.push({ range: { property, gte: this.coerceValue(filter.gte) } });
674
+ }
675
+ if ("lt" in filter && filter.lt !== void 0) {
676
+ result.push({ range: { property, lt: this.coerceValue(filter.lt) } });
677
+ }
678
+ if ("lte" in filter && filter.lte !== void 0) {
679
+ result.push({ range: { property, lte: this.coerceValue(filter.lte) } });
680
+ }
681
+ if ("exists" in filter) {
682
+ if (filter.exists === true) {
683
+ result.push({ exists: { property } });
684
+ } else if (filter.exists === false) {
685
+ result.push({ not: { exists: { property } } });
686
+ }
687
+ }
688
+ if ("prefix" in filter && filter.prefix !== void 0) {
689
+ result.push({ prefix: { property, value: this.coerceValue(filter.prefix) } });
690
+ }
691
+ if ("containsAll" in filter && filter.containsAll !== void 0) {
692
+ result.push({
693
+ containsAll: {
694
+ property,
695
+ values: this.coerceValue(filter.containsAll)
696
+ }
697
+ });
698
+ }
699
+ if ("containsAny" in filter && filter.containsAny !== void 0) {
700
+ result.push({
701
+ containsAny: {
702
+ property,
703
+ values: this.coerceValue(filter.containsAny)
704
+ }
705
+ });
706
+ }
707
+ return result;
708
+ }
709
+ async getNestedTargetView(property, rootView) {
710
+ const viewProp = rootView.properties[property];
711
+ if (!viewProp || !isViewPropertyDefinition(viewProp)) {
712
+ throw new Error(`Property "${property}" is not a mapped property`);
713
+ }
714
+ const source = getDirectRelationSource(viewProp);
715
+ if (!source) throw new Error(`Property "${property}" has no relation source`);
716
+ return this.viewMapper.getView(source.externalId);
717
+ }
718
+ coerceValue(value) {
719
+ if (value instanceof Date) return value.toISOString();
720
+ if (Array.isArray(value)) return value.map((v) => this.coerceValue(v));
721
+ return value;
722
+ }
723
+ };
724
+
725
+ // src/mappers/aggregate-mapper.ts
726
+ var AggregateMapper = class {
727
+ constructor(viewMapper) {
728
+ this.viewMapper = viewMapper;
729
+ this.filterMapper = new FilterMapper(viewMapper);
730
+ this.validator = new AggregateValidator(viewMapper);
731
+ }
732
+ async map(options) {
733
+ const { viewExternalId, filters, groupBy, aggregate } = options;
734
+ const rootView = await this.viewMapper.getView(viewExternalId);
735
+ await this.validator.validate(options, rootView);
736
+ const filterParts = filters ? await this.filterMapper.map(filters, rootView) : [];
737
+ const filter = filterParts.length === 0 ? void 0 : filterParts.length === 1 ? filterParts[0] : { and: filterParts };
738
+ return {
739
+ view: toViewReference(rootView),
740
+ instanceType: "node",
741
+ limit: AGGREGATE_LIMIT,
742
+ ...filter !== void 0 ? { filter } : {},
743
+ ...groupBy ? { groupBy: getSelectedGroupByKeys(groupBy) } : {},
744
+ ...aggregate ? { aggregates: [mapAggregateDefinition(aggregate)] } : {}
745
+ };
746
+ }
747
+ };
748
+ function mapAggregateDefinition(aggregate) {
749
+ if ("count" in aggregate) {
750
+ const property = aggregate.count;
751
+ if (property != null && typeof property === "object" && !Array.isArray(property) && Object.keys(property).length === 0) {
752
+ return { count: {} };
753
+ }
754
+ if (typeof property === "string") {
755
+ return { count: { property } };
756
+ }
757
+ return { count: {} };
758
+ }
759
+ if ("avg" in aggregate) {
760
+ return { avg: { property: aggregate.avg } };
761
+ }
762
+ if ("min" in aggregate) {
763
+ return { min: { property: aggregate.min } };
764
+ }
765
+ if ("max" in aggregate) {
766
+ return { max: { property: aggregate.max } };
767
+ }
768
+ if ("sum" in aggregate) {
769
+ return { sum: { property: aggregate.sum } };
770
+ }
771
+ throw new Error("Invalid aggregate definition");
772
+ }
773
+
774
+ // src/mappers/aggregate-result-mapper.ts
775
+ function isNodeId(value) {
776
+ return value != null && typeof value === "object" && "space" in value && "externalId" in value && typeof value.space === "string" && typeof value.externalId === "string";
777
+ }
778
+ var AggregateResultMapper = class {
779
+ map(response, options) {
780
+ const groupByKeys = options.groupBy ? getSelectedGroupByKeys(options.groupBy) : [];
781
+ return response.items.map((item) => {
782
+ let group;
783
+ if (item.group != null && groupByKeys.length > 0) {
784
+ group = {};
785
+ for (const key of groupByKeys) {
786
+ const value = item.group[key];
787
+ if (value === void 0) continue;
788
+ group[key] = isNodeId(value) ? { space: value.space, externalId: value.externalId } : value;
789
+ }
790
+ if (Object.keys(group).length === 0) {
791
+ group = void 0;
792
+ }
793
+ }
794
+ const aggregateValue = item.aggregates[0];
795
+ const aggregate = aggregateValue?.value !== void 0 ? aggregateValue.property != null ? { property: aggregateValue.property, value: aggregateValue.value } : { value: aggregateValue.value } : void 0;
796
+ return {
797
+ ...group !== void 0 ? { group } : {},
798
+ ...aggregate !== void 0 ? { aggregate } : {}
799
+ };
800
+ });
801
+ }
802
+ };
803
+
549
804
  // src/mappers/sort-mapper.ts
550
805
  var SortMapper = class {
551
806
  map(sort, rootView) {
@@ -1115,6 +1370,8 @@ var IndustrialModelClient = class {
1115
1370
  this.cognite = cognite;
1116
1371
  const viewMapper = new ViewMapper(cognite, dataModelId);
1117
1372
  this.queryMapper = new QueryMapper(viewMapper);
1373
+ this.aggregateMapper = new AggregateMapper(viewMapper);
1374
+ this.aggregateResultMapper = new AggregateResultMapper();
1118
1375
  this.resultMapper = new QueryResultMapper(viewMapper);
1119
1376
  this.resultValidator = new QueryResultValidator(viewMapper);
1120
1377
  this.validateResults = options.validateResults ?? false;
@@ -1123,6 +1380,19 @@ var IndustrialModelClient = class {
1123
1380
  const execute = (options) => this.queryInternal(options);
1124
1381
  return execute;
1125
1382
  }
1383
+ aggregate() {
1384
+ const execute = (options) => this.aggregateInternal(options);
1385
+ return execute;
1386
+ }
1387
+ async aggregateInternal(options) {
1388
+ const cogniteRequest = await this.aggregateMapper.map(options);
1389
+ const response = await this.cognite.aggregateInstances(cogniteRequest);
1390
+ const items = this.aggregateResultMapper.map(
1391
+ response,
1392
+ options
1393
+ );
1394
+ return { items };
1395
+ }
1126
1396
  async queryInternal(options) {
1127
1397
  const { viewExternalId, limit = DEFAULT_LIMIT } = options;
1128
1398
  const allPages = options.limit === -1;