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}