industrial-model 0.1.0 → 0.3.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/README.md CHANGED
@@ -21,11 +21,16 @@ npm install industrial-model
21
21
  npm install @cognite/sdk
22
22
  ```
23
23
 
24
+ ## Requirements
25
+
26
+ - Node.js `>=20`
27
+ - `@cognite/sdk` `^10.10.0` (peer dependency)
28
+
24
29
  ## Quick start
25
30
 
26
31
  ```ts
27
32
  import { CogniteClient } from "@cognite/sdk";
28
- import { IndustrialModel } from "industrial-model";
33
+ import { IndustrialModelClient } from "industrial-model";
29
34
 
30
35
  const client = new CogniteClient({
31
36
  appId: "my-app",
@@ -34,13 +39,13 @@ const client = new CogniteClient({
34
39
  oidcTokenProvider: async () => getAccessToken(),
35
40
  });
36
41
 
37
- const model = new IndustrialModel(client, {
42
+ const model = new IndustrialModelClient(client, {
38
43
  space: "cdf_cdm",
39
44
  externalId: "CogniteCore",
40
45
  version: "v1",
41
46
  });
42
47
 
43
- const { items } = await model.query({
48
+ const { items } = await model.query<{ name: string; description: string }>()({
44
49
  viewExternalId: "CogniteAsset",
45
50
  select: { name: true, description: true },
46
51
  filters: { name: { prefix: "Pump" } },
@@ -57,7 +62,7 @@ const { items } = await model.query({
57
62
  | Relations | [Parent/root](#query-assets-with-parent-and-root-relations), [Path](#query-assets-with-their-full-path), [Children](#query-child-assets-reverse-relation), [Edges](#traverse-edge-relations-360-images-on-3d-objects) |
58
63
  | Filters | [AND/OR/NOT](#combine-filters-with-and--or--not), [Nested](#filter-on-related-nodes), [Tags](#filter-assets-by-tags), [Batch IDs](#filter-by-multiple-external-ids) |
59
64
  | Select & sort | [Select all scalars](#select-all-scalar-fields), [Multi-field sort](#sort-by-multiple-fields) |
60
- | Pagination | [Manual cursor loop](#paginate-through-all-assets), [Fetch all pages](#fetch-all-pages-in-one-call) |
65
+ | Pagination | [Manual cursor loop](#paginate-through-all-assets), [Fetch all pages](#fetch-all-pages-automatically) |
61
66
  | Advanced | [Custom data model](#use-a-custom-data-model), [Full query](#full-example-assets-equipment-and-filters) |
62
67
 
63
68
  All examples below use the [Cognite Core Data Model](https://docs.cognite.com/cdf/data_modeling/reference_data_models/cognite_core/), space `cdf_cdm`, version `v1`.
@@ -65,52 +70,44 @@ All examples below use the [Cognite Core Data Model](https://docs.cognite.com/cd
65
70
  ### Shared type definitions
66
71
 
67
72
  ```ts
68
- import type { NodeId } from "industrial-model";
69
-
70
- type CogniteAsset = {
71
- name: string;
72
- description: string;
73
- tags: string[];
74
- aliases: string[];
75
- sourceId: string;
76
- sourceCreatedTime: string;
77
- sourceUpdatedTime: string;
78
- parent?: NodeId;
79
- root?: NodeId;
80
- path: NodeId[];
81
- assetClass?: NodeId;
82
- type?: NodeId;
83
- source?: NodeId;
84
- };
85
-
86
- type CogniteAssetRelations = {
87
- parent: CogniteAsset;
88
- root: CogniteAsset;
89
- path: CogniteAsset[];
90
- };
91
-
92
- type CogniteEquipment = {
93
- name: string;
94
- description: string;
95
- manufacturer: string;
96
- serialNumber: string;
97
- tags: string[];
98
- asset?: NodeId;
99
- equipmentType?: NodeId;
100
- source?: NodeId;
101
- };
102
-
103
- type CogniteTimeSeries = {
73
+ import type {
74
+ IndustrialModel,
75
+ ModelProps,
76
+ ModelRelations,
77
+ NodeId,
78
+ QueryResultItem,
79
+ } from "industrial-model";
80
+
81
+ type CogniteAssetClass = IndustrialModel<{
104
82
  name: string;
105
- description: string;
106
- isStep: boolean;
107
- sourceUnit: string;
108
- unit?: NodeId;
109
- assets: NodeId[];
110
- equipment: NodeId[];
111
- };
112
-
113
- type CogniteActivity = {
83
+ code: string;
84
+ }>;
85
+
86
+ type CogniteAsset = IndustrialModel<
87
+ {
88
+ name: string;
89
+ description: string;
90
+ tags: string[];
91
+ aliases: string[];
92
+ sourceId: string;
93
+ sourceCreatedTime: string;
94
+ sourceUpdatedTime: string;
95
+ parent?: NodeId;
96
+ root?: NodeId;
97
+ path: NodeId[];
98
+ assetClass?: NodeId;
99
+ type?: NodeId;
100
+ source?: NodeId;
101
+ },
102
+ {
103
+ parent?: CogniteAsset;
104
+ root?: CogniteAsset;
105
+ path?: CogniteAsset[];
106
+ assetClass?: CogniteAssetClass;
107
+ }
108
+ >;
109
+
110
+ type CogniteActivity = IndustrialModel<{
114
111
  name: string;
115
112
  description: string;
116
113
  startTime: string;
@@ -120,27 +117,60 @@ type CogniteActivity = {
120
117
  assets: NodeId[];
121
118
  equipment: NodeId[];
122
119
  timeSeries: NodeId[];
123
- };
120
+ }>;
121
+
122
+ type CogniteEquipment = IndustrialModel<
123
+ {
124
+ name: string;
125
+ description: string;
126
+ manufacturer: string;
127
+ serialNumber: string;
128
+ tags: string[];
129
+ asset?: NodeId;
130
+ equipmentType?: NodeId;
131
+ source?: NodeId;
132
+ },
133
+ {
134
+ asset?: CogniteAsset;
135
+ activities?: CogniteActivity[];
136
+ }
137
+ >;
124
138
 
125
- type CogniteUnit = {
139
+ type CogniteUnit = IndustrialModel<{
126
140
  name: string;
127
141
  symbol: string;
128
142
  quantity: string;
129
143
  source: string;
130
- };
131
-
132
- type CogniteUnitRelations = {
133
- unit: CogniteUnit;
134
- };
135
-
136
- type Cognite3DObject = {
137
- name: string;
138
- description: string;
139
- };
140
-
141
- type Cognite360ImageRelations = {
142
- images360: { takenAt: string };
143
- };
144
+ }>;
145
+
146
+ type CogniteTimeSeries = IndustrialModel<
147
+ {
148
+ name: string;
149
+ description: string;
150
+ isStep: boolean;
151
+ sourceUnit: string;
152
+ unit?: NodeId;
153
+ assets: NodeId[];
154
+ equipment: NodeId[];
155
+ },
156
+ {
157
+ unit?: CogniteUnit;
158
+ }
159
+ >;
160
+
161
+ type Cognite360Image = IndustrialModel<{
162
+ takenAt: string;
163
+ }>;
164
+
165
+ type Cognite3DObject = IndustrialModel<
166
+ {
167
+ name: string;
168
+ description: string;
169
+ },
170
+ {
171
+ images360?: Cognite360Image[];
172
+ }
173
+ >;
144
174
  ```
145
175
 
146
176
  ---
@@ -150,7 +180,7 @@ type Cognite360ImageRelations = {
150
180
  Fetch the first 100 assets whose name starts with `"Pump"`, sorted alphabetically.
151
181
 
152
182
  ```ts
153
- const { items, cursor } = await model.query<CogniteAsset>({
183
+ const { items, cursor } = await model.query<CogniteAsset>()({
154
184
  viewExternalId: "CogniteAsset",
155
185
  select: {
156
186
  name: true,
@@ -161,7 +191,7 @@ const { items, cursor } = await model.query<CogniteAsset>({
161
191
  filters: {
162
192
  name: { prefix: "Pump" },
163
193
  },
164
- sortClauses: { name: "ascending" },
194
+ sort: { name: "ascending" },
165
195
  limit: 100,
166
196
  });
167
197
  ```
@@ -171,7 +201,7 @@ const { items, cursor } = await model.query<CogniteAsset>({
171
201
  ### Query a single asset by externalId
172
202
 
173
203
  ```ts
174
- const { items } = await model.query<CogniteAsset>({
204
+ const { items } = await model.query<CogniteAsset>()({
175
205
  viewExternalId: "CogniteAsset",
176
206
  select: { name: true, description: true, tags: true },
177
207
  filters: {
@@ -189,7 +219,7 @@ const asset = items[0];
189
219
  Traverse up the asset hierarchy — fetch each asset alongside its direct parent and the root of the tree.
190
220
 
191
221
  ```ts
192
- const { items } = await model.query<CogniteAsset, CogniteAssetRelations>({
222
+ const { items } = await model.query<CogniteAsset>()({
193
223
  viewExternalId: "CogniteAsset",
194
224
  select: {
195
225
  name: true,
@@ -210,6 +240,8 @@ const { items } = await model.query<CogniteAsset, CogniteAssetRelations>({
210
240
  },
211
241
  limit: 50,
212
242
  });
243
+
244
+ const firstParentName = items[0]?.parent?.name;
213
245
  ```
214
246
 
215
247
  ---
@@ -219,7 +251,7 @@ const { items } = await model.query<CogniteAsset, CogniteAssetRelations>({
219
251
  The `path` property is a list of `NodeId` references representing the ancestor chain. Use it to reconstruct breadcrumbs.
220
252
 
221
253
  ```ts
222
- const { items } = await model.query<CogniteAsset, CogniteAssetRelations>({
254
+ const { items } = await model.query<CogniteAsset>()({
223
255
  viewExternalId: "CogniteAsset",
224
256
  select: {
225
257
  name: true,
@@ -239,7 +271,7 @@ const { items } = await model.query<CogniteAsset, CogniteAssetRelations>({
239
271
  ### Query equipment linked to an asset
240
272
 
241
273
  ```ts
242
- const { items } = await model.query<CogniteEquipment>({
274
+ const { items } = await model.query<CogniteEquipment>()({
243
275
  viewExternalId: "CogniteEquipment",
244
276
  select: {
245
277
  name: true,
@@ -252,7 +284,7 @@ const { items } = await model.query<CogniteEquipment>({
252
284
  asset: { eq: { space: "my-space", externalId: "WMT:VAL" } },
253
285
  manufacturer: { exists: true },
254
286
  },
255
- sortClauses: { name: "ascending" },
287
+ sort: { name: "ascending" },
256
288
  limit: 50,
257
289
  });
258
290
  ```
@@ -262,7 +294,7 @@ const { items } = await model.query<CogniteEquipment>({
262
294
  ### Query time series with their unit
263
295
 
264
296
  ```ts
265
- const { items } = await model.query<CogniteTimeSeries, CogniteUnitRelations>({
297
+ const { items } = await model.query<CogniteTimeSeries>()({
266
298
  viewExternalId: "CogniteTimeSeries",
267
299
  select: {
268
300
  name: true,
@@ -288,7 +320,7 @@ const { items } = await model.query<CogniteTimeSeries, CogniteUnitRelations>({
288
320
  ### Query activities in a time window
289
321
 
290
322
  ```ts
291
- const { items } = await model.query<CogniteActivity>({
323
+ const { items } = await model.query<CogniteActivity>()({
292
324
  viewExternalId: "CogniteActivity",
293
325
  select: {
294
326
  name: true,
@@ -301,7 +333,7 @@ const { items } = await model.query<CogniteActivity>({
301
333
  filters: {
302
334
  startTime: { gte: "2024-01-01T00:00:00Z", lte: "2024-12-31T23:59:59Z" },
303
335
  },
304
- sortClauses: { startTime: "ascending" },
336
+ sort: { startTime: "ascending" },
305
337
  limit: 500,
306
338
  });
307
339
  ```
@@ -313,7 +345,7 @@ const { items } = await model.query<CogniteActivity>({
313
345
  Fetch assets that are either tagged `"critical"` or have a name starting with `"Compressor"`, but exclude those from source `"legacy-system"`.
314
346
 
315
347
  ```ts
316
- const { items } = await model.query<CogniteAsset>({
348
+ const { items } = await model.query<CogniteAsset>()({
317
349
  viewExternalId: "CogniteAsset",
318
350
  select: { name: true, tags: true, sourceId: true },
319
351
  filters: {
@@ -333,10 +365,10 @@ const { items } = await model.query<CogniteAsset>({
333
365
 
334
366
  ```ts
335
367
  let cursor: string | null = null;
336
- const allAssets: Record<string, unknown>[] = [];
368
+ const allAssets: QueryResultItem<CogniteAsset, { name: true; description: true }>[] = [];
337
369
 
338
370
  do {
339
- const result = await model.query<CogniteAsset>({
371
+ const result = await model.query<CogniteAsset>()({
340
372
  viewExternalId: "CogniteAsset",
341
373
  select: { name: true, description: true },
342
374
  limit: 1000,
@@ -352,19 +384,19 @@ console.log(`Total assets: ${allAssets.length}`);
352
384
 
353
385
  ---
354
386
 
355
- ### Fetch all pages in one call
387
+ ### Fetch all pages automatically
356
388
 
357
- Pass `limit: -1` to automatically follow cursors until every page is loaded. The returned `cursor` is always `null`.
389
+ Pass `limit: -1` to follow root-view cursors until every page is loaded. The SDK issues multiple `instances.query` calls (1000 items per page by default). The returned `cursor` is always `null`.
358
390
 
359
391
  ```ts
360
- const { items } = await model.query<CogniteAsset>({
392
+ const { items } = await model.query<CogniteAsset>()({
361
393
  viewExternalId: "CogniteAsset",
362
394
  select: { name: true, description: true },
363
395
  filters: { tags: { containsAny: ["production"] } },
364
396
  limit: -1,
365
397
  });
366
398
 
367
- console.log(`Loaded ${items.length} assets in one request chain`);
399
+ console.log(`Loaded ${items.length} assets across all pages`);
368
400
  ```
369
401
 
370
402
  ---
@@ -374,7 +406,7 @@ console.log(`Loaded ${items.length} assets in one request chain`);
374
406
  Use `_all` to include every scalar property on the view without listing them individually. Relation fields are returned as `NodeId` references but are not expanded — add nested `select` blocks when you need related data.
375
407
 
376
408
  ```ts
377
- const { items } = await model.query<CogniteAsset>({
409
+ const { items } = await model.query<CogniteAsset>()({
378
410
  viewExternalId: "CogniteAsset",
379
411
  select: { _all: true },
380
412
  limit: 50,
@@ -386,7 +418,7 @@ const { items } = await model.query<CogniteAsset>({
386
418
  Combine `_all` with explicit relation expansion:
387
419
 
388
420
  ```ts
389
- const { items } = await model.query<CogniteAsset, CogniteAssetRelations>({
421
+ const { items } = await model.query<CogniteAsset>()({
390
422
  viewExternalId: "CogniteAsset",
391
423
  select: {
392
424
  _all: true,
@@ -401,7 +433,7 @@ const { items } = await model.query<CogniteAsset, CogniteAssetRelations>({
401
433
  ### Filter by multiple external IDs
402
434
 
403
435
  ```ts
404
- const { items } = await model.query<CogniteAsset>({
436
+ const { items } = await model.query<CogniteAsset>()({
405
437
  viewExternalId: "CogniteAsset",
406
438
  select: { name: true, description: true },
407
439
  filters: {
@@ -418,7 +450,7 @@ const { items } = await model.query<CogniteAsset>({
418
450
 
419
451
  ```ts
420
452
  // Match assets that have at least one of these tags
421
- const critical = await model.query<CogniteAsset>({
453
+ const critical = await model.query<CogniteAsset>()({
422
454
  viewExternalId: "CogniteAsset",
423
455
  select: { name: true, tags: true },
424
456
  filters: { tags: { containsAny: ["critical", "safety"] } },
@@ -426,7 +458,7 @@ const critical = await model.query<CogniteAsset>({
426
458
  });
427
459
 
428
460
  // Match assets that must have every tag
429
- const fullyTagged = await model.query<CogniteAsset>({
461
+ const fullyTagged = await model.query<CogniteAsset>()({
430
462
  viewExternalId: "CogniteAsset",
431
463
  select: { name: true, tags: true },
432
464
  filters: { tags: { containsAll: ["production", "verified"] } },
@@ -442,7 +474,7 @@ Filter the root view based on properties of a direct or nested relation. This us
442
474
 
443
475
  ```ts
444
476
  // Assets whose parent is named "Site Root"
445
- const { items } = await model.query<CogniteAsset>({
477
+ const { items } = await model.query<CogniteAsset>()({
446
478
  viewExternalId: "CogniteAsset",
447
479
  select: { name: true, parent: { name: true } },
448
480
  filters: {
@@ -452,7 +484,7 @@ const { items } = await model.query<CogniteAsset>({
452
484
  });
453
485
 
454
486
  // Assets whose parent's asset class code is "PUMP"
455
- const pumpsByClass = await model.query<CogniteAsset>({
487
+ const pumpsByClass = await model.query<CogniteAsset>()({
456
488
  viewExternalId: "CogniteAsset",
457
489
  select: {
458
490
  name: true,
@@ -465,7 +497,7 @@ const pumpsByClass = await model.query<CogniteAsset>({
465
497
  });
466
498
 
467
499
  // Combine root and nested conditions
468
- const filtered = await model.query<CogniteAsset>({
500
+ const filtered = await model.query<CogniteAsset>()({
469
501
  viewExternalId: "CogniteAsset",
470
502
  select: { name: true, parent: { name: true } },
471
503
  filters: {
@@ -482,14 +514,15 @@ const filtered = await model.query<CogniteAsset>({
482
514
 
483
515
  ### Query child assets (reverse relation)
484
516
 
485
- Declare reverse relations in the second generic parameter (`TRelation`). The library resolves the correct traversal direction from your data model.
517
+ Declare reverse relations in the `IndustrialModel<TProps, TRelations>` metadata. The library resolves the correct traversal direction from your data model.
486
518
 
487
519
  ```ts
488
- type AssetWithChildren = CogniteAsset & {
489
- children?: CogniteAsset[];
490
- };
520
+ type AssetWithChildren = IndustrialModel<
521
+ ModelProps<CogniteAsset>,
522
+ ModelRelations<CogniteAsset> & { children?: CogniteAsset[] }
523
+ >;
491
524
 
492
- const { items } = await model.query<AssetWithChildren, { children: CogniteAsset }>({
525
+ const { items } = await model.query<AssetWithChildren>()({
493
526
  viewExternalId: "CogniteAsset",
494
527
  select: {
495
528
  name: true,
@@ -511,7 +544,7 @@ const { items } = await model.query<AssetWithChildren, { children: CogniteAsset
511
544
  Some relations are modeled as edges rather than direct node links. Select them the same way — the SDK builds the edge hop automatically.
512
545
 
513
546
  ```ts
514
- const { items } = await model.query<Cognite3DObject, Cognite360ImageRelations>({
547
+ const { items } = await model.query<Cognite3DObject>()({
515
548
  viewExternalId: "Cognite3DObject",
516
549
  select: {
517
550
  name: true,
@@ -531,10 +564,10 @@ const { items } = await model.query<Cognite3DObject, Cognite360ImageRelations>({
531
564
  Sort clauses apply to primitive fields on the root view, including node-level properties like `externalId`.
532
565
 
533
566
  ```ts
534
- const { items } = await model.query<CogniteAsset>({
567
+ const { items } = await model.query<CogniteAsset>()({
535
568
  viewExternalId: "CogniteAsset",
536
569
  select: { name: true, sourceId: true },
537
- sortClauses: {
570
+ sort: {
538
571
  name: "ascending",
539
572
  externalId: "descending",
540
573
  },
@@ -546,22 +579,22 @@ const { items } = await model.query<CogniteAsset>({
546
579
 
547
580
  ### Use a custom data model
548
581
 
549
- Point the client at any FDM in your project — not only Cognite Core. Views and filters work the same way once your TypeScript types match the model.
582
+ Point the client at any FDM in your project — not only Cognite Core. Scalar fields work with a plain object type; use `IndustrialModel<TProps, TRelations>` when you need relation selects, filters, or inference.
550
583
 
551
584
  ```ts
552
- const model = new IndustrialModel(client, {
585
+ const model = new IndustrialModelClient(client, {
553
586
  space: "my-custom-space",
554
587
  externalId: "MyPlantModel",
555
588
  version: "1",
556
589
  });
557
590
 
558
- type PlantArea = {
591
+ type PlantArea = IndustrialModel<{
559
592
  name: string;
560
593
  code: string;
561
594
  site?: NodeId;
562
- };
595
+ }>;
563
596
 
564
- const { items } = await model.query<PlantArea>({
597
+ const { items } = await model.query<PlantArea>()({
565
598
  viewExternalId: "PlantArea",
566
599
  select: { name: true, code: true, site: true },
567
600
  filters: { code: { prefix: "AREA-" } },
@@ -576,11 +609,12 @@ const { items } = await model.query<PlantArea>({
576
609
  A single query combining nested selects, nested filters, sorting, and pagination.
577
610
 
578
611
  ```ts
579
- type AssetWithRelations = CogniteAsset & {
580
- parent?: CogniteAsset & { assetClass?: { name: string; code: string } };
581
- };
612
+ type AssetWithRelations = IndustrialModel<
613
+ ModelProps<CogniteAsset>,
614
+ ModelRelations<CogniteAsset> & { children?: CogniteAsset[] }
615
+ >;
582
616
 
583
- const { items, cursor } = await model.query<AssetWithRelations, CogniteAssetRelations>({
617
+ const { items, cursor } = await model.query<AssetWithRelations>()({
584
618
  viewExternalId: "CogniteAsset",
585
619
  select: {
586
620
  name: true,
@@ -599,14 +633,14 @@ const { items, cursor } = await model.query<AssetWithRelations, CogniteAssetRela
599
633
  { sourceId: { eq: "sap" } },
600
634
  ],
601
635
  },
602
- sortClauses: { name: "ascending" },
636
+ sort: { name: "ascending" },
603
637
  limit: 25,
604
638
  cursor: null,
605
639
  });
606
640
 
607
641
  // Follow-up page
608
642
  if (cursor) {
609
- const next = await model.query<AssetWithRelations, CogniteAssetRelations>({
643
+ const next = await model.query<AssetWithRelations>()({
610
644
  viewExternalId: "CogniteAsset",
611
645
  select: {
612
646
  name: true,
@@ -618,7 +652,7 @@ if (cursor) {
618
652
  name: { prefix: "WMT" },
619
653
  parent: { name: { exists: true } },
620
654
  },
621
- sortClauses: { name: "ascending" },
655
+ sort: { name: "ascending" },
622
656
  limit: 25,
623
657
  cursor,
624
658
  });
@@ -629,33 +663,86 @@ if (cursor) {
629
663
 
630
664
  ## API
631
665
 
632
- ### `new IndustrialModel(client, dataModelId)`
666
+ ### Exports
667
+
668
+ | Symbol | Description |
669
+ |--------|-------------|
670
+ | `IndustrialModelClient` | Main client |
671
+ | `IndustrialModel`, `ModelProps`, `ModelRelations` | Type helpers for models and relations |
672
+ | `NodeId`, `DataModelId` | Instance and data-model identifiers |
673
+ | `QueryOptions`, `QuerySelect`, `WhereInput`, `SortInput` | Query input types |
674
+ | `QueryResult`, `QueryResultItem`, `QueryResultMetadata` | Query output types |
675
+ | `buildViewSchema`, `nodeIdSchema` | Zod schemas built from Cognite view metadata |
676
+ | `SortDirection` | `"ascending"` \| `"descending"` |
677
+
678
+ ### `new IndustrialModelClient(client, dataModelId, options?)`
633
679
 
634
680
  | Parameter | Type | Description |
635
681
  |-----------|------|-------------|
636
682
  | `client` | `CogniteClient` | Authenticated Cognite SDK client |
637
683
  | `dataModelId` | `DataModelId` | Space, externalId, and version of the data model |
684
+ | `options.validateResults` | `boolean` | Optional. Validate and parse query results with Zod schemas derived from Cognite view metadata |
685
+
686
+ On the first query, view definitions are loaded from CDF and cached for the lifetime of the client instance.
638
687
 
639
- ### `model.query<T, TRelation?>(options)`
688
+ Query inputs are validated against the loaded view metadata before the Cognite request is built. Result validation is opt-in because it parses every returned item:
689
+
690
+ ```ts
691
+ const model = new IndustrialModelClient(client, dataModelId, {
692
+ validateResults: true,
693
+ });
694
+ ```
695
+
696
+ When `validateResults` is enabled, Cognite `date` and `timestamp` view properties are converted to JavaScript `Date` objects. Without this option, result values are returned as Cognite provides them, usually ISO strings for timestamps.
697
+
698
+ ### `model.query<TModel>()(options)`
640
699
 
641
700
  | Option | Type | Description |
642
701
  |--------|------|-------------|
643
702
  | `viewExternalId` | `string` | The view to query |
644
- | `select` | `QuerySelect<T, TRelation>` | Fields to include; use `_all: true` for all scalars |
645
- | `filters` | `WhereInput<T, TRelation>` | Filter conditions (supports nested relation filters) |
646
- | `sortClauses` | `SortInput<T>` | Sort by primitive fields |
647
- | `limit` | `number` | Max items per page (default 1000, max 10000). Use `-1` to fetch all pages |
703
+ | `select` | `QuerySelect<TModel>` | Optional. Defaults to `{ _all: true }` (all scalar fields). Use `_all: true` explicitly or list fields; use nested objects for relations |
704
+ | `filters` | `WhereInput<TModel>` | Filter conditions (supports nested relation filters) |
705
+ | `sort` | `SortInput<TModel>` | Sort by primitive fields on the **root** view only |
706
+ | `limit` | `number` | Root page size (default `1000`). Use `-1` to fetch all root pages automatically |
648
707
  | `cursor` | `string \| null` | Pagination cursor from a previous response |
649
708
 
650
- Returns `Promise<QueryResult>`:
709
+ `query()` uses a curried form so you can supply the model types first and still get return-type inference from `select`.
710
+
711
+ Use `IndustrialModel<TProps, TRelations>` when the model has expandable direct, reverse, or edge relations.
712
+
713
+ Returns `Promise<QueryResult<QueryResultItem<TModel, TSelect>>>`:
651
714
 
652
715
  ```ts
653
- type QueryResult = {
654
- items: Record<string, unknown>[];
655
- cursor: string | null; // null when no more pages
716
+ type QueryResult<TItem> = {
717
+ items: TItem[];
718
+ cursor: string | null; // null when no more root pages
656
719
  };
657
720
  ```
658
721
 
722
+ Each item always includes instance metadata (`space`, `externalId`, `createdTime`, `deletedTime`, `lastUpdatedTime`, `instanceType`) plus the fields you selected. With `{ _all: true }`, scalar view properties are included as well.
723
+
724
+ Example:
725
+
726
+ ```ts
727
+ const { items } = await model.query<CogniteAsset>()({
728
+ viewExternalId: "CogniteAsset",
729
+ select: {
730
+ parent: {
731
+ name: true,
732
+ },
733
+ },
734
+ });
735
+
736
+ items[0]?.parent?.name;
737
+ items[0]?.externalId;
738
+ ```
739
+
740
+ ### Automatic query behavior
741
+
742
+ - **`hasData` filter** — every root query includes a `hasData` constraint for the target view.
743
+ - **Nested relation limits** — expanded relations use an internal page size of `10000` per sub-query.
744
+ - **Dependency pagination** — when a nested sub-query returns `10000` items and a cursor, the client issues follow-up queries (up to 3 rounds) to load additional related data.
745
+
659
746
  ### Filter operators
660
747
 
661
748
  | Type | Operators |
@@ -663,7 +750,7 @@ type QueryResult = {
663
750
  | `string` | `eq`, `in`, `prefix`, `exists` |
664
751
  | `number` | `eq`, `in`, `gt`, `gte`, `lt`, `lte`, `exists` |
665
752
  | `boolean` | `eq`, `exists` |
666
- | `Date` | `eq`, `in`, `gt`, `gte`, `lt`, `lte`, `exists` |
753
+ | timestamp / `Date` | `eq`, `in`, `gt`, `gte`, `lt`, `lte`, `exists` — use ISO strings or `Date` values (coerced to ISO) |
667
754
  | `NodeId` | `eq`, `in`, `exists` |
668
755
  | `T[]` | `containsAny`, `containsAll`, `exists` |
669
756
 
@@ -671,10 +758,10 @@ Logical combinators `AND`, `OR`, and `NOT` are supported at any nesting level, i
671
758
 
672
759
  ### Relation traversal
673
760
 
674
- - **Direct relations** — `parent`, `asset`, `unit` (outwards from the current node)
675
- - **Reverse relations** — declare in `TRelation` (e.g. `children` on `CogniteAsset`)
676
- - **Edge relations** — declare in `TRelation` (e.g. `images360` on `Cognite3DObject`)
677
- - **Depth** — nested selects and filters up to 3 levels; dependency pages are fetched automatically
761
+ - **Direct relations** — `parent`, `asset`, `unit` (outwards from the current node). List relations such as `path` return arrays when expanded.
762
+ - **Reverse relations** — declare in `TRelations` (e.g. `children` on `CogniteAsset`)
763
+ - **Edge relations** — declare in `TRelations` (e.g. `images360` on `Cognite3DObject`)
764
+ - **Depth** — nested `select` and `filters` up to 3 levels; dependency pages for large nested result sets are fetched automatically (see above)
678
765
 
679
766
  ## Releasing
680
767