Skip to main content

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::*;