Skip to content
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

Phase 1 of search services #46742

Merged
merged 26 commits into from
Oct 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
e9d62d2
Phase 1 of search services
stacey-gammon Sep 26, 2019
1da04ee
First review feedback
lukasolson Oct 1, 2019
d2c6787
Merge pull request #11 from lukasolson/np-search-api
stacey-gammon Oct 1, 2019
c0d3070
Start on tests
stacey-gammon Oct 1, 2019
6c9a09a
Add functional tests for search explorer
stacey-gammon Oct 2, 2019
83806cc
Add unload and fix ts error
stacey-gammon Oct 2, 2019
606dcc0
Merge branch 'master' of github.com:elastic/kibana into 2019-09-25-np…
stacey-gammon Oct 2, 2019
00a22d6
Add index.test.ts files for coverage completeness
stacey-gammon Oct 2, 2019
ba50e95
Adding unit tests
lukasolson Oct 2, 2019
83eab32
Merge pull request #12 from lukasolson/np-search-api
stacey-gammon Oct 3, 2019
d75b3e9
use internal route terminology. No reason this should be a public rou…
stacey-gammon Oct 3, 2019
1617ffa
Move search service into data plugin
stacey-gammon Oct 3, 2019
95bde79
Merge branch 'master' of github.com:elastic/kibana into 2019-09-25-np…
stacey-gammon Oct 3, 2019
ce571b5
App mount search context needs to be optional
stacey-gammon Oct 3, 2019
e5ea60e
Merge branch 'master' of github.com:elastic/kibana into 2019-09-25-np…
stacey-gammon Oct 3, 2019
64de132
Add more unit tests for server stuff
lukasolson Oct 3, 2019
2c6c96f
Merge pull request #13 from lukasolson/np-search-api
stacey-gammon Oct 4, 2019
88e73f6
wip types fix
stacey-gammon Oct 7, 2019
e9e75ef
Merge branch 'master' of github.com:elastic/kibana into 2019-09-25-np…
stacey-gammon Oct 7, 2019
83aa47a
fix types for new context container stuff
stacey-gammon Oct 7, 2019
2c9b24c
put back all jest test coverage paths
stacey-gammon Oct 7, 2019
25ec030
address review comments
stacey-gammon Oct 8, 2019
82db4e7
Merge branch 'master' of github.com:elastic/kibana into 2019-09-25-np…
stacey-gammon Oct 8, 2019
8621708
delete the two test files that just tested the instantiation of the s…
stacey-gammon Oct 8, 2019
1678aec
expose search fn on StartContract... tested locally only
stacey-gammon Oct 9, 2019
ce0a93f
update mocks to account for new startcontract
stacey-gammon Oct 9, 2019
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
2 changes: 2 additions & 0 deletions src/dev/jest/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ export default {
'<rootDir>/test/functional/services/remote',
],
collectCoverageFrom: [
'src/plugins/**/*.{ts,tsx}',
'!src/plugins/**/*.d.ts',
'packages/kbn-ui-framework/src/components/**/*.js',
'!packages/kbn-ui-framework/src/components/index.js',
'!packages/kbn-ui-framework/src/components/**/*/index.js',
Expand Down
20 changes: 20 additions & 0 deletions src/plugins/data/common/search/es_search/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

export { IEsSearchRequest, IEsSearchResponse, ES_SEARCH_STRATEGY } from './types';
30 changes: 30 additions & 0 deletions src/plugins/data/common/search/es_search/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { SearchParams, SearchResponse } from 'elasticsearch';
import { IKibanaSearchRequest, IKibanaSearchResponse } from '../types';

export const ES_SEARCH_STRATEGY = 'es';

export interface IEsSearchRequest extends IKibanaSearchRequest {
params: SearchParams;
}

export interface IEsSearchResponse<Hits = unknown> extends IKibanaSearchResponse {
rawResponse: SearchResponse<Hits>;
}
26 changes: 26 additions & 0 deletions src/plugins/data/common/search/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { ES_SEARCH_STRATEGY } from './es_search';

export { IKibanaSearchResponse, IKibanaSearchRequest } from './types';

export const DEFAULT_SEARCH_STRATEGY = ES_SEARCH_STRATEGY;

export { IEsSearchRequest, IEsSearchResponse, ES_SEARCH_STRATEGY } from './es_search';
55 changes: 55 additions & 0 deletions src/plugins/data/common/search/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

export interface IKibanaSearchResponse {
/**
* Some responses may contain a unique id to identify the request this response came from.
*/
id?: string;

/**
* If relevant to the search strategy, return a percentage
* that represents how progress is indicated.
*/
percentComplete?: number;

/**
* If relevant to the search strategy, return a total number
* that represents how progress is indicated.
*/
total?: number;

/**
* If relevant to the search strategy, return a loaded number
* that represents how progress is indicated.
*/
loaded?: number;
}

export interface IKibanaSearchRequest {
/**
* An id can be used to uniquely identify this request.
*/
id?: string;

/**
* Optionally tell search strategies to output debug information.
*/
debug?: boolean;
}
3 changes: 3 additions & 0 deletions src/plugins/data/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@ export * from '../common';
export * from './autocomplete_provider';

export * from './types';

export { IRequestTypesMap, IResponseTypesMap } from './search';
export * from './search';
3 changes: 3 additions & 0 deletions src/plugins/data/public/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* under the License.
*/
import { Plugin } from '.';
import { searchSetupMock } from './search/mocks';

export type Setup = jest.Mocked<ReturnType<Plugin['setup']>>;
export type Start = jest.Mocked<ReturnType<Plugin['start']>>;
Expand All @@ -30,6 +31,7 @@ const autocompleteMock: any = {
const createSetupContract = (): Setup => {
const setupContract: Setup = {
autocomplete: autocompleteMock as Setup['autocomplete'],
search: searchSetupMock,
};

return setupContract;
Expand All @@ -39,6 +41,7 @@ const createStartContract = (): Start => {
const startContract: Start = {
autocomplete: autocompleteMock as Start['autocomplete'],
getSuggestions: jest.fn(),
search: { search: jest.fn() },
};
return startContract;
};
Expand Down
8 changes: 7 additions & 1 deletion src/plugins/data/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,29 @@
import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from '../../../core/public';
import { AutocompleteProviderRegister } from './autocomplete_provider';
import { DataPublicPluginSetup, DataPublicPluginStart } from './types';
import { SearchService } from './search/search_service';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why import both, or why even have searchService function, all it does is new SearchService(params) ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copied the plugin way of doing things (this was its own separate plugin so this was the index.ts file, at the plugin level, this is export plugin..., here I renamed it export searchService ...). Not necessary except for conformity. It is pretty silly when you take it outside of the plugin level. I can remove.

import { getSuggestionsProvider } from './suggestions_provider';

export class DataPublicPlugin implements Plugin<DataPublicPluginSetup, DataPublicPluginStart> {
private readonly autocomplete = new AutocompleteProviderRegister();
private readonly searchService: SearchService;

constructor(initializerContext: PluginInitializerContext) {}
constructor(initializerContext: PluginInitializerContext) {
this.searchService = new SearchService(initializerContext);
}

public setup(core: CoreSetup): DataPublicPluginSetup {
return {
autocomplete: this.autocomplete,
search: this.searchService.setup(core),
};
}

public start(core: CoreStart): DataPublicPluginStart {
return {
autocomplete: this.autocomplete,
getSuggestions: getSuggestionsProvider(core.uiSettings, core.http),
search: this.searchService.start(core),
};
}

Expand Down
13 changes: 13 additions & 0 deletions src/plugins/data/public/search/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# search

The `search` plugin provides the ability to register search strategies that take in a request
object, and return a response object, of a given shape.

Both client side search strategies can be registered, as well as server side search strategies.

The `search` plugin includes two one concrete client side implementations -
`SYNC_SEARCH_STRATEGY` and `ES_SEARCH_STRATEGY` which uses `SYNC_SEARCH_STRATEGY`. There is also one
default server side search strategy, `ES_SEARCH_STRATEGY`.

Includes the `esSearch` plugin in order to search for data from Elasticsearch using Elasticsearch
DSL.
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { createAppMountSearchContext } from './create_app_mount_context_search';
import { from } from 'rxjs';

describe('Create app mount search context', () => {
it('Returns search fn when there are no strategies', () => {
const context = createAppMountSearchContext({});
expect(context.search).toBeDefined();
});

it(`Search throws an error when the strategy doesn't exist`, () => {
const context = createAppMountSearchContext({});
expect(() => context.search({}, {}, 'noexist').toPromise()).toThrowErrorMatchingInlineSnapshot(
`"Strategy with name noexist does not exist"`
);
});

it(`Search fn is called on appropriate strategy name`, done => {
const context = createAppMountSearchContext({
mysearch: search =>
Promise.resolve({
search: () => from(Promise.resolve({ percentComplete: 98 })),
}),
anothersearch: search =>
Promise.resolve({
search: () => from(Promise.resolve({ percentComplete: 0 })),
}),
});

context.search({}, {}, 'mysearch').subscribe(response => {
expect(response).toEqual({ percentComplete: 98 });
done();
});
});

it(`Search fn is called with the passed in request object`, done => {
const context = createAppMountSearchContext({
mysearch: search => {
return Promise.resolve({
search: request => {
expect(request).toEqual({ greeting: 'hi' });
return from(Promise.resolve({}));
},
});
},
});
context
.search({ greeting: 'hi' } as any, {}, 'mysearch')
.subscribe(response => {}, () => {}, done);
});
});
57 changes: 57 additions & 0 deletions src/plugins/data/public/search/create_app_mount_context_search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { mergeMap } from 'rxjs/operators';
import { from } from 'rxjs';
import { ISearchAppMountContext } from './i_search_app_mount_context';
import { ISearchGeneric } from './i_search';
import {
TSearchStrategiesMap,
ISearchStrategy,
TSearchStrategyProviderEnhanced,
} from './i_search_strategy';
import { TStrategyTypes } from './strategy_types';
import { DEFAULT_SEARCH_STRATEGY } from '../../common/search';

export const createAppMountSearchContext = (
searchStrategies: TSearchStrategiesMap
): ISearchAppMountContext => {
const getSearchStrategy = <K extends TStrategyTypes = typeof DEFAULT_SEARCH_STRATEGY>(
strategyName?: K
): Promise<ISearchStrategy<K>> => {
const strategyProvider = searchStrategies[
strategyName ? strategyName : DEFAULT_SEARCH_STRATEGY
] as TSearchStrategyProviderEnhanced<K> | undefined;
if (!strategyProvider) {
throw new Error(`Strategy with name ${strategyName} does not exist`);
}
return strategyProvider(search);
};

const search: ISearchGeneric = (request, options, strategyName) => {
const strategyPromise = getSearchStrategy(strategyName);
return from(strategyPromise).pipe(
mergeMap(strategy => {
return strategy.search(request, options);
})
);
};

return { search };
};
43 changes: 43 additions & 0 deletions src/plugins/data/public/search/es_search/es_search_service.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { coreMock } from '../../../../../core/public/mocks';
import { EsSearchService } from './es_search_service';
import { CoreSetup } from '../../../../../core/public';
import { searchSetupMock } from '../mocks';

describe('ES search strategy service', () => {
let service: EsSearchService;
let mockCoreSetup: MockedKeys<CoreSetup>;
const opaqueId = Symbol();

beforeEach(() => {
service = new EsSearchService({ opaqueId });
mockCoreSetup = coreMock.createSetup();
});

describe('setup()', () => {
it('registers the ES search strategy', async () => {
service.setup(mockCoreSetup, {
search: searchSetupMock,
});
expect(searchSetupMock.registerSearchStrategyProvider).toBeCalled();
});
});
});
Loading