Skip to main content

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

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[][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