dict-DB, array-DB, and the ones backed by files.
| flavor | shape | best for |
|---|---|---|
DictDatabase | key โ value | look up by key, update by key |
ArrayDatabase | append-only sequence | event logs, metrics, history |
| FileBackedDB | typed entity store (Zen files) | persistent, git-friendly |
| TTGraphDatabase | full time-travel graph | full audit, temporal queries |
We'll focus on DictDatabase + ArrayDatabase here (the simplest). FileBacked and TTGraph are covered in their own docs โ similar API, more features.
The handle is a Zef value. You pass it around. The runtime resolves it to the actual store when you ask.
db = FX.CreateDB(
type=DictDatabase,
persistence='in_memory', # or 'vault', or 'local_disk'
) | run
# โ DictDatabase('๐-603478f5c40bc4f2a657')
| mode | survives exit? | notes |
|---|---|---|
'in_memory' | โ | fastest, no I/O |
'vault' | โ | zef-managed, discoverable by UID across processes |
'local_disk' | โ | you pick the path |
db = FX.CreateDB(
type=DictDatabase,
persistence='local_disk',
path='~/my-app/state.zef'
) | run
FX.UpdateDB(db=db, insert={
'count': 42,
'name': 'alice',
'scores': [95, 87, 92],
'config': {'debug': True, 'verbose': False},
}) | run
Pass any Zef value. Python types auto-convert:
int โ Int64_str โ String_list โ Array_dict โ Dict_ET.Something(...) โ stored as-isFX.QueryDB(db=db, get='name') | run # 'alice'
FX.QueryDB(db=db, get='scores') | run # [95, 87, 92]
# with a ZefOp query โ process on the way out
FX.QueryDB(db=db, query=keys | length) | run # 4
FX.QueryDB(db=db, query=values | filter(Int) | reduce(add)) | run
# sum of all int values
DictDatabase handles behave like python dicts:
db['name'] # 'alice'
db['name'] = 'bob' # UpdateDB under the hood
'name' in db # True
len(db) # number of keys
list(db.keys()) # keys
snap = FX.DBSnapshot(db=db) | run
snap.data # the Dict
snap.state_counter # mutation count at snapshot time
snap.creation_time # DB creation time
Mutations after the snapshot don't affect it. Useful for "take a picture and analyze without worrying about concurrent writes."
log_db = FX.CreateDB(type=ArrayDatabase, persistence='in_memory') | run
FX.UpdateDB(db=log_db, append=ET.Event(name='click', at=now())) | run
FX.UpdateDB(db=log_db, append=ET.Event(name='hover', at=now())) | run
# indexed access
log_db[0] # first event
log_db[-1] # latest event
len(log_db) # total events
Single mutations use optimistic concurrency: generate patches under a read lock, then try to commit under a write lock. If another write landed in between, retry. Invisible to you โ it just always succeeds eventually.
Batch operations hold a write lock for the whole batch โ use batches when you need transactional atomicity.
# activate an existing one
FX.ActivateDB(db=DictDatabase('๐-a86117bdafe4a1415115')) | run
# from a file โ type auto-detected
db = FX.ActivateDB(path='path/to/db.zef') | run
# sync to disk + unload
FX.DeactivateDB(db=db) | run
# permanently remove
FX.DeleteDB(db=db) | run
# list running DBs
FX.ListActiveDBs() | run
FX.ListDBsInVault() | run
A String stored in a Zef DB is the same String_
as the one in your Python variable. Bytes in, bytes out. No JSON encoding.
No schema-to-ORM translation. Round-trip is byte-exact.
This is why binary contiguous layout matters โ the layer that stores your data is the same layer that represents it in memory.
cache = FX.CreateDB(
type=DictDatabase,
persistence='local_disk',
path='~/.myapp/cache.zef',
) | run
def get_or_fetch(url):
if url in cache:
return cache[url]
resp = FX.HTTPRequest(url=url) | run
cache[url] = resp['body']
return resp['body']
| operation | latency |
|---|---|
| first access (cold) | ~1โ10 ms |
| cached access (thread-local) | ~10 ns |
| FX dispatch | microseconds |
Once cached, reads are effectively free. Writes hit the optimistic lock โ still fast.
FileBackedDB is for when you want entities (not just keys) stored on disk as versioned files:
db = FX.CreateDB(type=FileBackedDB, path='~/kb') | run
FX.UpdateDB(db=db, insert=[
ET.Page(0, title='Hello Zef', content='...'),
ET.Page(1, title='Getting Started', content='...'),
]) | run
# query by path, like a mini graph-DB
FX.QueryFileBackedDB(db=db, query=single(ET.Page(0)) | F.title | value) | run
# 'Hello Zef'
FileBackedDB stores entities as Zen files โ literal Python dict-like text.
You can cat them, git diff them, grep them. Great
for knowledge bases, CMS, config stores.
Build a tiny counter DB. Every time you run the program, increment the counter and print it.
db = FX.CreateDB(
type=DictDatabase,
persistence='local_disk',
path='~/tmp/counter.zef',
) | run
count = db.get('visits', 0)
db['visits'] = count + 1
print(f'visit #{count + 1}')
Next up: signals โ thread-safe variables with history. โ