Skip to content

Commit 0e4002c

Browse files
committed
feat: generic collection and library module restructuring
1 parent 0d96f6b commit 0e4002c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+825
-272
lines changed

typesense/src/client/alias.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//!
33
//! An `Alias` instance is created via the main `client.alias()` method.
44
5-
use super::{Client, Error};
5+
use crate::{Client, Error};
66
use std::sync::Arc;
77
use typesense_codegen::{
88
apis::{collections_api, configuration},

typesense/src/client/aliases.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//!
33
//! An `Aliases` instance is created via the main `client.aliases()` method.
44
5-
use super::{Client, Error};
5+
use crate::{Client, Error};
66
use std::sync::Arc;
77
use typesense_codegen::{
88
apis::{collections_api, configuration},

typesense/src/client/analytics/events.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//!
33
//! An `Events` instance is created via the `Client::analytics().events()` method.
44
5-
use super::{Client, Error};
5+
use crate::{Client, Error};
66
use std::sync::Arc;
77
use typesense_codegen::{
88
apis::{analytics_api, configuration},

typesense/src/client/analytics/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
pub mod events;
55
pub mod rule;
66
pub mod rules;
7-
use super::{Client, Error};
7+
use crate::Client;
88
pub use events::Events;
99
pub use rule::Rule;
1010
pub use rules::Rules;

typesense/src/client/analytics/rule.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//!
33
//! An `Rule` instance is created via the `Client::analytics().rule("rule_name")` method.
44
5-
use super::{Client, Error};
5+
use crate::{Client, Error};
66
use std::sync::Arc;
77
use typesense_codegen::{
88
apis::{analytics_api, configuration},

typesense/src/client/analytics/rules.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//!
33
//! An `Rules` instance is created via the `Client::analytics().rules()` method.
44
5-
use super::{Client, Error};
5+
use crate::{Client, Error};
66
use std::sync::Arc;
77
use typesense_codegen::{
88
apis::{analytics_api, configuration},

typesense/src/client/collection/document.rs

Lines changed: 99 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,84 +2,157 @@
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("collection_name").document("document_id")`
5+
//! `client.collection::<Book>("books").document("123")`
66
7-
use super::{Client, Error};
7+
use crate::{Client, Error};
8+
use serde::{de::DeserializeOwned, Serialize};
89
use std::sync::Arc;
9-
use typesense_codegen::apis::{configuration, documents_api};
10+
use typesense_codegen::{
11+
apis::{configuration, documents_api},
12+
models,
13+
};
1014

1115
/// Provides methods for interacting with a single document within a specific Typesense collection.
1216
///
13-
/// This struct is created by calling a method like `client.collection("collection_name").document("document_id")`.
14-
pub struct Document<'a> {
17+
/// This struct is created by calling a method like `client.collection::<T>("collection_name").document("document_id")`.
18+
/// The generic `T` represents the shape of the document and must implement `Serialize` and `DeserializeOwned`.
19+
/// If `T` is not specified, it defaults to `serde_json::Value` for schemaless interactions.
20+
pub struct Document<'a, T = serde_json::Value>
21+
where
22+
T: DeserializeOwned + Serialize + Send + Sync,
23+
{
1524
pub(super) client: &'a Client,
1625
pub(super) collection_name: &'a str,
1726
pub(super) document_id: &'a str,
27+
pub(super) _phantom: std::marker::PhantomData<T>,
1828
}
1929

20-
impl<'a> Document<'a> {
30+
impl<'a, T> Document<'a, T>
31+
where
32+
T: DeserializeOwned + Serialize + Send + Sync,
33+
{
2134
/// Creates a new `Document` instance for a specific document ID.
22-
/// This is intended for internal use by the parent `Documents` struct.
35+
/// This is intended for internal use by the parent `Collection` struct.
2336
pub(super) fn new(client: &'a Client, collection_name: &'a str, document_id: &'a str) -> Self {
2437
Self {
2538
client,
2639
collection_name,
2740
document_id,
41+
_phantom: std::marker::PhantomData,
2842
}
2943
}
3044

31-
/// Fetches this individual document from the collection.
32-
pub async fn retrieve(
33-
&self,
34-
) -> Result<serde_json::Value, Error<documents_api::GetDocumentError>> {
45+
/// Fetches this individual document from the collection and deserializes it into `T`.
46+
///
47+
/// # Returns
48+
/// A `Result` containing the strongly-typed document `T` if successful.
49+
pub async fn retrieve(&self) -> Result<T, Error<documents_api::GetDocumentError>> {
3550
let params = documents_api::GetDocumentParams {
3651
collection_name: self.collection_name.to_string(),
3752
document_id: self.document_id.to_string(),
3853
};
3954

40-
self.client
55+
let result_value = self
56+
.client
4157
.execute(|config: Arc<configuration::Configuration>| {
4258
let params_for_move = params.clone();
4359
async move { documents_api::get_document(&config, params_for_move).await }
4460
})
45-
.await
61+
.await?;
62+
63+
// Deserialize the raw JSON value into the user's type T.
64+
serde_json::from_value(result_value).map_err(Error::from)
4665
}
4766

4867
/// Updates this individual document. The update can be partial.
68+
/// The updated full document is returned.
4969
///
5070
/// # Arguments
51-
/// * `document` - A `serde_json::Value` containing the fields to update.
52-
pub async fn update(
71+
/// * `partial_document` - A serializable struct or a `serde_json::Value` containing the fields to update.
72+
/// For example: `serde_json::json!({ "in_stock": false })`.
73+
/// * `params` - An optional `DocumentIndexParameters` struct to specify additional
74+
/// 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.
75+
///
76+
/// # Returns
77+
/// A `Result` containing the full, updated document deserialized into `T`.
78+
///
79+
/// # Example
80+
/// ```no_run
81+
/// # use serde::{Serialize, Deserialize};
82+
/// # use typesense::{Client, MultiNodeConfiguration, models};
83+
/// # use reqwest::Url;
84+
/// # #[derive(Serialize, Deserialize)]
85+
/// # struct Book { id: String, title: String, pages: i32 }
86+
/// #
87+
/// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
88+
/// # let config = MultiNodeConfiguration {
89+
/// # nodes: vec![Url::parse("http://localhost:8108")?],
90+
/// # api_key: "xyz".to_string(),
91+
/// # ..Default::default()
92+
/// # };
93+
/// # let client = Client::new(config)?;
94+
/// let book_update = serde_json::json!({ "pages": 654 });
95+
///
96+
/// // Simple update
97+
/// let updated_book = client.collection_of::<Book>("books").document("123")
98+
/// .update(&book_update, None)
99+
/// .await?;
100+
///
101+
/// // Update with additional parameters
102+
/// let params = models::DocumentIndexParameters {
103+
/// dirty_values: Some(models::DirtyValues::CoerceOrReject),
104+
/// };
105+
/// let updated_book_with_params = client.collection_of::<Book>("books").document("124")
106+
/// .update(&book_update, Some(params))
107+
/// .await?;
108+
/// #
109+
/// # Ok(())
110+
/// # }
111+
/// ```
112+
pub async fn update<U: Serialize>(
53113
&self,
54-
document: serde_json::Value,
55-
) -> Result<serde_json::Value, Error<documents_api::UpdateDocumentError>> {
114+
partial_document: &U,
115+
params: Option<models::DocumentIndexParameters>,
116+
) -> Result<T, Error<documents_api::UpdateDocumentError>> {
56117
let params = documents_api::UpdateDocumentParams {
57118
collection_name: self.collection_name.to_string(),
58119
document_id: self.document_id.to_string(),
59-
body: document,
60-
dirty_values: None,
120+
body: serde_json::to_value(partial_document)?,
121+
dirty_values: params.unwrap_or_default().dirty_values,
61122
};
62-
self.client
123+
124+
let result_value = self
125+
.client
63126
.execute(|config: Arc<configuration::Configuration>| {
64127
let params_for_move = params.clone();
65128
async move { documents_api::update_document(&config, params_for_move).await }
66129
})
67-
.await
130+
.await?;
131+
132+
// Deserialize the raw JSON value of the updated document into T.
133+
serde_json::from_value(result_value).map_err(Error::from)
68134
}
69135

70136
/// Deletes this individual document from the collection.
71-
pub async fn delete(
72-
&self,
73-
) -> Result<serde_json::Value, Error<documents_api::DeleteDocumentError>> {
137+
/// The deleted document is returned.
138+
///
139+
/// # Returns
140+
/// A `Result` containing the deleted document deserialized into `T`.
141+
pub async fn delete(&self) -> Result<T, Error<documents_api::DeleteDocumentError>> {
74142
let params = documents_api::DeleteDocumentParams {
75143
collection_name: self.collection_name.to_string(),
76144
document_id: self.document_id.to_string(),
77145
};
78-
self.client
146+
147+
let result_value = self
148+
.client
79149
.execute(|config: Arc<configuration::Configuration>| {
80150
let params_for_move = params.clone();
81151
async move { documents_api::delete_document(&config, params_for_move).await }
82152
})
83-
.await
153+
.await?;
154+
155+
// Deserialize the raw JSON value of the deleted document into T.
156+
serde_json::from_value(result_value).map_err(Error::from)
84157
}
85158
}

0 commit comments

Comments
 (0)