29 روانشتاب
0.11.0 | 14 مارس 2023 |
---|---|
0.10.2 | 21 اکتبر 2022 |
0.10.0 | 30 دسامبر 2021 |
0.9.0 | 19 ژانویه 2021 |
0.7.0 | 24 ژوئیه 2020 |
#1236 در Database interfaces
77 دانلود در ماه
320KB
5.5K SLoC
یک مشتری async/sync rust برای DB دگراف
یک مشتری async/sync rust برای دگراف که با استفاده از gRPC با سرور ارتباط برقرار میکند و با استفاده از Tonic ساخته شده.
قبل از استفاده از این مشتری، توصیه میشود که به tour.dgraph.io و docs.dgraph.io بروید تا بفهمید چگونه دگراف را اجرا و با آن کار کنید.
جداول محتوای
نصب
dgraph-tonic
در crates.io موجود است. وابستگی زیر را به Cargo.toml
خود اضافه کنید.
[dependencies]
dgraph-tonic = "0.11"
ویژگی پیشفرض dgraph-1-1
است.
تمام ویژگیهای موجود میتوانند با
[dependencies]
dgraph-tonic = {version = "0.11", features = ["all"]}
اگر میخواهید از Dgraph v1.0.x استفاده کنید، این وابستگی را اضافه کنید
[dependencies]
dgraph-tonic = { version = "0.11", features = ["dgraph-1-0"], default-features = false }
ویژگیهای پشتیبانی شده
- acl: مشتری با احراز هویت را فعال کنید.
- all: ویژگیهای tls، acl و sync را با dgraph-1-1 فعال کنید
- dgraph-1-0: مشتری برای Dgraph v1.0.x فعال شود
- dgraph-1-1: مشتری برای Dgraph v1.1.x و v20.03.x فعال شود
- dgraph-21-03: مشتری برای Dgraph v21.03.x فعال شود
- slash-ql: مشتری برای سرویس Slash GraphQL فعال شود
- tls: مشتری TlsClient امن را فعال کنید
- sync: مشتری همزمان را فعال کنید
نسخههای پشتیبانی شده
در função از نسخه Dgraph که به آن متصل میشوید، باید ویژگی متفاوتی از این مشتری استفاده کنید (dgraph-1-0 نسخه پیشفرض است).
نسخه Dgraph | ویژگی |
---|---|
1.0.X | dgraph-1-0 |
1.1.X | dgraph-1-1 |
1.2.X | dgraph-1-1 |
20.03.X | dgraph-1-1 |
21.03.X | dgraph-21-03 |
注意:只有从 *dgraph-1-0 到 dgraph-1-1 的 API 破坏出现在函数 MutatedTxn.mutate()
中。该函数在 dgraph-1-0 中返回 Assigned
类型,但在 dgraph-1-1 中返回 Response
类型。
استفاده از مشتری
ایجاد یک مشتری
Client
对象可以通过传递一个端点 URI 或端点 URI 向量来初始化。连接到同一集群中的多个 Dgraph 服务器可以实现更好的工作负载分布。
以下代码片段仅展示了使用单个端点的情况。
use dgraph_tonic::Client;
fn main() {
let client = Client::new("http://127.0.0.1:19080").expect("Dgraph client");
}
或者您可以使用多个端点初始化新的客户端。不能使用空端点向量创建客户端。
use dgraph_tonic::Client;
fn main() {
let client = Client::new(vec!["http://127.0.0.1:9080","http://127.0.0.1:19080"]).expect("Dgraph client");
}
客户端还可以使用自定义的 端点配置。
use dgraph_tonic::{Endpoint, EndpointConfig, Client};
use std::time::Duration;
#[derive(Debug, Default)]
struct EndpointWithTimeout {}
impl EndpointConfig for EndpointWithTimeout {
fn configure_endpoint(&self, endpoint: Endpoint) -> Endpoint {
endpoint.timeout(Duration::from_secs(5))
}
}
fn main() {
let endpoint_config = EndpointWithTimeout::default();
let client = Client::new_with_endpoint_config("http://127.0.0.1:19080",endpoint_config).expect("Dgraph client");
}
ایجاد یک مشتری TLS
此外,tls
功能中提供了安全的 TLS 客户端。
[dependencies]
dgraph-tonic = { version = "0.11", features = ["tls"] }
use dgraph_tonic::TlsClient;
#[tokio::main]
async fn main() {
let server_root_ca_cert = tokio::fs::read("path/to/ca.crt").await.expect("CA cert");
let client_cert = tokio::fs::read("path/to/client.crt").await.expect("Client cert");
let client_key = tokio::fs::read("path/to/ca.key").await.expect("Client key");
let client = TlsClient::new(
vec!["http://192.168.0.10:19080", "http://192.168.0.11:19080"],
server_root_ca_cert,
client_cert,
client_key)
.expect("Dgraph TLS client");
}
所有证书都必须是 PEM
格式。
多租户
在 多租户 环境中,dgraph-tonic
提供了一个新的方法 login_into_namespace()
,这将允许用户登录到特定的命名空间。
为了创建一个客户端,并使其登录到命名空间 123
use dgraph_tonic::Client;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new("http://127.0.0.1:19080").expect("Dgraph client");
let logged = client.login_into_namespace("groot", "password", 123).await.expect("Logged into namespace");
Ok(())
}
在上面的示例中,客户端使用用户名 groot
和密码 password
登录到命名空间 123
。登录后,客户端可以执行命名空间 123
中 groot
用户允许的所有操作。
ایجاد یک مشتری Slash GraphQL
如果您的 Slash GraphQL 端点是 https://app.eu-central-1.aws.cloud.dgraph.io/graphql
,则 gRPC 客户端的连接端点是 http://app.grpc.eu-central-1.aws.cloud.dgraph.io:443
客户端在 slash-ql
功能中可用
[dependencies]
dgraph-tonic = { version = "0.11", features = ["slash-ql"] }
use dgraph_tonic::TlsClient;
#[tokio::main]
async fn main() {
let client = TlsClient::for_slash_ql(
"http://app.grpc.eu-central-1.aws.cloud.dgraph.io:443",
"API_KEY")
.expect("Slash GraphQL client");
}
ایجاد یک مشتری Sync
此外,带有 sync
功能的同步客户端(Tls、Acl)可在 dgraph_tonic::sync
模块中使用
[dependencies]
dgraph-tonic = { version = "0.11", features = ["sync"] }
use dgraph_tonic::sync::{Mutate, Client};
fn main() {
let p = Person {
uid: "_:alice".into(),
name: "Alice".into(),
};
let mut mu = Mutation::new();
mu.set_set_json(&p).expect("JSON");
let client = Client::new("http://127.0.0.1:19080").expect("Dgraph client");
let mut txn = client.new_mutated_txn();
let response = txn.mutate(mu).expect("Mutated");
txn.commit().expect("Transaction is commited");
}
所有同步客户端都支持与异步版本相同的功能。
تغییر دیتابیس
要设置模式,创建一个 Operation
实例并使用 Alter
端点。
use dgraph_tonic::Client;
#[tokio::main]
async fn main() {
let op = Operation {
schema: "name: string @index(exact) .".into(),
..Default::default()
};
let client = Client::new("http://127.0.0.1:19080").expect("Dgraph client");
let response = client.alter(op).await.expect("Schema set");
//you can set schema directly with
client.set_schema("name: string @index(exact) .").await.expect("Schema is not updated");
}
从 Dgraph 版本 20.03.0 开始,索引可以在后台计算。更多详情请参阅 此处。
use dgraph_tonic::Client;
#[tokio::main]
async fn main() {
let op = Operation {
schema: "name: string @index(exact) .".into(),
..Default::default()
};
let client = Client::new("http://127.0.0.1:19080").expect("Dgraph client");
let response = client.alter(op).await.expect("Schema set");
//you can set schema directly with
client.set_schema_in_background("name: string @index(exact) .").await.expect("Schema is not updated");
}
Operation
还包含其他字段,包括 DropAttr
和 DropAll
。如果希望丢弃所有数据并从头开始,而不需要关闭实例,则 DropAll
很有用。用于删除与谓词相关的所有数据的 DropAttr
。
如果您想删除数据库中的所有数据,可以使用
use dgraph_tonic::Client;
#[tokio::main]
async fn main() {
let client = Client::new("http://127.0.0.1:19080").expect("Dgraph client");
client.drop_all().await.expect("Data not dropped");
}
ایجاد یک تراکنش
事务使用 Rust 中的 Typestate 模式 来建模。Typestate 模式是一种 API 设计模式,它将对象运行时状态的信息编码在其编译时类型中。此原则允许我们在编译时识别某些类型错误,例如在只读事务中进行修改。事务类型包括
- 默认:可以转换为 ReadOnly、BestEffort、Mutated。可以执行
query
和query_with_vars
操作。 - ReadOnly:由于它们可以绕过通常的共识协议,因此可以提高读取速度。可以执行
query
和query_with_vars
操作,这些操作在Query
特性中定义。 - BestEffort:只读查询可以可选地设置为尽力而为。使用此标志将要求 Dgraph Alpha 尽力从内存中获取时间戳,以减少对 Zero 的出站请求次数。这可能在不需要可线性化读取的读取密集型工作中提供改进的延迟。可以执行
query
和query_with_vars
操作。 - 已更改:可以执行默认事务的所有操作并可以修改数据库中的数据。只能从默认事务创建。
客户端为事务提供了几个工厂方法。这些操作不会产生网络开销。
use dgraph_tonic::Client;
#[tokio::main]
async fn main() {
let client = Client::new("http://127.0.0.1:19080").expect("Dgraph client");
let txn = client.new_txn();
let read_only = client.new_read_only_txn();
let best_effort = client.new_best_effort_txn();
let mutated = client.new_mutated_txn();
}
对于已更改的事务,必须在丢弃事务变量之前始终调用 txn.dicard().await?
或 txn.commit().await?
函数。
由于事务的内部状态取决于使用的变体(plain、tls、plain + acl、tls + acl x 只读、已更改),您应该在结构中为事务参数使用特质。
struct MyTxn<Q: Query, M: Mutate> {
readonly_txn: Q,
mutated_txn: M,
}
或作为函数的返回参数
fn my_query_operation() -> impl Query {
//your code
}
fn my_mutation_operation() -> impl Mutate {
//your code
}
如果您无法使用泛型或特质对象,则可以使用预定义的已导出事务类型:Txn、TxnReadOnly、TxnBestEffort、TxnMutated、TxnTls、TxnTlsReadOnly、TxnTlsBestEffort、TxnTlsMutated、TxnAcl、TxnAclReadOnly、TxnAclBestEffort、TxnAclMutated、TxnAclTls、TxnAclTlsReadOnly、TxnAclTlsBestEffort、TxnAclTlsMutated
اجرای یک تغییر
txn.mutate(mu).await?
运行一个变更。它接受一个 Mutation
对象。您可以使用 JSON 或 RDF N-Quad 格式设置数据。存在针对 JSON 格式的辅助函数(mu.set_set_json(), mu.set_delete_json()
)。所有变更操作都在 Mutate
特质中定义。
示例
use dgraph_tonic::{Mutate, Client};
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Default, Debug)]
struct Person {
uid: String,
name: String,
}
#[tokio::main]
async fn main() {
let p = Person {
uid: "_:alice".into(),
name: "Alice".into(),
};
let mut mu = Mutation::new();
mu.set_set_json(&p).expect("JSON");
let client = Client::new("http://127.0.0.1:19080").expect("Dgraph client");
let mut txn = client.new_mutated_txn();
let response = txn.mutate(mu).await.expect("Mutated");
txn.commit().await.expect("Transaction is commited");
}
注意:从 dgraph-1-0 到 dgraph-1-1 的 API 破坏仅发生在函数 MutatedTxn.mutate()
中。在 dgraph-1-0 中,此函数返回一个 Assigned
类型,但在 dgraph-1-1 中返回一个 Response
类型。
有时,您只想提交一个变更,而不查询其他任何内容。在这种情况下,您可以使用 txn.mutate_and_commit_now(mu)
来指示必须立即提交变更。在这种情况下正在消耗事务对象。
在 dgraph-1-0
中,可以将 Mutation::with_ignored_index_conflict()
应用于 Mutation
对象,以不在索引上运行冲突检测,这会减少事务冲突和终止的数量。然而,这将以潜在的不一致更新操作为代价。此标志仅在 dgraph-1-0 中可用。
如何从响应中获取分配的 UIDs
您可以通过以下方式指定返回 uid 的自己的键:指定自己的返回 uid 键
use dgraph_tonic::{Mutate, Client};
use serde::{Serialize, Deserialize};
use serde_json::json;
#[tokio::main]
async fn main() {
let p = json!({
"uid": "_:diggy",
"name": "diggy",
"food": "pizza"
});
let mut mu = Mutation::new();
mu.set_set_json(&p).expect("JSON");
let client = Client::new("http://127.0.0.1:19080").expect("Dgraph client");
let mut txn = client.new_mutated_txn();
let response = txn.mutate(mu).await.expect("Mutated");
txn.commit().await.expect("Transaction is commited");
println!("{:?}", response.uids);
}
分配的 uids 返回在响应属性 uids
中。例如 printlns 某样东西
{"diggy": "0xc377"}
اجرای یک پرسش
您可以通过调用 txn.query(q)
来执行一个查询。您需要传递一个 GraphQL+- 查询字符串。如果您想传递一个额外的变量映射,以便在查询中设置,请调用 txn.query_with_vars(q, vars)
,并将变量映射作为第二个参数。所有查询操作都在 Query
特性中定义。
让我们用变量 $a 运行以下查询
query all($a: string) {
all(func: eq(name, $a))
{
uid
name
}
}
Response
提供了一个函数 try_into()
,它可以将返回的 JSON 转换为对应的实现了 serde Deserialize
特性的结构体对象。
use dgraph_tonic::{Client, Query};
use serde::Deserialize;
#[derive(Deserialize, Debug)]
struct Person {
uid: String,
name: String,
}
#[derive(Deserialize, Debug)]
struct Persons {
all: Vec<Person>
}
#[tokio::main]
async fn main() {
let q = r#"query all($a: string) {
all(func: eq(name, $a)) {
uid
name
}
}"#;
let mut vars = HashMap::new();
vars.insert("$a", "Alice");
let client = Client::new("http://127.0.0.1:19080").expect("Dgraph client");
let mut txn = client.new_read_only_txn();
let response = txn.query_with_vars(q, vars).await.expect("Response");
let persons: Persons = resp.try_into().except("Persons");
println!("Persons: {:?}", persons);
}
在运行模式查询时,模式响应位于 Response
的 Schema
字段中。
use dgraph_tonic::Client;
#[tokio::main]
async fn main() {
let q = r#"schema(pred: [name]) {
type
index
reverse
tokenizer
list
count
upsert
lang
}"#;
let client = Client::new("http://127.0.0.1:19080").expect("Dgraph client");
let mut txn = client.new_read_only_txn();
let response = txn.query(q).await.expect("Response");
println!("{:#?}", response.schema);
}
Stream/Iterator
这些函数在 experimental
功能中可用。
有时您不能一次性从查询中获取所有所需数据,因为响应可能很大,这可能导致 gRPC 错误等。在这种情况下,您可以转换您的查询为流 Stream<Item = Result<T, Error>>
(或在同步模式下的迭代器),这将按定义的容量以块的形式查询您的数据。在定义查询方面存在一些限制
- 您的查询必须接受
$first: string, $offset: string
输入参数。 - 流/迭代器的项必须以
items
名称返回块。
Stream/Iterator 在以下情况下结束
- 查询返回没有项目时,
- 查询返回错误,这是从流中返回的最后项目时,
- 查询响应无法反序列化为
Vec<T>
。
use std::collections::HashMap;
use failure::Error;
use futures::pin_mut;
use futures::stream::StreamExt;
use dgraph_tonic::{Client, Response, Query};
use serde::Deserialize;
#[derive(Deserialize, Debug)]
struct Person {
uid: String,
name: String,
}
#[tokio::main]
async fn main() {
let query = r#"query stream($first: string, $offset: string, $name: string) {
items(func: eq(name, $name), first: $first, offset: $offset) {
uid
name
}
}"#;
let mut vars = HashMap::new();
vars.insert("$name", "Alice");
let client = client().await;
let stream = client.new_read_only_txn().into_stream_with_vars(query, vars, 100);
pin_mut!(stream);
let alices: Vec<Result<Person, Error>> = stream.collect().await;
}
如果您不想指定输入变量,您可以通过调用 client.new_read_only_txn().into_stream(query, 100)
来实现。
同步 只读事务可以通过调用 client.new_read_only_txn().into_iter(query, 100)
和 client.new_read_only_txn().into_iter_with_vars(query, vars, 100)
转换为迭代器。
اجرای یک Upsert: Query + Mutation
自 dgraph-1-1
起可用。
txn.upsert(查询, 变更)
函数允许您运行由一个查询和一个或多个变更组成的 upsert 操作。查询变量可以使用 txn.upsert_with_vars(查询, 变量, 变更)
定义。如果您想提交 upsert 操作,可以使用 txn.upsert_with_vars_and_commit_now()
。在这种情况下,Txn 对象将被消耗。
想了解更多关于 upsert 的信息,我们强烈建议您查阅 https://docs.dgraph.io/mutations/#upsert-block 的文档。
use dgraph_tonic::{Mutate, Client};
#[tokio::main]
async fn main() {
let q = r#"
query {
user as var(func: eq(email, "[email protected]"))
}"#;
let mut mu = Mutation::new();
mu.set_set_nquads(r#"uid(user) <email> "[email protected]" ."#);
let client = Client::new("http://127.0.0.1:19080").expect("Dgraph client");
let txn = client.new_mutated_txn();
// Upsert: If wrong_email found, update the existing data or else perform a new mutation.
let response = txn.upsert(q, mu).await.expect("Upserted data");
tnx.commit().await.expect("Committed");
}
您可以使用一个变更或变更向量来进行 upsert 操作。如果您想提交 upsert 操作,可以使用 txn.upsert_and_commit_now()
。在这种情况下,Txn 对象将被消耗。
اجرای یک Upsert موقتانه
自 dgraph-1-1
起可用。
upsert 块允许使用 @if
指令指定条件变更块。只有当指定的条件为真时,才会执行变更。如果条件为假,则变更将被静默忽略。
更多关于条件 upsert 的信息请参阅 这里。
use dgraph_tonic::{Client, Mutate};
#[tokio::main]
async fn main() {
let q = r#"
query {
user as var(func: eq(email, "[email protected]"))
}"#;
let mut mu = Mutation::new();
mu.set_set_nquads(r#"uid(user) <email> "[email protected]" ."#);
mu.set_cond("@if(eq(len(user), 1))");
let client = Client::new("http://127.0.0.1:19080").expect("Dgraph client");
let txn = client.new_mutated_txn();
let response = txn.upsert(q, vec![mu]).await.expect("Upserted data");
tnx.commit().await.expect("Committed");
}
تراکنش را ارسال کنید
可以使用 txn.commit()
方法提交变更事务。如果您的交易仅由对 txn.query
或 txn.query_with_vars
的调用组成,而没有对 txn.mutate
的调用,则调用 txn.commit
是不必要的。
如果其他并发事务修改了此事务中修改的同一数据,将返回错误。当事务失败时,需要用户自行重试事务。
use dgraph_tonic::{Client, Mutate};
#[tokio::main]
async fn main() {
let client = Client::new("http://127.0.0.1:19080").expect("Dgraph client");
let mut txn = client.new_mutated_txn();
// Perform some queries and mutations.
//than commit
let res = txn.commit().await;
if res.is_err() {
// Retry or handle error
}
}
لیستهای کنترل دسترسی
此企业级 Dgraph 功能可以通过
[dependencies]
dgraph-tonic = { version = "0.11", features = ["acl"] }
访问控制列表 (ACL) 启用,为存储在 Dgraph 中的数据提供访问保护。当 ACL 功能开启时,客户端必须使用用户名和密码进行身份验证,才能执行任何事务,并且只能访问 ACL 规则允许的数据。
两者,Client
和 TlsClient
都可以使用 login(user_id,password)
函数登录。原始客户端将被消耗,并返回 AclClient
的实例,该实例可以使用 refresh_login()
函数刷新令牌。
use dgraph_tonic::Client;
#[tokio::main]
async fn main() {
let client = Client::new("http://127.0.0.1:19080").expect("Dgraph client");
let logged_in_client = client.login("groot", "password").await.expect("Logged in");
// use client
//than refresh token
logged_in_client.refresh_login().await.except("Refreshed access token");
}
نسخه را بررسی کنید
use dgraph_tonic::Client;
#[tokio::main]
async fn main() {
let client = Client::new("http://127.0.0.1:19080").expect("Dgraph client");
let version = client.check_version().await.expect("Version");
println!("{:#?}", version);
}
输出
Version {
tag: "v20.03.0",
}
مثالها
آزمونهای یکپارچه
测试需要在运行在 localhost:19080
上的 Dgraph 上运行。为了方便起见,在根目录中准备了两个 docker-compose.yaml
文件,具体取决于您要测试的 Dgraph 版本。
docker-compose -f docker-compose-1-X.yaml up -d
由于我们正在与数据库一起工作,因此测试也需要在单个线程中运行,以防止中止。根据您使用的 Dgraph 版本使用功能标志。例如。
cargo test --no-default-features --features dgraph-1-1 -- --test-threads=1
پیشنهادات
欢迎贡献。请随意提出问题,包括功能请求、错误修复和改进。
在创建拉取请求之前,运行以下命令
rustup component add rustfmt
cargo fmt
发布清单
这些必须在Dgraph 1.0和Dgraph 1.1+上执行
- 运行测试
- 尝试示例
更新版本并发布crate
- 更新Cargo.toml中的标签
- 更新README.md中的标签
gittag v0.X.X
gitpush origin v0.X.X
- 在GitHub上编写发布日志
cargopublish
ممنون از
依赖项
~16–29MB
~511K SLoC