From 5ffde1af5820099fe7eca2c32b3776587eb13a01 Mon Sep 17 00:00:00 2001 From: Rosalie Liu <52677246+rosalie-liu@users.noreply.github.com> Date: Mon, 4 Nov 2019 11:26:25 -0500 Subject: [PATCH] feat(pipelines): add mlassociations resource to pipelines feat(pipelines): add mlassociations resource to pipelines --- .../Models/ModelsInterfaces.ts | 9 +- .../MLAssociations/MLAssociations.ts | 66 +++++++++++++ .../MLAssociationsInterfaces.ts | 58 +++++++++++ .../Pipelines/MLAssociations/index.ts | 2 + .../tests/MLAssociations.spec.ts | 98 +++++++++++++++++++ src/resources/Pipelines/Pipelines.ts | 22 +++++ .../Pipelines/PipelinesInterfaces.ts | 3 + src/resources/Pipelines/index.ts | 3 + .../Pipelines/tests/Pipelines.spec.ts | 24 +++++ src/resources/PlatformResources.ts | 3 + src/resources/index.ts | 1 + src/resources/tests/PlatformResources.spec.ts | 9 ++ 12 files changed, 297 insertions(+), 1 deletion(-) create mode 100644 src/resources/Pipelines/MLAssociations/MLAssociations.ts create mode 100644 src/resources/Pipelines/MLAssociations/MLAssociationsInterfaces.ts create mode 100644 src/resources/Pipelines/MLAssociations/index.ts create mode 100644 src/resources/Pipelines/MLAssociations/tests/MLAssociations.spec.ts create mode 100644 src/resources/Pipelines/Pipelines.ts create mode 100644 src/resources/Pipelines/PipelinesInterfaces.ts create mode 100644 src/resources/Pipelines/index.ts create mode 100644 src/resources/Pipelines/tests/Pipelines.spec.ts diff --git a/src/resources/MachineLearning/Models/ModelsInterfaces.ts b/src/resources/MachineLearning/Models/ModelsInterfaces.ts index e2c6e6c5c..78323106f 100644 --- a/src/resources/MachineLearning/Models/ModelsInterfaces.ts +++ b/src/resources/MachineLearning/Models/ModelsInterfaces.ts @@ -1,7 +1,8 @@ import {IdAndDisplayNameModel} from '../../BaseInterfaces'; +import {AssociatedPipelineModel} from '../../Pipelines'; import {MLModelInfo} from '../ModelInformation/ModelInformationInterfaces'; -export interface MLModel extends MLModelInfo { +export interface MLModel extends MLModelInfo, ModelAttributes { orgId: string; id: string; engineId: string; @@ -53,3 +54,9 @@ export interface CustomerError { precision?: string; troubleshoot?: string; } + +export interface ModelAttributes { + associatedPipelines?: AssociatedPipelineModel[]; + parsedExportOffset?: string; + parsedExportPeriod?: string; +} diff --git a/src/resources/Pipelines/MLAssociations/MLAssociations.ts b/src/resources/Pipelines/MLAssociations/MLAssociations.ts new file mode 100644 index 000000000..d59e3c51f --- /dev/null +++ b/src/resources/Pipelines/MLAssociations/MLAssociations.ts @@ -0,0 +1,66 @@ +import Resource from '../../Resource'; +import Pipelines from '../Pipelines'; +import { + AssociatedPipelinesData, + AssociationsListModel, + CreateAssociation, + EditAssociation, + ListAssociationsParams, + MLAssociationModel, +} from './MLAssociationsInterfaces'; + +export default class MLAssociations extends Resource { + static getBaseUrl = (pipelineId: string) => `/rest/search/v2/admin/pipelines/${pipelineId}/ml/model/associations`; + + list(pipelineId: string, options?: ListAssociationsParams) { + return this.api.get(this.buildPath(MLAssociations.getBaseUrl(pipelineId), options)); + } + + associate(pipelineId: string, options: CreateAssociation) { + return this.api.post( + this.buildPath(MLAssociations.getBaseUrl(pipelineId), {organizationId: this.api.organizationId}), + options + ); + } + + getAssociation(pipelineId: string, associationId: string) { + return this.api.get( + this.buildPath(`${MLAssociations.getBaseUrl(pipelineId)}/${associationId}`, { + organizationId: this.api.organizationId, + }) + ); + } + + disassociate(pipelineId: string, modelId: string, associationId: string) { + return this.api.delete( + this.buildPath(`${MLAssociations.getBaseUrl(pipelineId)}/${associationId}/${modelId}`, { + organizationId: this.api.organizationId, + }) + ); + } + + updateAssociation(pipelineId: string, associationId: string, options?: EditAssociation) { + return this.api.put( + this.buildPath(`${MLAssociations.getBaseUrl(pipelineId)}/${associationId}`, { + organizationId: this.api.organizationId, + }), + options + ); + } + + updatePosition(pipelineId: string, associationId: string, position: number) { + return this.api.put( + this.buildPath(`${MLAssociations.getBaseUrl(pipelineId)}/${associationId}/position`, { + position, + organizationId: this.api.organizationId, + }), + {} + ); + } + + getAssociatedPipelines() { + return this.api.get( + this.buildPath(`${Pipelines.baseUrl}/ml/model/associations`, {organizationId: this.api.organizationId}) + ); + } +} diff --git a/src/resources/Pipelines/MLAssociations/MLAssociationsInterfaces.ts b/src/resources/Pipelines/MLAssociations/MLAssociationsInterfaces.ts new file mode 100644 index 000000000..2cb643ebd --- /dev/null +++ b/src/resources/Pipelines/MLAssociations/MLAssociationsInterfaces.ts @@ -0,0 +1,58 @@ +export interface AssociationsListModel { + rules: MLAssociationModel[]; + totalEntries: number; + totalPages: number; +} + +export interface MLAssociationModel { + id: string; + position: number; + modelId: string; + modelStatus: string; + cacheMaximumAge: string; + condition?: string; + conditionDefinition?: string; + customQueryParameters?: {}; + enableWordCompletion?: boolean; + exclusive?: boolean; + intelligentTermDetection?: boolean; + matchAdvancedExpression?: boolean; + matchBasicExpression?: boolean; + maxRecommendations?: number; + modelDisplayName?: string; + rankingModifier?: number; +} + +export interface ListAssociationsParams { + perPage?: number; + page?: number; +} + +export interface CreateAssociation extends EditAssociation { + modelId: string; +} + +export interface EditAssociation { + cacheMaximumAge?: string; + condition?: string; + customQueryParameters?: {}; + description?: string; + enableWordCompletion?: boolean; + exclusive?: boolean; + intelligentTermDetection?: boolean; + matchAdvancedExpression?: boolean; + matchBasicExpression?: boolean; + maxRecommendations?: number; + rankingModifier?: number; +} + +export interface AssociatedPipelinesData { + modelId: string; + associations: AssociatedPipelineModel[]; +} + +export interface AssociatedPipelineModel { + associationId: string; + pipelineId: string; + pipelineName: string; +} diff --git a/src/resources/Pipelines/MLAssociations/index.ts b/src/resources/Pipelines/MLAssociations/index.ts new file mode 100644 index 000000000..584bbd3cc --- /dev/null +++ b/src/resources/Pipelines/MLAssociations/index.ts @@ -0,0 +1,2 @@ +export * from './MLAssociations'; +export * from './MLAssociationsInterfaces'; diff --git a/src/resources/Pipelines/MLAssociations/tests/MLAssociations.spec.ts b/src/resources/Pipelines/MLAssociations/tests/MLAssociations.spec.ts new file mode 100644 index 000000000..e910b0d97 --- /dev/null +++ b/src/resources/Pipelines/MLAssociations/tests/MLAssociations.spec.ts @@ -0,0 +1,98 @@ +import API from '../../../../APICore'; +import Pipelines from '../../Pipelines'; +import MLAssociations from '../MLAssociations'; + +jest.mock('../../../../APICore'); + +const APIMock: jest.Mock = API as any; + +describe('MLAssociations', () => { + let associations: MLAssociations; + const api = new APIMock() as jest.Mocked; + + beforeEach(() => { + jest.clearAllMocks(); + associations = new MLAssociations(api); + }); + + describe('list', () => { + it('should make a GET call to the specific MLAssociations url', () => { + const pipelineId = 'diEnilEpip'; + + associations.list(pipelineId); + expect(api.get).toHaveBeenCalledTimes(1); + expect(api.get).toHaveBeenCalledWith(MLAssociations.getBaseUrl(pipelineId)); + }); + }); + + describe('associate', () => { + it('should make a POST call to the specific MLAssociations url', () => { + const pipelineId = '-_-'; + const options = {modelId: '0_0'}; + + associations.associate(pipelineId, options); + expect(api.post).toHaveBeenCalledTimes(1); + expect(api.post).toHaveBeenCalledWith(`${MLAssociations.getBaseUrl(pipelineId)}`, options); + }); + }); + + describe('getAssociation', () => { + it('should make a GET call to the specific MLAssociations url', () => { + const pipelineId = '-W-'; + const associationId = 'OWO'; + + associations.getAssociation(pipelineId, associationId); + expect(api.get).toHaveBeenCalledTimes(1); + expect(api.get).toHaveBeenCalledWith(`${MLAssociations.getBaseUrl(pipelineId)}/${associationId}`); + }); + }); + + describe('disassociate', () => { + it('should make a DELETE call to the specific MLAssociations url', () => { + const pipelineId = '123'; + const modelId = '321'; + const associationId = '000'; + + associations.disassociate(pipelineId, modelId, associationId); + expect(api.delete).toHaveBeenCalledTimes(1); + expect(api.delete).toHaveBeenCalledWith( + `${MLAssociations.getBaseUrl(pipelineId)}/${associationId}/${modelId}` + ); + }); + }); + + describe('updateAssociation', () => { + it('should make a PUT call to the specific MLAssociations url', () => { + const pipelineId = '999'; + const associationId = '111'; + const options = {exclusive: true}; + + associations.updateAssociation(pipelineId, associationId, options); + expect(api.put).toHaveBeenCalledTimes(1); + expect(api.put).toHaveBeenCalledWith(`${MLAssociations.getBaseUrl(pipelineId)}/${associationId}`, options); + }); + }); + + describe('updatePosition', () => { + it('should make a PUT call to the specific MLAssociations url', () => { + const pipelineId = '222'; + const associationId = '888'; + const position = 6; + + associations.updatePosition(pipelineId, associationId, position); + expect(api.put).toHaveBeenCalledTimes(1); + expect(api.put).toHaveBeenCalledWith( + `${MLAssociations.getBaseUrl(pipelineId)}/${associationId}/position?position=${position}`, + {} + ); + }); + }); + + describe('getAssociatedPipelines', () => { + it('should make a GET call to the specific MLAssociations url', () => { + associations.getAssociatedPipelines(); + expect(api.get).toHaveBeenCalledTimes(1); + expect(api.get).toHaveBeenCalledWith(`${Pipelines.baseUrl}/ml/model/associations`); + }); + }); +}); diff --git a/src/resources/Pipelines/Pipelines.ts b/src/resources/Pipelines/Pipelines.ts new file mode 100644 index 000000000..bf15368a0 --- /dev/null +++ b/src/resources/Pipelines/Pipelines.ts @@ -0,0 +1,22 @@ +import API from '../../APICore'; +import Resource from '../Resource'; +import MLAssociations from './MLAssociations/MLAssociations'; +import {PipelineBackendVersion} from './PipelinesInterfaces'; + +export default class Pipelines extends Resource { + static baseUrl = '/rest/search/v2/admin/pipelines'; + + associations: MLAssociations; + + constructor(protected api: API) { + super(api); + + this.associations = new MLAssociations(api); + } + + getBackendVersion() { + return this.api.get( + this.buildPath(`${Pipelines.baseUrl}/ml/version`, {organizationId: this.api.organizationId}) + ); + } +} diff --git a/src/resources/Pipelines/PipelinesInterfaces.ts b/src/resources/Pipelines/PipelinesInterfaces.ts new file mode 100644 index 000000000..17c0c3450 --- /dev/null +++ b/src/resources/Pipelines/PipelinesInterfaces.ts @@ -0,0 +1,3 @@ +export interface PipelineBackendVersion { + version: '1' | '2'; +} diff --git a/src/resources/Pipelines/index.ts b/src/resources/Pipelines/index.ts new file mode 100644 index 000000000..1732d6b6c --- /dev/null +++ b/src/resources/Pipelines/index.ts @@ -0,0 +1,3 @@ +export * from './Pipelines'; +export * from './PipelinesInterfaces'; +export * from './MLAssociations/'; diff --git a/src/resources/Pipelines/tests/Pipelines.spec.ts b/src/resources/Pipelines/tests/Pipelines.spec.ts new file mode 100644 index 000000000..bc489f2cc --- /dev/null +++ b/src/resources/Pipelines/tests/Pipelines.spec.ts @@ -0,0 +1,24 @@ +import API from '../../../APICore'; +import Pipelines from '../Pipelines'; + +jest.mock('../../../APICore'); + +const APIMock: jest.Mock = API as any; + +describe('Pipelines', () => { + let pipelines: Pipelines; + const api = new APIMock() as jest.Mocked; + + beforeEach(() => { + jest.clearAllMocks(); + pipelines = new Pipelines(api); + }); + + describe('getBackendVersion', () => { + it('should make a GET call to the specific Pipelines url', () => { + pipelines.getBackendVersion(); + expect(api.get).toHaveBeenCalledTimes(1); + expect(api.get).toHaveBeenCalledWith(`${Pipelines.baseUrl}/ml/version`); + }); + }); +}); diff --git a/src/resources/PlatformResources.ts b/src/resources/PlatformResources.ts index 1a2f7ed89..523cea4dc 100644 --- a/src/resources/PlatformResources.ts +++ b/src/resources/PlatformResources.ts @@ -7,6 +7,7 @@ import Group from './Groups/Groups'; import Index from './Indexes/Indexes'; import MachineLearning from './MachineLearning/MachineLearning'; import Organization from './Organizations/Organization'; +import Pipelines from './Pipelines/Pipelines'; import Resource from './Resource'; import SecurityCache from './SecurityCache/SecurityCache'; @@ -20,6 +21,7 @@ const resourcesMap: Array<{key: string; resource: typeof Resource}> = [ {key: 'securityCache', resource: SecurityCache}, {key: 'apiKey', resource: ApiKey}, {key: 'ml', resource: MachineLearning}, + {key: 'pipeline', resource: Pipelines}, ]; class PlatformResources { @@ -34,6 +36,7 @@ class PlatformResources { apiKey: ApiKey; ml: MachineLearning; securityCache: SecurityCache; + pipeline: Pipelines; registerAll() { resourcesMap.forEach(({key, resource}) => { diff --git a/src/resources/index.ts b/src/resources/index.ts index 2976fd8bf..304972cc2 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -10,3 +10,4 @@ export * from './License'; export * from './Organizations'; export * from './ApiKeys'; export * from './MachineLearning'; +export * from './Pipelines'; diff --git a/src/resources/tests/PlatformResources.spec.ts b/src/resources/tests/PlatformResources.spec.ts index 397b52122..45bb1943f 100644 --- a/src/resources/tests/PlatformResources.spec.ts +++ b/src/resources/tests/PlatformResources.spec.ts @@ -5,6 +5,7 @@ import Cluster from '../Clusters/Cluster'; import Group from '../Groups/Groups'; import MachineLearning from '../MachineLearning/MachineLearning'; import Organization from '../Organizations/Organization'; +import Pipelines from '../Pipelines/Pipelines'; import PlatformResources from '../PlatformResources'; import SecurityCache from '../SecurityCache/SecurityCache'; @@ -73,5 +74,13 @@ describe('PlatformResources', () => { expect(platformResources.ml).toBeDefined(); expect(platformResources.ml).toBeInstanceOf(MachineLearning); }); + + it('should register the pipeline resource on the platform instance', () => { + const platformResources = new PlatformResources(); + platformResources.registerAll(); + + expect(platformResources.pipeline).toBeDefined(); + expect(platformResources.pipeline).toBeInstanceOf(Pipelines); + }); }); });