Skip to content

Commit 23d3f6d

Browse files
authored
Proc macro typesense_derive (#35)
* Readme * Update * Proc macro fix * Fix * Required fields * Fix wasm
1 parent 16ed8c0 commit 23d3f6d

18 files changed

+277
-277
lines changed

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,5 @@ jobs:
6060
args: --all-features
6161
- name: Tests in WASM
6262
if: matrix.platform.target == 'wasm32-unknown-unknown'
63-
run: wasm-pack test --headless --chrome
63+
run: RUST_LOG=wasm_bindgen_test_runner wasm-pack test --headless --chrome
6464
working-directory: ./typesense

README.md

+10
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,14 @@
55

66
Rust client for Typesense | Work In Progress & Help Wanted!
77

8+
Codegen was generated with:
9+
10+
```
11+
docker run --rm \
12+
-v $PWD:/local openapitools/openapi-generator-cli generate \
13+
-i /local/openapi.yml \
14+
-g rust \
15+
-o /local/typesense_codegen_new
16+
```
17+
818
If you'd like to contribute, please join our [Slack Community](https://join.slack.com/t/typesense-community/shared_invite/zt-mx4nbsbn-AuOL89O7iBtvkz136egSJg) and say hello!

mocks/get.yaml

-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,4 @@ then:
99
header:
1010
- name: content-type
1111
value: text/html
12-
- name: Access-Control-Allow-Origin
13-
value: \*
1412
body: "Test Successful"

mocks/get_api_key_header.yaml

-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,4 @@ then:
99
header:
1010
- name: content-type
1111
value: text/html
12-
- name: Access-Control-Allow-Origin
13-
value: \*
1412
body: "Test with api key successful"

mocks/retrieve_all_collections.yaml

+4-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ then:
1818
{"name": "num_employees", "type": "int32"},
1919
{"name": "country", "type": "string", "facet": true}
2020
],
21-
"default_sorting_field": "num_employees"
21+
"default_sorting_field": "num_employees",
22+
"created_at": 0
2223
},
2324
{
2425
"num_documents": 1250,
@@ -28,5 +29,6 @@ then:
2829
{"name": "full_name", "type": "string"},
2930
{"name": "from_year", "type": "int32"}
3031
],
31-
"default_sorting_field": "num_employees"
32+
"default_sorting_field": "num_employees",
33+
"created_at": 0
3234
}]'

typesense/src/client/mod.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use http::Response;
22

33
use crate::collection::CollectionClient;
4-
use crate::transport::{HttpLowLevel, Transport, TransportCreator};
4+
#[allow(unused_imports)]
5+
use crate::transport::TransportCreator;
6+
use crate::transport::{HttpLowLevel, Transport};
57
use crate::Result;
68

