#dto #cypher #neo4j #query #graph #data-transfer

cypher-dto

用于处理Cypher和Neo4j数据传输对象的特性和宏集合

5 个不稳定版本

0.3.1 2024年3月24日
0.3.0 2024年3月1日
0.2.0 2023年8月12日
0.1.1 2023年8月7日
0.1.0 2023年8月6日

#310数据库接口

Download history 11/week @ 2024-03-07 2/week @ 2024-03-14 107/week @ 2024-03-21 19/week @ 2024-03-28 12/week @ 2024-04-04

每月204 次下载

MIT 许可证

64KB
1K SLoC

cypher-dto

Crates.io Github.com Docs.rs License

用于在Neo4j中处理数据传输对象的特性和宏集合。

简要概述

use cypher_dto::{Node, Relation};

#[derive(Node)]
struct Person {
  name: String
}

#[derive(Relation)]
struct Knows {
  since: u16
}

let alice = Person::new("Alice");
let bob = Person::new("Bob");
let knows = Knows::new(2020);

let graph = neo4rs::Graph::new(/*...*/);


let query: neo4rs::Query = alice.create();
graph.execute(query);

let alice = alice.into_builder().name("Allison").build();
let query = alice.update();
graph.execute(query);

let query = knows.create(RelationBound::Match(&alice), RelationBound::Create(&bob));
graph.execute(query);

示例

基本用法

use cypher_dto::Node;
use neo4rs::Query;

#[derive(Node)]
struct Person {
    id: String,     // Inferred to be the only #[id] field.
    name: String,
    #[name = "zip_code"]
    zip: String,
}
assert_eq!(Person::typename(), "Person");
assert_eq!(Person::field_names(), &["id", "name", "zip_code"]);

// For building parameterized cypher queries...
assert_eq!(Person::as_query_fields(), "id: $id, name: $name, zip_code: $zip_code");
assert_eq!(Person::as_query_obj(), "Person { id: $id, name: $name, zip_code: $zip_code }");

let person = Person::new("123", "John", "12345");

// Unitary CRUD operations are provided for convenience.
let query = person.create();

// Equivalent to:
let mut query = Query::new(format!(
    "CREATE (n:{})",
    Person::as_query_obj()
));
query = person.add_values_to_params(query, None, StampMode::Create);
#[derive(Clone, Debug, PartialEq, Relation)]
struct Knows;
assert_eq!(Knows::typename(), "KNOWS");

多值标识符

use cypher_dto::Node;
use neo4rs::Query;

#[derive(Node)]
struct Company {
  #[id]
  name: String,
  #[id]
  state: String,
  phone: String,
}
let company = Company::new("Acme", "CA", "555-555-5555");
let id = company.identifier();
assert_eq!(id.name(), "Acme");
assert_eq!(id.state(), "CA");
assert_eq!(id, CompanyId::new("Acme", "CA"));

assert_eq!(CompanyId::typename(), "Company");
assert_eq!(CompanyId::field_names(), &["name", "state"]);

let query = id.read();
// Equivalent to:
let mut query = Query::new(format!(
    "MATCH (n:{}) RETURN n",
    CompanyId::as_query_obj()
));
query = id.add_values_to_params(query, None, StampMode::Read);

构建器、new和getter

  • 生成的 ::new() 方法将接受 &str 作为 String 字段的参数,以及 &[T] 作为 Vec<T> 字段的参数。

  • 文档注释被复制到结构体的getter、FooId 结构体的getter以及FooBuilder 结构体的方法中。

#[derive(Node)]
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.into_builder().name("Ferris").build();
assert_eq!(p.name(), "Ferris");

时间戳

内置了对特殊时间戳字段的支持:created_atupdated_atcreatedupdated,或这四个中的任意一个。

use cypher_dto::timestamps;

#[timestamps]
struct Person {
  name: String,
}
// Adds two fields:
//   created_at: Option<DateTime<Utc>>,
//   updated_at: Option<DateTime<Utc>>,

#[timestamps = "short"]
struct Person {
  name: String,
}
// Adds two fields:
//   created: Option<DateTime<Utc>>,
//   updated: Option<DateTime<Utc>>,

#[timestamps = "updated_at"]
struct Person {
  name: String,
}
// Adds one field:
//   updated_at: Option<DateTime<Utc>>,

时间戳字段与其他字段的处理略有不同

  • 它们不是生成的 ::new() 方法的参数。
  • 它们有时在 ::to_query_fields() 中有硬编码的值。
    • 使用 to_query_fields() 并传递 StampMode::Create 将在查询中使用 datetime() 而不是例如 $created_at

Option<DateTime<Utc>> 用来代替 DateTime<Utc>,以便在创建新实例时,在它存在于数据库之前,字段可以设置为 None

有关宏变体的更多详细信息,请参阅 cypher-dto-macros 库。

单元CRUD操作

此库认为非平凡查询应手动管理,但它确实提供了基本的CRUD操作以方便使用。

#[derive(Node)]#[derive(Relation)] 结构体将获得 createupdate 方法,而相应的 FooId 结构体会获得 readdelete 方法,所有这些方法都返回一个 neo4rs::Query

这些方法甚至不需要任何参数,除了创建关系,需要知道它之间的起始和结束节点是否需要创建或已经存在。

use cypher_dto::{Node, Relation};

#[derive(Node)]
Person {
  name: String,
}

#[derive(Clone, Debug, PartialEq, Relation)]
struct Knows;

let alice = Person::new("Alice");
let bob = Person::new("Bob");
let knows = Knows; // Relations can have fields and ids too.

let query = knows.create(RelationBound::Create(&alice), RelationBound::Create(&bob));

节点标签

虽然可以使用 neo4rs::Node::labels( 从数据库中读取节点的当前标签,但此库提供了一种定义结构体应使用的标签的方法。然后,这些标签将由内置的CRUD操作使用。

#[derive(Node)]
#[labels("Person", "Employee")]
Person {
  name: String,
}

let person = Person::new("Alice");
assert_eq!(person.labels(), &["Person", "Employee"]);

依赖关系

~14–27MB
~491K SLoC