firestore 0.61.1

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

`FirestoreDocumentId` and `FirestoreCollectionId` are validated newtypes for IDs that arrive from
outside your process - a request path segment, a JSON body, a runtime-chosen collection name.
Construct one where the ID enters your system; a `/`, an empty string, or `.`/`..` is rejected
there instead of silently reaching Firestore or, in the case of a collection name, retargeting the
operation at a different collection.

```rust
# use firestore::*;
# fn example() -> Result<(), Box<dyn std::error::Error>> {
let id = FirestoreDocumentId::new("user-42")?;
let collection = FirestoreCollectionId::new("users")?;
# let _ = (id, collection);
# Ok(())
# }
```

A name known up front - the sort of thing you would today write as `const NAME: &str = "..."` -
can be declared as a validated `const` or `static` with `from_static`. An invalid literal there is
a compile error, not a runtime one:

```rust
# use firestore::*;
const USERS: FirestoreCollectionId = FirestoreCollectionId::from_static("users");
```

Use `from_static` for a literal you control, checked at compile time with no `Result` to handle;
use `new` for a value arriving at runtime, which returns a `FirestoreResult`.

Both implement `AsRef<str>`, so a reference drops straight into any call that already takes a
document or collection ID or name, with no conversion:

```rust,no_run
# use firestore::*;
# use serde::{Deserialize, Serialize};
# #[derive(Debug, Clone, Deserialize, Serialize)]
# struct MyTestStructure { some_id: String }
# async fn example(
#     db: FirestoreDb,
#     collection: FirestoreCollectionId,
#     id: FirestoreDocumentId,
# ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
db.fluent()
    .select()
    .by_id_in(&collection)
    .obj::<MyTestStructure>()
    .one(&id)
    .await?;
# Ok(())
# }
```

Store the validated type in your own structs instead of a bare `String` to carry the proof along
with the value; it deserializes through the same validation, so a `CreateSession` built from an
untrusted request body rejects a bad ID before it reaches Firestore:

```rust
# use firestore::*;
# use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Deserialize, Serialize)]
struct CreateSession {
    user_id: FirestoreDocumentId,
}
```

See `examples/crud.rs` and `examples/nested_collections.rs` for a document ID and a
`parent_path`/`at` pair built from validated IDs, and `examples/dynamic_doc_level_crud.rs` /
`examples/caching_dynamic_collections.rs` for a collection name chosen at runtime.