firestore/lib.rs
1//! # Firestore for Rust
2//!
3//! Library provides a simple API for Google Firestore:
4//! - Create or update documents using Rust structures and Serde;
5//! - Support for querying / streaming / listing / listening changes / aggregated queries of documents from Firestore;
6//! - Fluent high-level and strongly typed API;
7//! - Full async based on Tokio runtime;
8//! - Macro that helps you use JSON paths as references to your structure fields;
9//! - Implements own Serde serializer to Firestore gRPC values;
10//! - Supports for Firestore timestamp with `#[serde(with)]`;
11//! - Transactions support;
12//! - Streaming batch writes with automatic throttling to avoid time limits from Firestore;
13//! - Aggregated Queries;
14//! - Request tags (request options) to attribute Firestore usage;
15//! - Google client based on [gcloud-sdk library](https://github.com/abdolence/gcloud-sdk-rs)
16//! that automatically detects GKE environment or application default accounts for local development;
17//!
18//! ## Example using the Fluent API:
19//!
20//! ```rust,no_run
21//!
22//!use firestore::*;
23//!use serde::{Deserialize, Serialize};
24//!use futures::stream::BoxStream;
25//!use futures::StreamExt;
26//!
27//!pub fn config_env_var(name: &str) -> Result<String, String> {
28//! std::env::var(name).map_err(|e| format!("{}: {}", name, e))
29//!}
30//!
31//!// Example structure to play with
32//!#[derive(Debug, Clone, Deserialize, Serialize)]
33//!struct MyTestStructure {
34//! some_id: String,
35//! some_string: String,
36//! one_more_string: String,
37//! some_num: u64,
38//!}
39//!
40//!#[tokio::main]
41//!async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {//!
42//! // Create an instance
43//! let db = FirestoreDb::new(&config_env_var("PROJECT_ID")?).await?;
44//!
45//! const TEST_COLLECTION_NAME: &'static str = "test";
46//!
47//! let my_struct = MyTestStructure {
48//! some_id: "test-1".to_string(),
49//! some_string: "Test".to_string(),
50//! one_more_string: "Test2".to_string(),
51//! some_num: 42,
52//! };
53//!
54//! // Create documents
55//! let object_returned: MyTestStructure = db.fluent()
56//! .insert()
57//! .into(TEST_COLLECTION_NAME)
58//! .document_id(&my_struct.some_id)
59//! .object(&my_struct)
60//! .execute()
61//! .await?;
62//!
63//! // Update documents
64//! let object_updated: MyTestStructure = db.fluent()
65//! .update()
66//! .fields(paths!(MyTestStructure::{some_num, one_more_string})) // Update only specified fields
67//! .in_col(TEST_COLLECTION_NAME)
68//! .document_id(&my_struct.some_id)
69//! .object(&MyTestStructure {
70//! some_num: my_struct.some_num + 1,
71//! one_more_string: "updated-value".to_string(),
72//! ..my_struct.clone()
73//! })
74//! .execute()
75//! .await?;
76//!
77//! // Get a document as an object by id
78//! let find_it_again: Option<MyTestStructure> = db.fluent()
79//! .select()
80//! .by_id_in(TEST_COLLECTION_NAME)
81//! .obj()
82//! .one(&my_struct.some_id)
83//! .await?;
84//!
85//! // Query and read stream of objects
86//! let object_stream: BoxStream<MyTestStructure> = db.fluent()
87//! .select()
88//! .fields(paths!(MyTestStructure::{some_id, some_num, some_string, one_more_string})) // Optionally select the fields needed
89//! .from(TEST_COLLECTION_NAME)
90//! .filter(|q| { // Fluent filter API example
91//! q.for_all([
92//! q.field(path!(MyTestStructure::some_num)).is_not_null(),
93//! q.field(path!(MyTestStructure::some_string)).eq("Test"),
94//! // Sometimes you have optional filters
95//! Some("Test2")
96//! .and_then(|value| q.field(path!(MyTestStructure::one_more_string)).eq(value)),
97//! ])
98//! })
99//! .order_by([(
100//! path!(MyTestStructure::some_num),
101//! FirestoreQueryDirection::Descending,
102//! )])
103//! .obj() // Reading documents as structures using Serde gRPC deserializer
104//! .stream_query()
105//! .await?;
106//!
107//! let as_vec: Vec<MyTestStructure> = object_stream.collect().await;
108//! println!("{:?}", as_vec);
109//!
110//! // Delete documents
111//! db.fluent()
112//! .delete()
113//! .from(TEST_COLLECTION_NAME)
114//! .document_id(&my_struct.some_id)
115//! .execute()
116//! .await?;
117//!
118//! Ok(())
119//! }
120//! ```
121//!
122//! All examples and more docs available at: [github](https://github.com/abdolence/firestore-rs/tree/master/examples)
123//!
124
125#![allow(clippy::new_without_default)]
126#![allow(clippy::needless_lifetimes)]
127#![forbid(unsafe_code)]
128
129/// Defines the error types used throughout the `firestore-rs` crate.
130///
131/// This module contains the primary [`FirestoreError`](errors::FirestoreError) enum
132/// and various specific error structs that provide detailed information about
133/// issues encountered during Firestore operations.
134pub mod errors;
135
136mod firestore_value;
137
138/// Re-exports all public items from the `firestore_value` module.
139///
140/// The `firestore_value` module provides representations and utilities for
141/// working with Firestore's native data types (e.g., `Map`, `Array`, `Timestamp`).
142pub use firestore_value::*;
143
144mod db;
145
146/// Re-exports all public items from the `db` module.
147///
148/// The `db` module contains the core [`FirestoreDb`](db::FirestoreDb) client and
149/// functionalities for interacting with the Firestore database, such as CRUD operations,
150/// queries, and transactions.
151pub use db::*;
152
153mod firestore_serde;
154
155/// Re-exports all public items from the `firestore_serde` module.
156///
157/// This module provides custom Serde serializers and deserializers for converting
158/// Rust types to and from Firestore's data format. It enables seamless integration
159/// of user-defined structs with Firestore.
160pub use firestore_serde::*;
161
162mod struct_path_macro;
163
164/// Re-exports macros for creating type-safe paths to struct fields.
165///
166/// These macros, like `path!` and `paths!`, are used to refer to document fields
167/// in a way that can be checked at compile time, reducing runtime errors when
168/// specifying fields for queries, updates, or projections.
169/// The `#[allow(unused_imports)]` is present because these are macro re-exports
170/// and their usage pattern might trigger the lint incorrectly.
171#[allow(unused_imports)]
172pub use struct_path_macro::*;
173
174/// Re-export of the [`jiff`] crate, so that the date/time API used by this
175/// library is available without depending on `jiff` explicitly.
176pub use jiff;
177
178/// An exact instant in time, used by this library for Firestore timestamps.
179///
180/// This is an alias for [`jiff::Timestamp`]. Prefer this alias over naming
181/// `jiff::Timestamp` directly, so that your code does not need an explicit
182/// `jiff` dependency and stays insulated from changes of the underlying
183/// implementation.
184///
185/// Use it for the fields of your structures. To have a field serialized as a
186/// Firestore timestamp, either annotate it with one of the
187/// [`serialize_as_timestamp`] attributes, or wrap it in
188/// [`FirestoreTimestamp`], which does the same without an attribute.
189///
190/// # Examples
191///
192/// ```rust
193/// use firestore::*;
194/// use serde::{Deserialize, Serialize};
195///
196/// #[derive(Debug, Clone, Deserialize, Serialize)]
197/// struct MyTestStructure {
198/// #[serde(with = "firestore::serialize_as_timestamp")]
199/// created_at: FirestoreInstant,
200///
201/// #[serde(default)]
202/// #[serde(with = "firestore::serialize_as_optional_timestamp")]
203/// updated_at: Option<FirestoreInstant>,
204/// }
205/// ```
206pub type FirestoreInstant = jiff::Timestamp;
207
208/// The duration type used by this library.
209///
210/// This is an alias for [`jiff::SignedDuration`], used for values such as
211/// [`FirestoreTransactionOptions::max_elapsed_time`] and the query execution
212/// statistics.
213pub type FirestoreDuration = jiff::SignedDuration;
214
215/// Provides utility functions for working with Firestore timestamps.
216///
217/// This module includes helpers for converting between [`FirestoreInstant`]
218/// and Google's `Timestamp` protobuf type, often used with `#[serde(with)]`
219/// attributes for automatic conversion.
220pub mod timestamp_utils;
221
222use crate::errors::FirestoreError;
223
224/// A type alias for `std::result::Result<T, FirestoreError>`.
225///
226/// This is the standard result type used throughout the `firestore-rs` crate
227/// for operations that can fail, encapsulating either a successful value `T`
228/// or a [`FirestoreError`].
229pub type FirestoreResult<T> = std::result::Result<T, FirestoreError>;
230
231/// A type alias for the raw Firestore document representation.
232///
233/// This refers to `gcloud_sdk::google::firestore::v1::Document`, which is the
234/// underlying gRPC/protobuf structure for a Firestore document.
235pub type FirestoreDocument = gcloud_sdk::google::firestore::v1::Document;
236
237mod firestore_meta;
238
239/// Re-exports all public items from the `firestore_meta` module.
240///
241/// This module provides metadata associated with Firestore documents, such as
242/// `create_time`, `update_time`, and `read_time`. These are often included
243/// in responses from Firestore.
244pub use firestore_meta::*;
245
246mod firestore_document_functions;
247
248/// Re-exports helper functions for working with [`FirestoreDocument`]s.
249///
250/// These functions provide conveniences for extracting data or metadata
251/// from raw Firestore documents.
252pub use firestore_document_functions::*;
253
254mod fluent_api;
255
256/// Re-exports all public items from the `fluent_api` module.
257///
258/// This module provides a high-level, fluent interface for building and executing
259/// Firestore operations (select, insert, update, delete, list). It aims to make
260/// common database interactions more ergonomic and type-safe.
261pub use fluent_api::*;
262
263/// Re-exports the `struct_path` crate.
264///
265/// The `struct_path` crate is a dependency that provides the core functionality
266/// for the `path!` and `paths!` macros used for type-safe field path generation.
267pub extern crate struct_path;
268
269#[cfg(feature = "caching")]
270/// Provides caching capabilities for Firestore operations.
271///
272/// This module is only available if the `caching` feature is enabled.
273/// It allows for caching Firestore documents and query results to reduce latency
274/// and read costs.
275mod cache;
276
277#[cfg(feature = "caching")]
278/// Re-exports all public items from the `cache` module.
279///
280/// This is only available if the `caching` feature is enabled.
281/// It includes types like [`FirestoreCache`](cache::FirestoreCache) and various
282/// caching backends and configurations.
283pub use cache::*;