Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proc macro typesense_derive #35

Merged
merged 6 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,5 @@ jobs:
args: --all-features
- name: Tests in WASM
if: matrix.platform.target == 'wasm32-unknown-unknown'
run: wasm-pack test --headless --chrome
run: RUST_LOG=wasm_bindgen_test_runner wasm-pack test --headless --chrome
working-directory: ./typesense
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,14 @@

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

Codegen was generated with:

```
docker run --rm \
-v $PWD:/local openapitools/openapi-generator-cli generate \
-i /local/openapi.yml \
-g rust \
-o /local/typesense_codegen_new
```

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!
2 changes: 0 additions & 2 deletions mocks/get.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,4 @@ then:
header:
- name: content-type
value: text/html
- name: Access-Control-Allow-Origin
value: \*
body: "Test Successful"
2 changes: 0 additions & 2 deletions mocks/get_api_key_header.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,4 @@ then:
header:
- name: content-type
value: text/html
- name: Access-Control-Allow-Origin
value: \*
body: "Test with api key successful"
6 changes: 4 additions & 2 deletions mocks/retrieve_all_collections.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ then:
{"name": "num_employees", "type": "int32"},
{"name": "country", "type": "string", "facet": true}
],
"default_sorting_field": "num_employees"
"default_sorting_field": "num_employees",
"created_at": 0
},
{
"num_documents": 1250,
Expand All @@ -28,5 +29,6 @@ then:
{"name": "full_name", "type": "string"},
{"name": "from_year", "type": "int32"}
],
"default_sorting_field": "num_employees"
"default_sorting_field": "num_employees",
"created_at": 0
}]'
15 changes: 11 additions & 4 deletions typesense/src/client/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use http::Response;

use crate::collection::CollectionClient;
use crate::transport::{HttpLowLevel, Transport, TransportCreator};
#[allow(unused_imports)]
use crate::transport::TransportCreator;
use crate::transport::{HttpLowLevel, Transport};
use crate::Result;

#[cfg(target_arch = "wasm32")]
use crate::transport::WasmClient;

Check warning on line 10 in typesense/src/client/mod.rs

View workflow job for this annotation

GitHub Actions / tests (ubuntu, wasm32-unknown-unknown)

unused import: `crate::transport::WasmClient`

Check warning on line 10 in typesense/src/client/mod.rs

View workflow job for this annotation

GitHub Actions / tests (ubuntu, wasm32-unknown-unknown)

unused import: `crate::transport::WasmClient`

Check warning on line 10 in typesense/src/client/mod.rs

View workflow job for this annotation

GitHub Actions / tests (ubuntu, wasm32-unknown-unknown)

unused import: `crate::transport::WasmClient`

pub mod keys;

Expand All @@ -23,6 +25,7 @@

