From 6a76e914d00dd8f5271e903d47ebb0964372d9ff Mon Sep 17 00:00:00 2001 From: Miles Granger Date: Mon, 16 Mar 2026 19:08:02 +0100 Subject: [PATCH 1/6] Add chrono feature and impl for additional types --- typesense/Cargo.toml | 4 +++ typesense/src/traits/field_type.rs | 39 ++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/typesense/Cargo.toml b/typesense/Cargo.toml index 302dd1d5..599556ec 100644 --- a/typesense/Cargo.toml +++ b/typesense/Cargo.toml @@ -13,6 +13,9 @@ default = ["derive"] # Provide derive(Typesense) macro. derive = ["typesense_derive"] +# Add ToTypesenseField impls for chrono date/time types. +chrono = ["dep:chrono"] + [lib] crate-type = ["cdylib", "rlib"] @@ -24,6 +27,7 @@ base64 = { workspace = true } bon = { workspace = true } hmac = { workspace = true } reqwest-retry = { workspace = true } +chrono = { version = "0.4", optional = true } serde = { workspace = true } serde_json = { workspace = true } sha2 = { workspace = true } diff --git a/typesense/src/traits/field_type.rs b/typesense/src/traits/field_type.rs index e994e8d9..6616f45f 100644 --- a/typesense/src/traits/field_type.rs +++ b/typesense/src/traits/field_type.rs @@ -79,3 +79,42 @@ impl_to_typesense_field!(Vec, "float[]"); impl_to_typesense_field!(Vec, "bool[]"); impl_to_typesense_field!(Vec>, "object[]", T); impl_to_typesense_field!(Vec>, "object[]", T); + +impl_to_typesense_field!(Option, "string"); +impl_to_typesense_field!(Option, "int32"); +impl_to_typesense_field!(Option, "int32"); +impl_to_typesense_field!(Option, "int32"); +impl_to_typesense_field!(Option, "int32"); +impl_to_typesense_field!(Option, "int32"); +impl_to_typesense_field!(Option, "int64"); +impl_to_typesense_field!(Option, "int64"); +impl_to_typesense_field!(Option, "int64"); +impl_to_typesense_field!(Option, "int64"); +impl_to_typesense_field!(Option, "int64"); +impl_to_typesense_field!(Option, "float"); +impl_to_typesense_field!(Option, "float"); +impl_to_typesense_field!(Option, "bool"); + +impl_to_typesense_field!(Vec>, "string[]"); +impl_to_typesense_field!(Vec>, "int32[]"); +impl_to_typesense_field!(Vec>, "int64[]"); +impl_to_typesense_field!(Vec>, "float[]"); +impl_to_typesense_field!(Vec>, "float[]"); +impl_to_typesense_field!(Vec>, "bool[]"); + +#[cfg(feature = "chrono")] +mod chrono_support { + impl_to_typesense_field!(chrono::DateTime, "string"); + impl_to_typesense_field!(chrono::DateTime, "string"); + impl_to_typesense_field!(chrono::DateTime, "string"); + impl_to_typesense_field!(chrono::NaiveDate, "string"); + impl_to_typesense_field!(chrono::NaiveDateTime, "string"); + impl_to_typesense_field!(chrono::NaiveTime, "string"); + + impl_to_typesense_field!(Vec>, "string[]"); + impl_to_typesense_field!(Vec>, "string[]"); + impl_to_typesense_field!(Vec>, "string[]"); + impl_to_typesense_field!(Vec, "string[]"); + impl_to_typesense_field!(Vec, "string[]"); + impl_to_typesense_field!(Vec, "string[]"); +} From d5aade761813b64f8532158aac789bb7e09af778 Mon Sep 17 00:00:00 2001 From: Miles Granger Date: Mon, 16 Mar 2026 19:08:27 +0100 Subject: [PATCH 2/6] Small adjustment to derive macro qualified serde path --- typesense_derive/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typesense_derive/src/lib.rs b/typesense_derive/src/lib.rs index 0e1b658c..828035ec 100644 --- a/typesense_derive/src/lib.rs +++ b/typesense_derive/src/lib.rs @@ -138,7 +138,7 @@ fn impl_typesense_collection(item: ItemStruct) -> syn::Result { let name_partial = Ident::new(&(ident.to_string() + "Partial"), ident.span()); let generated_code = quote! { - #[derive(Default, Serialize)] + #[derive(Default, ::serde::Serialize)] #vis struct #name_partial { #(#optional_fields)* } From 2b05341e01b7ef0b76e23c228c84ab78bc0659a1 Mon Sep 17 00:00:00 2001 From: Miles Granger Date: Tue, 17 Mar 2026 07:56:28 +0100 Subject: [PATCH 3/6] Move chrono to workspace --- Cargo.toml | 1 + typesense/Cargo.toml | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 15776240..9c19c973 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ typesense_derive = { path = "./typesense_derive", version = "0.3" } anyhow = "1" base64 = "0.22" bon = "3" +chrono = "0.4" clap = { version = "4", features = ["derive"] } hmac = "0.12" indexmap = { version = "2", features = ["serde"] } diff --git a/typesense/Cargo.toml b/typesense/Cargo.toml index 599556ec..d0202aa2 100644 --- a/typesense/Cargo.toml +++ b/typesense/Cargo.toml @@ -9,13 +9,11 @@ description = "Client for typesense" [features] default = ["derive"] +chrono = ["dep:chrono"] # Provide derive(Typesense) macro. derive = ["typesense_derive"] -# Add ToTypesenseField impls for chrono date/time types. -chrono = ["dep:chrono"] - [lib] crate-type = ["cdylib", "rlib"] @@ -25,9 +23,9 @@ typesense_derive = { workspace = true, optional = true } anyhow = { workspace = true } base64 = { workspace = true } bon = { workspace = true } +chrono = { workspace = true, optional = true } hmac = { workspace = true } reqwest-retry = { workspace = true } -chrono = { version = "0.4", optional = true } serde = { workspace = true } serde_json = { workspace = true } sha2 = { workspace = true } From 06454548396f89f0aa68537005706315dff1ff72 Mon Sep 17 00:00:00 2001 From: Miles Granger Date: Tue, 17 Mar 2026 07:59:26 +0100 Subject: [PATCH 4/6] Impl ToTypesenseField via T for Option/Vec --- typesense/src/traits/field_type.rs | 33 +++++++++++------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/typesense/src/traits/field_type.rs b/typesense/src/traits/field_type.rs index 6616f45f..0c984a85 100644 --- a/typesense/src/traits/field_type.rs +++ b/typesense/src/traits/field_type.rs @@ -80,27 +80,18 @@ impl_to_typesense_field!(Vec, "bool[]"); impl_to_typesense_field!(Vec>, "object[]", T); impl_to_typesense_field!(Vec>, "object[]", T); -impl_to_typesense_field!(Option, "string"); -impl_to_typesense_field!(Option, "int32"); -impl_to_typesense_field!(Option, "int32"); -impl_to_typesense_field!(Option, "int32"); -impl_to_typesense_field!(Option, "int32"); -impl_to_typesense_field!(Option, "int32"); -impl_to_typesense_field!(Option, "int64"); -impl_to_typesense_field!(Option, "int64"); -impl_to_typesense_field!(Option, "int64"); -impl_to_typesense_field!(Option, "int64"); -impl_to_typesense_field!(Option, "int64"); -impl_to_typesense_field!(Option, "float"); -impl_to_typesense_field!(Option, "float"); -impl_to_typesense_field!(Option, "bool"); - -impl_to_typesense_field!(Vec>, "string[]"); -impl_to_typesense_field!(Vec>, "int32[]"); -impl_to_typesense_field!(Vec>, "int64[]"); -impl_to_typesense_field!(Vec>, "float[]"); -impl_to_typesense_field!(Vec>, "float[]"); -impl_to_typesense_field!(Vec>, "bool[]"); +impl ToTypesenseField for Option { + #[inline(always)] + fn to_typesense_type() -> &'static str { + T::to_typesense_type() + } +} +impl ToTypesenseField for Vec> { + #[inline(always)] + fn to_typesense_type() -> &'static str { + T::to_typesense_type() + } +} #[cfg(feature = "chrono")] mod chrono_support { From e8a8e9ba6be162e9af5ee7434eec6a8abec0499f Mon Sep 17 00:00:00 2001 From: RoDmitry Date: Tue, 17 Mar 2026 19:36:05 +0000 Subject: [PATCH 5/6] Impl ToTypesenseField for Vec in `impl_to_typesense_field!` --- typesense/src/traits/field_type.rs | 79 ++++++++++++++---------------- 1 file changed, 37 insertions(+), 42 deletions(-) diff --git a/typesense/src/traits/field_type.rs b/typesense/src/traits/field_type.rs index 0c984a85..4c85184e 100644 --- a/typesense/src/traits/field_type.rs +++ b/typesense/src/traits/field_type.rs @@ -6,7 +6,7 @@ pub type FieldType = String; /// Trait that should implement each type of a document, in order to properly serialize the /// Collection Schema according to the Typesense reference. pub trait ToTypesenseField { - /// Static function that should implement the types of the typesense documents. + /// Mapping of a Typesense type. fn to_typesense_type() -> &'static str; } /// Generic implementation for any type that is also a Typesense document. @@ -25,22 +25,54 @@ impl ToTypesenseField for Vec { } } +impl ToTypesenseField for Option { + #[inline(always)] + fn to_typesense_type() -> &'static str { + T::to_typesense_type() + } +} + /// macro used internally to add implementations of ToTypesenseField for several rust types. #[macro_export] macro_rules! impl_to_typesense_field ( - ($for:ty, $typesense_variant:expr) => { + ($for:ty, $typesense_type:expr) => { impl $crate::prelude::ToTypesenseField for $for { #[inline(always)] fn to_typesense_type() -> &'static str { - $typesense_variant + $typesense_type + } + } + impl $crate::prelude::ToTypesenseField for Vec<$for> { + #[inline(always)] + fn to_typesense_type() -> &'static str { + concat!($typesense_type, "[]") + } + } + impl $crate::prelude::ToTypesenseField for Vec> { + #[inline(always)] + fn to_typesense_type() -> &'static str { + concat!($typesense_type, "[]") } } }; - ($for:ty, $typesense_variant:expr, $any:ident) => { + + ($for:ty, $typesense_type:expr, $any:ident) => { impl<$any> $crate::prelude::ToTypesenseField for $for { #[inline(always)] fn to_typesense_type() -> &'static str { - $typesense_variant + $typesense_type + } + } + impl<$any> $crate::prelude::ToTypesenseField for Vec<$for> { + #[inline(always)] + fn to_typesense_type() -> &'static str { + concat!($typesense_type, "[]") + } + } + impl<$any> $crate::prelude::ToTypesenseField for Vec> { + #[inline(always)] + fn to_typesense_type() -> &'static str { + concat!($typesense_type, "[]") } } }; @@ -63,36 +95,6 @@ impl_to_typesense_field!(bool, "bool"); impl_to_typesense_field!(HashMap, "object", T); impl_to_typesense_field!(BTreeMap, "object", T); -impl_to_typesense_field!(Vec, "string[]"); -impl_to_typesense_field!(Vec, "int32[]"); -impl_to_typesense_field!(Vec, "int32[]"); -impl_to_typesense_field!(Vec, "int32[]"); -impl_to_typesense_field!(Vec, "int32[]"); -impl_to_typesense_field!(Vec, "int32[]"); -impl_to_typesense_field!(Vec, "int64[]"); -impl_to_typesense_field!(Vec, "int64[]"); -impl_to_typesense_field!(Vec, "int64[]"); -impl_to_typesense_field!(Vec, "int64[]"); -impl_to_typesense_field!(Vec, "int64[]"); -impl_to_typesense_field!(Vec, "float[]"); -impl_to_typesense_field!(Vec, "float[]"); -impl_to_typesense_field!(Vec, "bool[]"); -impl_to_typesense_field!(Vec>, "object[]", T); -impl_to_typesense_field!(Vec>, "object[]", T); - -impl ToTypesenseField for Option { - #[inline(always)] - fn to_typesense_type() -> &'static str { - T::to_typesense_type() - } -} -impl ToTypesenseField for Vec> { - #[inline(always)] - fn to_typesense_type() -> &'static str { - T::to_typesense_type() - } -} - #[cfg(feature = "chrono")] mod chrono_support { impl_to_typesense_field!(chrono::DateTime, "string"); @@ -101,11 +103,4 @@ mod chrono_support { impl_to_typesense_field!(chrono::NaiveDate, "string"); impl_to_typesense_field!(chrono::NaiveDateTime, "string"); impl_to_typesense_field!(chrono::NaiveTime, "string"); - - impl_to_typesense_field!(Vec>, "string[]"); - impl_to_typesense_field!(Vec>, "string[]"); - impl_to_typesense_field!(Vec>, "string[]"); - impl_to_typesense_field!(Vec, "string[]"); - impl_to_typesense_field!(Vec, "string[]"); - impl_to_typesense_field!(Vec, "string[]"); } From f5b3bbd1dc2f60c2b19a8ef1ae09ec47ad824495 Mon Sep 17 00:00:00 2001 From: RoDmitry Date: Tue, 17 Mar 2026 19:57:32 +0000 Subject: [PATCH 6/6] `impl_to_typesense_field!` allow type bound --- typesense/src/traits/field_type.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/typesense/src/traits/field_type.rs b/typesense/src/traits/field_type.rs index 4c85184e..032becff 100644 --- a/typesense/src/traits/field_type.rs +++ b/typesense/src/traits/field_type.rs @@ -56,20 +56,20 @@ macro_rules! impl_to_typesense_field ( } }; - ($for:ty, $typesense_type:expr, $any:ident) => { - impl<$any> $crate::prelude::ToTypesenseField for $for { + ($for:ty, $typesense_type:expr, $any:ident $(: $any_bound:path)?) => { + impl<$any $(: $any_bound)?> $crate::prelude::ToTypesenseField for $for { #[inline(always)] fn to_typesense_type() -> &'static str { $typesense_type } } - impl<$any> $crate::prelude::ToTypesenseField for Vec<$for> { + impl<$any $(: $any_bound)?> $crate::prelude::ToTypesenseField for Vec<$for> { #[inline(always)] fn to_typesense_type() -> &'static str { concat!($typesense_type, "[]") } } - impl<$any> $crate::prelude::ToTypesenseField for Vec> { + impl<$any $(: $any_bound)?> $crate::prelude::ToTypesenseField for Vec> { #[inline(always)] fn to_typesense_type() -> &'static str { concat!($typesense_type, "[]") @@ -97,9 +97,7 @@ impl_to_typesense_field!(BTreeMap, "object", T); #[cfg(feature = "chrono")] mod chrono_support { - impl_to_typesense_field!(chrono::DateTime, "string"); - impl_to_typesense_field!(chrono::DateTime, "string"); - impl_to_typesense_field!(chrono::DateTime, "string"); + impl_to_typesense_field!(chrono::DateTime, "string", T: chrono::TimeZone); impl_to_typesense_field!(chrono::NaiveDate, "string"); impl_to_typesense_field!(chrono::NaiveDateTime, "string"); impl_to_typesense_field!(chrono::NaiveTime, "string");