firestore 0.61.1

Library provides a simple API for Google Firestore and own Serde serializer based on efficient gRPC API
Documentation
# Querying

The library supports rich querying API with filters, ordering, pagination, etc.

```rust,no_run
# use firestore::*;
# use futures::stream::BoxStream;
# use futures::TryStreamExt;
# use serde::{Deserialize, Serialize};
# #[derive(Debug, Clone, Deserialize, Serialize)]
# struct MyTestStructure {
#     some_id: String,
#     some_string: String,
#     one_more_string: String,
#     some_num: u64,
#     created_at: FirestoreTimestamp,
# }
# const TEST_COLLECTION_NAME: &str = "test-query";
# async fn example(db: FirestoreDb) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
// Query as a stream our data
let object_stream: BoxStream<FirestoreResult<MyTestStructure>> = db
    .fluent()
    .select()
    .fields(
        paths!(MyTestStructure::{some_id, some_num, some_string, one_more_string, created_at}),
    ) // Optionally select the fields needed
    .from(TEST_COLLECTION_NAME)
    .filter(|q| {
        // Fluent filter API example
        q.for_all([
            q.field(path!(MyTestStructure::some_num)).is_not_null(),
            q.field(path!(MyTestStructure::some_string)).eq("Test"),
            // Sometimes you have optional filters
            Some("Test2")
                .and_then(|value| q.field(path!(MyTestStructure::one_more_string)).eq(value)),
        ])
    })
    .order(|o| o.fields([o.field(path!(MyTestStructure::some_num)).desc()]))
    .obj() // Reading documents as structures using Serde gRPC deserializer
    .stream_query_with_errors()
    .await?;

let as_vec: Vec<MyTestStructure> = object_stream.try_collect().await?;
println!("{:?}", as_vec);
# Ok(())
# }
```

## Filtering

`.filter()` takes a closure that receives a filter builder and returns an
`Option<FirestoreQueryFilter>`. Conditions can be optional, since a `None` entry in the list is
dropped, as `one_more_string` in the example above.

Use:

- `q.for_all` for AND conditions
- `q.for_any` for OR conditions (Firestore has just recently added support for OR conditions)

You can nest `q.for_all`/`q.for_any`.

## Ordering

`.order()` takes a closure that receives an order builder and returns a `Vec`, the same shape as
`.filter()` and `.transforms()`. List multiple fields to sort by more than one, in priority order:

```rust,no_run
# use firestore::*;
# use serde::{Deserialize, Serialize};
# #[derive(Debug, Clone, Deserialize, Serialize)]
# struct MyTestStructure {
#     some_id: String,
#     some_num: u64,
# }
# const TEST_COLLECTION_NAME: &str = "test-query";
# async fn example(db: FirestoreDb) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let ordered: Vec<MyTestStructure> = db
    .fluent()
    .select()
    .from(TEST_COLLECTION_NAME)
    .order(|o| {
        o.fields([
            o.field(path!(MyTestStructure::some_num)).desc(),
            o.field(path!(MyTestStructure::some_id)).asc(),
        ])
    })
    .obj()
    .query()
    .await?;
# let _ = ordered;
# Ok(())
# }
```

An entry can be conditional, since `field(..).asc()`/`.desc()` return `Option<FirestoreQueryOrder>`
and `None` is dropped:

```rust,no_run
# use firestore::*;
# use serde::{Deserialize, Serialize};
# #[derive(Debug, Clone, Deserialize, Serialize)]
# struct MyTestStructure {
#     some_id: String,
#     some_num: u64,
# }
# const TEST_COLLECTION_NAME: &str = "test-query";
# async fn example(db: FirestoreDb, sort_by_num: bool) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let ordered: Vec<MyTestStructure> = db
    .fluent()
    .select()
    .from(TEST_COLLECTION_NAME)
    .order(|o| {
        o.fields([sort_by_num.then(|| o.field(path!(MyTestStructure::some_num)).desc())])
    })
    .obj()
    .query()
    .await?;
# let _ = ordered;
# Ok(())
# }
```

Each call to `.order()` replaces any ordering set by a previous call; it does not add to it. An
empty result (every entry conditional and every condition false) clears the ordering entirely.

If the query also uses `start_at`/`end_at`, the cursor's value count must match the number of
ordered fields - this is not enforced by the library, so a mismatch is a runtime error from
Firestore rather than a compile-time one.

`.order_by([(path!(..), FirestoreQueryDirection::Descending)])` still works but is deprecated in
favor of `.order()`.