Skip to content

Commit 0320f8b

Browse files
committed
Rename: collection() requires trait Document
1 parent 0070ab2 commit 0320f8b

File tree

11 files changed

+173
-80
lines changed

11 files changed

+173
-80
lines changed

typesense/src/client/collection/document.rs

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,31 @@
22
//!
33
//! An instance of `Document` is scoped to a specific document and is created
44
//! via a parent `Collection` struct, for example:
5-
//! `client.collection::<Book>("books").document("123")`
5+
//! `client.collection::<Book>().document("123")`
66
77
use crate::{Client, Error, execute_wrapper};
88
use serde::{Serialize, de::DeserializeOwned};
99
use typesense_codegen::apis::documents_api;
1010

1111
/// Provides methods for interacting with a single document within a specific Typesense collection.
1212
///
13-
/// This struct is created by calling a method like `client.collection("collection_name").document("document_id")` or `client.collection_of::<MyType>("collection_name").document("document_id")`.
14-
/// The generic `T` represents the shape of the document and must implement `Serialize` and `DeserializeOwned`.
15-
/// If `T` is not specified, it defaults to `serde_json::Value` for schemaless interactions.
13+
/// This struct is created by calling a method like `client.collection_schemaless("collection_name").document("document_id")`
14+
/// or `client.collection::<MyType>().document("document_id")`.
15+
/// The generic `D` represents the shape of the document and must implement `Serialize` and `DeserializeOwned`.
16+
/// If `D` is not specified, it defaults to `serde_json::Value` for schemaless interactions.
1617
pub struct Document<'c, 'n, D = serde_json::Value>
1718
where
18-
D: DeserializeOwned + Serialize + Send + Sync,
19+
D: DeserializeOwned + Serialize,
1920
{
20-
pub(super) client: &'c Client,
21-
pub(super) collection_name: &'n str,
22-
pub(super) document_id: String,
23-
pub(super) _phantom: std::marker::PhantomData<D>,
21+
client: &'c Client,
22+
collection_name: &'n str,
23+
document_id: String,
24+
_phantom: std::marker::PhantomData<D>,
2425
}
2526

2627
impl<'c, 'n, D> Document<'c, 'n, D>
2728
where
28-
D: DeserializeOwned + Serialize + Send + Sync,
29+
D: DeserializeOwned + Serialize,
2930
{
3031
/// Creates a new `Document` instance for a specific document ID.
3132
#[inline]
@@ -38,10 +39,10 @@ where
3839
}
3940
}
4041

