Writing to Graphs
This is a list with minimal examples of the different approaches to write to ZefDB.
Single Entities / Atoms
db = DB()
alfred = ET.Person | transact[db] | run # returns a reference (ZefRef) to the entity in the DB
bertrand = ET.Person | db | run # shorthand
Multiple Unrelated Atoms
my_refs = [ET.Person, ET.City, AET.Bool, AET.String] | db | run
Relations (aka Facts)
(alfred, RT.teacher_of, bertrand) | db | run # using existing entities
_,_,ludwig = (bertrand, RT.teacher_of, ET.Person) | db, run # instantiate a new entity and a relation to it
[
(ludwig, RT.surname, 'Wittgenstein'), # if values other than `ET. ...` are used, these are interpreted as AE and assignement
(ludwig, RT.born_in, ET.City[V.vienna]), # relation to new
(V.vienna, RT.name, Val('Vienna')), # wrapping a value in `Val` says: "don't create an attribute entity, link directly to the value node"
ET.Country # we can also create separate entities in this list
]
Object Notation
alan = ET.Person(
first_name='Alan',
surname='Turing', # creates an RT.surname to an AET[String] and assigns "turing"
born_in=ET.City( # we can nest entities (unlike JSON/dicts, with explicit types!)
name='London',
in_country=ET.Country(name='England'),
),
) | db | run
# in the object notation, only the ZefRef to the root (the actual "object") is returned
# using existing refs to entities: express intent which fields to set
[
alan(
phd_supervisor=ET.Person(first_name='Alonso'),
)
]
# this can also be combined with other syntax in a list of graph changes.
[
(V.jonny, RT.born_in, ET.City(name='Budapest')),
ET.Person[V.jonny](
first_name='János',
surname='von Neumann',
),
(V.jonny, RT.tried_to_hire, alan),
alan.year_of_birth << 1912, # if the field exists as an AE: assign. Otherwise instantiate and assign. Field must be unique.
alan.student_of << ludwig, # !!!!! WRONG !!!!!! This notation is only for assigning values, not linking with other entities!
alan.phd_supervisor.surname << 'Church', # we can chain outgoing relations though
]
Dealing with Fields on Relations
alonso = db | now | all[ET.Person & (Z.surname=='Church')] | single
[
ET.Person[V.alonso](
surname='Church'
),
alan({
RT.phd_thesis(supervisor=V.alonso, year_of_completion=1938): ET.Document()
})
]
Tools for Dealing with Fields
[
alan.bank_balance | update[add[100*usd]],
jonny.bank_balance | update[subtract[100*usd]],
]
Putting Constraints on Attribute Entities
Since new values can be assigned at later times, you may want to put upfront restrictions on a given AE
# create new AE. even if one is present. Assign a value in same TX.
(living_room, RT.temperature, AE[Temperature] << 25*celsius)
Multiary Relations
using sets with {...}
indicates that multiple elements are associated under that relation type and order is not important.
jonny(
friends = {alan, ET.Person(first_name='Claude')}
)
# The set can be understood as multiple enttities being
# linked via the same relation type.
# In this context, when used on an existing entity, it means: we want this set as the resulting state.
# If previous things were connected and they are no longer in the new list: too bad, they will be killed off.
Workings in diffs
# add or remove items from the set
[
ET.Person[ET.freeman](first_name='Freeman', surname='Dyson')
jonny.friends | add[V.freeman, alonso] # add to set. Do not clear previous members. Won't be added if present.
jonny.friends | remove[alan] # remove: you have to use references to existing entities.
# open question: if not in list, should removal requests error or accept silently?
]
Ordered Lists on Graphs
# don't add these at first. Only ideas for later, but only when an actual use case arises.
# insert_after
# insert_before
# update_at
# remove_at
# sort
# reverse
Dictionary Notation
{ET.Person : {
RT.FirstName: "Fred",
RT.YearOfBirth: 1970,
RT.Parent: z1
},
} | g | run
This notation is no longer required since the object notation became possible. It will probably be sunset.
Accessing Atoms by Event Type
db | now | all[Instantiated] # does this return ZefRef to atoms?
db | now | all[Terminated[RT]] # With subtype