Skip to content
Merged
65 changes: 65 additions & 0 deletions doc/examples/server/synonymSets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { Client } from "../../src/Typesense";

const client = new Client({
nodes: [
{
host: "localhost",
port: 8108,
protocol: "http",
},
],
apiKey: "xyz",
connectionTimeoutSeconds: 2,
});

async function synonymSetsExample(): Promise<void> {
try {
// Create a synonym set
const synonymSet = await client.synonymSets().upsert({
name: "foobar",
synonyms: [
{
id: "dummy",
synonyms: ["foo", "bar", "baz"],
},
],
});
console.log("Created synonym set:", synonymSet);

// Retrieve all synonym sets
const allSynonymSets = await client.synonymSets().retrieve();
console.log("All synonym sets:", allSynonymSets);

// Get a specific synonym set
const specificSynonymSet = await client.synonymSets("foobar").retrieve();
console.log("Specific synonym set:", specificSynonymSet);

// Create a collection with synonym sets
const collection = await client.collections().create({
name: "products",
fields: [
{
name: "name",
type: "string",
},
],
synonym_sets: ["foobar", "index1", "index2"],
});
console.log("Created collection with synonym sets:", collection);

// Update a collection to add synonym sets
const updatedCollection = await client.collections("products").update({
synonym_sets: ["foobar", "index1", "index2", "index3"],
});
console.log("Updated collection:", updatedCollection);

// Delete a synonym set
const deletedSynonymSet = await client.synonymSets("foobar").delete();
console.log("Deleted synonym set:", deletedSynonymSet);
} catch (error) {
console.error("Error:", error);
}
}

// Run the example
synonymSetsExample();
22 changes: 22 additions & 0 deletions src/Typesense/Client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import Conversation from "./Conversation";
import Stemming from "./Stemming";
import NLSearchModels from "./NLSearchModels";
import NLSearchModel from "./NLSearchModel";
import SynonymSets from "./SynonymSets";
import SynonymSet from "./SynonymSet";

