cypher-dto

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!()).

Usage

sh cargo add cypher-dto

```rust use cypher_dto::Node;

[derive(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);

[derive(Relation)]

struct WorksAt { since: u32, }

/// Multi-valued keys are supported.

[derive(Node)]

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.

Lets load a user from their ID:

```rust

[derive(Node)]

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 ```

Updating: Merge and Replace

```rust

[node]

struct User { id: String, email: String, phone: Option } let user = User::new("u1".toowned(), "abc@example.com".toowned(), None); let user2 = user.builder().email("foo@example.com").build();

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. ```