Quick Start
Welcome to Zef! This Quick Start is designed to give you a taste of the major ideas and concepts of Zef. Start at the top and work your way down!
Creating a graph
from zef import * # good to violate PEP in the first line
from zef.ops import *
g = Graph() # this creates an empty graph
Adding data to the graph
Let's add some domain entities to out graph.
p1 = ET.Person | g | run # this adds an entity to the graph
# add "fields" via relations triples: (source, relation, target)
(p1, RT.FirstName, "Yolandi") | g | run
Above, ET.Person
defines the entity type "Person", just as RT.FirstName
defines the relation type "FirstName". These are not predefined types, try
using some different names like RT.MyFavoriteRelation
.
Exploring the graph
Let's see what's on the graph
g | yo # yo can always be used to get info
p1 | now | yo # it can also be used on specific entities
p1 | now | yo | collect # yo | collect gives detailed info
now
is a ZefOp that takes us to the latest time slice (see now reference for details).
Traversing the graph
Given the output of the above operation, let's traverse the graph.
name_rel = p1 | now | out_rel[RT.FirstName] # step onto the edge
name_rel | yo | collect
name_aet = p1 | now | Out[RT.FirstName] # step to the target
name_aet | yo | collect
name_rel
is a reference to a Relation.
p1
is a reference to an Entity.
name_aet
is a reference to an Atomic Entity.
References in Zef are of type "ZefRef".
Retrieving values
How can we retrieve values?
current_name: str = name_aet | value | collect
print(current_name)
Note that zef is very lazy: 'collect' triggers the expression to evaluate.
Persisting graphs
Suppose we now decide that we want to persist this graph
g | sync | run
This saves and syncs all future changes on zefhub.
Sharing graphs
Let's share our graph with a friend
# ---------------- Python Session A (You) -----------------
g | uid | to_clipboard | run # uid is used to retrieve a graph uid
# or
g | tag['share-stories'] | run
"your-friends-email" | grant[KW.view][g] | run
Note: to_clipboard copies this to our clipboard that we can slack it over.
Our friend can access our graph with the shared uid or tag (you can also open a new Python shell yourself)
# ---------------- Python Session B (Friend) -----------------
graph_uid = '...' # copied from Slack
g = Graph(graph_uid)
# or
graph_tag = '<your-user-name>/share-stories'
g = Graph(graph_tag)
g | now | all[ET] | collect # let's see all entities in the latest graph slice
Our friend wants to add data to our graph as well
p2 = ET.Person | g | run # Oh no, this returns: Error('user has no append privileges')
we grant them this right, along with read-access for everyone
"your-friends-email" | grant[KW.append][g] | run
"group:everyone" | grant[KW.view][g] | run
"group:everyone" | grant[KW.discover][g] | run
-TODO insert image: Slack/whatsapp ask for write access "ughh, i can't add anything. Can you give me rights?"
Collaborating and live updates
Let's subscribe to any changes that happen.
# ---------------- Python Session A (You) -----------------
g | on[Instantiated[ET]] | subscribe[print] # we want to be informed any time an ET is added
Our friend can make multiple changes to the graph in one transaction.
# ---------------- Python Session B (Friend) -----------------
p1 = (g
| now
| all[ET.Person]
| single # there is only one ET.Person on the graph so far
| collect
)
actions = [
(ET.Person['p2'], RT.Name, "Ninja"), # 'p2' is an internal id / name
(p1, RT.FriendOf, Z['p2']), # Z is used to refer to entities by internal name
]
actions | transact[g] | run # convert the actions to a transact Effect and execute
Since we hooked up a subscription, a message will now show up in Session A.
Exploring past values and making a change
p1_name = p1 | Out[RT.FirstName] | collect
p1_name | yo | collect # explore all past names
p1_name | assign_value["Anri"] | g | run # Atomic entities can have values reassigned
Time travel
We can still access every previous graph state
# ---------------- Python Session B (Friend) -----------------
g | all[TX] | collect # transactions are first class: list all
p1_past = p1 | time_travel[Time('2021 December 4 15:31:00 (+0100)')] | collect # go to a past state
Let's create a zef function on the same graph that can be used across users and explore across time.
# ---------------- Python Session A (You) -----------------
@func(g) # make it a zef function on g
def number_of_friends(z):
return z | Outs[RT.FriendOf] | length
num_friends_past = p1_past | number_of_friends | collect # 0
num_friends_now = p1_past | now | number_of_friends | collect # 1