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