8 个版本
0.2.6 | 2021 年 10 月 23 日 |
---|---|
0.2.5 | 2021 年 10 月 22 日 |
0.1.0 | 2021 年 10 月 12 日 |
#2258 in 数据库接口
45KB
860 行
tiny-firestore-odm
tiny-firestore-odm
是 Firestore 的轻量级对象文档映射器。它构建在 firestore-serde
(用于文档/对象转换)之上,并为 Firestore 的 集合 提供了 Rust 表示形式,以及创建/修改/删除它们的相应方法。
其意图不是提供 Firestore 的所有功能,而是提供一个围绕将 Firestore 作为任意 Rust 对象(序列化)集合的键值存储来使用的简化接口。
有关兼容的 Rust/GCP 堆栈,请参阅 Are We Google Cloud Yet?
用法
use google_authz::Credentials;
use tiny_firestore_odm::{Collection, Database, NamedDocument};
use serde::{Deserialize, Serialize};
use tokio_stream::StreamExt;
// Define our data model.
// Any Rust type that implements Serialize and Deserialize can be stored in a Collection.
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct ActorRole {
actor: String,
role: String,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Movie {
pub name: String,
pub year: u32,
pub runtime: u32,
pub cast: Vec<ActorRole>,
}
#[tokio::main(flavor = "current_thread")]
async fn main() {
// Use `google-authz` for credential discovery.
let creds = Credentials::default().await;
// Firestore databases are namespaced by project ID, so we need that too.
let project_id = std::env::var("GCP_PROJECT_ID").expect("Expected GCP_PROJECT_ID env var.");
// A Database is the main wrapper around a raw FirestoreClient.
// It gives us a way to create Collections.
let database = Database::new(creds.into(), &project_id).await;
// A Collection is a reference to a Firestore collection, combined with a type.
let movies: Collection<Movie> = database.collection("tiny-firestore-odm-example-movies");
// Construct a movie to insert into our collection.
let movie = Movie {
name: "The Big Lebowski".to_string(),
year: 1998,
runtime: 117,
cast: vec![
ActorRole {
actor: "Jeff Bridges".to_string(),
role: "The Dude".to_string(),
},
ActorRole {
actor: "John Goodman".to_string(),
role: "Walter Sobchak".to_string(),
},
ActorRole {
actor: "Julianne Moore".to_string(),
role: "Maude Lebowski".to_string(),
},
]
};
// Save the movie to the collection. When we insert a document with `create`, it is assigned
// a random key which is returned to us if it is created successfully.
let movie_id = movies.create(&movie).await.unwrap();
// We can use the key that was returned to fetch the film.
let movie_copy = movies.get(&movie_id).await.unwrap();
assert_eq!(movie, movie_copy);
// Alternatively, we can supply a string to use as the key, like this:
movies.try_create(&movie, "The Big Lebowski").await.unwrap();
// Then, we can retrieve it with the same string.
let movie_copy2 = movies.get("The Big Lebowski").await.unwrap();
assert_eq!(movie, movie_copy2);
// To clean up, let's loop over documents in the collection and delete them.
let mut result = movies.list();
// List returns a `futures_core::Stream` of `NamedDocument` objects.
while let Some(NamedDocument {name, ..}) = result.next().await {
movies.delete(&name).await.unwrap();
}
}
文档存在语义
提供了不同的方法来实现对文档是否存在的不同语义,如下表所示。
方法 | 对象存在时的行为 | 对象不存在时的行为 |
---|---|---|
create |
不适用(选择新键) | 创建 |
create_with_key |
错误 | 创建 |
try_create |
不执行任何操作;返回 Ok(false) |
创建;返回 Ok(true) |
upsert |
替换 | 创建 |
update |
替换 | 错误 |
delete |
删除 | 错误 |
局限性
该软件包旨在为将 Firestore 作为键值存储的工作流程设计,其中每个集合对应一个 Rust 类型(尽管一个 Rust 类型可能对应多个 Firestore 集合)。
目前不支持以下功能
- 除键之外的其他查询
- 只更新文档的一部分
- 事务
- 订阅更新
(我没有排除支持这些功能,但该软件包的目标不是全面支持所有 GCP 功能,而是一个小但有用的子集。)
运行测试
要运行此软件包中的单元测试,无需任何特殊设置。要这样做,请运行
cargo test --lib
此外,还有一些集成测试,用于测试与外部世界的交互功能。要使用这些测试,您必须提供谷歌云凭证。我建议为集成测试创建一个专门的谷歌云项目,因为Firestore是以项目为命名空间的,这样可以避免集成测试写入用于其他目的的数据库。
然后,设置两个环境变量
GOOGLE_APPLICATION_CREDENTIALS
,包含磁盘上.json
文件的绝对路径,该文件包含服务帐户凭证。您可以通过谷歌云控制台下载此文件。GCP_PROJECT_ID
,包含您希望使用的项目的名称。这通常与服务帐户JSON文件的project_id
字段相同。
设置好这些后,您可以运行
cargo test
来运行所有单元和集成测试。
依赖项
~65MB
~1M SLoC