Skip to main content

Add to a Graph

All changes to a graph are appended to a graph. As long as you have append privileges for a graph, you may add new facts to it, even if you do not currently host the graph.

As a GraphDelta!!!

The general syntax is:

receipt = list_of_actions | transact[g] | run

Entities can appear in the list as single items:

receipt = [
ET.Machine,
] | transact[g] | run

Attribute entities can be given with value assignment operations:

receipt = [
AET.String | assign["TX-9000"],
] | transact[g] | run

Individual relations can appear as a triple in the list:

receipt = [
(ET.Machine, RT.Model, "TX-9000"),
] | transact[g] | run

The above will create a relation of type RT.Model that connects the source and target to the first and third elements respectively of the triple. These are created automatically, such that the above is equivalent to:

receipt = [
(Z["source"], RT.Model, Z["target"]),
ET.Machine["source"],
AET.String["target"] | assign["TX-9000"],
] | transact[g] | run

A Z[internal_id] references a different RAE in the GraphDelta. RAEs that can be referenced are ET, AET, RT, QuantityInt and QuantityFloat. These references will then appear in the receipt. For example, the previous receipt should satisfy:

assert receipt["source"] | is_a[ET.Machine] | collect
assert receipt["target"] | is_a[AET.String] | collect
assert receipt["target"] | value | equals["TX-9000"] | collect

A RAE from any graph can be referenced or merged using the GraphDelta:

g_machines = Graph()
g_employees = Graph()

r1 = [ET.Machine["machine"]] | transact[g_machines] | run
r2 = [ET.Employee["alex"]] | transact[g_employees] | run

assert type(r1["machine"]) == ZefRef
assert type(r2["alex"]) == ZefRef

receipt = [
(r1["machine"], RT.OperatedBy, r2["alex"])
] | transact[g_machines] | run

Composite relation syntax

It is common to create an entity with many fields simulataneously. This can be done via the long-winded way:

receipt = [
ET.Person["p"],
(Z["p"], RT.FirstName, "Alex"),
(Z["p"], RT.LastName, "Smith"),
(Z["p"], RT.DOB, now()),
(Z["p"], RT.WorksFor, "Actionable Items"),
] | transact[g] | run

or made more concise by using a length-2 tuple, where the second element is a list of (relation, value) pairs:

receipt = [
(ET.Person["p"], [
(RT.FirstName, "Alex"),
(RT.LastName, "Smith"),
(RT.DOB, now()),
(RT.WorksFor, "Actionable Items"),
])
] | transact[g] | run

In a different scenario, many relations of the same type are made to connect entities, which in long-winded format could be:

receipt = [
ET.Person["p"],
ET.Pet["rufus"],
ET.Pet["spot"],
ET.Pet["mittens"],

(Z["p"], RT.OwnerOf, Z["rufus"]),
(Z["p"], RT.OwnerOf, Z["spot"]),
(Z["p"], RT.OwnerOf, Z["mittens"]),
] | transact[g] | run

This can instead be written as as length-3 tuple, where the 3rd element is a list:

receipt = [
(ET.Person["p"], RT.OwnerOf, [
ET.Pet["rufus"],
ET.Pet["spot"],
ET.Pet["mittens"],
]),
] | transact[g] | run

Separation of actions from GraphDelta

You can build the list of changes separately to creating the GraphDelta. This is useful when building a large GraphDelta in multiple functions:

def create_machine(name, model, is_large=False):
actions = [
ET.Character[name],
(Z[name], [(RT.Name, name),
(RT.Modle, model)])
]
if is_large:
actions += [(Z[name], RT.Large, True)]

return actions

actions = []
actions += create_machine("Maker", "TX-9000", True)
actions += create_machine("Generator", "TX-8000")
actions += create_machine("Creator", "CZ-9999")

receipt = actions | transact[g] | run

Shorthand syntax

When a single item is being created, an even shorter syntax is permitted, allowing you to avoid creating a GraphDelta and without needing to unpack the receipt by hand. For example:

z = ET.Machine | g | run

is equivalent to:

receipt = [ET.Machine["z"]] | transact[g] | run
z = receipt["z"]

A more complicated example is shown below:

person,rel,[pet1,pet2,pet3] = (ET.Person, RT.OwnerOf, [ET.Pet, ET.Pet, ET.Pet]) | g | run

is equivalent to:

receipt =[
(ET.Person["person"], RT.OwnerOf, [
ET.Pet["pet1"],
ET.Pet["pet2"],
ET.Pet["pet3"],
])
] | transact[g] | run
person = receipt["person"]
rel = None
pet1 = receipt["pet1"]
pet2 = receipt["pet2"]
pet3 = receipt["pet3"]

Note that rel is None. This is to allow the same "unpacking" structure as the input, but substituting None where the output maps to multiple values. This is because the above creates three relations, so it is nonsensical to return any particular relation in the output.