Skip to main content

firebase_admin_sdk/firestore/
snapshot.rs

1use super::models::Document;
2use super::reference::{convert_fields_to_serde_value, convert_value_to_serde_value, DocumentReference};
3use super::FirestoreError;
4use serde::de::DeserializeOwned;
5
6/// A snapshot of a document in Firestore.
7///
8/// It contains data read from a document in your Firestore database.
9/// The data can be extracted with `.data()`.
10#[derive(Debug, Clone)]
11pub struct DocumentSnapshot<'a> {
12    pub(crate) id: String,
13    pub(crate) reference: DocumentReference<'a>,
14    pub(crate) document: Option<Document>,
15    pub(crate) read_time: Option<String>,
16}
17
18impl<'a> DocumentSnapshot<'a> {
19    /// The ID of the document.
20    pub fn id(&self) -> &str {
21        &self.id
22    }
23
24    /// The `DocumentReference` for the document.
25    pub fn reference(&self) -> &DocumentReference<'a> {
26        &self.reference
27    }
28
29    /// Returns `true` if the document exists.
30    pub fn exists(&self) -> bool {
31        self.document.is_some()
32    }
33
34    /// The time the document was created. Returns `None` if the document does not exist.
35    pub fn create_time(&self) -> Option<&str> {
36        self.document.as_ref().map(|d| d.create_time.as_str())
37    }
38
39    /// The time the document was last updated. Returns `None` if the document does not exist.
40    pub fn update_time(&self) -> Option<&str> {
41        self.document.as_ref().map(|d| d.update_time.as_str())
42    }
43
44    /// The time this snapshot was read.
45    pub fn read_time(&self) -> Option<&str> {
46        self.read_time.as_deref()
47    }
48
49    /// Retrieves all fields in the document as a specific type.
50    ///
51    /// Returns `Ok(None)` if the document does not exist.
52    pub fn data<T: DeserializeOwned>(&self) -> Result<Option<T>, FirestoreError> {
53        if let Some(doc) = &self.document {
54            let serde_value = convert_fields_to_serde_value(doc.fields.clone())?;
55            let obj = serde_json::from_value(serde_value)?;
56            Ok(Some(obj))
57        } else {
58            Ok(None)
59        }
60    }
61
62    /// Retrieves a specific field from the document.
63    ///
64    /// # Arguments
65    ///
66    /// * `path` - The path to the field (e.g., "address.city").
67    pub fn get_field<T: DeserializeOwned>(&self, path: &str) -> Result<Option<T>, FirestoreError> {
68        if let Some(doc) = &self.document {
69            // Simple field access for now. Nested fields would require parsing the path.
70            // For now, we only support top-level fields or simple map traversal if implemented manually.
71            // TODO: Support dot notation for nested fields properly.
72
73            if let Some(value) = doc.fields.get(path) {
74                let serde_value = convert_value_to_serde_value(value.clone())?;
75                let obj = serde_json::from_value(serde_value)?;
76                Ok(Some(obj))
77            } else {
78                 // Try to traverse if dot is present?
79                 // For now, just return None if not found at top level.
80                 Ok(None)
81            }
82        } else {
83            Ok(None)
84        }
85    }
86}
87
88/// A `QuerySnapshot` contains zero or more `DocumentSnapshot` objects.
89#[derive(Debug, Clone)]
90pub struct QuerySnapshot<'a> {
91    pub(crate) documents: Vec<DocumentSnapshot<'a>>,
92    pub(crate) read_time: Option<String>,
93}
94
95impl<'a> QuerySnapshot<'a> {
96    /// The documents in this snapshot.
97    pub fn documents(&self) -> &Vec<DocumentSnapshot<'a>> {
98        &self.documents
99    }
100
101    /// Returns `true` if there are no documents in the snapshot.
102    pub fn empty(&self) -> bool {
103        self.documents.is_empty()
104    }
105
106    /// The number of documents in the snapshot.
107    pub fn size(&self) -> usize {
108        self.documents.len()
109    }
110
111    /// The time this snapshot was read.
112    pub fn read_time(&self) -> Option<&str> {
113        self.read_time.as_deref()
114    }
115
116    /// Iterates over the document snapshots.
117    pub fn iter(&self) -> std::slice::Iter<'_, DocumentSnapshot<'a>> {
118        self.documents.iter()
119    }
120}
121
122impl<'a> IntoIterator for &'a QuerySnapshot<'a> {
123    type Item = &'a DocumentSnapshot<'a>;
124    type IntoIter = std::slice::Iter<'a, DocumentSnapshot<'a>>;
125
126    fn into_iter(self) -> Self::IntoIter {
127        self.documents.iter()
128    }
129}
130
131/// The result of a write operation.
132#[derive(Debug, Clone)]
133pub struct WriteResult {
134    /// The time the write occurred.
135    pub write_time: String,
136}