export default class Client {
configuration: Configuration;
Expand All @@ -50,6 +52,8 @@ export default class Client {
private readonly individualConversations: Record<string, Conversation>;
private readonly _nlSearchModels: NLSearchModels;
private readonly individualNLSearchModels: Record<string, NLSearchModel>;
private readonly _synonymSets: SynonymSets;
private readonly individualSynonymSets: Record<string, SynonymSet>;

constructor(options: ConfigurationOptions) {
options.sendApiKeyAsQueryParam = options.sendApiKeyAsQueryParam ?? false;
Expand Down Expand Up @@ -78,6 +82,8 @@ export default class Client {
this.individualConversations = {};
this._nlSearchModels = new NLSearchModels(this.apiCall);
this.individualNLSearchModels = {};
this._synonymSets = new SynonymSets(this.apiCall);
this.individualSynonymSets = {};
}

collections(): Collections;
Expand Down Expand Up @@ -176,4 +182,20 @@ export default class Client {
return this.individualNLSearchModels[id];
}
}

synonymSets(): SynonymSets;
synonymSets(synonymSetName: string): SynonymSet;
synonymSets(synonymSetName?: string): SynonymSets | SynonymSet {
if (synonymSetName === undefined) {
return this._synonymSets;
} else {
if (this.individualSynonymSets[synonymSetName] === undefined) {
this.individualSynonymSets[synonymSetName] = new SynonymSet(
synonymSetName,
this.apiCall,
);
}
return this.individualSynonymSets[synonymSetName];
}
}
}
1 change: 1 addition & 0 deletions src/Typesense/Collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export interface CollectionDropFieldSchema {
export interface CollectionUpdateSchema
extends Partial<Omit<CollectionCreateSchema, "name" | "fields">> {
fields?: (CollectionFieldSchema | CollectionDropFieldSchema)[];
synonym_sets?: string[];
}

export interface CollectionDeleteOptions {
Expand Down
1 change: 1 addition & 0 deletions src/Typesense/Collections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export interface BaseCollectionCreateSchema {
voice_query_model?: {
model_name?: string;
};
synonym_sets?: string[];
}

interface CollectionCreateSchemaWithSrc
Expand Down
34 changes: 34 additions & 0 deletions src/Typesense/SynonymSet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import ApiCall from "./ApiCall";
import SynonymSets from "./SynonymSets";
import type { SynonymSetCreateSchema, SynonymSetSchema } from "./SynonymSets";

export interface SynonymSetDeleteSchema {
name: string;
}

export type SynonymSetRetrieveSchema = SynonymSetCreateSchema;

export default class SynonymSet {
constructor(
private synonymSetName: string,
private apiCall: ApiCall,
) {}

async upsert(
params: SynonymSetCreateSchema,
): Promise<SynonymSetCreateSchema> {
return this.apiCall.put<SynonymSetSchema>(this.endpointPath(), params);
}

async retrieve(): Promise<SynonymSetRetrieveSchema> {
return this.apiCall.get<SynonymSetRetrieveSchema>(this.endpointPath());
}

async delete(): Promise<SynonymSetDeleteSchema> {
return this.apiCall.delete<SynonymSetDeleteSchema>(this.endpointPath());
}

private endpointPath(): string {
return `${SynonymSets.RESOURCEPATH}/${encodeURIComponent(this.synonymSetName)}`;
}
}
30 changes: 30 additions & 0 deletions src/Typesense/SynonymSets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import ApiCall from "./ApiCall";

export interface SynonymItemSchema {
id: string;
synonyms: string[];
root?: string;
locale?: string;
symbols_to_index?: string[];
}

export interface SynonymSetCreateSchema {
synonyms: SynonymItemSchema[];
}

export interface SynonymSetSchema extends SynonymSetCreateSchema {
name: string;
}

export interface SynonymSetsRetrieveSchema {
synonym_sets: SynonymSetSchema[];
}

export default class SynonymSets {
constructor(private apiCall: ApiCall) {}
static readonly RESOURCEPATH = "/synonym_sets";

async retrieve(): Promise<SynonymSetSchema[]> {
return this.apiCall.get<SynonymSetSchema[]>(SynonymSets.RESOURCEPATH);
}
}
2 changes: 2 additions & 0 deletions src/Typesense/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export const arrayableParams: ArraybleParams = {
override_tags: "override_tags",
num_typos: "num_typos",
prefix: "prefix",
synonym_sets: "synonym_sets",
sort_by: "sort_by",
};

Expand Down Expand Up @@ -145,6 +146,7 @@ export interface SearchParams<
drop_tokens_mode?: DropTokensMode;
typo_tokens_threshold?: number; // default: 100
pinned_hits?: string | string[];
synonym_sets?: string[] | string;
hidden_hits?: string | string[];
limit_hits?: number; // default: no limit
pre_segmented_query?: boolean;
Expand Down
25 changes: 13 additions & 12 deletions test/Typesense/AnalyticsEvents.spec.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import { describe, it, expect, beforeAll, afterAll } from "vitest";
import { Client as TypesenseClient } from "../../src/Typesense";
import { ObjectNotFound } from "../../src/Typesense/Errors";
import { isV30OrAbove } from "../utils";

describe("AnalyticsEvents", function () {
const typesense = new TypesenseClient({
nodes: [
{
host: "localhost",
port: 8108,
protocol: "http",
},
],
apiKey: "xyz",
connectionTimeoutSeconds: 180,
});
const typesense = new TypesenseClient({
nodes: [
{
host: "localhost",
port: 8108,
protocol: "http",
},
],
apiKey: "xyz",
connectionTimeoutSeconds: 180,
});

describe.skipIf(await isV30OrAbove(typesense))("AnalyticsEvents", function () {
const analyticsEvents = typesense.analytics.events();

beforeAll(async function () {
Expand Down
25 changes: 13 additions & 12 deletions test/Typesense/AnalyticsRule.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,21 @@ import {
ObjectAlreadyExists,
} from "../../src/Typesense/Errors";
import { AnalyticsRuleCreateSchema } from "../../src/Typesense/AnalyticsRule";
import { isV30OrAbove } from "../utils";

describe("AnalyticsRule", function () {
const typesense = new TypesenseClient({
nodes: [
{
host: "localhost",
port: 8108,
protocol: "http",
},
],
apiKey: "xyz",
connectionTimeoutSeconds: 180,
});
const typesense = new TypesenseClient({
nodes: [
{
host: "localhost",
port: 8108,
protocol: "http",
},
],
apiKey: "xyz",
connectionTimeoutSeconds: 180,
});

describe.skipIf(await isV30OrAbove(typesense))("AnalyticsRule", function () {
const testRuleName = "test_analytics_rule";
const testRuleData = {
type: "popular_queries",
Expand Down
25 changes: 13 additions & 12 deletions test/Typesense/AnalyticsRules.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,21 @@ import {
ObjectAlreadyExists,
} from "../../src/Typesense/Errors";
import { AnalyticsRuleCreateSchema } from "../../src/Typesense/AnalyticsRule";
import { isV30OrAbove } from "../utils";

describe("AnalyticsRules", function () {
const typesense = new TypesenseClient({
nodes: [
{
host: "localhost",
port: 8108,
protocol: "http",
},
],
apiKey: "xyz",
connectionTimeoutSeconds: 180,
});
const typesense = new TypesenseClient({
nodes: [
{
host: "localhost",
port: 8108,
protocol: "http",
},
],
apiKey: "xyz",
connectionTimeoutSeconds: 180,
});

describe.skipIf(await isV30OrAbove(typesense))("AnalyticsRules", function () {
const analyticsRules = typesense.analytics.rules();
const testRuleName = "search_suggestions";
const testRuleData = {
Expand Down
25 changes: 13 additions & 12 deletions test/Typesense/Synonym.spec.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import { describe, it, expect, beforeEach, afterEach } from "vitest";
import { Client as TypesenseClient } from "../../src/Typesense";
import { ObjectNotFound } from "../../src/Typesense/Errors";
import { isV30OrAbove } from "../utils";

describe("Synonym", function () {
const typesense = new TypesenseClient({
nodes: [
{
host: "localhost",
port: 8108,
protocol: "http",
},
],
apiKey: "xyz",
connectionTimeoutSeconds: 180,
});
const typesense = new TypesenseClient({
nodes: [
{
host: "localhost",
port: 8108,
protocol: "http",
},
],
apiKey: "xyz",
connectionTimeoutSeconds: 180,
});

describe.skipIf(await isV30OrAbove(typesense))("Synonym", function () {
const testCollectionName = "test_companies_synonym";
const testSynonymId = "synonym-set-1";
const synonymData = {
Expand Down
Loading
Loading