firestore_db_and_auth/documents/
query.rs

1use super::*;
2use std::vec::IntoIter;
3
4///
5/// Queries the database for specific documents, for example all documents in a collection of 'type' == "car".
6///
7/// Example:
8/// ```no_run
9/// # use serde::{Serialize, Deserialize};
10/// #[derive(Debug, Serialize, Deserialize)]
11/// struct DemoDTO { a_string: String, an_int: u32, }
12///
13/// use firestore_db_and_auth::{documents, dto};
14/// # use firestore_db_and_auth::{credentials::Credentials, ServiceSession, errors::Result};
15/// # use firestore_db_and_auth::credentials::doctest_credentials;
16/// # tokio_test::block_on(async {
17/// # let session = ServiceSession::new(doctest_credentials().await).await.unwrap();
18///
19/// let values: documents::Query = documents::query(&session, "tests", "Sam Weiss".into(), dto::FieldOperator::EQUAL, "id").await.unwrap();
20/// for metadata in values {
21///     println!("id: {}, created: {}, updated: {}", &metadata.name, metadata.create_time.as_ref().unwrap(), metadata.update_time.as_ref().unwrap());
22///     // Fetch the actual document
23///     // The data is wrapped in a Result<> because fetching new data could have failed
24///     let doc : DemoDTO = documents::read_by_name(&session, &metadata.name).await.unwrap();
25///     println!("{:?}", doc);
26/// }
27/// # })
28/// ```
29///
30/// ## Arguments
31/// * 'auth' The authentication token
32/// * 'collectionid' The collection id; "my_collection" or "a/nested/collection"
33/// * 'value' The query / filter value. For example "car".
34/// * 'operator' The query operator. For example "EQUAL".
35/// * 'field' The query / filter field. For example "type".
36pub async fn query(
37    auth: &impl FirebaseAuthBearer,
38    collection_id: &str,
39    value: serde_json::Value,
40    operator: dto::FieldOperator,
41    field: &str,
42) -> Result<Query> {
43    let url = firebase_url_query(auth.project_id());
44    let value = crate::firebase_rest_to_rust::serde_value_to_firebase_value(&value);
45
46    let query_request = dto::RunQueryRequest {
47        structured_query: Some(dto::StructuredQuery {
48            select: Some(dto::Projection { fields: None }),
49            where_: Some(dto::Filter {
50                field_filter: Some(dto::FieldFilter {
51                    value,
52                    op: operator,
53                    field: dto::FieldReference {
54                        field_path: field.to_owned(),
55                    },
56                }),
57                ..Default::default()
58            }),
59            from: Some(vec![dto::CollectionSelector {
60                collection_id: Some(collection_id.to_owned()),
61                ..Default::default()
62            }]),
63            ..Default::default()
64        }),
65        ..Default::default()
66    };
67
68    let resp = auth
69        .client()
70        .post(&url)
71        .bearer_auth(auth.access_token().await)
72        .json(&query_request)
73        .send()
74        .await?;
75
76    let resp = extract_google_api_error_async(resp, || collection_id.to_owned()).await?;
77
78    let json: Option<Vec<dto::RunQueryResponse>> = resp.json().await?;
79
80    Ok(Query(json.unwrap_or_default().into_iter()))
81}
82
83/// This type is returned as a result by [`query`].
84/// Use it as an iterator. The query API returns a list of document references, not the documents itself.
85///
86/// If you just need the meta data like the document name or update time, you are already settled.
87/// To fetch the document itself, use [`read_by_name`].
88///
89/// Please note that this API acts as an iterator of same-like documents.
90/// This type is not suitable if you want to list documents of different types.
91#[derive(Debug)]
92pub struct Query(IntoIter<dto::RunQueryResponse>);
93
94impl Iterator for Query {
95    type Item = dto::Document;
96
97    // Skip empty entries
98    fn next(&mut self) -> Option<Self::Item> {
99        while let Some(r) = self.0.next() {
100            if let Some(document) = r.document {
101                return Some(document);
102            }
103        }
104        return None;
105    }
106}