firestore_db_and_auth/documents/
list.rs1use super::*;
2use bytes::Bytes;
3use core::pin::Pin;
4use futures::{
5 stream::{self, Stream},
6 task::{Context, Poll},
7 Future,
8};
9use std::boxed::Box;
10
11pub fn list<T, AUTH>(
45 auth: &AUTH,
46 collection_id: impl Into<String>,
47) -> Pin<Box<dyn Stream<Item = Result<(T, dto::Document)>> + Send>>
48where
49 for<'b> T: Deserialize<'b> + 'static,
50 AUTH: FirebaseAuthBearer + Clone + Send + Sync + 'static,
51{
52 let auth = auth.clone();
53 let collection_id = collection_id.into();
54
55 Box::pin(stream::unfold(
56 ListInner {
57 url: firebase_url(auth.project_id(), &collection_id),
58 auth,
59 next_page_token: None,
60 documents: vec![],
61 current: 0,
62 done: false,
63 collection_id: collection_id.to_string(),
64 },
65 |this| async move {
66 let mut this = this.clone();
67 if this.done {
68 return None;
69 }
70
71 if this.documents.len() <= this.current {
72 let url = match &this.next_page_token {
73 Some(next_page_token) => format!("{}pageToken={}", this.url, next_page_token),
74 None => this.url.clone(),
75 };
76
77 let result = get_new_data(&this.collection_id, &url, &this.auth).await;
78 match result {
79 Err(e) => {
80 this.done = true;
81 return Some((Err(e), this));
82 }
83 Ok(v) => match v.documents {
84 None => return None,
85 Some(documents) => {
86 this.documents = documents;
87 this.current = 0;
88 this.next_page_token = v.next_page_token;
89 }
90 },
91 }
92 }
93
94 let doc = this.documents.get(this.current).unwrap().clone();
95
96 this.current += 1;
97
98 if this.documents.len() <= this.current && this.next_page_token.is_none() {
99 this.done = true;
100 }
101
102 let result = document_to_pod(&doc, None);
103 match result {
104 Err(e) => Some((Err(e), this)),
105 Ok(pod) => Some((
106 Ok((
107 pod,
108 dto::Document {
109 update_time: doc.update_time.clone(),
110 create_time: doc.create_time.clone(),
111 name: doc.name.clone(),
112 fields: None,
113 },
114 )),
115 this,
116 )),
117 }
118 },
119 ))
120}
121
122async fn get_new_data<'a>(
123 collection_id: &str,
124 url: &str,
125 auth: &'a impl FirebaseAuthBearer,
126) -> Result<dto::ListDocumentsResponse> {
127 let resp = auth
128 .client()
129 .get(url)
130 .bearer_auth(auth.access_token().await)
131 .send()
132 .await?;
133
134 let resp = extract_google_api_error_async(resp, || collection_id.to_owned()).await?;
135
136 let json: dto::ListDocumentsResponse = resp.json().await?;
137 Ok(json)
138}
139
140#[derive(Clone)]
141struct ListInner<AUTH> {
142 auth: AUTH,
143 next_page_token: Option<String>,
144 documents: Vec<dto::Document>,
145 current: usize,
146 done: bool,
147 url: String,
148 collection_id: String,
149}