Skip to content

Create a synonym client and associated types #22

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
5 changes: 4 additions & 1 deletion typesense/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
//! 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
/// Document
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;
}
1 change: 1 addition & 0 deletions typesense/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down
112 changes: 112 additions & 0 deletions typesense/src/synonym.rs
Original file line number Diff line number Diff line change
@@ -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<T> {
pub(crate) client: Client<T>,
}

impl<T> SynonymClient<T>
where
T: HttpLowLevel,
{
/// Create a collection in Typesense for a [`Document`] type.
pub async fn create<D: Document>(&self) -> Result<SynonymResponse> {
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<SynonymResponse> {
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<SynonymResponse> {
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<SynonymListResponse> {
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<SynonymResponse> {
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<String>,
/// List of synonyms
pub synonyms: Vec<String>
}

/// 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<String>,
/// List of associated synonyms stored in Typesense
pub synonyms: Vec<String>,
}

/// Represents a List format Response from the Typesense Synonym API.
#[derive(Deserialize, Serialize)]
pub struct SynonymListResponse {
/// List of synonyms
pub synonyms: Vec<SynonymResponse>
}