cognite/dto/data_modeling/instances.rs
1use std::collections::HashMap;
2
3use derivative::Derivative;
4use serde::{Deserialize, Serialize};
5use serde_with::skip_serializing_none;
6
7use crate::{
8 models::{ItemId, PropertySort, SourceReference, TaggedViewReference},
9 AdvancedFilter, RawValue, SetCursor,
10};
11
12use super::views::ViewCorePropertyType;
13mod extensions;
14pub use extensions::*;
15
16#[skip_serializing_none]
17#[derive(Serialize, Deserialize, Derivative, Clone, Debug)]
18#[serde(rename_all = "camelCase")]
19/// A list of nodes and edges to create. Parametrized by the type used for
20/// instance properties.
21pub struct NodeAndEdgeCreateCollection<TProperties> {
22 /// Nodes and edges to create.
23 pub items: Vec<NodeOrEdgeCreate<TProperties>>,
24 /// Whether to auto create direct relations that do not exist.
25 pub auto_create_direct_relations: Option<bool>,
26 /// Whether to auto create start nodes that do not exist.
27 pub auto_create_start_nodes: Option<bool>,
28 /// Whether to auto create end nodes that do not exist.
29 pub auto_create_end_nodes: Option<bool>,
30 /// If `existing_version` is specified on any of the nodes/edges in the input,
31 /// the default behaviour is that the entire ingestion will fail when
32 /// version conflicts occur. If `skip_on_version_conflict` is set to true,
33 /// items with version conflicts will be skipped instead. If no version is
34 /// specified for nodes/edges, it will do the write directly.
35 pub skip_on_version_conflict: Option<bool>,
36 /// How do we behave when a property value exists?
37 /// Do we replace all matching and existing values with the supplied values (true)?
38 /// Or should we merge in new values for properties together with the existing values (false)?
39 /// Note: This setting applies for all nodes or edges specified in the ingestion call.
40 pub replace: Option<bool>,
41}
42
43impl<TProperties> Default for NodeAndEdgeCreateCollection<TProperties> {
44 fn default() -> Self {
45 Self {
46 items: vec![],
47 auto_create_direct_relations: None,
48 auto_create_start_nodes: None,
49 auto_create_end_nodes: None,
50 skip_on_version_conflict: None,
51 replace: None,
52 }
53 }
54}
55
56#[derive(Serialize, Deserialize, Clone, Debug)]
57#[serde(rename_all = "camelCase", tag = "instanceType")]
58/// Enum of instance types being created.
59pub enum NodeOrEdgeCreate<TProperties> {
60 /// Create a node.
61 Node(NodeWrite<TProperties>),
62 /// Create an edge.
63 Edge(EdgeWrite<TProperties>),
64}
65
66#[skip_serializing_none]
67#[derive(Serialize, Deserialize, Default, Derivative, Clone, Debug)]
68#[serde(rename_all = "camelCase")]
69/// Node to create.
70pub struct NodeWrite<TProperties> {
71 /// Node space.
72 pub space: String,
73 /// Node external ID.
74 pub external_id: String,
75 /// List of properties in various containers or views.
76 pub sources: Option<Vec<EdgeOrNodeData<TProperties>>>,
77 /// Fail the ingestion request if the node's version is greater than or equal to this value.
78 /// If no `existing_version` is specified, the ingestion will always overwrite any existing
79 /// data for the node (for the specified container or view). If `existing_version` is
80 /// set to 0, the upsert will behave as an insert, so it will fail the bulk if the
81 /// item already exists. If skipOnVersionConflict is set on the ingestion request,
82 /// then the item will be skipped instead of failing the ingestion request.
83 pub existing_version: Option<i32>,
84 /// Node type (direct relation).
85 pub r#type: Option<InstanceId>,
86}
87
88#[skip_serializing_none]
89#[derive(Serialize, Deserialize, Default, Derivative, Clone, Debug)]
90#[serde(rename_all = "camelCase")]
91/// Edge to create.
92pub struct EdgeWrite<TProperties> {
93 /// Edge space.
94 pub space: String,
95 /// Edge type (direct relation).
96 pub r#type: InstanceId,
97 /// Edge external ID.
98 pub external_id: String,
99 /// Edge start node.
100 pub start_node: InstanceId,
101 /// Edge end node.
102 pub end_node: InstanceId,
103 /// List of properties in various containers or views.
104 pub sources: Option<Vec<EdgeOrNodeData<TProperties>>>,
105 /// Fail the ingestion request if the edge's version is greater than or equal to this value.
106 /// If no `existing_version` is specified, the ingestion will always overwrite any existing
107 /// data for the edge (for the specified container or view). If `existing_version` is
108 /// set to 0, the upsert will behave as an insert, so it will fail the bulk if the
109 /// item already exists. If skipOnVersionConflict is set on the ingestion request,
110 /// then the item will be skipped instead of failing the ingestion request.
111 pub existing_version: Option<i32>,
112}
113
114#[derive(Serialize, Deserialize, Clone, Debug)]
115/// Data in a single container or view for an edge or a node.
116pub struct EdgeOrNodeData<TProperties> {
117 /// Reference to the container or view this data belongs to.
118 pub source: SourceReference,
119 /// Property values on the form `{ property_name: value, ... }`
120 pub properties: TProperties,
121}
122
123#[derive(Serialize, Deserialize, Clone, Debug)]
124#[serde(rename_all = "camelCase", tag = "instanceType")]
125/// Minimal representation of a node or edge.
126pub enum SlimNodeOrEdge {
127 /// Slim node
128 Node(SlimNodeDefinition),
129 /// Slim edge
130 Edge(SlimEdgeDefinition),
131}
132
133#[skip_serializing_none]
134#[derive(Serialize, Deserialize, Clone, Debug)]
135#[serde(rename_all = "camelCase")]
136/// Minimal representation of a node.
137pub struct SlimNodeDefinition {
138 /// Node space.
139 pub space: String,
140 /// Node version.
141 pub version: i32,
142 /// Whether or not the node was midified by this ingestion. We only
143 /// update nodes if the input differs from the existing state.
144 pub was_modified: bool,
145 /// Node external ID.
146 pub external_id: String,
147 /// Time this node was created, in milliseconds since epoch.
148 pub created_time: Option<i64>,
149 /// Time this node was last modified, in milliseconds since epoch.
150 pub last_updated_time: Option<i64>,
151}
152#[skip_serializing_none]
153#[derive(Serialize, Deserialize, Clone, Debug)]
154#[serde(rename_all = "camelCase")]
155/// Minimal representation of an edge.
156pub struct SlimEdgeDefinition {
157 /// Edge space.
158 pub space: String,
159 /// Edge version.
160 pub version: i32,
161 /// Whether or not the edge was midified by this ingestion. We only
162 /// update nodes if the input differs from the existing state.
163 pub was_modified: bool,
164 /// Edge external ID.
165 pub external_id: String,
166 /// Time this edge was created, in milliseconds since epoch.
167 pub created_time: Option<i64>,
168 /// Time this edge was last modified, in milliseconds since epoch.
169 pub last_updated_time: Option<i64>,
170}
171
172#[derive(Serialize, Deserialize, Clone, Debug)]
173#[serde(rename_all = "camelCase", tag = "instanceType")]
174/// Node or edge with properties.
175pub enum NodeOrEdge<TProperties> {
176 /// Full node.
177 Node(NodeDefinition<TProperties>),
178 /// Full edge.
179 Edge(EdgeDefinition<TProperties>),
180}
181
182#[skip_serializing_none]
183#[derive(Serialize, Deserialize, Derivative, Clone, Debug)]
184#[serde(rename_all = "camelCase")]
185/// Representation of a node with properties.
186pub struct NodeDefinition<TProperties> {
187 /// Node space.
188 pub space: String,
189 /// Node version.
190 pub version: i32,
191 /// Node external ID.
192 pub external_id: String,
193 /// Node type.
194 pub r#type: Option<InstanceId>,
195 /// Time this node was created, in milliseconds since epoch.
196 pub created_time: i64,
197 /// Time this node was last modified, in milliseconds since epoch.
198 pub last_updated_time: i64,
199 /// Timestamp when the node was soft deleted. Note that deleted nodes are
200 /// filtered out of query results, but present in sync results.
201 /// This means that this value will only be present in sync results.
202 pub deleted_time: Option<i64>,
203 /// Node properties.
204 pub properties: Option<PropertiesObject<TProperties>>,
205}
206
207#[skip_serializing_none]
208#[derive(Serialize, Deserialize, Derivative, Clone, Debug)]
209#[serde(rename_all = "camelCase")]
210/// Representation of an edge with properties.
211pub struct EdgeDefinition<TProperties> {
212 /// Edge space.
213 pub space: String,
214 /// Edge type.
215 pub r#type: InstanceId,
216 /// Edge version.
217 pub version: i32,
218 /// Edge external ID.
219 pub external_id: String,
220 /// Time this edge was created, in milliseconds since epoch.
221 pub created_time: i64,
222 /// Time this edge was last modified, in milliseconds since epoch.
223 pub last_updated_time: i64,
224 /// Edge start node.
225 pub start_node: InstanceId,
226 /// Edge end node.
227 pub end_node: InstanceId,
228 /// Timestamp when the edge was soft deleted. Note that deleted nodes are
229 /// filtered out of query results, but present in sync results.
230 /// This means that this value will only be present in sync results.
231 pub deleted_time: Option<i64>,
232 /// Edge properties.
233 pub properties: Option<PropertiesObject<TProperties>>,
234}
235
236/// Shorthand for map from space and view/container external ID to properties object.
237pub type PropertiesObject<TProperties> = HashMap<String, HashMap<String, TProperties>>;
238
239#[derive(Serialize, Deserialize, Default, Clone, Debug, Hash, PartialEq, Eq)]
240#[serde(rename_all = "camelCase")]
241/// Direct reference to a node.
242pub struct InstanceId {
243 /// Node space.
244 pub space: String,
245 /// Node external ID.
246 pub external_id: String,
247}
248
249impl PartialEq<crate::time_series::InstanceId> for InstanceId {
250 fn eq(&self, other: &crate::time_series::InstanceId) -> bool {
251 self.space == other.space && self.external_id == other.external_id
252 }
253}
254
255impl PartialEq<InstanceId> for crate::time_series::InstanceId {
256 fn eq(&self, other: &InstanceId) -> bool {
257 self.space == other.space && self.external_id == other.external_id
258 }
259}
260
261#[skip_serializing_none]
262#[derive(Serialize, Deserialize, Derivative, Clone, Debug)]
263#[serde(rename_all = "camelCase")]
264/// Request for retrieving nodes or edges by ID.
265pub struct NodeAndEdgeRetrieveRequest {
266 /// List of sources to include properties from.
267 pub sources: Option<Vec<SourceReferenceInternal>>,
268 /// List of node or edge IDs to retrieve.
269 pub items: Vec<NodeOrEdgeSpecification>,
270 #[derivative(Default(value = "false"))]
271 /// Whether to include type information in the response.
272 pub include_typing: Option<bool>,
273}
274
275#[derive(Serialize, Deserialize, Derivative, Clone, Debug)]
276#[serde(rename_all = "camelCase")]
277/// Wrapped reference to a view.
278pub struct SourceReferenceInternal {
279 /// View ID.
280 pub source: TaggedViewReference,
281}
282
283#[skip_serializing_none]
284#[derive(Serialize, Deserialize, Derivative, Clone, Debug)]
285#[serde(rename_all = "camelCase")]
286/// Response for retrieving nodes and edges.
287pub struct NodeAndEdgeRetrieveResponse<TProperties> {
288 /// Retrieved nodes and edges.
289 pub items: Vec<NodeOrEdge<TProperties>>,
290 /// Type information if requested.
291 pub typing: Option<TypeInformation>,
292}
293
294#[derive(Serialize, Deserialize, Clone, Debug)]
295#[serde(rename_all = "camelCase", tag = "instanceType")]
296/// ID of a node or an edge.
297pub enum NodeOrEdgeSpecification {
298 /// Node ID.
299 Node(ItemId),
300 /// Edge ID.
301 Edge(ItemId),
302}
303
304#[derive(Serialize, Deserialize, Clone, Debug, Default)]
305#[serde(rename_all = "camelCase")]
306/// Enum over instance types.
307pub enum InstanceType {
308 /// Node instances.
309 #[default]
310 Node,
311 /// Edge instances.
312 Edge,
313}
314
315#[skip_serializing_none]
316#[derive(Serialize, Deserialize, Clone, Debug, Default)]
317#[serde(rename_all = "camelCase")]
318/// Request for filtering instances.
319pub struct FilterInstancesRequest {
320 /// Whether to include type information in the response.
321 pub include_typing: Option<bool>,
322 /// List of sources to retrieve data from.
323 pub sources: Option<Vec<SourceReferenceInternal>>,
324 /// Type of instances to filter.
325 pub instance_type: InstanceType,
326 /// Optional cursor for pagination.
327 pub cursor: Option<String>,
328 /// Maximum number of instances to retrieve. Default 1000, maximum 1000.
329 pub limit: Option<i32>,
330 /// Optional list of properties to sort the result by.
331 pub sort: Option<Vec<PropertySort>>,
332 /// Optional filter.
333 pub filter: Option<AdvancedFilter>,
334}
335
336impl SetCursor for FilterInstancesRequest {
337 fn set_cursor(&mut self, cursor: Option<String>) {
338 self.cursor = cursor;
339 }
340}
341
342#[skip_serializing_none]
343#[derive(Serialize, Deserialize, Derivative, Clone, Debug)]
344#[serde(rename_all = "camelCase")]
345/// Defintion of a property in type information.
346pub struct TypePropertyDefinition {
347 /// Whether the property is nullable.
348 pub nullable: Option<bool>,
349 /// Whether the property auto increments.
350 pub auto_increment: Option<bool>,
351 /// Property default value.
352 pub default_value: Option<RawValue>,
353 /// Description of the content and suggested use for this property.
354 pub description: Option<String>,
355 /// Readable property name.
356 pub name: Option<String>,
357 /// The data-type to use when storing the property.
358 pub r#type: ViewCorePropertyType,
359}
360
361#[derive(Serialize, Deserialize, Clone, Debug)]
362#[serde(rename_all = "camelCase")]
363/// Type information retrieved when doing filter or retrieve requests and setting
364/// `include_typing` to `true`.
365///
366/// Map from space to view/container to property.
367pub struct TypeInformation(
368 HashMap<String, HashMap<String, HashMap<String, TypePropertyDefinition>>>,
369);
370
371impl TypeInformation {
372 /// Get information about a property by space, view/container external ID,
373 /// and property name, if it is present in the type information.
374 pub fn get_property_info(
375 &self,
376 space: &str,
377 view_or_container: &str,
378 property: &str,
379 ) -> Option<&TypePropertyDefinition> {
380 self.0.get(space)?.get(view_or_container)?.get(property)
381 }
382}
383
384#[skip_serializing_none]
385#[derive(Serialize, Deserialize, Clone, Debug)]
386#[serde(rename_all = "camelCase")]
387/// Response when filtering instances.
388pub struct InstancesFilterResponse<TProperties> {
389 /// List of retrieved nodes and edges.
390 pub items: Vec<NodeOrEdge<TProperties>>,
391 /// Type information if requested.
392 pub typing: Option<TypeInformation>,
393 /// Cursor for pagination.
394 pub next_cursor: Option<String>,
395}
396
397#[derive(Serialize, Deserialize, Clone, Debug)]
398#[serde(rename_all = "camelCase", rename_all_fields = "camelCase")]
399/// Requested aggregate on instances.
400pub enum InstancesAggregate {
401 /// Average of values of specified property.
402 Avg {
403 /// Numerical property to compute average of.
404 property: String,
405 },
406 /// Counts the number of items. When you specify a property,
407 /// it returns the number of non-null values for that property.
408 Count {
409 /// The property to count. If specified, counts non-null values.
410 property: Option<String>,
411 },
412 /// Calculate the lowest value for a numerical property.
413 Min {
414 /// Numerical property to compute minimum value for.
415 property: String,
416 },
417 /// Calculate the highest value for a numerical property.
418 Max {
419 /// Numerical proeprty to compute maximum value for.
420 property: String,
421 },
422 /// Calculate the sum of values for a numerical property.
423 Sum {
424 /// Numerical property to compute sum for.
425 property: String,
426 },
427 /// A histogram aggregator function. This function will generate a histogram from the values of
428 /// the specified property. It uses the specified interval as defined in your interval argument.
429 Histogram {
430 /// Numerical property to compute histogram for.
431 property: String,
432 /// Interval between each bucket.
433 interval: f64,
434 },
435}
436
437#[skip_serializing_none]
438#[derive(Serialize, Deserialize, Clone, Debug)]
439#[serde(rename_all = "camelCase")]
440/// Request for aggregating accross instances.
441pub struct AggregateInstancesRequest {
442 /// Optional query string. The API will parse the query string,
443 /// and use it to match the text properties on elements to use for the aggregate(s).
444 pub query: Option<String>,
445 /// Optional list of properties to apply the `query` to. If no properties are listed,
446 /// text fields are searched by default.
447 pub properties: Option<Vec<String>>,
448 /// Maximum number of results to return. The default is 100, maximum is 1000.
449 pub limit: Option<i32>,
450 /// List of aggregates to calculate.
451 pub aggregates: Option<Vec<InstancesAggregate>>,
452 /// The selection of fields to group the results by when doing aggregations.
453 ///
454 /// When you do not specify any aggregates. The fields in the `groupBy` clause will
455 /// return the unique values stored for each field.
456 pub group_by: Option<Vec<String>>,
457 /// Optional filter on nodes or edges.
458 pub filter: Option<AdvancedFilter>,
459 /// Instance type to aggregate accross.
460 pub instance_type: InstanceType,
461 /// Reference to a view to query.
462 pub view: TaggedViewReference,
463}
464
465#[derive(Serialize, Deserialize, Clone, Debug)]
466#[serde(untagged)]
467/// Value of an aggregate group.
468pub enum AggregateGroupValue {
469 /// String value.
470 String(String),
471 /// Numerical value.
472 Number(f64),
473 /// Boolean value.
474 Boolean(bool),
475}
476
477#[derive(Serialize, Deserialize, Clone, Debug)]
478#[serde(rename_all = "camelCase")]
479/// Result of a numerical aggregate.
480pub struct NumericAggregateResult {
481 /// Aggregated property.
482 pub property: String,
483 /// Aggregate value.
484 pub value: f64,
485}
486
487#[derive(Serialize, Deserialize, Clone, Debug)]
488#[serde(rename_all = "camelCase")]
489/// Result of a count aggregate.
490pub struct CountAggregateResult {
491 /// Aggregated property.
492 pub property: Option<String>,
493 /// Aggregate value.
494 pub value: f64,
495}
496
497#[derive(Serialize, Deserialize, Clone, Debug)]
498#[serde(rename_all = "camelCase")]
499/// A single bucket in a histogram aggregate.
500pub struct HistogramBucket {
501 /// Start value of bucket.
502 pub start: f64,
503 /// Number of values in bucket.
504 pub count: u64,
505}
506
507#[derive(Serialize, Deserialize, Clone, Debug)]
508#[serde(rename_all = "camelCase", rename_all_fields = "camelCase")]
509/// Result item in instances aggregate response.
510pub enum AggregateResult {
511 /// Result of average aggregate.
512 Avg(NumericAggregateResult),
513 /// Result of min aggregate.
514 Min(NumericAggregateResult),
515 /// Result of max aggregate.
516 Max(NumericAggregateResult),
517 /// Result of count aggregate.
518 Count(CountAggregateResult),
519 /// Result of sum aggregate.
520 Sum(NumericAggregateResult),
521 /// Result of histogram aggregate.
522 Histogram {
523 /// Histogram interval.
524 interval: f64,
525 /// Aggregate property.
526 property: String,
527 /// List of buckets with start and count.
528 buckets: Vec<HistogramBucket>,
529 },
530}
531
532#[skip_serializing_none]
533#[derive(Serialize, Deserialize, Clone, Debug)]
534#[serde(rename_all = "camelCase")]
535/// A single item in the result of an instances aggregate request.
536pub struct AggregateResultItem {
537 /// Type of instance aggregated.
538 pub instance_type: InstanceType,
539 /// Value of group in aggregate.
540 pub group: Option<HashMap<String, AggregateGroupValue>>,
541 /// List of computed aggregates for this group.
542 pub aggregates: Vec<AggregateResult>,
543}
544
545#[skip_serializing_none]
546#[derive(Serialize, Deserialize, Clone, Debug)]
547#[serde(rename_all = "camelCase")]
548/// Result when aggregating instances.
549pub struct AggregateInstancesResponse {
550 /// Computed aggregates.
551 pub items: Vec<AggregateResultItem>,
552 /// Type information if requested.
553 pub typing: Option<TypeInformation>,
554}
555
556#[skip_serializing_none]
557#[derive(Serialize, Deserialize, Clone, Debug)]
558#[serde(rename_all = "camelCase")]
559/// Query for searching text fields for nodes or edges.
560pub struct SearchInstancesRequest {
561 /// View to search in.
562 pub view: TaggedViewReference,
563 /// Query string that will be parsed for search.
564 pub query: Option<String>,
565 /// Instance type to search.
566 pub instance_type: InstanceType,
567 /// List of properties to search through. If you do not specify one
568 /// or more properties, the service will search all text fields
569 /// in the view.
570 pub properties: Option<Vec<String>>,
571 /// Optional advanced filter.
572 pub filter: Option<AdvancedFilter>,
573 /// Maximum number of results to return. Default 1000, maximum 1000.
574 pub limit: Option<i32>,
575}