Datalog
Nucleus includes a built-in Datalog engine for recursive queries and logic programming. Define facts and rules, then query with automatic fixed-point evaluation — integrated directly with your relational and graph data.
Facts
Assert ground truth:
SELECT DATALOG_ASSERT('parent(alice, bob).');
SELECT DATALOG_ASSERT('parent(bob, charlie).');
SELECT DATALOG_ASSERT('parent(charlie, diana).');
Rules
Define derived relations:
-- Direct parent relationship
SELECT DATALOG_RULE('ancestor(X, Y) :- parent(X, Y).');
-- Transitive closure (recursive)
SELECT DATALOG_RULE('ancestor(X, Z) :- ancestor(X, Y), parent(Y, Z).');
Queries
-- Who are Alice's descendants?
SELECT DATALOG_QUERY('?- ancestor(alice, Who).');
-- → [{"Who":"bob"}, {"Who":"charlie"}, {"Who":"diana"}]
-- Is Alice an ancestor of Diana?
SELECT DATALOG_QUERY('?- ancestor(alice, diana).');
-- → [{}] (empty binding = true)
Retracting Facts
-- Remove a specific fact
SELECT DATALOG_RETRACT('parent(bob, charlie).');
-- Clear all facts for a predicate
SELECT DATALOG_CLEAR('parent');
Cross-Model Integration
Import data from relational tables and the graph engine:
-- Import rows from a SQL table as facts
-- Each row becomes: predicate(col1, col2, ...)
SELECT DATALOG_IMPORT('employees', 'employee');
-- Import graph edges as facts
-- Each edge becomes: predicate(from_id, edge_type, to_id)
SELECT DATALOG_IMPORT_GRAPH('edge');
-- Import graph nodes
-- Each node becomes: predicate(node_id, label)
SELECT DATALOG_IMPORT_NODES('node');
Then query across models:
-- Find all employees reachable through the management graph
SELECT DATALOG_RULE('manages(X, Y) :- edge(X, "MANAGES", Y).');
SELECT DATALOG_RULE('manages(X, Z) :- manages(X, Y), edge(Y, "MANAGES", Z).');
SELECT DATALOG_QUERY('?- manages(1, Who).');
Negation
Stratified negation using \+:
SELECT DATALOG_RULE('orphan(X) :- person(X), \\+ parent(_, X).');
SELECT DATALOG_QUERY('?- orphan(Who).');
Aggregates
Built-in aggregate functions in rule heads:
-- Count children per parent
SELECT DATALOG_RULE('child_count(X, count<Y>) :- parent(X, Y).');
SELECT DATALOG_QUERY('?- child_count(Who, Count).');
Supported aggregates: count, sum, min, max.
How It Works
- Semi-naive evaluation — Only new facts from the previous iteration are used to derive new facts, avoiding redundant computation
- Indexed EDB — O(1) fact lookups for efficient joins
- Stratified negation — Safe handling of negated predicates
- WAL-backed — Crash-safe fact persistence
Use Cases
- Access control — Recursive permission inheritance
- Graph analytics — Transitive closure, reachability
- Data lineage — Track data provenance and dependencies
- Rule engines — Business rules and compliance checks
- Ontologies — Taxonomic reasoning and classification