Neo4j Query Builder

Licenses Licenses X

A flexible and intuitive query builder for Neo4j and Cypher. Write queries in Rust just as you would write them in Cypher. ## Installation ```toml neo4j_cypher = { version = "0.2", features=["derive"] } ``` ## Usage ### Container attributes * **#[cypher(rename = "...")]** This attribute can be used when in your code you wanted to have the name **A**, but in Neo4j you wanted to save the structure as a node with name **B**. ### Field attributes * **#[cypher(rename = "...")]** Rename attribute also can used as s field attribute. The principle of it's operation is similar to that described above. It should be used when you want to automatically change the field name when you build a query with a properties object of Neo4j entity. * **#[cypher(skip)]** Use this attribute when you what to hide some struct field when you build a query. * **#[cypher(label)]** You can use such attribute if you want the field value to be used as the label of the node. It is recommended to use enums as a value of such field. * **#[cypher(default)]** If the field type is some kind of `Option` you can use this att and when field value will be `None`, default value for this type will be set. ***Attention***: For the type that is used with the simple attribute **default**, there must be a mandatory implementation of the trait `Default` * **#[cypher(default = "...")]** If using a default value for the whole type doesn't work for you, you can use the default value for a one field. The default value should always be specified as a string, but it will be cast to the required type when the query is generated. ### Entities * **Node** Create node: ```rust let node = Node::new("n", "Profile", None, None); ``` But you can set derive attribute to the struct `#[derive(Debug, Clone, CypQueSet)]` and node will be automatically generated! * **Relation** Create relation: ```rust use neo4j_cypher::entity::Relation; let rel = Relation::new(a1.node("n1"), a2.node("n2"), "SUBSCRIBE", None); ``` Where `a1` and `a2` it's a structs with `CypQue` derive marco. Of course, instead of **None**, you can specify an object of `Props` or vector of `Label`. ### Templates ```toml neo4j_cypher = { version = "...", features=[ "derive", "templates" ] } ``` **Example of a request without using templates** ```rust use neo4j_cypher::query::match_query::CompOper; let query = Query::init().r#match(&a1.node("n1").into(), false) .r#where("name", CompOper::Equal, PropType::str("admin")) .r#match(&a2.node("n2").into(), false) .r#where("name", CompOper::Equal, PropType::str("dev")) .return_many(vec!["n1", "n2"]) .finalize(); ``` **Example request with using templates** To include templates, you must add `templates` to the **features** dependency sections. ```rust let q = Query::init() .r#match(&a1.node("n1").into(), false) .where_eq_str("name", "admin") .r#match(&a2.node("n2").into(), false) .where_eq_str("name", "dev") .return_many(vec!["n1", "n2"]) .finalize(); ``` ### Example #### Node ```rust use std::fmt::Display; use neo4j_cypher::query::match_query::CompOper; use neo4j_cypher::CypQue; /// Example of access levels in the system #[derive(Debug, Clone)] enum Perm { Admin, User, } /// An example of a structure that should be converted into a Neo4j node. /// /// In your code you use name Account and the Neo4j node label will be Profile. /// Field `username` will be renamed; /// Field `secret` will be hidden; /// Field `perm` will be used as second a node label; /// Field `level` and `friends` will used a default value if they will be None; #[derive(Debug, Clone, CypQue)] #[cypher(rename = "Profile")] struct Account { #[cypher(rename = "name")] username: String, password: String, age: i32, status: Option, online: bool, #[cypher(skip)] secret: u8, #[cypher(label)] perm: Perm, #[cypher(default = "5")] level: Option, #[cypher(default = "['Bob', 'Tom']")] friends: Option>, } fn main() { // Init some example struct let data = Account { username: String::from("mi1fhunter"), password: String::from("1234f4321"), age: 32, status: None, online: false, secret: 1, perm: Perm::User, level: None, friends: Some(vec![ "Bob".to_string(), "Tom".to_string(), "Sam".to_string(), ]), }; // Let's build some query let query = Query::init() .create(vec![&a1.node("n").into()]) .r#return("n") .finalize(); println!("{}", query); } ``` So, the query builder automatically generated such query for you: ```sql CREATE (n:Profile { password: '1234f4321',level: 5,name: 'mi1fhunter',age: 32,friends: ['Bob','Tom','Sam'],online: false }) SET n:User RETURN n ``` Example of creating a match query: ```rust let query = Query::init() .r#match(&a1.node("n1").into(), false) .where_eq_str("name", "admin") .r#match(&a2.node("n2").into(), false) .where_eq_str("name", "dev") .return_many(vec!["n1", "n2"]) .finalize(); ``` The result will be like this: ```sql MATCH (n1:Profile) WHERE n1.name = 'admin' MATCH (n2:Profile) WHERE n2.name = 'dev' RETURN n1,n2 ``` If you need to return the value of some propertie or get another `var` name, you can write it like this: ```rust let query = Query::init() .create(vec![&model.node("n").into()]) .r#return_field("n", "age") .finalize(); ``` The result will be: ```sql CREATE (n:Profile { name: 'admin',friends: ['Bob','Tom','Sam'],password: '1234f4321',online: false,level: 5,age: 32 }) SET n:User RETURN n.age ``` OR ```rust let query = Query::init() .create(vec![&model.node("n").into()]) .r#return("n") .r#as("node") .finalize(); ``` Result: ```sql CREATE (n:Profile { age: 32,uname: 'mi1fhunter',online: false,level: 5,friends: ['Bob','Tom','Sam'],password: '1234f4321' }) SET n:User RETURN n AS node ``` #### Relation ```rust let rel1 = Entity::rel("n1", "n2", "SUBSCRIBE", None); let rel2 = Entity::rel("n2", "n1", "SUBSCRIBE", None); let query = Query::init() .r#match(&a1.node("n1").into(), false) .where_eq_str("name", "admin") .r#match(&a2.node("n2").into(), false) .where_eq_str("name", "dev") .return_many(vec!["n1", "n2"]) .create(vec![&rel1.into(), &rel2.into()]) .finalize(); ``` Result: ```sql MATCH (n1:Profile) WHERE n1.age = 1 AND n1.level = 10 MATCH (n1:Profile) WHERE n1.age = 10 CREATE (n1)-[:SUBSCRIBE]->(n2), (n2)-[:SUBSCRIBE]->(n1) ```