Python V1 · Deprecated

Runtime EDB

Runtime EDB in the Python V1 binding.

The Python V1 runtime edb reference continues the Python V1 overview.

EDB: adding facts

The binding exports four type aliases that describe the public term boundary:

CODE
from maelys_datalog import Fact, InputTerm, RawFact, ResolvedTerm

# InputTerm    = str | int | bool | Term
# ResolvedTerm = str | int | bool
# Fact         = tuple[ResolvedTerm, ...]
# RawFact      = tuple[Term, ...]

ruleset.edb() returns a fresh, independent EDB object, and Edb.add_fact accepts a Sequence[InputTerm]. EDB facts take Python values directly — add_fact converts str, int, and bool for you. Use Term explicitly only when you need to disambiguate (for example, forcing a small integer to be treated as a pre-interned symbol ID rather than a fresh string to intern — see Inserting by pre-interned symbol ID below):

CODE
from maelys_datalog import Engine, Predicate, PRED_EDB, PRED_IDB, PRED_QUERY

# This example needs its own vocabulary: document_access above declares
# neither quota_exceeded nor has_flag.
with Engine() as engine:
    engine.register_domain('typed_facts_docs', [
        Predicate('owns', 2, PRED_EDB),
        Predicate('quota_exceeded', 2, PRED_EDB),
        Predicate('has_flag', 2, PRED_EDB),
        Predicate('allow', 2, PRED_IDB | PRED_QUERY),
    ])
    ruleset = engine.load_inline_ruleset(
        'typed_facts_docs', 'typed.main',
        'allow(User, Document) :- owns(User, Document).',
    )
    edb = ruleset.edb()
    edb.add_fact('owns', ['alice', 'roadmap.pdf'])  # str + str
    edb.add_fact('quota_exceeded', ['alice', 1024])  # str + int
    edb.add_fact('has_flag', ['alice', True])  # str + bool
Python valueEncoded asNotes
strTERM_SYMBOLInterned via ruleset.intern_symbol() — idempotent, same string returns the same id.
intTERM_INTFull native int64_t range — no 32-bit split, unlike the WASM binding.
boolTERM_BOOLChecked before int — a bool is not treated as 0/1 integer.
Term.symbol_id(id)TERM_SYMBOLInsert by an already-interned id, skipping a redundant intern call.
Term.integer(v)TERM_INTExplicit form of the int case above.
Term.boolean(v)TERM_BOOLExplicit form of the bool case above.

An add_fact call can fail in two very different ways, from two different layers — a wrongly shaped call caught in Python, or a well-shaped call the engine rejects. They raise different exception types, so it is worth keeping them apart.

Inserting by pre-interned symbol ID

add_fact with a str value is ergonomic sugar: internally it calls ruleset.intern_symbol(value) and wraps the result in Term.symbol_id(...) for you, on every call. Use the ID path directly when the same symbol is inserted many times (dense graphs, repeated nodes): intern once, reuse the integer handle, and skip the redundant intern lookup on every fact.

CODE
from maelys_datalog import Term

alice = ruleset.intern_symbol('alice')      # -> positive int handle
doc   = ruleset.intern_symbol('roadmap.pdf')

edb = ruleset.edb()
edb.add_fact('owns', [Term.symbol_id(alice), Term.symbol_id(doc)])

intern_symbol is idempotent — interning 'alice' twice returns the same id — and is not scoped to one EDB session. The current WASM binding accepts typed values instead of symbol IDs. In this historical Python V1 API, it reads and writes the ruleset's own symbol table directly, so the same handle stays valid across every Edb created from that Ruleset, including ones created after the intern call.

Batch insertion

The current maelys_datalog.Edb has no add_facts() method. add_fact() inserts one fact through the native shim on each call. Performance comparisons with the WASM boundary require measurements; neither binding removes the engine's capacity limits.

Read engine.limits.max_edb_facts and max_facts_per_pred from the loaded library. The SMALL and LARGE builds allow at most 1,024 and 2,048 input facts respectively, with additional per-predicate and symbol limits.

The separate Python Next binding supports add_fact() and add_facts() as Python-buffer operations, then submits the entire buffer in one native solve call. That changes when native validation errors surface; it does not add a batch method to this binding.