diff --git a/clients/algoliasearch-client-javascript/client-search/model/clearAllSynonymsResponse.ts b/clients/algoliasearch-client-javascript/client-search/model/clearAllSynonymsResponse.ts new file mode 100644 index 00000000000..8dc07e6503e --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-search/model/clearAllSynonymsResponse.ts @@ -0,0 +1,10 @@ +export type ClearAllSynonymsResponse = { + /** + * TaskID of the indexing task to wait for. + */ + taskID: number; + /** + * Date of last update (ISO-8601 format). + */ + updatedAt: Date; +}; diff --git a/clients/algoliasearch-client-javascript/client-search/model/deleteSynonymResponse.ts b/clients/algoliasearch-client-javascript/client-search/model/deleteSynonymResponse.ts new file mode 100644 index 00000000000..575406c024a --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-search/model/deleteSynonymResponse.ts @@ -0,0 +1,10 @@ +export type DeleteSynonymResponse = { + /** + * TaskID of the indexing task to wait for. + */ + taskID: number; + /** + * Date of deletion (ISO-8601 format). + */ + deletedAt: Date; +}; diff --git a/clients/algoliasearch-client-javascript/client-search/model/highlightedSynonym.ts b/clients/algoliasearch-client-javascript/client-search/model/highlightedSynonym.ts new file mode 100644 index 00000000000..7b163e856bd --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-search/model/highlightedSynonym.ts @@ -0,0 +1,26 @@ +export type HighlightedSynonym = { + /** + * Markup text with occurrences highlighted. + */ + value?: string; + /** + * Indicates how well the attribute matched the search query. + */ + matchLevel?: HighlightedSynonym.MatchLevelEnum; + /** + * List of words from the query that matched the object. + */ + matchedWords?: string[]; + /** + * Whether the entire attribute value is highlighted. + */ + fullyHighlighted?: boolean; +}; + +export namespace HighlightedSynonym { + export enum MatchLevelEnum { + None = 'none', + Partial = 'partial', + Full = 'full', + } +} diff --git a/clients/algoliasearch-client-javascript/client-search/model/models.ts b/clients/algoliasearch-client-javascript/client-search/model/models.ts index 2fb37bde759..a832ec37140 100644 --- a/clients/algoliasearch-client-javascript/client-search/model/models.ts +++ b/clients/algoliasearch-client-javascript/client-search/model/models.ts @@ -7,7 +7,9 @@ export * from './baseSearchResponse'; export * from './baseSearchResponseFacetsStats'; export * from './batchObject'; export * from './batchResponse'; +export * from './clearAllSynonymsResponse'; export * from './deleteIndexResponse'; +export * from './deleteSynonymResponse'; export * from './errorBase'; export * from './highlightResult'; export * from './index'; @@ -24,12 +26,17 @@ export * from './rankingInfo'; export * from './rankingInfoMatchedGeoLocation'; export * from './record'; export * from './saveObjectResponse'; +export * from './saveSynonymResponse'; +export * from './saveSynonymsResponse'; export * from './searchHits'; export * from './searchParams'; export * from './searchParamsAsString'; export * from './searchResponse'; +export * from './searchSynonymsResponse'; export * from './setSettingsResponse'; export * from './snippetResult'; +export * from './synonymHit'; +export * from './synonymHitHighlightResult'; export interface Authentication { /** diff --git a/clients/algoliasearch-client-javascript/client-search/model/saveSynonymResponse.ts b/clients/algoliasearch-client-javascript/client-search/model/saveSynonymResponse.ts new file mode 100644 index 00000000000..35979a159c9 --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-search/model/saveSynonymResponse.ts @@ -0,0 +1,14 @@ +export type SaveSynonymResponse = { + /** + * TaskID of the indexing task to wait for. + */ + taskID: number; + /** + * Date of last update (ISO-8601 format). + */ + updatedAt: Date; + /** + * ObjectID of the inserted object. + */ + id: string; +}; diff --git a/clients/algoliasearch-client-javascript/client-search/model/saveSynonymsResponse.ts b/clients/algoliasearch-client-javascript/client-search/model/saveSynonymsResponse.ts new file mode 100644 index 00000000000..fe37f948a04 --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-search/model/saveSynonymsResponse.ts @@ -0,0 +1,10 @@ +export type SaveSynonymsResponse = { + /** + * TaskID of the indexing task to wait for. + */ + taskID: number; + /** + * Date of last update (ISO-8601 format). + */ + updatedAt: Date; +}; diff --git a/clients/algoliasearch-client-javascript/client-search/model/searchSynonymsResponse.ts b/clients/algoliasearch-client-javascript/client-search/model/searchSynonymsResponse.ts new file mode 100644 index 00000000000..b50c74feac1 --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-search/model/searchSynonymsResponse.ts @@ -0,0 +1,12 @@ +import type { SynonymHit } from './synonymHit'; + +export type SearchSynonymsResponse = { + /** + * Array of synonym objects. + */ + hits: SynonymHit[]; + /** + * Number of hits that the search query matched. + */ + nbHits: number; +}; diff --git a/clients/algoliasearch-client-javascript/client-search/model/synonymHit.ts b/clients/algoliasearch-client-javascript/client-search/model/synonymHit.ts new file mode 100644 index 00000000000..990865f1ca5 --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-search/model/synonymHit.ts @@ -0,0 +1,50 @@ +import type { SynonymHitHighlightResult } from './synonymHitHighlightResult'; + +/** + * Synonym object. + */ +export type SynonymHit = { + /** + * Unique identifier of the synonym object to be created or updated. + */ + objectID: string; + /** + * Type of the synonym object. + */ + type: SynonymHit.TypeEnum; + /** + * Words or phrases to be considered equivalent. + */ + synonyms?: string[]; + /** + * Word or phrase to appear in query strings (for onewaysynonym). + */ + input?: string; + /** + * Word or phrase to appear in query strings (for altcorrection1 and altcorrection2). + */ + word?: string; + /** + * Words to be matched in records. + */ + corrections?: string[]; + /** + * Token to be put inside records. + */ + placeholder?: string; + /** + * List of query words that will match the token. + */ + replacements?: string[]; + _highlightResult?: SynonymHitHighlightResult; +}; + +export namespace SynonymHit { + export enum TypeEnum { + Synonym = 'synonym', + Onewaysynonym = 'onewaysynonym', + Altcorrection1 = 'altcorrection1', + Altcorrection2 = 'altcorrection2', + Placeholder = 'placeholder', + } +} diff --git a/clients/algoliasearch-client-javascript/client-search/model/synonymHitHighlightResult.ts b/clients/algoliasearch-client-javascript/client-search/model/synonymHitHighlightResult.ts new file mode 100644 index 00000000000..6d475481437 --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-search/model/synonymHitHighlightResult.ts @@ -0,0 +1,9 @@ +import type { HighlightResult } from './highlightResult'; + +/** + * Highlighted results. + */ +export type SynonymHitHighlightResult = { + type?: HighlightResult; + synonyms?: HighlightResult[]; +}; diff --git a/clients/algoliasearch-client-javascript/client-search/model/synonymType.ts b/clients/algoliasearch-client-javascript/client-search/model/synonymType.ts new file mode 100644 index 00000000000..f6c10b8ee4d --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-search/model/synonymType.ts @@ -0,0 +1,10 @@ +/** + * Type of the synonym object. + */ +export enum SynonymType { + Synonym = 'synonym', + Onewaysynonym = 'onewaysynonym', + Altcorrection1 = 'altcorrection1', + Altcorrection2 = 'altcorrection2', + Placeholder = 'placeholder', +} diff --git a/clients/algoliasearch-client-javascript/client-search/src/searchApi.ts b/clients/algoliasearch-client-javascript/client-search/src/searchApi.ts index 9484c7b09e9..0fd22b66f8c 100644 --- a/clients/algoliasearch-client-javascript/client-search/src/searchApi.ts +++ b/clients/algoliasearch-client-javascript/client-search/src/searchApi.ts @@ -1,6 +1,8 @@ import type { BatchObject } from '../model/batchObject'; import type { BatchResponse } from '../model/batchResponse'; +import type { ClearAllSynonymsResponse } from '../model/clearAllSynonymsResponse'; import type { DeleteIndexResponse } from '../model/deleteIndexResponse'; +import type { DeleteSynonymResponse } from '../model/deleteSynonymResponse'; import type { IndexSettings } from '../model/indexSettings'; import type { ListIndicesResponse } from '../model/listIndicesResponse'; import { ApiKeyAuth } from '../model/models'; @@ -9,10 +11,14 @@ import type { MultipleQueriesResponse } from '../model/multipleQueriesResponse'; import type { OperationIndexObject } from '../model/operationIndexObject'; import type { OperationIndexResponse } from '../model/operationIndexResponse'; import type { SaveObjectResponse } from '../model/saveObjectResponse'; +import type { SaveSynonymResponse } from '../model/saveSynonymResponse'; +import type { SaveSynonymsResponse } from '../model/saveSynonymsResponse'; import type { SearchParams } from '../model/searchParams'; import type { SearchParamsAsString } from '../model/searchParamsAsString'; import type { SearchResponse } from '../model/searchResponse'; +import type { SearchSynonymsResponse } from '../model/searchSynonymsResponse'; import type { SetSettingsResponse } from '../model/setSettingsResponse'; +import type { SynonymHit } from '../model/synonymHit'; import { Transporter } from '../utils/Transporter'; import { shuffle } from '../utils/helpers'; import type { Requester } from '../utils/requester/Requester'; @@ -147,6 +153,46 @@ export class SearchApi { return this.sendRequest(request, requestOptions); } + /** + * Remove all synonyms from an index. + * + * @summary Clear all synonyms. + * @param indexName - The index in which to perform the request. + * @param forwardToReplicas - When true, changes are also propagated to replicas of the given indexName. + */ + clearAllSynonyms( + indexName: string, + forwardToReplicas?: boolean + ): Promise { + const path = '/1/indexes/{indexName}/synonyms/clear'.replace( + '{indexName}', + encodeURIComponent(String(indexName)) + ); + const headers: Headers = { Accept: 'application/json' }; + const queryParameters: Record = {}; + + if (indexName === null || indexName === undefined) { + throw new Error( + 'Required parameter indexName was null or undefined when calling clearAllSynonyms.' + ); + } + + if (forwardToReplicas !== undefined) { + queryParameters.forwardToReplicas = forwardToReplicas.toString(); + } + + const request: Request = { + method: 'POST', + path, + }; + + const requestOptions: RequestOptions = { + headers, + queryParameters, + }; + + return this.sendRequest(request, requestOptions); + } /** * Delete an existing index. * @@ -179,6 +225,53 @@ export class SearchApi { return this.sendRequest(request, requestOptions); } + /** + * Delete a single synonyms set, identified by the given objectID. + * + * @summary Delete synonym. + * @param indexName - The index in which to perform the request. + * @param objectID - Unique identifier of an object. + * @param forwardToReplicas - When true, changes are also propagated to replicas of the given indexName. + */ + deleteSynonym( + indexName: string, + objectID: string, + forwardToReplicas?: boolean + ): Promise { + const path = '/1/indexes/{indexName}/synonyms/{objectID}' + .replace('{indexName}', encodeURIComponent(String(indexName))) + .replace('{objectID}', encodeURIComponent(String(objectID))); + const headers: Headers = { Accept: 'application/json' }; + const queryParameters: Record = {}; + + if (indexName === null || indexName === undefined) { + throw new Error( + 'Required parameter indexName was null or undefined when calling deleteSynonym.' + ); + } + + if (objectID === null || objectID === undefined) { + throw new Error( + 'Required parameter objectID was null or undefined when calling deleteSynonym.' + ); + } + + if (forwardToReplicas !== undefined) { + queryParameters.forwardToReplicas = forwardToReplicas.toString(); + } + + const request: Request = { + method: 'DELETE', + path, + }; + + const requestOptions: RequestOptions = { + headers, + queryParameters, + }; + + return this.sendRequest(request, requestOptions); + } /** * Retrieve settings of a given indexName. * @@ -210,6 +303,44 @@ export class SearchApi { return this.sendRequest(request, requestOptions); } + /** + * Fetch a synonym object identified by its objectID. + * + * @summary Get synonym. + * @param indexName - The index in which to perform the request. + * @param objectID - Unique identifier of an object. + */ + getSynonym(indexName: string, objectID: string): Promise { + const path = '/1/indexes/{indexName}/synonyms/{objectID}' + .replace('{indexName}', encodeURIComponent(String(indexName))) + .replace('{objectID}', encodeURIComponent(String(objectID))); + const headers: Headers = { Accept: 'application/json' }; + const queryParameters: Record = {}; + + if (indexName === null || indexName === undefined) { + throw new Error( + 'Required parameter indexName was null or undefined when calling getSynonym.' + ); + } + + if (objectID === null || objectID === undefined) { + throw new Error( + 'Required parameter objectID was null or undefined when calling getSynonym.' + ); + } + + const request: Request = { + method: 'GET', + path, + }; + + const requestOptions: RequestOptions = { + headers, + queryParameters, + }; + + return this.sendRequest(request, requestOptions); + } /** * List existing indexes from an application. * @@ -353,6 +484,118 @@ export class SearchApi { return this.sendRequest(request, requestOptions); } + /** + * Create a new synonym object or update the existing synonym object with the given object ID. + * + * @summary Save synonym. + * @param indexName - The index in which to perform the request. + * @param objectID - Unique identifier of an object. + * @param synonymHit - The synonymHit. + * @param forwardToReplicas - When true, changes are also propagated to replicas of the given indexName. + */ + saveSynonym( + indexName: string, + objectID: string, + synonymHit: SynonymHit, + forwardToReplicas?: boolean + ): Promise { + const path = '/1/indexes/{indexName}/synonyms/{objectID}' + .replace('{indexName}', encodeURIComponent(String(indexName))) + .replace('{objectID}', encodeURIComponent(String(objectID))); + const headers: Headers = { Accept: 'application/json' }; + const queryParameters: Record = {}; + + if (indexName === null || indexName === undefined) { + throw new Error( + 'Required parameter indexName was null or undefined when calling saveSynonym.' + ); + } + + if (objectID === null || objectID === undefined) { + throw new Error( + 'Required parameter objectID was null or undefined when calling saveSynonym.' + ); + } + + if (synonymHit === null || synonymHit === undefined) { + throw new Error( + 'Required parameter synonymHit was null or undefined when calling saveSynonym.' + ); + } + + if (forwardToReplicas !== undefined) { + queryParameters.forwardToReplicas = forwardToReplicas.toString(); + } + + const request: Request = { + method: 'PUT', + path, + data: synonymHit, + }; + + const requestOptions: RequestOptions = { + headers, + queryParameters, + }; + + return this.sendRequest(request, requestOptions); + } + /** + * Create/update multiple synonym objects at once, potentially replacing the entire list of synonyms if replaceExistingSynonyms is true. + * + * @summary Save a batch of synonyms. + * @param indexName - The index in which to perform the request. + * @param synonymHit - The synonymHit. + * @param forwardToReplicas - When true, changes are also propagated to replicas of the given indexName. + * @param replaceExistingSynonyms - Replace all synonyms of the index with the ones sent with this request. + */ + saveSynonyms( + indexName: string, + synonymHit: SynonymHit[], + forwardToReplicas?: boolean, + replaceExistingSynonyms?: boolean + ): Promise { + const path = '/1/indexes/{indexName}/synonyms/batch'.replace( + '{indexName}', + encodeURIComponent(String(indexName)) + ); + const headers: Headers = { Accept: 'application/json' }; + const queryParameters: Record = {}; + + if (indexName === null || indexName === undefined) { + throw new Error( + 'Required parameter indexName was null or undefined when calling saveSynonyms.' + ); + } + + if (synonymHit === null || synonymHit === undefined) { + throw new Error( + 'Required parameter synonymHit was null or undefined when calling saveSynonyms.' + ); + } + + if (forwardToReplicas !== undefined) { + queryParameters.forwardToReplicas = forwardToReplicas.toString(); + } + + if (replaceExistingSynonyms !== undefined) { + queryParameters.replaceExistingSynonyms = + replaceExistingSynonyms.toString(); + } + + const request: Request = { + method: 'POST', + path, + data: synonymHit, + }; + + const requestOptions: RequestOptions = { + headers, + queryParameters, + }; + + return this.sendRequest(request, requestOptions); + } /** * Get search results. * @@ -398,6 +641,69 @@ export class SearchApi { return this.sendRequest(request, requestOptions); } + /** + * Search or browse all synonyms, optionally filtering them by type. + * + * @summary Get all synonyms that match a query. + * @param indexName - The index in which to perform the request. + * @param query - Search for specific synonyms matching this string. + * @param type - Only search for specific types of synonyms. + * @param page - Requested page (zero-based). When specified, will retrieve a specific page; the page size is implicitly set to 100. When null, will retrieve all indices (no pagination). + * @param hitsPerPage - Maximum number of objects to retrieve. + */ + searchSynonyms( + indexName: string, + query?: string, + type?: + | 'altcorrection1' + | 'altcorrection2' + | 'onewaysynonym' + | 'placeholder' + | 'synonym', + page?: number, + hitsPerPage?: number + ): Promise { + const path = '/1/indexes/{indexName}/synonyms/search'.replace( + '{indexName}', + encodeURIComponent(String(indexName)) + ); + const headers: Headers = { Accept: 'application/json' }; + const queryParameters: Record = {}; + + if (indexName === null || indexName === undefined) { + throw new Error( + 'Required parameter indexName was null or undefined when calling searchSynonyms.' + ); + } + + if (query !== undefined) { + queryParameters.query = query.toString(); + } + + if (type !== undefined) { + queryParameters.type = type.toString(); + } + + if (page !== undefined) { + queryParameters.Page = page.toString(); + } + + if (hitsPerPage !== undefined) { + queryParameters.hitsPerPage = hitsPerPage.toString(); + } + + const request: Request = { + method: 'POST', + path, + }; + + const requestOptions: RequestOptions = { + headers, + queryParameters, + }; + + return this.sendRequest(request, requestOptions); + } /** * Update settings of a given indexName. Only specified settings are overridden; unspecified settings are left unchanged. Specifying null for a setting resets it to its default value. * diff --git a/specs/common/parameters.yml b/specs/common/parameters.yml index ac0faf7da69..7034d231c1d 100644 --- a/specs/common/parameters.yml +++ b/specs/common/parameters.yml @@ -8,6 +8,15 @@ IndexName: type: string example: 'myIndexName' +ObjectID: + name: objectID + in: path + description: Unique identifier of an object. + required: true + schema: + type: string + example: '123' + # query ForwardToReplicas: in: query @@ -16,7 +25,6 @@ ForwardToReplicas: schema: type: boolean -# query Page: in: query name: Page @@ -26,6 +34,23 @@ Page: nullable: true default: null +PageDefault0: + in: query + name: Page + description: Requested page (zero-based). When specified, will retrieve a specific page; the page size is implicitly set to 100. When null, will retrieve all indices (no pagination). + schema: + type: integer + nullable: true + default: 0 + +HitsPerPage: + in: query + name: hitsPerPage + description: Maximum number of objects to retrieve. + schema: + type: integer + default: 100 + # misc taskID: type: integer @@ -35,6 +60,10 @@ objectID: type: string description: Unique identifier of the object. +id: + type: string + description: objectID of the inserted object. + objectIDs: type: array items: diff --git a/specs/search/common/schemas/SearchResponse.yml b/specs/search/common/schemas/SearchResponse.yml index d05cff23f13..c4d7756e62c 100644 --- a/specs/search/common/schemas/SearchResponse.yml +++ b/specs/search/common/schemas/SearchResponse.yml @@ -12,6 +12,11 @@ searchHits: items: $ref: 'Record.yml#/record' +nbHits: + type: integer + description: Number of hits that the search query matched + example: 20 + baseSearchResponse: type: object additionalProperties: false @@ -90,9 +95,7 @@ baseSearchResponse: type: string description: Used to return warnings about the query. nbHits: - type: integer - description: Number of hits that the search query matched - example: 20 + $ref: '#/nbHits' nbPages: type: integer description: Number of pages available for the current query diff --git a/specs/search/paths/synonyms/batchSynonyms.yml b/specs/search/paths/synonyms/batchSynonyms.yml index 6adb517bf4f..b26c6acaace 100644 --- a/specs/search/paths/synonyms/batchSynonyms.yml +++ b/specs/search/paths/synonyms/batchSynonyms.yml @@ -1 +1,41 @@ post: + tags: + - search + operationId: saveSynonyms + summary: Save a batch of synonyms. + description: Create/update multiple synonym objects at once, potentially replacing the entire list of synonyms if replaceExistingSynonyms is true. + parameters: + - $ref: '../../../common/parameters.yml#/IndexName' + - $ref: '../../../common/parameters.yml#/ForwardToReplicas' + - $ref: 'common/parameters.yml#/ReplaceExistingSynonyms' + requestBody: + required: true + content: + application/json: + schema: + $ref: 'common/schemas.yml#/synonymHits' + responses: + '200': + description: OK + content: + application/json: + schema: + title: saveSynonymsResponse + type: object + additionalProperties: false + properties: + taskID: + $ref: '../../../common/parameters.yml#/taskID' + updatedAt: + $ref: '../../../common/parameters.yml#/updatedAt' + required: + - taskID + - updatedAt + '400': + $ref: '../../../common/responses/BadRequest.yml' + '402': + $ref: '../../../common/responses/FeatureNotEnabled.yml' + '403': + $ref: '../../../common/responses/MethodNotAllowed.yml' + '404': + $ref: '../../../common/responses/IndexNotFound.yml' diff --git a/specs/search/paths/synonyms/clearAllSynonyms.yml b/specs/search/paths/synonyms/clearAllSynonyms.yml index 6adb517bf4f..9a992969f81 100644 --- a/specs/search/paths/synonyms/clearAllSynonyms.yml +++ b/specs/search/paths/synonyms/clearAllSynonyms.yml @@ -1 +1,34 @@ post: + tags: + - search + operationId: clearAllSynonyms + summary: Clear all synonyms. + description: Remove all synonyms from an index. + parameters: + - $ref: '../../../common/parameters.yml#/IndexName' + - $ref: '../../../common/parameters.yml#/ForwardToReplicas' + responses: + '200': + description: OK + content: + application/json: + schema: + title: clearAllSynonymsResponse + type: object + additionalProperties: false + properties: + taskID: + $ref: '../../../common/parameters.yml#/taskID' + updatedAt: + $ref: '../../../common/parameters.yml#/updatedAt' + required: + - taskID + - updatedAt + '400': + $ref: '../../../common/responses/BadRequest.yml' + '402': + $ref: '../../../common/responses/FeatureNotEnabled.yml' + '403': + $ref: '../../../common/responses/MethodNotAllowed.yml' + '404': + $ref: '../../../common/responses/IndexNotFound.yml' diff --git a/specs/search/paths/synonyms/common/parameters.yml b/specs/search/paths/synonyms/common/parameters.yml new file mode 100644 index 00000000000..a2232c6cc6f --- /dev/null +++ b/specs/search/paths/synonyms/common/parameters.yml @@ -0,0 +1,29 @@ +ReplaceExistingSynonyms: + in: query + name: replaceExistingSynonyms + schema: + type: boolean + description: Replace all synonyms of the index with the ones sent with this request. + +Query: + in: query + name: query + description: Search for specific synonyms matching this string. + schema: + type: string + default: '' + +Type: + in: query + name: type + description: Only search for specific types of synonyms. + schema: + type: string + enum: + [ + 'synonym', + 'onewaysynonym', + 'altcorrection1', + 'altcorrection2', + 'placeholder', + ] diff --git a/specs/search/paths/synonyms/common/schemas.yml b/specs/search/paths/synonyms/common/schemas.yml new file mode 100644 index 00000000000..ec441a370ef --- /dev/null +++ b/specs/search/paths/synonyms/common/schemas.yml @@ -0,0 +1,75 @@ +synonymHits: + type: array + description: Array of synonym objects. + items: + $ref: '#/synonymHit' + +synonymHit: + type: object + description: Synonym object. + additionalProperties: false + properties: + objectID: + type: string + description: Unique identifier of the synonym object to be created or updated. + type: + type: string + description: Type of the synonym object. + enum: + [ + 'synonym', + 'onewaysynonym', + 'altcorrection1', + 'altcorrection2', + 'placeholder', + ] + synonyms: + type: array + items: + type: string + description: Words or phrases to be considered equivalent. + input: + type: string + description: Word or phrase to appear in query strings (for onewaysynonym). + word: + type: string + description: Word or phrase to appear in query strings (for altcorrection1 and altcorrection2). + corrections: + type: array + items: + type: string + description: Words to be matched in records. + placeholder: + type: string + description: Token to be put inside records. + replacements: + type: array + items: + type: string + description: List of query words that will match the token. + _highlightResult: + type: object + description: Highlighted results + additionalProperties: false + properties: + type: + $ref: '../../../common/schemas/Record.yml#/highlightResult' + synonyms: + type: array + items: + $ref: '../../../common/schemas/Record.yml#/highlightResult' + required: + - objectID + - type + +searchSynonymsResponse: + type: object + additionalProperties: true + properties: + hits: + $ref: '#/synonymHits' + nbHits: + $ref: '../../../common/schemas/SearchResponse.yml#/nbHits' + required: + - hits + - nbHits diff --git a/specs/search/paths/synonyms/searchSynonyms.yml b/specs/search/paths/synonyms/searchSynonyms.yml index 6adb517bf4f..2cd0ffaf89b 100644 --- a/specs/search/paths/synonyms/searchSynonyms.yml +++ b/specs/search/paths/synonyms/searchSynonyms.yml @@ -1 +1,27 @@ post: + tags: + - search + operationId: searchSynonyms + summary: Get all synonyms that match a query. + description: Search or browse all synonyms, optionally filtering them by type. + parameters: + - $ref: '../../../common/parameters.yml#/IndexName' + - $ref: 'common/parameters.yml#/Query' + - $ref: 'common/parameters.yml#/Type' + - $ref: '../../../common/parameters.yml#/PageDefault0' + - $ref: '../../../common/parameters.yml#/HitsPerPage' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: 'common/schemas.yml#/searchSynonymsResponse' + '400': + $ref: '../../../common/responses/BadRequest.yml' + '402': + $ref: '../../../common/responses/FeatureNotEnabled.yml' + '403': + $ref: '../../../common/responses/MethodNotAllowed.yml' + '404': + $ref: '../../../common/responses/IndexNotFound.yml' diff --git a/specs/search/paths/synonyms/synonym.yml b/specs/search/paths/synonyms/synonym.yml index 9157e5af9a3..88401016761 100644 --- a/specs/search/paths/synonyms/synonym.yml +++ b/specs/search/paths/synonyms/synonym.yml @@ -1,3 +1,105 @@ put: + tags: + - search + operationId: saveSynonym + summary: Save synonym. + description: Create a new synonym object or update the existing synonym object with the given object ID. + parameters: + - $ref: '../../../common/parameters.yml#/IndexName' + - $ref: '../../../common/parameters.yml#/ObjectID' + - $ref: '../../../common/parameters.yml#/ForwardToReplicas' + requestBody: + required: true + content: + application/json: + schema: + $ref: 'common/schemas.yml#/synonymHit' + responses: + '200': + description: OK + content: + application/json: + schema: + title: saveSynonymResponse + type: object + additionalProperties: false + properties: + taskID: + $ref: '../../../common/parameters.yml#/taskID' + updatedAt: + $ref: '../../../common/parameters.yml#/updatedAt' + id: + $ref: '../../../common/parameters.yml#/id' + required: + - taskID + - updatedAt + - id + '400': + $ref: '../../../common/responses/BadRequest.yml' + '402': + $ref: '../../../common/responses/FeatureNotEnabled.yml' + '403': + $ref: '../../../common/responses/MethodNotAllowed.yml' + '404': + $ref: '../../../common/responses/IndexNotFound.yml' + get: + tags: + - search + operationId: getSynonym + summary: Get synonym. + description: Fetch a synonym object identified by its objectID. + parameters: + - $ref: '../../../common/parameters.yml#/IndexName' + - $ref: '../../../common/parameters.yml#/ObjectID' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: './common/schemas.yml#/synonymHit' + '400': + $ref: '../../../common/responses/BadRequest.yml' + '402': + $ref: '../../../common/responses/FeatureNotEnabled.yml' + '403': + $ref: '../../../common/responses/MethodNotAllowed.yml' + '404': + $ref: '../../../common/responses/IndexNotFound.yml' + delete: + tags: + - search + operationId: deleteSynonym + summary: Delete synonym. + description: Delete a single synonyms set, identified by the given objectID. + parameters: + - $ref: '../../../common/parameters.yml#/IndexName' + - $ref: '../../../common/parameters.yml#/ObjectID' + - $ref: '../../../common/parameters.yml#/ForwardToReplicas' + responses: + '200': + description: OK + content: + application/json: + schema: + title: deleteSynonymResponse + type: object + additionalProperties: false + properties: + taskID: + $ref: '../../../common/parameters.yml#/taskID' + deletedAt: + $ref: '../../../common/parameters.yml#/deleteAt' + required: + - taskID + - deletedAt + '400': + $ref: '../../../common/responses/BadRequest.yml' + '402': + $ref: '../../../common/responses/FeatureNotEnabled.yml' + '403': + $ref: '../../../common/responses/MethodNotAllowed.yml' + '404': + $ref: '../../../common/responses/IndexNotFound.yml' diff --git a/specs/search/spec.yml b/specs/search/spec.yml index e75bddb1848..778518685f4 100644 --- a/specs/search/spec.yml +++ b/specs/search/spec.yml @@ -56,14 +56,14 @@ paths: # ########################## # ### Synonyms Endpoints ### # ########################## - # /1/indexes/{indexName}/synonyms/{objectID}: - # $ref: './paths/synonyms/synonym.yml' - # /1/indexes/{indexName}/synonyms/batch: - # $ref: './paths/synonyms/batchSynonyms.yml' - # /1/indexes/{indexName}/synonyms/clear: - # $ref: './paths/synonyms/clearAllSynonyms.yml' - # /1/indexes/{indexName}/synonyms/search: - # $ref: './paths/synonyms/searchSynonyms.yml' + /1/indexes/{indexName}/synonyms/{objectID}: + $ref: './paths/synonyms/synonym.yml' + /1/indexes/{indexName}/synonyms/batch: + $ref: './paths/synonyms/batchSynonyms.yml' + /1/indexes/{indexName}/synonyms/clear: + $ref: './paths/synonyms/clearAllSynonyms.yml' + /1/indexes/{indexName}/synonyms/search: + $ref: './paths/synonyms/searchSynonyms.yml' # ###################### # ### Keys Endpoints ### diff --git a/tests/CTS/clients/search/clearAllSynonyms.json b/tests/CTS/clients/search/clearAllSynonyms.json new file mode 100644 index 00000000000..a1d6dbb09e2 --- /dev/null +++ b/tests/CTS/clients/search/clearAllSynonyms.json @@ -0,0 +1,13 @@ +[ + { + "testName": "clearAllSynonyms", + "method": "clearAllSynonyms", + "parameters": [ + "indexName" + ], + "request": { + "path": "/1/indexes/indexName/synonyms/clear", + "method": "POST" + } + } +] diff --git a/tests/CTS/clients/search/deleteSynonym.json b/tests/CTS/clients/search/deleteSynonym.json new file mode 100644 index 00000000000..7e0d7d698b2 --- /dev/null +++ b/tests/CTS/clients/search/deleteSynonym.json @@ -0,0 +1,14 @@ +[ + { + "testName": "deleteSynonym", + "method": "deleteSynonym", + "parameters": [ + "indexName", + "id1" + ], + "request": { + "path": "/1/indexes/indexName/synonyms/id1", + "method": "DELETE" + } + } +] diff --git a/tests/CTS/clients/search/getSynonym.json b/tests/CTS/clients/search/getSynonym.json new file mode 100644 index 00000000000..53a36a3f2a0 --- /dev/null +++ b/tests/CTS/clients/search/getSynonym.json @@ -0,0 +1,14 @@ +[ + { + "testName": "getSynonym", + "method": "getSynonym", + "parameters": [ + "indexName", + "id1" + ], + "request": { + "path": "/1/indexes/indexName/synonyms/id1", + "method": "GET" + } + } +] diff --git a/tests/CTS/clients/search/saveSynonym.json b/tests/CTS/clients/search/saveSynonym.json new file mode 100644 index 00000000000..ecec571c2e0 --- /dev/null +++ b/tests/CTS/clients/search/saveSynonym.json @@ -0,0 +1,25 @@ +[ + { + "testName": "saveSynonym", + "method": "saveSynonym", + "parameters": [ + "indexName", + "id1", + { + "objectID" : "id1", + "type": "synonym", + "synonyms": ["car", "vehicule", "auto"] + }, + true + ], + "request": { + "path": "/1/indexes/indexName/synonyms/id1", + "method": "PUT", + "data": { + "objectID" : "id1", + "type": "synonym", + "synonyms": ["car", "vehicule", "auto"] + } + } + } +] diff --git a/tests/CTS/clients/search/saveSynonyms.json b/tests/CTS/clients/search/saveSynonyms.json new file mode 100644 index 00000000000..531ed9e5170 --- /dev/null +++ b/tests/CTS/clients/search/saveSynonyms.json @@ -0,0 +1,41 @@ +[ + { + "testName": "saveSynonyms", + "method": "saveSynonyms", + "parameters": [ + "indexName", + [ + { + "objectID" : "id1", + "type": "synonym", + "synonyms": ["car", "vehicule", "auto"] + }, + { + "objectID" : "id2", + "type": "onewaysynonym", + "input": "iphone", + "synonyms": ["ephone", "aphone", "yphone"] + } + ], + true, + false + ], + "request": { + "path": "/1/indexes/indexName/synonyms/batch", + "method": "POST", + "data": [ + { + "objectID" : "id1", + "type": "synonym", + "synonyms": ["car", "vehicule", "auto"] + }, + { + "objectID" : "id2", + "type": "onewaysynonym", + "input": "iphone", + "synonyms": ["ephone", "aphone", "yphone"] + } + ] + } + } +] diff --git a/tests/CTS/clients/search/searchSynonyms.json b/tests/CTS/clients/search/searchSynonyms.json new file mode 100644 index 00000000000..3836ec78601 --- /dev/null +++ b/tests/CTS/clients/search/searchSynonyms.json @@ -0,0 +1,15 @@ +[ + { + "testName": "searchSynonyms", + "method": "searchSynonyms", + "parameters": [ + "indexName", + "queryString", + "onewaysynonym" + ], + "request": { + "path": "/1/indexes/indexName/synonyms/search", + "method": "POST" + } + } +] diff --git a/tests/CTS/templates/javascript.mustache b/tests/CTS/templates/javascript.mustache index 77bad11f3e3..a9279f15c40 100644 --- a/tests/CTS/templates/javascript.mustache +++ b/tests/CTS/templates/javascript.mustache @@ -1,3 +1,4 @@ +// @ts-nocheck import { {{client}}, EchoRequester } from '{{{import}}}'; describe('Common Test Suite', () => { @@ -9,7 +10,7 @@ describe('Common Test Suite', () => { expect(req).toMatchObject({ path: '{{{request.path}}}', method: '{{{request.method}}}', - data: {{{request.data}}}, + {{#request.data}}data: {{{request.data}}},{{/request.data}} }) }); diff --git a/tests/output/javascript/search.test.ts b/tests/output/javascript/search.test.ts index 7765d0557ed..fee71e30f6e 100644 --- a/tests/output/javascript/search.test.ts +++ b/tests/output/javascript/search.test.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { SearchApi, EchoRequester } from '@algolia/client-search'; describe('Common Test Suite', () => { @@ -7,6 +8,68 @@ describe('Common Test Suite', () => { { requester: new EchoRequester() } ); + test('searchSynonyms', async () => { + const req = await client.searchSynonyms( + 'indexName', + 'queryString', + 'onewaysynonym' + ); + expect(req).toMatchObject({ + path: '/1/indexes/indexName/synonyms/search', + method: 'POST', + }); + }); + + test('saveSynonyms', async () => { + const req = await client.saveSynonyms( + 'indexName', + [ + { + objectID: 'id1', + type: 'synonym', + synonyms: ['car', 'vehicule', 'auto'], + }, + { + objectID: 'id2', + type: 'onewaysynonym', + input: 'iphone', + synonyms: ['ephone', 'aphone', 'yphone'], + }, + ], + true, + false + ); + expect(req).toMatchObject({ + path: '/1/indexes/indexName/synonyms/batch', + method: 'POST', + data: { + synonymHit: [ + { + objectID: 'id1', + type: 'synonym', + synonyms: ['car', 'vehicule', 'auto'], + }, + { + objectID: 'id2', + type: 'onewaysynonym', + input: 'iphone', + synonyms: ['ephone', 'aphone', 'yphone'], + }, + ], + ForwardToReplicas: true, + ReplaceExistingSynonyms: false, + }, + }); + }); + + test('getSynonym', async () => { + const req = await client.getSynonym('indexName', 'id1'); + expect(req).toMatchObject({ + path: '/1/indexes/indexName/synonyms/id1', + method: 'GET', + }); + }); + test('search', async () => { const req = await client.search('indexName', { query: 'queryString' }); expect(req).toMatchObject({ @@ -15,4 +78,45 @@ describe('Common Test Suite', () => { data: { query: 'queryString' }, }); }); + + test('clearAllSynonyms', async () => { + const req = await client.clearAllSynonyms('indexName'); + expect(req).toMatchObject({ + path: '/1/indexes/indexName/synonyms/clear', + method: 'POST', + }); + }); + + test('deleteSynonym', async () => { + const req = await client.deleteSynonym('indexName', 'id1'); + expect(req).toMatchObject({ + path: '/1/indexes/indexName/synonyms/id1', + method: 'DELETE', + }); + }); + + test('saveSynonym', async () => { + const req = await client.saveSynonym( + 'indexName', + 'id1', + { + objectID: 'id1', + type: 'synonym', + synonyms: ['car', 'vehicule', 'auto'], + }, + true + ); + expect(req).toMatchObject({ + path: '/1/indexes/indexName/synonyms/id1', + method: 'PUT', + data: { + synonymHit: { + objectID: 'id1', + type: 'synonym', + synonyms: ['car', 'vehicule', 'auto'], + }, + ForwardToReplicas: true, + }, + }); + }); });