impl<C> Client<C> {
/// Gets the transport of the client
#[inline]
pub fn transport(&self) -> &Transport<C> {
&self.transport
}
Expand All @@ -35,11 +38,10 @@
Transport<C>: TransportCreator,
{
/// Create Client
#[inline]
pub fn new(host: impl Into<String>, api_key: impl Into<String>) -> Self {
let transport = crate::transport::Transport::new();

Self {
transport,
transport: Transport::new(),
host: host.into(),
api_key: api_key.into(),
}
Expand All @@ -48,11 +50,13 @@

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

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

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

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

#[inline]
pub(crate) async fn delete(&self, path: &str) -> Result<Response<Vec<u8>>> {
self.send(http::Method::DELETE, path, Vec::new()).await
}
Expand Down
57 changes: 44 additions & 13 deletions typesense/src/collection/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,44 +12,75 @@ pub struct CollectionSchemaBuilder {
name: String,
fields: Vec<Field>,
default_sorting_field: Option<String>,
token_separators: Option<Vec<String>>,
enable_nested_fields: Option<bool>,
symbols_to_index: Option<Vec<String>>,
}

impl CollectionSchemaBuilder {
/// Create a builder for [CollectionSchema]
pub fn new(name: impl Into<String>) -> Self {
#[inline]
pub fn new(name: impl Into<String>, fields: Vec<Field>) -> Self {
Self {
name: name.into(),
fields,
..Default::default()
}
}

/// Insert field
#[inline]
pub fn field(mut self, field: Field) -> Self {
self.fields.push(field);
self
}

/// Set fields
#[inline]
pub fn fields(mut self, fields: &[Field]) -> Self {
self.fields.extend_from_slice(fields);
self
}

/// Set default_sorting_field
pub fn default_sorting_field(mut self, default_sorting_field: String) -> Self {
self.default_sorting_field = Some(default_sorting_field);
/// Set default sorting field
#[inline]
pub fn default_sorting_field(mut self, default_sorting_field: impl Into<String>) -> Self {
self.default_sorting_field = Some(default_sorting_field.into());
self
}

/// Set token separators
#[inline]
pub fn token_separators(mut self, token_separators: Vec<String>) -> Self {
self.token_separators = Some(token_separators);
self
}

/// Enable nested fields
#[inline]
pub fn enable_nested_fields(mut self, enable_nested_fields: Option<bool>) -> Self {
self.enable_nested_fields = enable_nested_fields;
self
}

/// Set symbols to index
#[inline]
pub fn symbols_to_index(mut self, symbols_to_index: Vec<String>) -> Self {
self.symbols_to_index = Some(symbols_to_index);
self
}

/// Create a `CollectionSchema` with the current values of the builder,
/// It can fail if any of the required fields is not not defined.
#[inline]
pub fn build(self) -> CollectionSchema {
CollectionSchema {
name: self.name,
fields: self.fields,
default_sorting_field: self.default_sorting_field,
token_separators: None,
enable_nested_fields: None,
symbols_to_index: None,
token_separators: self.token_separators,
enable_nested_fields: self.enable_nested_fields,
symbols_to_index: self.symbols_to_index,
}
}
}
Expand All @@ -63,17 +94,17 @@ mod test {
#[test]
fn collection_schema_serializes_as_expected() {
let fields = [
("company_name".to_owned(), "string".to_owned(), None),
("num_employees".to_owned(), "int32".to_owned(), None),
("country".to_owned(), "string".to_owned(), Some(true)),
("company_name", "string".to_owned(), None),
("num_employees", "int32".to_owned(), None),
("country", "string".to_owned(), Some(true)),
]
.map(|(name, typesense_type, facet)| {
FieldBuilder::new(name, typesense_type).facet(facet).build()
});
})
.to_vec();

let collection = CollectionSchemaBuilder::new("companies".to_owned())
let collection = CollectionSchemaBuilder::new("companies", fields)
.default_sorting_field("num_employees".to_owned())
.fields(&fields)
.build();

let expected = json!(
Expand Down
23 changes: 21 additions & 2 deletions typesense/src/field/field_type.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::{BTreeMap, HashMap};

/// Type for a field. Currently it is a wrapping to a `String` but it could be extended to a enum
pub type FieldType = String;

Expand All @@ -11,8 +13,17 @@ pub trait ToTypesenseField {
/// macro used internally to add implementations of ToTypesenseField for several rust types.
#[macro_export]
macro_rules! impl_to_typesense_field (
($from:ty, $typesense_variant:expr) => {
impl ToTypesenseField for $from {
($for:ty, $typesense_variant:expr) => {
impl ToTypesenseField for $for {
#[inline(always)]
fn to_typesense_type() -> &'static str {
$typesense_variant
}
}
};
($for:ty, $typesense_variant:expr, $any:ident) => {
impl<$any> ToTypesenseField for $for {
#[inline(always)]
fn to_typesense_type() -> &'static str {
$typesense_variant
}
Expand All @@ -29,9 +40,17 @@ impl_to_typesense_field!(usize, "int64");
impl_to_typesense_field!(f32, "float");
impl_to_typesense_field!(f64, "float");
impl_to_typesense_field!(bool, "bool");
impl_to_typesense_field!(HashMap<String, T>, "object", T);
impl_to_typesense_field!(BTreeMap<String, T>, "object", T);

impl_to_typesense_field!(Vec<String>, "string[]");
impl_to_typesense_field!(Vec<u8>, "int32[]");
impl_to_typesense_field!(Vec<i32>, "int32[]");
impl_to_typesense_field!(Vec<i64>, "int64[]");
impl_to_typesense_field!(Vec<u32>, "int64[]");
impl_to_typesense_field!(Vec<usize>, "int64[]");
impl_to_typesense_field!(Vec<f32>, "float[]");
impl_to_typesense_field!(Vec<f64>, "float[]");
impl_to_typesense_field!(Vec<bool>, "bool[]");
impl_to_typesense_field!(Vec<HashMap<String, T>>, "object[]", T);
impl_to_typesense_field!(Vec<BTreeMap<String, T>>, "object[]", T);
42 changes: 29 additions & 13 deletions typesense/src/field/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub struct FieldBuilder {

impl FieldBuilder {
/// Create a Builder
#[inline]
pub fn new(name: impl Into<String>, typesense_type: FieldType) -> Self {
Self {
name: name.into(),
Expand All @@ -32,50 +33,65 @@ impl FieldBuilder {
}
}

/// Set if field is facet.
pub fn facet(mut self, facet: Option<bool>) -> Self {
self.facet = facet;
self
}

/// Set if field is optional.
#[inline]
pub fn optional(mut self, optional: Option<bool>) -> Self {
self.optional = optional;
self
}

/// Set if field is facet.
#[inline]
pub fn facet(mut self, facet: Option<bool>) -> Self {
self.facet = facet;
self
}

/// Set if field is index.
#[inline]
pub fn index(mut self, index: Option<bool>) -> Self {
self.index = index;
self
}

/// Set field locale.
#[inline]
pub fn locale(mut self, locale: Option<String>) -> Self {
self.locale = locale;
self
}

/// Set sort attribute from field
/// Set sort attribute for field
#[inline]
pub fn sort(mut self, sort: Option<bool>) -> Self {
self.sort = sort;
self
}

/// Set drop attribute from field
pub fn drop(mut self, drop: Option<bool>) -> Self {
self.drop = drop;
/// Set infix attribute for field
#[inline]
pub fn infix(mut self, infix: Option<bool>) -> Self {
self.infix = infix;
self
}

/// Set infix attribute from field
pub fn infix(mut self, infix: Option<bool>) -> Self {
self.infix = infix;
/// Set num_dim attribute for field
#[inline]
pub fn num_dim(mut self, num_dim: Option<i32>) -> Self {
self.num_dim = num_dim;
self
}

/// Set drop attribute for field
#[inline]
pub fn drop(mut self, drop: Option<bool>) -> Self {
self.drop = drop;
self
}

/// Create a `Field` with the current values of the builder,
/// It can fail if the name or the typesense_type are not defined.
#[inline]
pub fn build(self) -> Field {
Field {
name: self.name,
Expand Down
4 changes: 3 additions & 1 deletion typesense/src/transport/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub struct Transport<C> {

#[cfg(all(feature = "tokio-rt", not(target_arch = "wasm32")))]
impl Default for Transport<HyperHttpsClient> {
#[inline]
fn default() -> Self {
Transport::new()
}
Expand All @@ -42,7 +43,7 @@ where
}
}

#[allow(missing_docs)]
#[doc(hidden)]
pub trait TransportCreator {
/// Create new Transport
fn new() -> Self;
Expand All @@ -68,6 +69,7 @@ impl TransportCreator for Transport<HyperHttpsClient> {
#[cfg_attr(docsrs, doc(cfg(target_arch = "wasm32")))]
impl TransportCreator for Transport<WasmClient> {
/// Used to make a new wasm client.
#[inline]
fn new() -> Self {
Self {
client: http_low_level::WasmClient,
Expand Down
3 changes: 1 addition & 2 deletions typesense/tests/collection_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,7 @@ mod hyper_tests {

#[allow(dead_code)]
#[derive(Document, Serialize, Deserialize)]
#[typesense(default_sorting_field = "num_employees")]
#[typesense(collection_name = "companies")]
#[typesense(collection_name = "companies", default_sorting_field = "num_employees")]
struct Company {
company_name: String,
num_employees: i32,
Expand Down
Loading
Loading