1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
//! # Firestore for Rust
//!
//! A client for Google Firestore built on the official gRPC API, with a fluent, strongly typed
//! query builder and its own Serde serializer for Firestore's protobuf values.
//!
//! Full documentation, with a chapter per topic: <https://firestore-rust.abdolence.dev>
//!
//! ## Example
//!
//! ```rust,no_run
//! use firestore::*;
//! use serde::{Deserialize, Serialize};
//!
//! #[derive(Debug, Clone, Deserialize, Serialize)]
//! struct MyTestStructure {
//! some_id: FirestoreDocumentId,
//! some_string: String,
//! some_num: u64,
//! }
//!
//! # async fn example() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
//! let db = FirestoreDb::new("my-project-id").await?;
//!
//! const TEST_COLLECTION_NAME: FirestoreCollectionId =
//! FirestoreCollectionId::from_static("test");
//!
//! let my_struct = MyTestStructure {
//! some_id: FirestoreDocumentId::from_static("test-1"),
//! some_string: "Test".to_string(),
//! some_num: 42,
//! };
//!
//! // Create a document from a Rust structure
//! let created: MyTestStructure = db.fluent()
//! .insert()
//! .into(TEST_COLLECTION_NAME)
//! .document_id(&my_struct.some_id)
//! .object(&my_struct)
//! .execute()
//! .await?;
//!
//! // Query, selecting fields by compile-time checked paths
//! let as_vec: Vec<MyTestStructure> = db.fluent()
//! .select()
//! .fields(paths!(MyTestStructure::{some_id, some_num, some_string}))
//! .from(TEST_COLLECTION_NAME)
//! .filter(|q| q.for_all([
//! q.field(path!(MyTestStructure::some_num)).is_not_null(),
//! q.field(path!(MyTestStructure::some_string)).eq("Test"),
//! ]))
//! .order(|o| o.fields([o.field(path!(MyTestStructure::some_num)).desc()]))
//! .obj()
//! .query()
//! .await?;
//!
//! db.fluent()
//! .delete()
//! .from(TEST_COLLECTION_NAME)
//! .document_id(&my_struct.some_id)
//! .execute()
//! .await?;
//! # Ok(())
//! # }
//! ```
//!
//! ## Where to look
//!
//! | For | Start at |
//! |---|---|
//! | Creating a client | [`FirestoreDb::new`], [`FirestoreDb::with_options`], [`FirestoreDb::with_options_auth`] |
//! | Every read and write | [`FirestoreDb::fluent`] |
//! | Document and collection IDs | [`FirestoreDocumentId`], [`FirestoreCollectionId`], [`ParentPathBuilder`] |
//! | Field paths in queries and updates | [`path!`], [`paths!`] |
//! | Transactions | [`FirestoreDb::run_transaction`], [`FirestoreTransaction`] |
//! | Batch writes | [`FirestoreDb::create_simple_batch_writer`], [`FirestoreDb::create_streaming_batch_writer`] |
//! | Realtime changes | [`FirestoreDb::create_listener`], [`FirestoreListener`] |
//! | Timestamps | [`FirestoreTimestamp`], [`FirestoreInstant`], [`serialize_as_timestamp`] |
//! | Schemaless documents | [`FirestoreDb::serialize_map_to_doc`], [`FirestoreValue`] |
//! | Errors | [`errors`] |
//!
//!
//! ## Cargo features
//!
//! | Feature | Effect |
//! |---|---|
//! | `tls-roots` (default) | TLS trust anchors from the platform's native root store |
//! | `tls-webpki-roots` | TLS trust anchors bundled from the `webpki-roots` crate instead |
//! | `auth-default-crypto` (default) | The aws-lc-rs rustls crypto provider service account keys sign their tokens with; without it, install a rustls `CryptoProvider` before creating a client |
//! | `caching-memory` | In-memory collection and document cache, kept current by a listener |
//! | `caching-persistent` | The same cache backed by an on-disk database |
//! | `admin` | Declarative index management and bulk delete: composite indexes, vector indexes, single-field overrides, TTL policy, and `BulkDeleteDocuments` |
//!
//! Runnable examples for every topic:
//! <https://github.com/abdolence/firestore-rs/tree/master/examples>
/// Defines the error types used throughout the `firestore-rs` crate.
///
/// This module contains the primary [`FirestoreError`] enum
/// and various specific error structs that provide detailed information about
/// issues encountered during Firestore operations.
pub use *;
pub use *;
pub use *;
pub use *;
/// Re-export of the [`macro@async_trait`] macro.
///
/// It is needed to implement the public async traits of this crate, such as
/// [`FirestoreResumeStateStorage`] and the cache backend traits, without having to depend on
/// `async-trait` directly.
pub use async_trait;
/// Re-export of [`rvstruct::ValueStruct`].
///
/// This trait provides the `.value()` accessor on the newtypes of this crate, such as
/// [`FirestoreListenerTarget`] and [`FirestoreListenerToken`], whose inner fields are private.
/// Implementations of [`FirestoreResumeStateStorage`] need it to read those values.
pub use ValueStruct;
/// Re-export of the gcloud-sdk version this crate compiles against, for building
/// [`gcloud_sdk::GoogleAuthHeaders`] and `google_cloud_auth` credentials.
pub use gcloud_sdk;
/// Re-export of the [`jiff`] crate, so that the date/time API used by this
/// library is available without depending on `jiff` explicitly.
pub use jiff;
/// An exact instant in time, used by this library for Firestore timestamps.
///
/// This is an alias for [`jiff::Timestamp`]. Prefer this alias over naming
/// `jiff::Timestamp` directly, so that your code does not need an explicit
/// `jiff` dependency and stays insulated from changes of the underlying
/// implementation.
///
/// Use it for the fields of your structures. To have a field serialized as a
/// Firestore timestamp, either annotate it with one of the
/// [`serialize_as_timestamp`] attributes, or wrap it in
/// [`FirestoreTimestamp`], which does the same without an attribute.
///
/// # Examples
///
/// ```rust
/// use firestore::*;
/// use serde::{Deserialize, Serialize};
///
/// #[derive(Debug, Clone, Deserialize, Serialize)]
/// struct MyTestStructure {
/// #[serde(with = "firestore::serialize_as_timestamp")]
/// created_at: FirestoreInstant,
///
/// #[serde(default)]
/// #[serde(with = "firestore::serialize_as_optional_timestamp")]
/// updated_at: Option<FirestoreInstant>,
/// }
/// ```
pub type FirestoreInstant = Timestamp;
/// The type of durations that Firestore reports.
///
/// This is an alias for [`jiff::SignedDuration`], used for values such as
/// [`FirestoreExecutionStats::execution_duration`]. Settings such as retry
/// limits take a [`std::time::Duration`].
pub type FirestoreDuration = SignedDuration;
/// Provides utility functions for working with Firestore timestamps.
///
/// This module includes helpers for converting between [`FirestoreInstant`]
/// and Google's `Timestamp` protobuf type, often used with `#[serde(with)]`
/// attributes for automatic conversion.
use crateFirestoreError;
/// A type alias for `std::result::Result<T, FirestoreError>`.
///
/// This is the standard result type used throughout the `firestore-rs` crate
/// for operations that can fail, encapsulating either a successful value `T`
/// or a [`FirestoreError`].
pub type FirestoreResult<T> = Result;
/// A type alias for the raw Firestore document representation.
///
/// This refers to `gcloud_sdk::google::firestore::v1::Document`, which is the
/// underlying gRPC/protobuf structure for a Firestore document.
pub type FirestoreDocument = Document;
/// The kind of change a listener reports for one of its targets.
///
/// This refers to `gcloud_sdk::google::firestore::v1::target_change::TargetChangeType`, and is
/// re-exported so that a
/// [`FirestoreListenEvent::TargetChange`](crate::FirestoreListenEvent::TargetChange) can be
/// matched without depending on `gcloud-sdk` directly:
///
/// ```rust,no_run
/// # use firestore::*;
/// # fn example(event: FirestoreListenEvent) {
/// if let FirestoreListenEvent::TargetChange(target_change) = event {
/// match FirestoreListenerTargetChangeType::try_from(target_change.target_change_type) {
/// // The target now reflects a consistent snapshot.
/// Ok(FirestoreListenerTargetChangeType::Current) => {}
/// // With a `cause`, Firestore removed the target on its own. With none, it
/// // acknowledges `remove_target`, or ends a target added once.
/// Ok(FirestoreListenerTargetChangeType::Remove) => {}
/// _ => {}
/// }
/// }
/// # }
/// ```
pub type FirestoreListenerTargetChangeType =
TargetChangeType;
pub use *;
pub use *;
pub use *;
/// The crate backing [`path!`] and [`paths!`].
///
/// Re-exported because those macros expand to paths into it, so a caller cannot use them
/// without it being in scope.
pub extern crate struct_path;
pub use *;