MarsDB
An embeddable property-graph database with an openCypher query subset: single binary, single file, optional in-memory mode.
$ marsdb :memory:
MarsDB graph database. Enter Cypher statements terminated by `;`. Ctrl-D to exit.
marsdb> CREATE (a:Person {name: 'Alice'})-[:KNOWS]->(b:Person {name: 'Bob'});
marsdb> MATCH (a:Person)-[:KNOWS]->(b:Person) RETURN a.name, b.name;
a.name | b.name
Alice | Bob
Install
CLI — installs the marsdb binary:
cargo install marsdb-cli
Rust library:
cargo add marsdb
let db = marsdb::Database::in_memory()?; // or Database::open("path/to.db")
db.execute("CREATE (a:Person {name: 'Alice'})")?;
let result = db.execute("MATCH (n:Person) RETURN n.name")?;
// Or run a `;`-separated batch, one transaction per statement, one
// QueryResult per statement back:
let results = db.execute_batch("CREATE (a:Person {name: 'Alice'}); CREATE (b:Person {name: 'Bob'})")?;
More: cargo run -p marsdb --example task_tracker (CRUD + aggregation),
--example social_graph (variable-length traversal, MATCH...CREATE), or
--example params_and_batch ($parameters, execute_batch) — full
source in marsdb/examples/. Each also writes an SVG
chart of its query result (via plotters)
to the current directory.
Python:
pip install marsdb
import marsdb
db = marsdb.Database.in_memory() # or .open(path)
db.execute("CREATE (a:Person {name: 'Alice'})-[:KNOWS]->(b:Person {name: 'Bob'})")
db.execute("MATCH (n:Person) RETURN n.name")
# -> [{'n.name': 'Alice'}, {'n.name': 'Bob'}]
Prebuilt wheels cover macOS (arm64, x86_64) and Linux (x86_64, manylinux); other platforms install from the source distribution and need a Rust toolchain. To build from source directly:
cd marsdb-python
python3 -m venv .venv && source .venv/bin/activate
pip install maturin && maturin develop
CLI usage
marsdb # in-memory REPL
marsdb mydata.db # file-backed REPL
marsdb mydata.db "MATCH (n) RETURN n" # run one query, exit
marsdb :memory: "..." # explicit in-memory, one-shot
marsdb mydata.db "CREATE (a); CREATE (b); MATCH (n) RETURN n" # ;-separated batch
Architecture
marsdb-storage thin trait boundary over redb (file + in-memory backends)
marsdb-graph property graph model, CRUD, KV/adjacency encoding
marsdb-query openCypher subset: pest grammar -> AST -> IR -> executor
marsdb embeddable public Rust API (Database::open/in_memory/execute)
marsdb-cli the `marsdb` binary (REPL + one-shot mode)
marsdb-python PyO3 bindings, builds via maturin
Storage runs on redb, a pure-Rust
single-file MVCC embedded KV engine. Query execution compiles Cypher to a
small Gremlin-shaped logical IR (AllNodesScan, NodeByLabelScan,
Seed, Expand, VarExpand, Filter) so a future Gremlin frontend can
target the same executor. Every Cypher statement runs inside one
transaction — a read-only MATCH ... RETURN opens a ReadTransaction
(a consistent snapshot that runs alongside other concurrent readers or a
concurrent writer without contending for redb's single-writer lock),
everything else opens a WriteTransaction, committed or aborted as a
whole.
Numbers: BENCHMARKS.md.
Cypher coverage
CREATE, multi-label nodes ((n:Post:Message)), $parameters,
backslash-escaped string literals (\' \" \\ \n \r \t \b \f),
MATCH/OPTIONAL MATCH, undirected (-[r:TYPE]-) and variable-length
([:TYPE*min..max]) relationship patterns, WHERE, one WITH boundary
per statement (projection/rename, its own WHERE/WITH...WHERE/ORDER BY/LIMIT), RETURN/DELETE/DETACH DELETE/SET/MATCH ... CREATE
(adds an edge between two already-matched nodes — a node token whose
variable is already bound reuses that node instead of creating a new
one), multi-key ORDER BY, LIMIT, CASE, the built-in functions
coalesce()/toInteger(), and implicit-GROUP-BY aggregation
(count()/count(*)/sum()/avg()/min()/max()/collect(), with
DISTINCT — inside an aggregate call only; a standalone RETURN DISTINCT
result-set modifier doesn't exist yet). Two independent MATCH parts
across one WITH boundary (MATCH (a) WITH a MATCH (b) ..., where b's
pattern doesn't chain from a) correctly cross-join, carrying a
alongside every row b produces. UNWIND <list> AS x (fans a list out
into one row per element, cross-joined against existing rows; its own
WHERE works without needing a second WITH) — <list> is an inline
Cypher-text list literal ([1, 2, 'a', $p]) or a variable bound by a
preceding WITH ... collect(...); UNWIND $param where $param itself
names a list isn't supported yet (no list-valued parameters — every
$param is a single scalar). MERGE <pattern> [ON CREATE SET ...] [ON MATCH SET ...] (match-or-create: tries the pattern as an ordinary MATCH
first, creates exactly one new instance if nothing matched) — capped at
one relationship hop (MERGE (n:Label {props}) or MERGE (a)-[:TYPE]-> (b)); an unconstrained node pattern that isn't already bound (MERGE (n), no label or property) is rejected rather than matching/creating
arbitrarily. Named-path capture (MATCH p = (a)-[:KNOWS]->(b) RETURN p,
fixed-hop patterns only) and shortestPath((a)-[:TYPE*..N]-(b)) (real
shortest-path search via BFS, not just the first path found — both
endpoints must already be matched by a preceding clause), plus
length(p) to measure one.
Verified against all 7 of LDBC SNB Interactive's short-read reference
queries (IS1-IS7) — see marsdb-query/tests/ldbc_is_queries.rs. Not
verified: LDBC's complex queries (IC1-14: the full query set beyond one
hand-crafted grouping+WITH...WHERE+ORDER BY+LIMIT+collect()
checkpoint — see marsdb-query/tests/smoke.rs), comma-separated patterns
within one MATCH/CREATE clause beyond a single linear chain (general
cross-joins — different from the cross-join WITH-chaining above, which
works), chaining past one WITH boundary, MERGE patterns with more than
one relationship hop (whole-pattern atomicity across multiple
simultaneously-unbound hops isn't attempted), named-path capture over a
variable-length pattern (only shortestPath() tracks the hop-by-hop chain
needed to reconstruct a path over *-traversal), or shortestPath() with
a minimum hop count greater than 1 (a plain visited-set BFS can't
correctly answer "shortest path of at least N hops" for N > 1 without a
different algorithm).
Roadmap
LIMITshort-circuitingRETURN DISTINCT(result-set-level dedup;DISTINCTinside an aggregate call already works)- List-valued
$parameters, to unblockUNWIND $items AS x - From-scratch storage engine (page format, B-tree, crash recovery) as an
alternate
marsdb-storagebackend, independent of redb - Gremlin frontend targeting the existing IR
Testing
cargo test --workspace # ~1s
cargo test -p marsdb-graph --test stress -- --ignored --nocapture # ~15s, large-scale
cargo bench -p marsdb-graph
cargo bench -p marsdb
License
Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file marsdb-0.4.0.tar.gz.
File metadata
- Download URL: marsdb-0.4.0.tar.gz
- Upload date:
- Size: 104.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
24437dc49d66495e6cb1aab95adf08a9d96765899bde191fc3c4dbc94d561009
|
|
| MD5 |
0eeec7bc39048a4c8791c1ef2f54a0f0
|
|
| BLAKE2b-256 |
bdf195e1540eb97e974aecad23a9972776145d7292c8d3ccb02c7086a8b5a905
|
File details
Details for the file marsdb-0.4.0-cp314-cp314-macosx_11_0_arm64.whl.
File metadata
- Download URL: marsdb-0.4.0-cp314-cp314-macosx_11_0_arm64.whl
- Upload date:
- Size: 929.0 kB
- Tags: CPython 3.14, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cf16598c86c6fda615836eac8c9f2a263ef44d94e7b42d34ac760884e7b847ec
|
|
| MD5 |
9ea45d410e94e4c6dd2548a8673a1860
|
|
| BLAKE2b-256 |
04e8bb75f3959615e5fa4f64a7850bac4e1b626a7998b06b798fb96c63dbc9a9
|
File details
Details for the file marsdb-0.4.0-cp314-cp314-macosx_10_12_x86_64.whl.
File metadata
- Download URL: marsdb-0.4.0-cp314-cp314-macosx_10_12_x86_64.whl
- Upload date:
- Size: 983.2 kB
- Tags: CPython 3.14, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
338818e43bec4ce7d8826aff2344831be5d3341cd20e0873655721f9e323df2f
|
|
| MD5 |
9750efa286daa15b6aa82351166d7352
|
|
| BLAKE2b-256 |
67783d00db68e2144a14899ffde522372dff0c32c45de78154c1a895f337c606
|
File details
Details for the file marsdb-0.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: marsdb-0.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 1.1 MB
- Tags: CPython 3.9, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
95571e2ca24c3905031bc54ef7272c5c4a3349b5c7151cdf2d17bf4203b410c6
|
|
| MD5 |
2c14949455d593c0bdaca868cc454e21
|
|
| BLAKE2b-256 |
98bac27fefd6658bef7017fa73e6d852283155454b8b0267695e979b4cf87d67
|