79
#[cfg(target_arch = "wasm32")]
@@ -23,6 +25,7 @@ pub struct Client<C> {
2325

2426
impl<C> Client<C> {
2527
/// Gets the transport of the client
28+
#[inline]
2629
pub fn transport(&self) -> &Transport<C> {
2730
&self.transport
2831
}
@@ -35,11 +38,10 @@ where
3538
Transport<C>: TransportCreator,
3639
{
3740
/// Create Client
41+
#[inline]
3842
pub fn new(host: impl Into<String>, api_key: impl Into<String>) -> Self {
39-
let transport = crate::transport::Transport::new();
40-
4143
Self {
42-
transport,
44+
transport: Transport::new(),
4345
host: host.into(),
4446
api_key: api_key.into(),
4547
}
@@ -48,11 +50,13 @@ where
4850

4951
impl<T> Client<T> {
5052
/// Make the ClientKeys struct, to interact with the Keys API.
53+
#[inline]
5154
pub fn keys(&self) -> ClientKeys<'_, T> {
5255
ClientKeys { client: self }
5356
}
5457

5558
/// Creates a [`CollectionClient`] to interact with the Typesense Collection API
59+
#[inline]
5660
pub fn collection(&self) -> CollectionClient<'_, T> {
5761
CollectionClient { client: self }
5862
}
@@ -75,14 +79,17 @@ where
7579
self.transport.send(method, &uri, headers, body).await
7680
}
7781

82+
#[inline]
7883
pub(crate) async fn get(&self, path: &str) -> Result<Response<Vec<u8>>> {
7984
self.send(http::Method::GET, path, Vec::new()).await
8085
}
8186

87+
#[inline]
8288
pub(crate) async fn post(&self, path: &str, body: Vec<u8>) -> Result<Response<Vec<u8>>> {
8389
self.send(http::Method::POST, path, body).await
8490
}
8591

92+
#[inline]
8693
pub(crate) async fn delete(&self, path: &str) -> Result<Response<Vec<u8>>> {
8794
self.send(http::Method::DELETE, path, Vec::new()).await
8895
}

typesense/src/collection/schema.rs

+44-13
Original file line numberDiff line numberDiff line change
@@ -12,44 +12,75 @@ pub struct CollectionSchemaBuilder {
1212
name: String,
1313
fields: Vec<Field>,
1414
default_sorting_field: Option<String>,
15+
token_separators: Option<Vec<String>>,
16+
enable_nested_fields: Option<bool>,
17+
symbols_to_index: Option<Vec<String>>,
1518
}
1619

1720
impl CollectionSchemaBuilder {
1821
/// Create a builder for [CollectionSchema]
19-
pub fn new(name: impl Into<String>) -> Self {
22+
#[inline]
23+
pub fn new(name: impl Into<String>, fields: Vec<Field>) -> Self {
2024
Self {
2125
name: name.into(),
26+
fields,
2227
..Default::default()
2328
}
2429
}
30+
2531
/// Insert field
32+
#[inline]
2633
pub fn field(mut self, field: Field) -> Self {
2734
self.fields.push(field);
2835
self
2936
}
3037

3138
/// Set fields
39+
#[inline]
3240
pub fn fields(mut self, fields: &[Field]) -> Self {
3341
self.fields.extend_from_slice(fields);
3442
self
3543
}
3644

37-
/// Set default_sorting_field
38-
pub fn default_sorting_field(mut self, default_sorting_field: String) -> Self {
39-
self.default_sorting_field = Some(default_sorting_field);
45+
/// Set default sorting field
46+
#[inline]
47+
pub fn default_sorting_field(mut self, default_sorting_field: impl Into<String>) -> Self {
48+
self.default_sorting_field = Some(default_sorting_field.into());
49+
self
50+
}
51+
52+
/// Set token separators
53+
#[inline]
54+
pub fn token_separators(mut self, token_separators: Vec<String>) -> Self {
55+
self.token_separators = Some(token_separators);
56+
self
57+
}
58+
59+
/// Enable nested fields
60+
#[inline]
61+
pub fn enable_nested_fields(mut self, enable_nested_fields: Option<bool>) -> Self {
62+
self.enable_nested_fields = enable_nested_fields;
63+
self
64+
}
65+
66+
/// Set symbols to index
67+
#[inline]
68+
pub fn symbols_to_index(mut self, symbols_to_index: Vec<String>) -> Self {
69+
self.symbols_to_index = Some(symbols_to_index);
4070
self
4171
}
4272

4373
/// Create a `CollectionSchema` with the current values of the builder,
4474
/// It can fail if any of the required fields is not not defined.
75+
#[inline]
4576
pub fn build(self) -> CollectionSchema {
4677
CollectionSchema {
4778
name: self.name,
4879
fields: self.fields,
4980
default_sorting_field: self.default_sorting_field,
50-
token_separators: None,
51-
enable_nested_fields: None,
52-
symbols_to_index: None,
81+
token_separators: self.token_separators,
82+
enable_nested_fields: self.enable_nested_fields,
83+
symbols_to_index: self.symbols_to_index,
5384
}
5485
}
5586
}
@@ -63,17 +94,17 @@ mod test {
6394
#[test]
6495
fn collection_schema_serializes_as_expected() {
6596
let fields = [
66-
("company_name".to_owned(), "string".to_owned(), None),
67-
("num_employees".to_owned(), "int32".to_owned(), None),
68-
("country".to_owned(), "string".to_owned(), Some(true)),
97+
("company_name", "string".to_owned(), None),
98+
("num_employees", "int32".to_owned(), None),
99+
("country", "string".to_owned(), Some(true)),
69100
]
70101
.map(|(name, typesense_type, facet)| {
71102
FieldBuilder::new(name, typesense_type).facet(facet).build()
72-
});
103+
})
104+
.to_vec();
73105

74-
let collection = CollectionSchemaBuilder::new("companies".to_owned())
106+
let collection = CollectionSchemaBuilder::new("companies", fields)
75107
.default_sorting_field("num_employees".to_owned())
76-
.fields(&fields)
77108
.build();
78109

79110
let expected = json!(

typesense/src/field/field_type.rs

+21-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::collections::{BTreeMap, HashMap};
2+
13
/// Type for a field. Currently it is a wrapping to a `String` but it could be extended to a enum
24
pub type FieldType = String;
35

@@ -11,8 +13,17 @@ pub trait ToTypesenseField {
1113
/// macro used internally to add implementations of ToTypesenseField for several rust types.
1214
#[macro_export]
1315
macro_rules! impl_to_typesense_field (
14-
($from:ty, $typesense_variant:expr) => {
15-
impl ToTypesenseField for $from {
16+
($for:ty, $typesense_variant:expr) => {
17+
impl ToTypesenseField for $for {
18+
#[inline(always)]
19+
fn to_typesense_type() -> &'static str {
20+
$typesense_variant
21+
}
22+
}
23+
};
24+
($for:ty, $typesense_variant:expr, $any:ident) => {
25+
impl<$any> ToTypesenseField for $for {
26+
#[inline(always)]
1627
fn to_typesense_type() -> &'static str {
1728
$typesense_variant
1829
}
@@ -29,9 +40,17 @@ impl_to_typesense_field!(usize, "int64");
2940
impl_to_typesense_field!(f32, "float");
3041
impl_to_typesense_field!(f64, "float");
3142
impl_to_typesense_field!(bool, "bool");
43+
impl_to_typesense_field!(HashMap<String, T>, "object", T);
44+
impl_to_typesense_field!(BTreeMap<String, T>, "object", T);
45+
3246
impl_to_typesense_field!(Vec<String>, "string[]");
47+
impl_to_typesense_field!(Vec<u8>, "int32[]");
3348
impl_to_typesense_field!(Vec<i32>, "int32[]");
3449
impl_to_typesense_field!(Vec<i64>, "int64[]");
50+
impl_to_typesense_field!(Vec<u32>, "int64[]");
51+
impl_to_typesense_field!(Vec<usize>, "int64[]");
3552
impl_to_typesense_field!(Vec<f32>, "float[]");
3653
impl_to_typesense_field!(Vec<f64>, "float[]");
3754
impl_to_typesense_field!(Vec<bool>, "bool[]");
55+
impl_to_typesense_field!(Vec<HashMap<String, T>>, "object[]", T);
56+
impl_to_typesense_field!(Vec<BTreeMap<String, T>>, "object[]", T);

typesense/src/field/mod.rs

+29-13
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub struct FieldBuilder {
2424

2525
impl FieldBuilder {
2626
/// Create a Builder
27+
#[inline]
2728
pub fn new(name: impl Into<String>, typesense_type: FieldType) -> Self {
2829
Self {
2930
name: name.into(),
@@ -32,50 +33,65 @@ impl FieldBuilder {
3233
}
3334
}
3435

35-
/// Set if field is facet.
36-
pub fn facet(mut self, facet: Option<bool>) -> Self {
37-
self.facet = facet;
38-
self
39-
}
40-
4136
/// Set if field is optional.
37+
#[inline]
4238
pub fn optional(mut self, optional: Option<bool>) -> Self {
4339
self.optional = optional;
4440
self
4541
}
4642

43+
/// Set if field is facet.
44+
#[inline]
45+
pub fn facet(mut self, facet: Option<bool>) -> Self {
46+
self.facet = facet;
47+
self
48+
}
49+
4750
/// Set if field is index.
51+
#[inline]
4852
pub fn index(mut self, index: Option<bool>) -> Self {
4953
self.index = index;
5054
self
5155
}
5256

5357
/// Set field locale.
58+
#[inline]
5459
pub fn locale(mut self, locale: Option<String>) -> Self {
5560
self.locale = locale;
5661
self
5762
}
5863

59-
/// Set sort attribute from field
64+
/// Set sort attribute for field
65+
#[inline]
6066
pub fn sort(mut self, sort: Option<bool>) -> Self {
6167
self.sort = sort;
6268
self
6369
}
6470

65-
/// Set drop attribute from field
66-
pub fn drop(mut self, drop: Option<bool>) -> Self {
67-
self.drop = drop;
71+
/// Set infix attribute for field
72+
#[inline]
73+
pub fn infix(mut self, infix: Option<bool>) -> Self {
74+
self.infix = infix;
6875
self
6976
}
7077

71-
/// Set infix attribute from field
72-
pub fn infix(mut self, infix: Option<bool>) -> Self {
73-
self.infix = infix;
78+
/// Set num_dim attribute for field
79+
#[inline]
80+
pub fn num_dim(mut self, num_dim: Option<i32>) -> Self {
81+
self.num_dim = num_dim;
82+
self
83+
}
84+
85+
/// Set drop attribute for field
86+
#[inline]
87+
pub fn drop(mut self, drop: Option<bool>) -> Self {
88+
self.drop = drop;
7489
self
7590
}
7691

7792
/// Create a `Field` with the current values of the builder,
7893
/// It can fail if the name or the typesense_type are not defined.
94+
#[inline]
7995
pub fn build(self) -> Field {
8096
Field {
8197
name: self.name,

typesense/src/transport/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub struct Transport<C> {
2121

2222
#[cfg(all(feature = "tokio-rt", not(target_arch = "wasm32")))]
2323
impl Default for Transport<HyperHttpsClient> {
24+
#[inline]
2425
fn default() -> Self {
2526
Transport::new()
2627
}
@@ -42,7 +43,7 @@ where
4243
}
4344
}
4445

45-
#[allow(missing_docs)]
46+
#[doc(hidden)]
4647
pub trait TransportCreator {
4748
/// Create new Transport
4849
fn new() -> Self;
@@ -68,6 +69,7 @@ impl TransportCreator for Transport<HyperHttpsClient> {
6869
#[cfg_attr(docsrs, doc(cfg(target_arch = "wasm32")))]
6970
impl TransportCreator for Transport<WasmClient> {
7071
/// Used to make a new wasm client.
72+
#[inline]
7173
fn new() -> Self {
7274
Self {
7375
client: http_low_level::WasmClient,

typesense/tests/collection_client.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,7 @@ mod hyper_tests {
8686

8787
#[allow(dead_code)]
8888
#[derive(Document, Serialize, Deserialize)]
89-
#[typesense(default_sorting_field = "num_employees")]
90-
#[typesense(collection_name = "companies")]
89+
#[typesense(collection_name = "companies", default_sorting_field = "num_employees")]
9190
struct Company {
9291
company_name: String,
9392
num_employees: i32,

0 commit comments

Comments
 (0)