From 223dd521964197fcb9b73c63bf06c582a1fdb7ff Mon Sep 17 00:00:00 2001 From: Devdutt Shenoi Date: Thu, 10 Mar 2022 20:51:12 +0530 Subject: [PATCH] Create a synonym client and associated types --- typesense/src/document.rs | 5 +- typesense/src/lib.rs | 1 + typesense/src/synonym.rs | 112 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 typesense/src/synonym.rs diff --git a/typesense/src/document.rs b/typesense/src/document.rs index 7c57084..7bd8496 100644 --- a/typesense/src/document.rs +++ b/typesense/src/document.rs @@ -3,7 +3,7 @@ //! In Typesense, documents are each one of the JSON elements that are stored in the collections. //! A document to be indexed in a given collection must conform to the schema of the collection. //! -use crate::collection::CollectionSchema; +use crate::{collection::CollectionSchema, synonym::SynonymSchema}; use serde::{de::DeserializeOwned, Serialize}; /// Trait that should implement every struct that wants to be represented as a Typesense @@ -11,4 +11,7 @@ use serde::{de::DeserializeOwned, Serialize}; pub trait Document: DeserializeOwned + Serialize { /// Collection schema associated with the document. fn collection_schema() -> CollectionSchema; + + /// Synonym schema associated with the document. + fn synonym_schema() -> SynonymSchema; } diff --git a/typesense/src/lib.rs b/typesense/src/lib.rs index 29a833b..7651005 100644 --- a/typesense/src/lib.rs +++ b/typesense/src/lib.rs @@ -11,6 +11,7 @@ pub mod document; mod error; pub mod field; pub mod transport; +pub mod synonym; pub use client::{keys, Client, ClientBuilder}; pub use error::{Result, TypesenseError}; diff --git a/typesense/src/synonym.rs b/typesense/src/synonym.rs new file mode 100644 index 0000000..6313ba9 --- /dev/null +++ b/typesense/src/synonym.rs @@ -0,0 +1,112 @@ +//! # Synonyms +//! +//! The synonyms feature allows you to define search terms that should be considered +//! equivalent. For eg: when you define a synonym for `sneaker` as `shoe`, searching +//! for `sneaker` will now return all records with the word `shoe` in them, in addition +//! to records with the word `sneaker`. +//! +//! Typesense supports two types of synonyms: +//! 1. **One-way synonyms:** Defining the words `iphone` and `android` as one-way synonyms +//! of `smart phone` will cause searches for `smart phone` to return documents containing +//! `iphone` or `android` or both. +//! 2. **Multi-way synonyms:** Defining the words `blazer`, `coat` and `jacket` as multi-way +//! synonyms will cause searches for any one of those words (eg: `coat`) to return documents +//! containing at least one of the words in the synonym set (eg: records with `blazer` or +//! `coat` or `jacket` are returned). +//! + +use serde::{Deserialize, Serialize}; + +use crate::client::Client; +use crate::document::Document; +use crate::transport::HttpLowLevel; +use crate::Result; + +/// Client for the Typesense SynonymAPI +pub struct SynonymClient { + pub(crate) client: Client, +} + +impl SynonymClient +where + T: HttpLowLevel, +{ + /// Create a collection in Typesense for a [`Document`] type. + pub async fn create(&self) -> Result { + let schema = D::synonym_schema(); + self.create_from_schema(schema).await + } + + /// Create a Synonym in Typesense given a ['SynonymSchema`] + pub async fn create_from_schema(&self, schema: SynonymSchema) -> Result { + let body = serde_json::to_vec(&schema)?; + + let response_body = self + .client + .post("/synonyms", body) + .await? + .into_body(); + + let response: SynonymResponse = serde_json::from_slice(&response_body)?; + + Ok(response) + } + + /// Retrieve a single synonym + pub async fn retrieve(&self, synonym_name: &str) -> Result { + let path = format!("/synonyms/{}", synonym_name); + + let response_body = self.client.get(&path).await?.into_body(); + + let response: SynonymResponse = serde_json::from_slice(&response_body)?; + + Ok(response) + } + + /// List all synonyms associated with a given collection + pub async fn list_all(&self) -> Result { + let response_body = self.client.get("/synonyms").await?.into_body(); + let response: SynonymListResponse = serde_json::from_slice(&response_body)?; + + Ok(response) + } + + /// Delete a synonym associated with a collection. + pub async fn delete(&self, synonym_name: &str) -> Result { + let path = format!("/synonyms/{}", synonym_name); + + let response_body = self.client.delete(&path).await?.into_body(); + let response: SynonymResponse = serde_json::from_slice(&response_body)?; + + Ok(response) + } +} + +/// Schema to create Synonyms in the Typesense Synonym API. +#[derive(Deserialize, Serialize)] +pub struct SynonymSchema { + /// root word associated with a One-way Synonym + /// NOTE: Left as None in the case of Multi-way synonym + pub root: Option, + /// List of synonyms + pub synonyms: Vec +} + +/// Represents a Response from the Typesense Synonym API. +#[derive(Deserialize, Serialize)] +pub struct SynonymResponse { + /// id associated with the synonym stored in Typesense + pub id: String, + /// root of a one-way synonym stored in Typesense + /// NOTE: Will be None in case of multi-way synonyms + pub root: Option, + /// List of associated synonyms stored in Typesense + pub synonyms: Vec, +} + +/// Represents a List format Response from the Typesense Synonym API. +#[derive(Deserialize, Serialize)] +pub struct SynonymListResponse { + /// List of synonyms + pub synonyms: Vec +}