The rustler API seems to have changed a bit. Functions now get auto registered when defining the #[rustler::nif] macro.
You can only define traits for structs when you either define the trait or define the struct. But here the trait is defined by rustler and the struct defined by sparrowdb. So we have to wrap it in our own type.
rustler also converts a Result type automatically to a tagged tuple in Elixir. Either {:ok, _} or {:error, _}.
use rustler::{Resource, ResourceArc};
use sparrowdb::GraphDb;
rustler::init!("Elixir.Spare.Native");
struct GraphDbResource(GraphDb);
#[rustler::resource_impl]
impl Resource for GraphDbResource {}
#[rustler::nif]
fn open(base: &str) -> Result<ResourceArc<GraphDbResource>, String> {
match GraphDb::open(std::path::Path::new(base)) {
Ok(graph) => Ok(ResourceArc::new(GraphDbResource(graph))),
Err(e) => Err(e.to_string()),
}
}
#[rustler::nif]
fn execute(graph_resource: ResourceArc<GraphDbResource>, cypher: &str) -> Result<String, String> {
let db = &graph_resource.0;
match db.execute(cypher) {
Ok(result) => Ok(format!("{:?}", result)),
Err(e) => Err(e.to_string()),
}
}
With the example from the sparrowdb README:
iex(1)> {:ok, db} = Spare.Native.open("social.db")
{:ok, #Reference<0.3497539546.3541958666.218184>}
iex(2)> Spare.Native.execute(db, "CREATE (alice:Person {name: 'Alice', age: 30})")
{:ok, "QueryResult { columns: [], rows: [] }"}
iex(3)> Spare.Native.execute(db, "CREATE (bob:Person {name: 'Bob', age: 25})")
{:ok, "QueryResult { columns: [], rows: [] }"}
iex(4)> Spare.Native.execute(db, "MATCH (a:Person {name:'Alice'}), (b:Person {name:'Bob'}) CREATE (a)-[:KNOWS]->(b)")
{:ok, "QueryResult { columns: [], rows: [] }"}
iex(5)> Spare.Native.execute(db, "MATCH (a:Person {name:'Alice'})-[:KNOWS*1..2]->(f) RETURN DISTINCT f.name")
{:ok,
"QueryResult { columns: [\"f.name\"], rows: [[String(\"Bob\")]] }"}
Happy hacking!






















