Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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: 5 additions & 0 deletions specs/common/responses/IndexAlreadyExists.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
description: Destination index already exists.
content:
application/json:
schema:
$ref: '../schemas/ErrorBase.yml'
5 changes: 5 additions & 0 deletions specs/common/responses/IndexInSameApp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
description: Indices are in the same application. Use operationIndex instead.
content:
application/json:
schema:
$ref: '../schemas/ErrorBase.yml'
35 changes: 35 additions & 0 deletions specs/search/helpers/accountCopyIndex.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
method:
post:
x-helper: true
tags:
- Account
operationId: accountCopyIndex
summary: Copies the index of an Algolia application, to an other Algolia application
description: |
Copies the index of an Algolia application, to an other Algolia application.
parameters:
- in: query
name: sourceIndexName
description: The name of the index to copy in the `sourceClient`.
required: true
schema:
type: string
- in: query
name: destinationClient
description: The already initialized search client with write ACL credentials, this is the application to copy the index to.
required: true
schema:
type: object
- in: query
name: destinationIndexName
description: The name of the index to write the copied index to in the `destinationClient`.
required: true
schema:
type: string
responses:
'400':
$ref: '../../common/responses/IndexInSameApp.yml'
'403':
$ref: '../../common/responses/IndexAlreadyExists.yml'
'404':
$ref: '../../common/responses/IndexNotFound.yml'
81 changes: 81 additions & 0 deletions templates/javascript/clients/client/api/nodeHelpers.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,85 @@ generateSecuredApiKey: ({

const queryParameters = serializeQueryParameters(mergedRestrictions);
return Buffer.from(createHmac('sha256', parentApiKey).update(queryParameters).digest('hex') + queryParameters,).toString('base64');
},

/**
* Helper: Copies the given `sourceIndexName` to the `destinationIndexName` of the `destinationClient`.
* See https://api-clients-automation.netlify.app/docs/add-new-api-client#5-helpers for implementation details.
*
* @summary Helper: Copies the given `sourceIndexName` to the `destinationIndexName` of the `destinationClient`.
* @param accountCopyIndex - The `accountCopyIndex` object.
* @param accountCopyIndex.sourceIndexName - The name of the index to copy
* @param accountCopyIndex.destinationClient - The already initialized search client with write ACL credentials, this is the application to copy the index to.
* @param accountCopyIndex.destinationIndexName - The name of the index to write the copied index to in the `destinationClient`.
* @param requestOptions - The requestOptions to send along with the query, they will be forwarded to the `setSettings`, `saveRules`, `saveSynonyms` and `saveObjects` method and merged with the transporter requestOptions.
*/
async accountCopyIndex(
{ sourceIndexName, destinationClient, destinationIndexName }: AccountCopyIndexOptions,
requestOptions?: RequestOptions,
): Promise<void> {
const responses: Array<{ taskID: UpdatedAtResponse['taskID'] }> = [];

if (this.appId === destinationClient.appId) {
throw new AlgoliaError(
'Indices are in the same application. Use operationIndex instead.',
'IndicesInTheSameAppError',
);
}

if (!(await this.indexExists({ indexName: sourceIndexName }))) {
throw new AlgoliaError(
`${sourceIndexName} does not exist in the source application ${this.appId}`,
'IndexNotFound',
);
}

if (await destinationClient.indexExists({ indexName: sourceIndexName })) {
throw new AlgoliaError('Destination indice already exists.', 'DestinationIndiceAlreadyExistsError');
}

responses.push(
await destinationClient.setSettings(
{
indexName: destinationIndexName,
indexSettings: await this.getSettings({ indexName: sourceIndexName }),
},
requestOptions,
),
);

await this.browseRules({
indexName: sourceIndexName,
async aggregator(response: SearchRulesResponse) {
responses.push(
await destinationClient.saveRules({ indexName: destinationIndexName, rules: response.hits }, requestOptions),
);
},
});

await this.browseSynonyms({
indexName: sourceIndexName,
async aggregator(response: SearchSynonymsResponse) {
responses.push(
await destinationClient.saveSynonyms(
{ indexName: destinationIndexName, synonymHit: response.hits },
requestOptions,
),
);
},
});

await this.browseObjects({
indexName: sourceIndexName,
async aggregator(response: BrowseResponse) {
await destinationClient.saveObjects(
{ indexName: destinationIndexName, objects: response.hits, waitForTasks: true },
requestOptions,
);
},
});

for (const response of responses) {
await destinationClient.waitForTask({ indexName: destinationIndexName, taskID: response.taskID });
}
},
15 changes: 12 additions & 3 deletions templates/javascript/clients/client/builds/definition.mustache
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { createXhrRequester } from '@algolia/requester-browser-xhr';
import { createHttpRequester } from '@algolia/requester-node-http';
import { createFetchRequester } from '@algolia/requester-fetch';
import { createNullLogger, createMemoryCache, createFallbackableCache, createBrowserLocalStorageCache, createNullCache, serializeQueryParameters } from '@algolia/client-common';
import { AlgoliaError, createNullLogger, createMemoryCache, createFallbackableCache, createBrowserLocalStorageCache, createNullCache, serializeQueryParameters } from '@algolia/client-common';

import type { ClientOptions } from '@algolia/client-common';
import type { RequestOptions, ClientOptions } from '@algolia/client-common';

import { create{{#lambda.titlecase}}{{clientName}}{{/lambda.titlecase}}, apiClientVersion } from '../src/{{#isCompositionFullClient}}compositionFullClient{{/isCompositionFullClient}}{{^isCompositionFullClient}}{{clientName}}{{/isCompositionFullClient}}';

Expand All @@ -28,7 +28,16 @@ export * from '../model';

{{#isSearchClient}}
{{^isAlgoliasearchClient}}
import type { GenerateSecuredApiKeyOptions, GetSecuredApiKeyRemainingValidityOptions, SearchClientNodeHelpers } from '../model';
import type {
AccountCopyIndexOptions,
BrowseResponse,
GenerateSecuredApiKeyOptions,
GetSecuredApiKeyRemainingValidityOptions,
SearchClientNodeHelpers,
SearchRulesResponse,
SearchSynonymsResponse,
UpdatedAtResponse,
} from '../model';
{{/isAlgoliasearchClient}}
{{/isSearchClient}}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type { {{classname}} } from '{{filename}}';

{{! Imports for the helpers method of the search client }}
{{#isSearchClient}}
import type { createSearchClient } from '../src/searchClient';
import type { CreateIterablePromise } from '@algolia/client-common';
{{/isSearchClient}}

Expand Down Expand Up @@ -127,9 +128,10 @@ export type GetSecuredApiKeyRemainingValidityOptions = {
}

export type SearchClientNodeHelpers = {
accountCopyIndex: (opts: AccountCopyIndexOptions) => Promise<void>;
generateSecuredApiKey: (opts: GenerateSecuredApiKeyOptions) => string;
getSecuredApiKeyRemainingValidity: (opts: GetSecuredApiKeyRemainingValidityOptions) => number;
}
};
{{/isSearchClient}}

export type DeleteObjectsOptions = Pick<ChunkedBatchOptions, 'indexName' | 'waitForTasks' | 'batchSize'> & {
Expand Down Expand Up @@ -187,6 +189,23 @@ export type ReplaceAllObjectsOptions = {
*/
scopes?: Array<ScopeType>;
}

export type AccountCopyIndexOptions = {
/**
* The name of the index to copy to the `destinationClient`.
*/
sourceIndexName: string;

/**
* The already initialized search client with write ACLs, this must target the application to copy the index to.
*/
destinationClient: ReturnType<typeof createSearchClient>;

/**
* The name of the index to write the copy in.
*/
destinationIndexName: string;
};
{{/isAlgoliasearchClient}}
{{/isSearchClient}}
{{#isCompositionFullClient}}
Expand Down
Loading