Open Data Model Mutations
GraphQL Mutations allow to perform insert/update/and delete operations on Open Data Model entities. They are provided by the Open Data Model, meaning that the schema may not contain a Mutation type definition.
The Open Data Model allows the creation of nodes and relations, the deletion of nodes, the delete of relations, the update of nodes and the update of relations.
If you intent to put comments in your mutation, please have a look at the recommended way to do it.
Note
The Open Data Model does not support GraphQL arguments
Warning
The Open Data Model will reject any mutation operation performed on Data Hub internal types (DataHubSite, DataHubSiource or DataHubVariable). You must perform such operation through the standard Data Hub API.
Create nodes and relations
The schema provided by the Open Data Model is:
input NodeProperty {
Name: String!
Value: ID
}
input Node {
KeyProperty: String!
KeyValue: ID!
NodeType: String!
Properties: [NodeProperty!]
}
input RelationProperty {
Name: String!
Value: ID
}
input DestinationNodes {
NodeType: String!
NodeSelector: String!
}
input Relation {
SourceNode: Node!
DestinationNodes: DestinationNodes!
RelationType: String!
Properties: [RelationProperty!]
}
type CreationResult {
WhatIf: Int
NumberOfNodes: Int
NumberOfRelations: Int
Info: String
}
type Mutation {
CreateNodesAndRelations(
Nodes: [Node!]!,
Relations: [Relation!],
WhatIf:Int) : CreationResult
}
Remember that you don't have to provide this schema by yourself, it is appended to your schema by the Open Data Model engine
Mutation.CreateNodesAndRelations: the name of the mutation
CreateNodesAndRelations.WhatIf: if > 0, the Open Data Model will apply the mutation without creating the nodes and/or relations. This is a way to verify the validity of the mutation. Default is 0, which will create the requested entities if it is not specified.
Nodes creation
CreateNodesAndRelations.Nodes: the list of nodes to create
Node.KeyProperty: the name of the node property that is knwon as the node Key. This field is used to uniquely identify nodes, avoiding duplicates. The whole mutation will be rejected in the following cases:
The same Key/Value already exists in the Opend Data Model storage on a node of the same type
The same Key/Value exists in the Node.KeyValue/Node.KeyProperty of the mutation on a node of the same type.
The same Key/Value exists in any of the Node.Properties on a node of the same type
Node.KeyValue: the value of the property Node.KeyProperty.
Node.NodeType: the type of the node to create.
Node.Properties: the list of node properties (additinal to Node.KeyProperty) to create. This list may not include Node.KeyProperty.
Property.Name: the name of the property.
Property.Value: the value of the property.
Note
The primary key will become a property of the node, just like any property specified in Node.Properties, allowing to query nodes based on the primary key value.
Here is a sample of node creation mutation:
mutation {
# This is a comment that if well handled by the Open Data Model but that creates problem with Swagger
# This is a comment that works well with Swagger and the Open Data Model and that is GraphQL-compatible due to new line symbol at the end \n
CreateNodesAndRelations(
Nodes: [
{
KeyProperty: "Key",
KeyValue: "Custom variables1",
NodeType: "VARIABLE_GROUP" ,
Properties : [ {Name : "Type",Value: "Custom1"}]}
],
WhatIf : 0
) { WhatIf NumberOfNodes }}
This mutation will a node of type VARIABLE_GROUP having 2 properties
- Key = "Custom variables 1" which is the primary key
- Name = "Custom1"
Note that the WhatIf property is specified and is projected in the mutation result.
Warning
- All node types specified in nodes must exist in the schema
- It is mandatory to project at least one result even if you don't use it. In this example, NumberOfNodes
Relations creation
CreateNodesAndRelations.Relations: the list of relations to create.
Relation.SourceNode: a single node that is the source of the relation. If multiple nodes satisfy the KeyProperty/KeyValue/NodeType combination, the wole mutation will be rejected. The Relation.SourceNode.Properties property is ignored.
Relation.DestinationNodes.NodeSelector: a filter expression that identifies one or many nodes that must be the destinations of this relation.
Relation.DestinationNodes.NodeType: the type of nodes to consider when applying the Relation.DestinationNodes.NodeSelector.
Relation.RelationType: the type of the relation to create. This type must be one of the custom types defined in the schema.
Relation.Properties: the list of relation properties to create.
Property.Name: the name of the property.
Property.Value: the value of the property.
Here is a sample of relation creation mutation:
mutation {
CreateNodesAndRelations(
Relations: [
{
SourceNode : {
KeyProperty: "Key",
KeyValue: "Custom variables1",
NodeType: "VARIABLE_GROUP"},
DestinationNodes: {
NodeSelector : "PARENT(DataHubSource,Id) = 123 AND Name LIKE 'test'",
NodeType: "DataHubVariable" },
RelationType : "GROUP_MEMBER",
Properties : [ { Name : "FomDate", Value : "2021-01-01"}, { Name : "ToDate", Value : "2022-12-31"}]
}]
) { NumberOfRelations}}
This mutation will create a relation of type GROUP_MEMBER
- starting from a node of type VARIABLE_GROUP having a property Key = "Custom variables1"
- ending on all nodes of type DH_VARIABLE being child of source Id 123 and having a property Name that contains 'test'
- with 2 properties, FomDate = 2021-01-01 and ToDate = 2022-12-31.
Warning
- The Open Data Model engine will reject the whole mutation if one of the relations specifies a Data Hub internal types as the source of a relation. The Data Hub internal types can only be referenced as relation target.
- A relation type may not start with "DH_" to prevent interference with internal Data Hub relations.
- All source and target node types specified in relations must exist in the schema
- It is mandatory to project at least one result even if you don't use it. In this example, NumberOfNodes and NumberOfRelations
Delete nodes
The schema provided by the Open Data Model is:
input DestinationNodes {
NodeType: String!
NodeSelector: String!
}
type DeletionResult {
WhatIf: Int
NumberOfNodes: Int
NumberOfRelations: Int
Info: String
}
type Mutation {
DeleteNodes(
Nodes: DestinationNodes!,
WhatIf:Int) : DeletionResult
}
Remember that you don't have to provide this schema by yourself, it is appended to your schema by the Open Data Model engine
Mutation.DeleteNodes: the name of the mutation.
DeleteNodes.NodeSelector: a filter expression that identifies one or many nodes to delete.
DeleteNodes.NodeType: the type of nodes to consider when applying the Mutation.DeleteNodes.NodeSelector.
DeleteNodes.WhatIf: if > 0, the Open Data Model will apply the mutation without deleting the nodes. When set to 1, the projected property NumberOfNodes will contain the number of nodes that would be deleted. Default is 0, which will delete the requested nodes if it is not specified.
Here is a sample of node deletion mutation:
mutation {
DeleteNodes(
Nodes: {
NodeSelector : "Key = 'Custom variables1'"
NodeType: "VARIABLE_GROUP"
}
)
{ NumberOfNodes}}
This will delete all nodes of type VARIABLE_GROUP having a property Key = "Custom variables1".
It is mandatory to project at least one result even if you don't use it, in this example, NumberOfNodes and WhatIf.
Delete relations
The schema provided by the Open Data Model is:
input RelationsFilter {
RelationType: String!
RelationSelector: String
}
input RelationsDeletion {
SourceNode: Node!
DestinationNodes: DestinationNodes!
RelationsFilter: RelationsFilter!
}
type DeletionResult {
WhatIf: Int
NumberOfNodes: Int
NumberOfRelations: Int
Info: String
}
type Mutation {
DeleteRelations(
Relations: [RelationsDeletion!],
WhatIf:Int) : DeletionResult
}
Remember that you don't have to provide this schema by yourself, it is appended to your schema by the Open Data Model engine.
Mutation.DeleteRelations: the name of the mutation.
DeleteRelations.Relations: the list of relations to delete.
Relation.SourceNode: a single node that is the source of the relation. If multiple nodes satisfy the KeyProperty/KeyValue/NodeType combination, the wole mutation will be rejected. The Relation.SourceNode.Properties property is ignored.
Relation.DestinationNodes.NodeSelector: a filter expression that identifies one or many nodes that must be the destinations of this relation.
Relation.RelationsFilter.RelationType: the type of nodes to consider when applying the Relation.DestinationNodes.NodeSelector.
Relation.RelationsFilter.RelationSelector: a filter expression that identifies which relation to delete.
Relation.RelationType: the type of the relation to delete. This type must be one of the custom types defined in the schema.
DeleteRelations.WhatIf: if > 0, the Open Data Model will apply the mutation without deleting the relations. When set to 1, the projected property NumberOfRelations will contain the number of relations that would be deleted. Default is 0, which will delete the requested relations if it is not specified.
Here is a sample of relation deletion mutation:
mutation {
DeleteRelations(
Relations: [{
SourceNode : {
KeyProperty: "Key",
KeyValue: "Custom variables1",
NodeType: "VARIABLE_GROUP"},
DestinationNodes: {
NodeSelector : "Id = 123",
NodeType: "DataHubVariable" },
RelationsFilter: {RelationType : "GROUP_MEMBER", RelationSelector : "Date > '2000'"}
}]
){ NumberOfRelations}}
This mutation will delete all relations of type GROUP_MEMBER
- having a property Date > '2000'
- starting from nodes of type VARIABLE_GROUP having property names Key with value "Custom variables1"
- ending on Data Hub variable node Id = 123
Wildcard source node
If Relation.SourceNode.KeyProperty and Relation.SourceNode.KeyValue are set to "*", the mutation engine will delete all relations coming from nodes of type Relation.SourceNode.NodeType and reaching nodes Relation.DestinationNodes
Wildcard destination node
Provided that all destination nodes of type Relation.DestinationNodes.NodeType have the same property, let's say "XYZ", setting Relation.DestinationNodes.NodeSelector to "NOT XYZ IS NULL" will select all nodes of type Relation.DestinationNodes.NodeType.
Destination nodes by parent property
An architecture that is often encoutered is many sources corresponding to a physical device with many variables reprensenting this device, the grouping source/variables being always the same.
Imagine that a custom model needs to link a custom node to many variables of a source. One way of doing it is to specify individual variable Ids, like this:
mutation { CreateNodesAndRelations(
Relations: [
{ ... , DestinationNodes: {NodeSelector : "Id IN [1,2,3, ...]", NodeType: "DataHubVariable" }},
{ ... , DestinationNodes: {NodeSelector : "Id IN [30,31,32, ...]", NodeType: "DataHubVariable" }}
...
]){ NumberOfRelations }}
Obviously, this is far from being readable, nothing shows up the variable names to consider.
Using the PARENT() expression allows to make the query much more readable:
mutation { CreateNodesAndRelations(
Relations: [
{ ... , DestinationNodes: {NodeSelector : "PARENT(DataHubSource, Name) = 'src1' AND Name STARTS WITH 'var'", NodeType: "DataHubVariable" }},
{ ... , DestinationNodes: {NodeSelector : "PARENT(DataHubSource, Name) = 'src2' AND Name STARTS WITH 'var'", NodeType: "DataHubVariable" }}
...
]){ NumberOfRelations }}
In this case, PARENT(DataHubSource, Name) is resolved to the Name property of the parent node type DataHubSource. A parent node P of a node N is a node having a direct relation from P to N, whatever the type of relationship.
Important
- If the destination node is the target of more than one parent node of the given node type, the result is unpredictable.
- A node selector may not contain mode than 1 PARENT() expression.
Update nodes
The schema provided by the Open Data Model is:
input NodeProperty {
Name: String!
Value: ID
}
input DestinationNodes {
NodeType: String!
NodeSelector: String!
}
type UpdateResult {
WhatIf: Int
NumberOfNodes: Int
NumberOfRelations: Int
Info: String
}
type Mutation {
UpdateNodes(
Nodes: DestinationNodes!,
Properties:[NodeProperty!],
, WhatIf:Int) : UpdateResult
}
Remember that you don't have to provide this schema by yourself, it is appended to your schema by the Open Data Model engine.
Mutation.UpdateNodes: the name of the mutation.
UpdateNodes.NodeSelector: a filter expression that identifies one or many nodes to update.
UpdateNodes.NodeType: the type of nodes to consider when applying the Mutation.UpdateNodes.NodeSelector.
UpdateNodes.Properties: the list of properties to update. The node properties are affected according to the following table:
Node exists | Property exists | Update value is null | Operation on property |
---|---|---|---|
Yes | Yes | Yes | The property is deleted |
Yes | Yes | No | The property is set to the Update value |
Yes | No | Yes | Nothing |
Yes | No | No | The property is created and set to the update value |
No | - | - | Nothing |
UpdateNodes.WhatIf: if > 0, the Open Data Model will apply the mutation without updating the nodes. When set to 1, the projected property NumberOfNodes will contain the number of nodes that would be updated. Default is 0, which will update the requested nodes if it is not specified.
Here is a sample of node update mutation:
mutation {
UpdateNodes(
Nodes: {
NodeSelector : "Type = 'Custom'",
NodeType: "VARIABLE_GROUP"},
Properties: [ {Name : "NewProperty", Value:"Modified"}, {Name: "OldProperty", Value:null} ]
) { NumberOfNodes }}
This mutation updates a node of type VARIABLE_GROUP having a proprty Type = 'Custom'. It will update or create property NewProperty with the value 'Modified' and will delete property OldProperty if it exists.
Update relations
The schema provided by the Open Data Model is:
input DestinationNodes {
NodeType: String!
NodeSelector: String!
}
input RelationProperty {
Name: String!
Value: ID
}
input RelationsFilter {
RelationType: String!
RelationSelector: String
}
input RelationUpdate {
SourceNode: Node!
DestinationNodes: DestinationNodes!
RelationsFilter: RelationsFilter!
Properties: [RelationProperty!]
}
type Mutation {
UpdateRelations(
Relations: [RelationUpdate!],
Properties:[NodeProperty!,
WhatIf:Int) : UpdateResult
}
Remember that you don't have to provide this schema by yourself, it is appended to your schema by the Open Data Model engine.
Mutation.UpdateRelations: the name of the mutation.
UpdateRelations.Relations: the list of relations to update. See delete relations for a detailed explaination of Relation object.
UpdateRelations.NodeType: the type of nodes to consider when applying the Mutation.UpdateNodes.NodeSelector.
UpdateRelations.Properties: the list of properties to update. The relation properties are affected according to the following table:
Relation exists | Property exists | Update value is null | Operation on property |
---|---|---|---|
Yes | Yes | Yes | The property is deleted |
Yes | Yes | No | The property is set to the Update value |
Yes | No | Yes | Nothing |
Yes | No | No | The property is created and set to the update value |
No | - | - | Nothing |
UpdateRelations.WhatIf: if > 0, the Open Data Model will apply the mutation without updating the relations. When set to 1, the projected property NumberOfRelations will contain the number of relations that would be updated. Default is 0, which will update the requested relations if it is not specified.
Here is a sample of relation update mutation:
mutation {
UpdateRelations(
Relations: [{
SourceNode : {
KeyProperty: "Key",
KeyValue: "Custom variables",
NodeType: "VARIABLE_GROUP"},
DestinationNodes: {
NodeSelector : "Id = 123",
NodeType: "DataHubVariable" },
RelationsFilter: {RelationType : "GROUP_MEMBER", RelationSelector : "Date > '2000'"},
Properties: [ {Name : "NewProperty", Value:456}, {Name: "OldProperty", Value:null} ]
}]
) { NumberOfRelations }}
This mutation will update all relations of type GROUP_MEMBER
- having a property Date > '2000'
- starting from nodes of type VARIABLE_GROUP having property Date > '2000'
- ending on Data Hub variable node Id = 123. It will update/create property NewProperty with value 456 and delete property OldProperty if it exists