Skip to content

Commit 4f07a42

Browse files
committed
fix: contract
1 parent 8f032cd commit 4f07a42

5 files changed

Lines changed: 148 additions & 75 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "algolia-recommend-rs"
33
authors = ["Raed667"]
4-
version = "0.0.3"
4+
version = "0.0.4"
55
edition = "2021"
66
license = "MIT"
77
description = """

README.md

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ $ cargo add algolia-recommend-rs
3131
## ⚡️ Quick start
3232

3333
```rust
34-
use algolia_recommend::{RecommendClient, RecommendRequest, TrendingFacetsRequest};
34+
use algolia_recommend_rs::{RecommendClient, models::{RecommendRequest, Model, TrendingFacetsRequest}};
3535
use serde::Deserialize;
3636

3737
#[derive(Debug, Deserialize)]
@@ -43,18 +43,30 @@ struct Product {
4343
async fn main() -> Result<(), Box<dyn std::error::Error>> {
4444
let client = RecommendClient::new("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY");
4545

46-
// Recommendations with typed hits
47-
let recs = client
48-
.get_recommendations::<Product>(
49-
"products",
50-
vec![
51-
Model::BoughtTogether,
52-
Model::RelatedProducts,
53-
Model::TrendingItems,
54-
Model::LookingSimilar,
55-
],
56-
)
57-
.await?;
46+
// Build recommendation requests
47+
let requests = vec![
48+
RecommendRequest {
49+
index_name: "products".to_string(),
50+
model: Model::BoughtTogether,
51+
object_id: Some("example-object-id".to_string()),
52+
threshold: Some(0),
53+
max_recommendations: None,
54+
facet_name: None,
55+
query_parameters: None,
56+
},
57+
RecommendRequest {
58+
index_name: "products".to_string(),
59+
model: Model::TrendingItems,
60+
object_id: None,
61+
threshold: Some(0),
62+
max_recommendations: None,
63+
facet_name: None,
64+
query_parameters: None,
65+
},
66+
];
67+
68+
// Fetch recommendations
69+
let recs = client.get_recommendations::<Product>(requests).await?;
5870
println!("results: {}", recs.results.len());
5971

6072
for result in recs.results.iter() {
@@ -63,7 +75,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
6375
}
6476
}
6577

66-
// 2) Trending facets
78+
// Fetch trending facets
6779
let trending = client
6880
.get_trending_facets(vec![TrendingFacetsRequest::new("products", "category")])
6981
.await?;

src/client.rs

Lines changed: 1 addition & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -190,52 +190,8 @@ impl RecommendClient {
190190
// Public API
191191
pub async fn get_recommendations<T: serde::de::DeserializeOwned + Send + 'static>(
192192
&self,
193-
index_name: impl Into<String>,
194-
models: Vec<Model>,
193+
requests: Vec<RecommendRequest>,
195194
) -> Result<RecommendResponse<T>> {
196-
let index_name = index_name.into();
197-
// Build requests internally; forbid trending-facets here
198-
let mut requests: Vec<RecommendRequest> = Vec::with_capacity(models.len());
199-
for model in models {
200-
match model {
201-
Model::TrendingFacets => {
202-
return Err(Error::Api {
203-
status: StatusCode::BAD_REQUEST.as_u16(),
204-
message: Some(
205-
"trending-facets must be requested via get_trending_facets".to_string(),
206-
),
207-
body: String::new(),
208-
});
209-
}
210-
Model::TrendingItems => {
211-
requests.push(RecommendRequest {
212-
index_name: index_name.clone(),
213-
model,
214-
object_id: None,
215-
threshold: None,
216-
max_recommendations: None,
217-
facet_name: None,
218-
query_parameters: None,
219-
});
220-
}
221-
Model::BoughtTogether | Model::RelatedProducts | Model::LookingSimilar => {
222-
let oid = self.default_object_id.as_ref().ok_or_else(|| Error::Api {
223-
status: StatusCode::BAD_REQUEST.as_u16(),
224-
message: Some("default objectID not set; call with_default_object_id or set_default_object_id".to_string()),
225-
body: String::new(),
226-
})?;
227-
requests.push(RecommendRequest {
228-
index_name: index_name.clone(),
229-
model,
230-
object_id: Some(oid.clone()),
231-
threshold: None,
232-
max_recommendations: None,
233-
facet_name: None,
234-
query_parameters: None,
235-
});
236-
}
237-
}
238-
}
239195
#[derive(Serialize)]
240196
struct Body<'a> {
241197
requests: &'a [RecommendRequest],

tests/live_tests.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,20 @@ async fn live_smoke_get_recommendations() {
1515
let client = RecommendClient::new(app_id, api_key).with_default_object_id("test-record-123");
1616

1717
// Minimal request; index and object may not exist; we only assert no transport/serde crash
18+
use algolia_recommend_rs::models::RecommendRequest;
19+
20+
let requests = vec![RecommendRequest {
21+
index_name: "products".to_string(),
22+
model: Model::TrendingItems,
23+
object_id: None,
24+
threshold: Some(0),
25+
max_recommendations: None,
26+
facet_name: None,
27+
query_parameters: None,
28+
}];
29+
1830
let result = client
19-
.get_recommendations::<serde_json::Value>("products", vec![Model::TrendingItems])
31+
.get_recommendations::<serde_json::Value>(requests)
2032
.await;
2133

2234
match result {

tests/recommend_tests.rs

Lines changed: 107 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,49 @@ async fn test_get_recommendations_excludes_trending_facets_and_parses_hits() {
2929
let client = RecommendClient::with_base_url("APPID", "KEY", server.base_url())
3030
.with_default_object_id("obj-1");
3131

32+
use algolia_recommend_rs::models::RecommendRequest;
33+
34+
let requests = vec![
35+
RecommendRequest {
36+
index_name: "products".to_string(),
37+
model: Model::BoughtTogether,
38+
object_id: Some("obj-1".to_string()),
39+
threshold: Some(0),
40+
max_recommendations: None,
41+
facet_name: None,
42+
query_parameters: None,
43+
},
44+
RecommendRequest {
45+
index_name: "products".to_string(),
46+
model: Model::RelatedProducts,
47+
object_id: Some("obj-1".to_string()),
48+
threshold: Some(0),
49+
max_recommendations: None,
50+
facet_name: None,
51+
query_parameters: None,
52+
},
53+
RecommendRequest {
54+
index_name: "products".to_string(),
55+
model: Model::TrendingItems,
56+
object_id: None,
57+
threshold: Some(0),
58+
max_recommendations: None,
59+
facet_name: None,
60+
query_parameters: None,
61+
},
62+
RecommendRequest {
63+
index_name: "products".to_string(),
64+
model: Model::LookingSimilar,
65+
object_id: Some("obj-1".to_string()),
66+
threshold: Some(0),
67+
max_recommendations: None,
68+
facet_name: None,
69+
query_parameters: None,
70+
},
71+
];
72+
3273
let resp = client
33-
.get_recommendations::<Product>(
34-
"products",
35-
vec![
36-
Model::BoughtTogether,
37-
Model::RelatedProducts,
38-
Model::TrendingItems,
39-
Model::LookingSimilar,
40-
],
41-
)
74+
.get_recommendations::<Product>(requests)
4275
.await
4376
.expect("request ok");
4477

@@ -95,8 +128,20 @@ async fn test_non_2xx_api_error_is_mapped() {
95128

96129
let client = RecommendClient::with_base_url("APPID", "KEY", server.base_url());
97130

131+
use algolia_recommend_rs::models::RecommendRequest;
132+
133+
let requests = vec![RecommendRequest {
134+
index_name: "products".to_string(),
135+
model: Model::TrendingItems,
136+
object_id: None,
137+
threshold: Some(0),
138+
max_recommendations: None,
139+
facet_name: None,
140+
query_parameters: None,
141+
}];
142+
98143
let err = client
99-
.get_recommendations::<Product>("products", vec![Model::TrendingItems])
144+
.get_recommendations::<Product>(requests)
100145
.await
101146
.expect_err("should error");
102147

@@ -118,8 +163,20 @@ async fn test_malformed_json_yields_serde_error() {
118163

119164
let client = RecommendClient::with_base_url("APPID", "KEY", server.base_url());
120165

166+
use algolia_recommend_rs::models::RecommendRequest;
167+
168+
let requests = vec![RecommendRequest {
169+
index_name: "products".to_string(),
170+
model: Model::TrendingItems,
171+
object_id: None,
172+
threshold: Some(0),
173+
max_recommendations: None,
174+
facet_name: None,
175+
query_parameters: None,
176+
}];
177+
121178
let err = client
122-
.get_recommendations::<Product>("products", vec![Model::TrendingItems])
179+
.get_recommendations::<Product>(requests)
123180
.await
124181
.expect_err("should error");
125182

@@ -155,8 +212,20 @@ async fn test_retry_on_5xx_then_succeed_on_next_host() {
155212
let hosts = vec![primary.base_url(), fallback.base_url()];
156213
let client = RecommendClient::with_hosts("APPID", "KEY", hosts).with_default_object_id("obj-1");
157214

215+
use algolia_recommend_rs::models::RecommendRequest;
216+
217+
let requests = vec![RecommendRequest {
218+
index_name: "products".to_string(),
219+
model: Model::TrendingItems,
220+
object_id: None,
221+
threshold: Some(0),
222+
max_recommendations: None,
223+
facet_name: None,
224+
query_parameters: None,
225+
}];
226+
158227
let resp = client
159-
.get_recommendations::<Product>("products", vec![Model::TrendingItems])
228+
.get_recommendations::<Product>(requests)
160229
.await
161230
.expect("request ok after retry");
162231

@@ -185,8 +254,20 @@ async fn test_retry_on_network_error_then_succeed() {
185254
let hosts = vec![bad_host, ok_server.base_url()];
186255
let client = RecommendClient::with_hosts("APPID", "KEY", hosts).with_default_object_id("obj-1");
187256

257+
use algolia_recommend_rs::models::RecommendRequest;
258+
259+
let requests = vec![RecommendRequest {
260+
index_name: "products".to_string(),
261+
model: Model::TrendingItems,
262+
object_id: None,
263+
threshold: Some(0),
264+
max_recommendations: None,
265+
facet_name: None,
266+
query_parameters: None,
267+
}];
268+
188269
let resp = client
189-
.get_recommendations::<Product>("products", vec![Model::TrendingItems])
270+
.get_recommendations::<Product>(requests)
190271
.await
191272
.expect("request ok after network retry");
192273

@@ -219,8 +300,20 @@ async fn test_non_retryable_4xx_does_not_try_next_host() {
219300
let hosts = vec![first.base_url(), second.base_url()];
220301
let client = RecommendClient::with_hosts("APPID", "KEY", hosts).with_default_object_id("obj-1");
221302

303+
use algolia_recommend_rs::models::RecommendRequest;
304+
305+
let requests = vec![RecommendRequest {
306+
index_name: "products".to_string(),
307+
model: Model::TrendingItems,
308+
object_id: None,
309+
threshold: Some(0),
310+
max_recommendations: None,
311+
facet_name: None,
312+
query_parameters: None,
313+
}];
314+
222315
let err = client
223-
.get_recommendations::<Product>("products", vec![Model::TrendingItems])
316+
.get_recommendations::<Product>(requests)
224317
.await
225318
.expect_err("should fail with 400 and not retry");
226319

0 commit comments

Comments
 (0)