use crate::select_order_builder::FirestoreQueryOrderBuilder;
use crate::{
FirestoreListCollectionIdsParams, FirestoreListCollectionIdsResult, FirestoreListDocParams,
FirestoreListDocResult, FirestoreListingSupport, FirestoreQueryOrder, FirestoreRequestOptions,
FirestoreRequestTag, FirestoreResult,
};
use futures::stream::BoxStream;
use gcloud_sdk::google::firestore::v1::Document;
use serde::Deserialize;
use std::marker::PhantomData;
#[derive(Clone, Debug)]
pub struct FirestoreListingInitialBuilder<'a, D>
where
D: FirestoreListingSupport,
{
db: &'a D,
return_only_fields: Option<Vec<String>>,
}
impl<'a, D> FirestoreListingInitialBuilder<'a, D>
where
D: FirestoreListingSupport,
{
#[inline]
pub(crate) fn new(db: &'a D) -> Self {
Self {
db,
return_only_fields: None,
}
}
#[inline]
pub fn fields<I>(self, return_only_fields: I) -> Self
where
I: IntoIterator,
I::Item: AsRef<str>,
{
Self {
return_only_fields: Some(
return_only_fields
.into_iter()
.map(|field| field.as_ref().to_string())
.collect(),
),
..self
}
}
#[inline]
pub fn from<S: AsRef<str>>(self, collection: S) -> FirestoreListingDocBuilder<'a, D> {
let params: FirestoreListDocParams =
FirestoreListDocParams::new(collection.as_ref().to_string())
.opt_return_only_fields(self.return_only_fields);
FirestoreListingDocBuilder::new(self.db, params)
}
#[inline]
pub fn collections(self) -> FirestoreListCollectionIdsBuilder<'a, D> {
FirestoreListCollectionIdsBuilder::new(self.db)
}
}
#[derive(Clone, Debug)]
pub struct FirestoreListingDocBuilder<'a, D>
where
D: FirestoreListingSupport,
{
db: &'a D,
params: FirestoreListDocParams,
}
impl<'a, D> FirestoreListingDocBuilder<'a, D>
where
D: FirestoreListingSupport,
{
#[inline]
pub(crate) fn new(db: &'a D, params: FirestoreListDocParams) -> Self {
Self { db, params }
}
#[inline]
pub fn obj<T>(self) -> FirestoreListingObjBuilder<'a, D, T>
where
T: Send,
for<'de> T: Deserialize<'de>,
{
FirestoreListingObjBuilder::new(self.db, self.params)
}
#[inline]
pub fn parent<S>(self, parent: S) -> Self
where
S: AsRef<str>,
{
Self {
params: self.params.with_parent(parent.as_ref().to_string()),
..self
}
}
#[inline]
pub fn page_size(self, value: usize) -> Self {
Self {
params: self.params.with_page_size(value),
..self
}
}
#[inline]
pub fn page_token(self, value: String) -> Self {
Self {
params: self.params.with_page_token(value),
..self
}
}
#[deprecated(
since = "0.55.0",
note = "Superseded by `.order()`, which takes a closure builder: \
`.order(|o| o.fields([o.field(path!(T::some_num)).desc()]))`. \
This method keeps working and will not be removed in 0.x."
)]
#[inline]
pub fn order_by<I>(self, fields: I) -> Self
where
I: IntoIterator,
I::Item: Into<FirestoreQueryOrder>,
{
Self {
params: self
.params
.with_order_by(fields.into_iter().map(|field| field.into()).collect()),
..self
}
}
#[inline]
pub fn order<FN>(self, order: FN) -> Self
where
FN: Fn(FirestoreQueryOrderBuilder) -> Vec<FirestoreQueryOrder>,
{
let orders = order(FirestoreQueryOrderBuilder::new());
Self {
params: self.params.opt_order_by(if orders.is_empty() {
None
} else {
Some(orders)
}),
..self
}
}
#[inline]
pub fn request_tags<I>(self, request_tags: I) -> Self
where
I: IntoIterator,
I::Item: Into<FirestoreRequestTag>,
{
self.request_options(FirestoreRequestOptions::from_tags(request_tags))
}
#[inline]
pub fn request_options(self, options: FirestoreRequestOptions) -> Self {
Self {
params: self.params.with_request_options(options),
..self
}
}
pub async fn get_page(self) -> FirestoreResult<FirestoreListDocResult> {
self.db.list_doc(self.params).await
}
pub async fn stream_all<'b>(self) -> FirestoreResult<BoxStream<'b, Document>> {
self.db.stream_list_doc(self.params).await
}
pub async fn stream_all_with_errors<'b>(
self,
) -> FirestoreResult<BoxStream<'b, FirestoreResult<Document>>> {
self.db.stream_list_doc_with_errors(self.params).await
}
}
#[derive(Clone, Debug)]
pub struct FirestoreListingObjBuilder<'a, D, T>
where
D: FirestoreListingSupport,
T: Send,
for<'de> T: Deserialize<'de>,
{
db: &'a D,
params: FirestoreListDocParams,
_pd: PhantomData<T>,
}
impl<'a, D, T> FirestoreListingObjBuilder<'a, D, T>
where
D: FirestoreListingSupport,
T: Send,
for<'de> T: Deserialize<'de>,
{
pub(crate) fn new(
db: &'a D,
params: FirestoreListDocParams,
) -> FirestoreListingObjBuilder<'a, D, T> {
Self {
db,
params,
_pd: PhantomData,
}
}
#[inline]
pub fn request_tags<I>(self, request_tags: I) -> Self
where
I: IntoIterator,
I::Item: Into<FirestoreRequestTag>,
{
self.request_options(FirestoreRequestOptions::from_tags(request_tags))
}
#[inline]
pub fn request_options(self, options: FirestoreRequestOptions) -> Self {
Self {
params: self.params.with_request_options(options),
..self
}
}
pub async fn stream_all<'b>(self) -> FirestoreResult<BoxStream<'b, T>>
where
T: 'b,
{
self.db.stream_list_obj(self.params).await
}
pub async fn stream_all_with_errors<'b>(
self,
) -> FirestoreResult<BoxStream<'b, FirestoreResult<T>>>
where
T: 'b,
{
self.db.stream_list_obj_with_errors(self.params).await
}
}
#[derive(Clone, Debug)]
pub struct FirestoreListCollectionIdsBuilder<'a, D>
where
D: FirestoreListingSupport,
{
db: &'a D,
params: FirestoreListCollectionIdsParams,
}
impl<'a, D> FirestoreListCollectionIdsBuilder<'a, D>
where
D: FirestoreListingSupport,
{
#[inline]
pub(crate) fn new(db: &'a D) -> Self {
Self {
db,
params: FirestoreListCollectionIdsParams::new(),
}
}
#[inline]
pub fn parent<S>(self, parent: S) -> Self
where
S: AsRef<str>,
{
Self {
params: self.params.with_parent(parent.as_ref().to_string()),
..self
}
}
#[inline]
pub fn page_size(self, value: usize) -> Self {
Self {
params: self.params.with_page_size(value),
..self
}
}
#[inline]
pub fn request_tags<I>(self, request_tags: I) -> Self
where
I: IntoIterator,
I::Item: Into<FirestoreRequestTag>,
{
self.request_options(FirestoreRequestOptions::from_tags(request_tags))
}
#[inline]
pub fn request_options(self, options: FirestoreRequestOptions) -> Self {
Self {
params: self.params.with_request_options(options),
..self
}
}
pub async fn get_page(self) -> FirestoreResult<FirestoreListCollectionIdsResult> {
self.db.list_collection_ids(self.params).await
}
pub async fn stream_all(self) -> FirestoreResult<BoxStream<'a, String>> {
self.db.stream_list_collection_ids(self.params).await
}
pub async fn stream_all_with_errors(
self,
) -> FirestoreResult<BoxStream<'a, FirestoreResult<String>>> {
self.db
.stream_list_collection_ids_with_errors(self.params)
.await
}
}
#[cfg(test)]
mod tests {
use crate::fluent_api::tests::*;
use crate::fluent_api::FirestoreExprBuilder;
use crate::{path, FirestoreQueryDirection, FirestoreQueryOrder, FirestoreRequestOptions};
#[test]
fn list_doc_builder_request_tags() {
let builder = FirestoreExprBuilder::new(&mockdb::MockDatabase {})
.list()
.from("test")
.request_tags(["tag-1", "tag-2"]);
assert_eq!(
builder.params.request_options,
Some(FirestoreRequestOptions::from_tags(["tag-1", "tag-2"]))
)
}
#[test]
fn list_collection_ids_builder_request_tags() {
let builder = FirestoreExprBuilder::new(&mockdb::MockDatabase {})
.list()
.collections()
.request_tags(["tag-1"]);
assert_eq!(
builder.params.request_options,
Some(FirestoreRequestOptions::from_tags(["tag-1"]))
)
}
#[test]
fn list_doc_builder_order() {
let builder = FirestoreExprBuilder::new(&mockdb::MockDatabase {})
.list()
.from("test")
.order(|o| {
o.fields([
o.field(path!(TestStructure::some_num)).desc(),
o.field(path!(TestStructure::some_id)).asc(),
])
});
assert_eq!(
builder.params.order_by,
Some(vec![
FirestoreQueryOrder::new(
path!(TestStructure::some_num),
FirestoreQueryDirection::Descending
),
FirestoreQueryOrder::new(
path!(TestStructure::some_id),
FirestoreQueryDirection::Ascending
),
])
)
}
#[test]
fn list_doc_builder_order_empty_is_none() {
let builder = FirestoreExprBuilder::new(&mockdb::MockDatabase {})
.list()
.from("test")
.order(|o| o.fields(Vec::<FirestoreQueryOrder>::new()));
assert_eq!(builder.params.order_by, None)
}
#[test]
#[allow(deprecated)]
fn list_doc_builder_order_by_tuples_are_still_accepted() {
let tuple_builder = FirestoreExprBuilder::new(&mockdb::MockDatabase {})
.list()
.from("test")
.order_by([(
path!(TestStructure::some_num),
FirestoreQueryDirection::Descending,
)]);
let closure_builder = FirestoreExprBuilder::new(&mockdb::MockDatabase {})
.list()
.from("test")
.order(|o| o.fields([o.field(path!(TestStructure::some_num)).desc()]));
assert_eq!(tuple_builder.params, closure_builder.params);
}
}