A collection of traits and macros for working Data Transfer Objects (DTOs) in Neo4j.
sh
cargo add cypher-dto #--features serde
```rust
struct Person { id: String, // Inferred to be the only #[id] field. name: String, #[name = "zipcode"] zip: String, } asserteq!(Person::typename(), "Person"); asserteq!(Person::fieldnames(), &["id", "name", "zip_code"]);
// For building parameterized cypher queries... asserteq!(Person::asqueryfields(), "id: $id, name: $name, zipcode: $zipcode"); asserteq!(Person::asqueryobj(), "Person { id: $id, name: $name, zipcode: $zipcode }");
let person = Person::new("123", "John", "12345");
// Unitary CRUD operations are provided for convenience. let query: neo4rs::Query = person.create();
// Equivalent to:
let mut query = Query::new(format!(
"CREATE (n:{})",
Person::asqueryobj()
));
query = person.addvaluesto_params(query);
rust
struct Knows; assert_eq!(Knows::typename(), "KNOWS"); ```
```rust
struct Company { #[id] name: String, #[id] state: String, phone: String, } let company = Company::new("Acme", "CA", "555-555-5555"); let id = company.identifier(); asserteq!(id.name(), "Acme"); asserteq!(id.state(), "CA"); assert_eq!(id, CompanyId::new("Acme", "CA"));
asserteq!(CompanyId::typename(), "Company"); asserteq!(CompanyId::field_names(), &["name", "state"]);
let query: neo4rs::Query = id.read(); // Equivalent to: let mut query = Query::new(format!( "MATCH (n:{}) RETURN n", CompanyId::asqueryobj() )); query = id.addvaluesto_params(query); ```
The generated ::new()
method will accept &str
for String
fields, and &[T]
for Vec<T>
fields.
Doc comments are copied to the getters for the struct, the getter(s) on the FooId
struct, and the methods on the FooBuilder
struct.
```rust
struct Person { /// This comment is copied to the getter, the Id getter, and the builder method. name: String, } let p = Person::new("John"); let p = p.intobuilder().name("Ferris").build(); asserteq!(p.name(), "Ferris"); ```
#[node]
or #[relation]
```rust
struct Knows;
// Equivalent to:
struct Knows;
// Or, if the serde
feature is enabled:
```
For more details about the macro variations, see the cypher-dto-macros crate.
There's built-in support for special timestamp fields: created_at
and updated_at
, created
and updated
, or any single one of those four.
```rust
struct Person {
name: String,
}
// Adds two fields:
// createdat: Option
struct Person {
name: String,
}
// Adds two fields:
// created: Option
struct Person {
name: String,
}
// Adds one field:
// updated_at: Option
The timestamp fields are treated a little bit differently than other fields:
::new()
method.::as_query_fields()
.
as_query_fields()
with StampMode::Create
will use datetime()
in the query instead of $created_at
for example.Option<DateTime<Utc>>
is used instead of DateTime<Utc>
so that the fields can be None
when creating a new instance, before it exists in the database.
NOTE: Support for Option params in the
neo4rs
crate is in master, but not yet released.You are welcome to depend on the master branch of this library to enable full support for timestamps.
toml [dependencies] cypher-dto = { git = "https://github.com/jifalops/cypher-dto.git" }
This library takes the point of view that non-trivial queries should be managed by hand, but it does provide basic CRUD operations for convenience. Hopefully what you've seen so far shows how it can help create more readable complex queries.
#[node]
and #[relation]
structs get create()
and update()
methods, while the corresponding FooId
structs get read()
and delete()
methods, all of which return a neo4rs::Query
.
None of those methods even take any arguments, with the exception of creating a relation, which needs to know if the start and end nodes it's between need created or already exist.
```rust
Person { name: String, }
struct Knows;
let alice = Person::new("Alice"); let bob = Person::new("Bob"); let knows = Knows; // Relations can have fields and ids too of course.
let query = knows.create(RelationBound::Create(&alice), RelationBound::Create(&bob)); ```