Skip to content

Feature list (cheat sheet)

A quick reference of what liel provides. For a stakeholder-oriented map (audience and value by area), see the capability matrix. For API details, see the Python API.

The deliberate non-goals (with considered alternatives, why-rejected, why-chosen) live in product trade-offs.

If your need is outside the use case

Highly concurrent servers, Cypher, terabyte-scale, full-text-led workloads — for these, use a different mature tool. The README's When NOT to use table lists representative alternatives. liel concentrates on standalone, single-file, dependency-light.


1. Product positioning (core value)

Item Detail
Form factor Portable external-brain library; no DB server process
Persistence Single file .liel (or :memory:)
Model Property graph (nodes and edges with labels and properties)
Dependencies Rust core kept minimal; no external service required at runtime
Query No Cypher. Python API and QueryBuilder (method chaining)

2. Database lifecycle

Feature Description
liel.open(path) Open a DB by file path or :memory:
close() / context manager End the session and release resources
Crash safety Page-level WAL for commit consistency. commit() is the durability boundary and is limited by disk sync latency; batch bulk inserts with db.transaction(). The detailed fsync/recovery contract lives in reliability and failure model; byte layout lives in format spec §6.

3. Nodes

Feature Description
Create add_node(labels, **props) — multiple labels, recursive property values
Read get_node / all_nodes / node_count
Update / delete update_node / delete_node (also deletes incident edges). If an error occurs while deleting incident edges, the call returns the exception and dirty pages are left as-is; without calling commit(), a close()open() rolls back to the last committed state. rollback() has the same effect.
Enumerate / search Via the QueryBuilder (below)

4. Edges

Feature Description
Create add_edge(from, label, to, **props)
Idempotent create merge_edge — reuses an existing edge if (from, label, to, **props) matches exactly, otherwise creates one (see product trade-offs §6.6)
Read get_edge / all_edges / edge_count
Update / delete update_edge / delete_edge (deletion re-links the adjacency lists)

5. Adjacency and traversal

Feature Description
Edge enumeration out_edges / in_edges
Neighbour nodes neighbors (filterable by edge label)
Traversal bfs / dfs (with optional max depth)
Shortest path shortest_pathdirected, unweighted, minimum-hop (BFS-based). Edge properties are not used as weights.
Bulk read all_nodes_as_records / all_edges_as_records (dict-based bulk fetch)
Helpers degree_stats (full edge scan to aggregate degrees) / edges_between (full edge scan, then filter by endpoint set)

6. QueryBuilder (filtered enumeration)

Target Example
Nodes db.nodes().label(...).where_(...).skip(...).limit(...).fetch(), etc.
Edges db.edges().label(...).where_(...).count() / exists(), etc.

7. Transactions

Feature Description
Explicit commit / rollback (begin() is a compatibility no-op)
Context transaction()

8. Maintenance and metadata

Feature Description
vacuum() Compact the property region (crash-safe via copy-on-write + atomic rename)
clear() Fully reset the database to an empty state, discard dirty pages, and reset ID counters
repair_adjacency() Rebuild node adjacency heads, degree counters, and edge next-pointers from the live edge set
info() Read metadata and statistics

vacuum() on a file-backed database operates as a copy-on-write rewrite (product-tradeoffs.md §5.6): a sibling <file>.liel.tmp is built, fsynced, and atomically renamed over the live file. A crash mid-vacuum leaves the original file intact, and the next liel.open() reclaims any leftover .tmp on its own. :memory: databases fall back to the original in-place algorithm (there is nothing to crash-corrupt). The only caveat is that disk usage temporarily peaks at 2× while vacuum runs. | merge_from(other, *, node_key=None, edge_strategy="append", on_node_conflict="keep_dst") | Import all nodes and edges from another GraphDB. IDs are remapped automatically (no file-format change). With node_key, an existing node can be reused based on a property key; with edge_strategy="idempotent", edges are deduplicated like merge_edge. The returned MergeReport contains the src→dst ID map and per-class counts. |


9. Properties and types

The on-disk encoding is a custom binary format (no external serde). The canonical type tags and byte layout live in format spec.


10. Notes for Python developers

Item Detail
liel.__version__ Matches the installed Python package version
Type hints python/liel/liel.pyi
Exceptions GraphDBError and its subclasses (NodeNotFoundError, …) — see Python API

11. Practical scale (guidance, not a guarantee)

For everyday use, a few gigabytes of file size is typically a comfortable working range. Hardware and workload pattern can change this significantly, so this is operational guidance, not a numeric guarantee. Extreme graphs and highly concurrent writes are out of scope.

For scan-heavy and traversal-heavy APIs, see the performance notes embedded in the Python guide.


12. Not included (cheat sheet)

The reasoning ("why not, considered alternatives, why rejected, why chosen") is consolidated in product trade-offs. Items only:

  • Cypher / custom DSL
  • Weighted shortest paths (Dijkstra etc.)
  • Undirected-only graph model
  • Property index
  • Standard reserved metadata keys (creation time, update time, source, session); these may be added later, but no metadata convention is enforced today
  • Full-text search and aggregation engines
  • Visualization API in core
  • JSON export/import in core
  • Server mode
  • Concurrent mutation by multiple writer processes on the same file (dangerous double-open is rejected with AlreadyOpenError)
  • WASM / browser distribution
  • C FFI / other-language bindings (out of phase)