41-
/// Fetches this individual document from the collection and deserializes it into `T`.
42+
/// Fetches this individual document from the collection and deserializes it into `D`.
4243
///
4344
/// # Returns
44-
/// A `Result` containing the strongly-typed document `T` if successful.
45+
/// A `Result` containing the strongly-typed document `D` if successful.
4546
pub async fn retrieve(&self) -> Result<D, Error<documents_api::GetDocumentError>> {
4647
let params = documents_api::GetDocumentParams {
4748
collection_name: self.collection_name.to_owned(),
@@ -62,7 +63,7 @@ where
6263
/// * `params` - An optional `DocumentIndexParameters` struct to specify additional parameters, such as `dirty_values` which determines what Typesense should do when the type of a particular field being indexed does not match the previously inferred type for that field, or the one defined in the collection's schema.
6364
///
6465
/// # Returns
65-
/// A `Result` containing the full, updated document deserialized into `T`.
66+
/// A `Result` containing the full, updated document deserialized into `D`.
6667
///
6768
/// # Example
6869
/// ```no_run
@@ -81,15 +82,15 @@ where
8182
/// let book_update = serde_json::json!({ "pages": 654 });
8283
///
8384
/// // Simple update
84-
/// let updated_book = client.collection_of::<Book>("books").document("123")
85+
/// let updated_book = client.collection_named::<Book>("books").document("123")
8586
/// .update(&book_update, None)
8687
/// .await?;
8788
///
8889
/// // Update with additional parameters
8990
/// let params = models::DocumentIndexParameters {
9091
/// dirty_values: Some(models::DirtyValues::CoerceOrReject),
9192
/// };
92-
/// let updated_book_with_params = client.collection_of::<Book>("books").document("124")
93+
/// let updated_book_with_params = client.collection_named::<Book>("books").document("124")
9394
/// .update(&book_update, Some(params))
9495
/// .await?;
9596
/// #
@@ -118,7 +119,7 @@ where
118119
/// The deleted document is returned.
119120
///
120121
/// # Returns
121-
/// A `Result` containing the deleted document deserialized into `T`.
122+
/// A `Result` containing the deleted document deserialized into `D`.
122123
pub async fn delete(&self) -> Result<D, Error<documents_api::DeleteDocumentError>> {
123124
let params = documents_api::DeleteDocumentParams {
124125
collection_name: self.collection_name.to_owned(),

typesense/src/client/collection/documents.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! Provides access to the document, search, and override-related API endpoints.
22
//!
33
//! An instance of `Documents` is scoped to a specific collection and is created
4-
//! via the main `client.collection("collection_name").documents()` method or
5-
//! `client.collection_of::<T>("...").documents()`.
4+
//! via the main `client.collection_schemaless("collection_name").documents()` method or
5+
//! `client.collection_named::<T>("...").documents()`.
66
77
use crate::{
88
Client, Error, execute_wrapper,
@@ -18,21 +18,21 @@ use typesense_codegen::{
1818
};
1919
/// Provides methods for interacting with documents within a specific Typesense collection.
2020
///
21-
/// This struct is generic over the document type `T`. If created via `client.collection(...)`,
22-
/// `T` defaults to `serde_json::Value`. If created via `client.collection_of::<MyType>(...)`,
23-
/// `T` will be `MyType`.
21+
/// This struct is generic over the document type `D`. If created via `client.collection_schemaless(...)`,
22+
/// `D` defaults to `serde_json::Value`. If created via `client.collection_named::<MyType>(...)`,
23+
/// `D` will be `MyType`.
2424
pub struct Documents<'c, 'n, D = serde_json::Value>
2525
where
26-
D: DeserializeOwned + Serialize + Send + Sync,
26+
D: DeserializeOwned + Serialize,
2727
{
28-
pub(super) client: &'c Client,
29-
pub(super) collection_name: &'n str,
30-
pub(super) _phantom: std::marker::PhantomData<D>,
28+
client: &'c Client,
29+
collection_name: &'n str,
30+
_phantom: std::marker::PhantomData<D>,
3131
}
3232

3333
impl<'c, 'n, D> Documents<'c, 'n, D>
3434
where
35-
D: DeserializeOwned + Serialize + Send + Sync,
35+
D: DeserializeOwned + Serialize,
3636
{
3737
/// Creates a new `Documents` instance.
3838
#[inline]
@@ -85,7 +85,7 @@ where
8585
/// Creates a new document or updates an existing one if an ID match is found.
8686
///
8787
/// This method requires the full document to be sent. For partial updates, use
88-
/// `collection("...").document("...").update()`. The indexed document is returned.
88+
/// `collection().document("...").update()`. The indexed document is returned.
8989
///
9090
/// # Arguments
9191
/// * `document` - A serializable struct or a `serde_json::Value` representing the document to upsert.
@@ -184,7 +184,7 @@ where
184184
}
185185

186186
/// Searches for documents in the collection that match the given criteria.
187-
/// The search results will have their `document` field deserialized into type `T`.
187+
/// The search results will have their `document` field deserialized into type `D`.
188188
///
189189
/// # Arguments
190190
/// * `params` - A `SearchParameters` struct containing all search parameters.

typesense/src/client/collection/mod.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,19 @@ use typesense_codegen::{apis::collections_api, models};
1111

1212
/// Provides methods for interacting with a Typesense collection.
1313
///
14-
/// This struct is created by calling `client.collection("collection_name")`.
14+
/// This struct is created by calling `client.collection()`.
1515
pub struct Collection<'c, 'n, D = serde_json::Value>
1616
where
17-
D: DeserializeOwned + Serialize + Send + Sync,
17+
D: DeserializeOwned + Serialize,
1818
{
19-
pub(super) client: &'c Client,
20-
pub(super) collection_name: &'n str,
21-
pub(super) _phantom: std::marker::PhantomData<D>,
19+
client: &'c Client,
20+
collection_name: &'n str,
21+
_phantom: std::marker::PhantomData<D>,
2222
}
2323

2424
impl<'c, 'n, D> Collection<'c, 'n, D>
2525
where
26-
D: DeserializeOwned + Serialize + Send + Sync,
26+
D: DeserializeOwned + Serialize,
2727
{
2828
/// Creates a new `Collection` instance.
2929
#[inline]

typesense/src/client/mod.rs

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
//! .unwrap();
3434
//!
3535
//! // Retrieve details for a collection
36-
//! let collection = client.collection("products").retrieve().await?;
36+
//! let collection = client.collection_schemaless("products").retrieve().await?;
3737
//! println!("Collection Name: {}", collection.name);
3838
//!
3939
//! // Search for a document
@@ -44,7 +44,7 @@
4444
//! };
4545
//!
4646
//! let search_results = client
47-
//! .collection("products")
47+
//! .collection_schemaless("products")
4848
//! .documents()
4949
//! .search(search_params)
5050
//! .await?;
@@ -84,7 +84,7 @@
8484
//! .unwrap();
8585
//!
8686
//! // Retrieve details for a collection
87-
//! match client.collection("products").retrieve().await {
87+
//! match client.collection_schemaless("products").retrieve().await {
8888
//! Ok(collection) => println!("Collection Name: {}", collection.name),
8989
//! Err(e) => eprintln!("Error retrieving collection: {}", e),
9090
//! }
@@ -96,7 +96,7 @@
9696
//! ..Default::default()
9797
//! };
9898
//!
99-
//! match client.collection("products").documents().search(search_params).await {
99+
//! match client.collection_schemaless("products").documents().search(search_params).await {
100100
//! Ok(search_results) => {
101101
//! println!("Found {} hits.", search_results.found.unwrap_or(0));
102102
//! }
@@ -112,7 +112,7 @@ mod key;
112112
mod keys;
113113
mod multi_search;
114114

115-
use crate::Error;
115+
use crate::{Error, traits::Document};
116116
use collection::Collection;
117117
use collections::Collections;
118118
use key::Key;
@@ -368,7 +368,7 @@ impl Client {
368368
/// stored in that collection.
369369
///
370370
/// # Type Parameters
371-
/// * `T` - The type of the documents in the collection. It must be serializable and deserializable.
371+
/// * `D` - The type of the documents in the collection. It must be serializable and deserializable.
372372
///
373373
/// # Arguments
374374
/// * `collection_name` - The name of the collection to interact with.
@@ -392,7 +392,7 @@ impl Client {
392392
/// # .build()
393393
/// # .unwrap();
394394
/// // Get a typed handle to the "books" collection
395-
/// let books_collection = client.collection_of::<Book>("books");
395+
/// let books_collection = client.collection_named::<Book>("books");
396396
///
397397
/// // Retrieve a single book, it returns `Result<Book, ...>`
398398
/// let book = books_collection.document("123").retrieve().await?;
@@ -403,17 +403,62 @@ impl Client {
403403
/// # }
404404
/// ```
405405
#[inline]
406-
pub fn collection_of<'c, 'n, T>(&'c self, collection_name: &'n str) -> Collection<'c, 'n, T>
406+
pub fn collection_named<'c, 'n, D>(&'c self, collection_name: &'n str) -> Collection<'c, 'n, D>
407407
where
408-
T: DeserializeOwned + Serialize + Send + Sync,
408+
D: DeserializeOwned + Serialize,
409409
{
410410
Collection::new(self, collection_name)
411411
}
412412

413+
/// Provides access to API endpoints for a specific collection.
414+
///
415+
/// This method returns a `Collection<T>` handle, which is generic over the type of document
416+
/// stored in that collection.
417+
///
418+
/// # Type Parameters
419+
/// * `D` - The type of the documents in the collection. It must be of trait Document.
420+
///
421+
/// # Example: Working with a strongly-typed collection
422+
///
423+
/// When you want to retrieve or search for documents and have them automatically
424+
/// deserialized into your own structs.
425+
/// ```no_run
426+
/// # #[cfg(not(target_family = "wasm"))]
427+
/// # {
428+
/// # use typesense::{Client, Typesense};
429+
/// # use serde::{Serialize, Deserialize};
430+
/// #
431+
/// # #[derive(Typesense, Serialize, Deserialize, Debug)]
432+
/// # struct Book { id: String, title: String }
433+
/// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
434+
/// # let client = Client::builder()
435+
/// # .nodes(vec!["http://localhost:8108"])
436+
/// # .api_key("xyz")
437+
/// # .build()
438+
/// # .unwrap();
439+
/// // Get a typed handle to the "books" collection
440+
/// let books_collection = client.collection::<Book>();
441+
///
442+
/// // Retrieve a single book, it returns `Result<Book, ...>`
443+
/// let book = books_collection.document("123").retrieve().await?;
444+
/// println!("Retrieved book: {:?}", book);
445+
/// #
446+
/// # Ok(())
447+
/// # }
448+
/// # }
449+
/// ```
450+
#[inline]
451+
pub fn collection<'c, 'n, D>(&'c self) -> Collection<'c, 'n, D>
452+
where
453+
D: Document,
454+
{
455+
Collection::new(self, D::COLLECTION_NAME)
456+
}
457+
413458
/// Provides access to API endpoints for a specific collection using schemaless `serde_json::Value` documents.
414459
///
415460
/// This is the simplest way to interact with a collection when you do not need strong typing.
416-
/// It is a convenient shorthand for `client.collection_of::<serde_json::Value>("...")`.
461+
/// It is a convenient shorthand for `client.collection_named::<serde_json::Value>("...")`.
417462
///
418463
/// The returned handle can be used for both document operations (which will return `serde_json::Value`)
419464
/// and collection-level operations (like `.delete()` or `.retrieve()`).
@@ -432,18 +477,18 @@ impl Client {
432477
/// # .api_key("xyz")
433478
/// # .build()
434479
/// # .unwrap();
435-
/// let products_collection = client.collection("products");
480+
/// let products_collection = client.collection_schemaless("products");
436481
/// #
437482
/// # Ok(())
438483
/// # }
439484
/// # }
440485
/// ```
441486
#[inline]
442-
pub fn collection<'c, 'n>(
487+
pub fn collection_schemaless<'c, 'n>(
443488
&'c self,
444489
collection_name: &'n str,
445490
) -> Collection<'c, 'n, serde_json::Value> {
446-
self.collection_of(collection_name)
491+
Collection::new(self, collection_name)
447492
}
448493

449494
/// Provides access to endpoints for managing the collection of API keys.

typesense/src/traits/document.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ use serde::{Serialize, de::DeserializeOwned};
99
/// Trait that should implement every struct that wants to be represented as a Typesense
1010
/// Document
1111
pub trait Document: DeserializeOwned + Serialize {
12+
/// Collection name
13+
const COLLECTION_NAME: &'static str;
14+
1215
/// Collection schema associated with the document.
1316
fn collection_schema() -> CollectionSchema;
1417
}

typesense/src/traits/multi_search_ext.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ pub trait MultiSearchResultExt {
1212
/// * `index` - The zero-based index of the search result to parse.
1313
///
1414
/// # Type Parameters
15-
/// * `T` - The concrete document type to deserialize the hits into.
16-
fn parse_at<T: DeserializeOwned>(
15+
/// * `D` - The concrete document type to deserialize the hits into.
16+
fn parse_at<D: DeserializeOwned>(
1717
&self,
1818
index: usize,
19-
) -> Result<SearchResult<T>, MultiSearchParseError>;
19+
) -> Result<SearchResult<D>, MultiSearchParseError>;
2020
}
2121

2222
/// Small helpers to convert documents stored as `serde_json::Value` into a concrete `D`.

0 commit comments

Comments
 (0)