A collection of traits and macros for working Data Transfer Objects (DTOs) in Cypher.
This library introduces an identifier concept to structs that represent a node or relation in Neo4j.
It can help with translating structs (or the <Foo>Id
counterpart) into Cypher queries.
However, it takes the stance that non trivial queries should be managed by hand.
So while it does provide basic CRUD queries ([neo4rs::Query
]), for nodes and relations,
it also provides the building block methods for constructing your own queries more cleanly
(i.e. with format!()
).
sh
cargo add cypher-dto
```rust use cypher_dto::Node;
struct Person { id: String, // Inferred as an #[id] field name: String, age: u8, }
asserteq!(Person::fieldnames(), &["id", "name", "age"]); asserteq!(Person::asqueryfields(), "id: $id, name: $name, age: $age"); asserteq!(Person::asqueryobj(), "Person { id: $id, name: $name, age: $age }");
let alice = Person { id: "p1".toowned(), name: "Alice".tostring(), age: 30 };
// Basic CRUD queries are built-in for node and relation structs. let q: neo4rs::Query = alice.create();
// or manually... let mut q2 = Query::new(format!("CREATE (n:{})", Person::asqueryobj())); q2 = alice.addvaluesto_params(q2);
assert_eq!(q, q2);
struct WorksAt { since: u32, }
/// Multi-valued keys are supported.
struct Company { #[id] name: String, #[id] state: String, #[name = "zipcode"] zip: String, } asserteq!(Company::asqueryobj(), "Company { name: $name, state: $state, zipcode: $zipcode }");
let acme = Company { name: "Acme LLC".toowned(), state: "CA".toowned(), zip: "90210".to_owned() }; let rel = WorksAt { since: 2010 };
let query = rel.create(RelationBound::Match(alice.into(), RelationBound::Create(acme))); // MATCH (s:Person { id: $sid }) // CREATE (e:Company { name: $ename, state: $estate, zipcode: $ezipcode }) // CREATE (s)-[r:WORKS_AT { since: $since }]->(e) ```
An extra struct, <StructName>Id
, is created for each derived Node
or Relation
.
It represents the zero-to-many valued key for uniquely identifying an entity.
#[id]
or named id
.typename()
.Lets load a user from their ID:
```rust
struct User { id: String, email: String, }
let id = UserId { id: "u1".toowned() };
let query = id.read();
// MATCH (n:User { id: $id })
// RETURN n
let stream = db.execute(query).await?;
let row = result.next().await?;
let node: neo4rs::Node = row.get("n").okor(...)?;
let user = User::try_from(node)?; // neo4rs::{Row, Node, Relation, UnboundedRelation}
are supported.
let query = id.delete(); // MATCH (n:User { id: $id }) // DETACH DELETE n ```
```rust
struct User {
id: String,
email: String,
phone: Option
let query = user2.update(UpdateMode::Merge); // MATCH (n:User { id: $id }) // SET n += { id: $id, email: $email, phone: $phone } let query = user2.update(UpdateMode::Replace); // MATCH (n:User { id: $id }) // SET n = { id: $id, email: $email, phone: $phone }
// Note: Merge and Replace have the same effect in this example. ```