Skip to content

Commit

Permalink
Allow passing a default operator to use on saved object client find o…
Browse files Browse the repository at this point in the history
…perations (elastic#29339)

* Allow passing a default operator to use on find operations

* Default operator to OR like elasticsearch to avoid passing null

* Add dashboard search tests

* Make search_operator optional

* Fix query_params.test.js

* Include searchOperator in saved_object_finder

* Apply PR feedback

* Rename searchOperator to defaultSearchOperator
  • Loading branch information
mikecote committed Jan 30, 2019
1 parent 177ddab commit 9ba7344
Show file tree
Hide file tree
Showing 15 changed files with 99 additions and 12 deletions.
2 changes: 2 additions & 0 deletions docs/api/saved-objects/find.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ saved objects by various conditions.
(number) The page of objects to return
`search` (optional)::
(string) A {ref}/query-dsl-simple-query-string-query.html[simple_query_string] Elasticsearch query to filter the objects in the response
`default_search_operator` (optional)::
(string) The default operator to use for the `simple_query_string`
`search_fields` (optional)::
(array|string) The fields to perform the `simple_query_string` parsed query against
`fields` (optional)::
Expand Down
1 change: 1 addition & 0 deletions src/server/saved_objects/routes/find.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export const createFindRoute = (prereqs) => ({
page: Joi.number().min(0).default(1),
type: Joi.array().items(Joi.string()).single().required(),
search: Joi.string().allow('').optional(),
default_search_operator: Joi.string().valid('OR', 'AND').default('OR'),
search_fields: Joi.array().items(Joi.string()).single(),
sort_field: Joi.array().items(Joi.string()).single(),
fields: Joi.array().items(Joi.string()).single()
Expand Down
14 changes: 7 additions & 7 deletions src/server/saved_objects/routes/find.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ describe('GET /api/saved_objects/_find', () => {
expect(savedObjectsClient.find.calledOnce).toBe(true);

const options = savedObjectsClient.find.getCall(0).args[0];
expect(options).toEqual({ perPage: 20, page: 1, type: ['foo', 'bar'] });
expect(options).toEqual({ perPage: 20, page: 1, type: ['foo', 'bar'], defaultSearchOperator: 'OR' });
});

it('accepts the query parameter page/per_page', async () => {
Expand All @@ -119,7 +119,7 @@ describe('GET /api/saved_objects/_find', () => {
expect(savedObjectsClient.find.calledOnce).toBe(true);

const options = savedObjectsClient.find.getCall(0).args[0];
expect(options).toEqual({ perPage: 10, page: 50, type: ['foo'] });
expect(options).toEqual({ perPage: 10, page: 50, type: ['foo'], defaultSearchOperator: 'OR' });
});

it('accepts the query parameter search_fields', async () => {
Expand All @@ -133,7 +133,7 @@ describe('GET /api/saved_objects/_find', () => {
expect(savedObjectsClient.find.calledOnce).toBe(true);

const options = savedObjectsClient.find.getCall(0).args[0];
expect(options).toEqual({ perPage: 20, page: 1, searchFields: ['title'], type: ['foo'] });
expect(options).toEqual({ perPage: 20, page: 1, searchFields: ['title'], type: ['foo'], defaultSearchOperator: 'OR' });
});

it('accepts the query parameter fields as a string', async () => {
Expand All @@ -147,7 +147,7 @@ describe('GET /api/saved_objects/_find', () => {
expect(savedObjectsClient.find.calledOnce).toBe(true);

const options = savedObjectsClient.find.getCall(0).args[0];
expect(options).toEqual({ perPage: 20, page: 1, fields: ['title'], type: ['foo'] });
expect(options).toEqual({ perPage: 20, page: 1, fields: ['title'], type: ['foo'], defaultSearchOperator: 'OR' });
});

it('accepts the query parameter fields as an array', async () => {
Expand All @@ -162,7 +162,7 @@ describe('GET /api/saved_objects/_find', () => {

const options = savedObjectsClient.find.getCall(0).args[0];
expect(options).toEqual({
perPage: 20, page: 1, fields: ['title', 'description'], type: ['foo']
perPage: 20, page: 1, fields: ['title', 'description'], type: ['foo'], defaultSearchOperator: 'OR'
});
});

Expand All @@ -177,7 +177,7 @@ describe('GET /api/saved_objects/_find', () => {
expect(savedObjectsClient.find.calledOnce).toBe(true);

const options = savedObjectsClient.find.getCall(0).args[0];
expect(options).toEqual({ perPage: 20, page: 1, type: ['index-pattern'] });
expect(options).toEqual({ perPage: 20, page: 1, type: ['index-pattern'], defaultSearchOperator: 'OR' });
});

it('accepts the query parameter type as an array', async () => {
Expand All @@ -191,6 +191,6 @@ describe('GET /api/saved_objects/_find', () => {
expect(savedObjectsClient.find.calledOnce).toBe(true);

const options = savedObjectsClient.find.getCall(0).args[0];
expect(options).toEqual({ perPage: 20, page: 1, type: ['index-pattern', 'visualization'] });
expect(options).toEqual({ perPage: 20, page: 1, type: ['index-pattern', 'visualization'], defaultSearchOperator: 'OR' });
});
});
3 changes: 3 additions & 0 deletions src/server/saved_objects/service/lib/repository.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ export class SavedObjectsRepository {
* @param {object} [options={}]
* @property {(string|Array<string>)} [options.type]
* @property {string} [options.search]
* @property {string} [options.defaultSearchOperator]
* @property {Array<string>} [options.searchFields] - see Elasticsearch Simple Query String
* Query field argument for more information
* @property {integer} [options.page=1]
Expand All @@ -295,6 +296,7 @@ export class SavedObjectsRepository {
const {
type,
search,
defaultSearchOperator = 'OR',
searchFields,
page = 1,
perPage = 20,
Expand Down Expand Up @@ -327,6 +329,7 @@ export class SavedObjectsRepository {
version: true,
...getSearchDsl(this._mappings, this._schema, {
search,
defaultSearchOperator,
searchFields,
type,
sortField,
Expand Down
3 changes: 2 additions & 1 deletion src/server/saved_objects/service/lib/repository.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -814,7 +814,7 @@ describe('SavedObjectsRepository', () => {
}
});

it('passes mappings, schema, search, searchFields, type, sortField, and sortOrder to getSearchDsl', async () => {
it('passes mappings, schema, search, defaultSearchOperator, searchFields, type, sortField, and sortOrder to getSearchDsl', async () => {
callAdminCluster.returns(namespacedSearchResults);
const relevantOpts = {
namespace: 'foo-namespace',
Expand All @@ -823,6 +823,7 @@ describe('SavedObjectsRepository', () => {
type: 'bar',
sortField: 'name',
sortOrder: 'desc',
defaultSearchOperator: 'AND',
};

await savedObjectsRepository.find(relevantOpts);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,10 @@ function getClauseForType(schema, namespace, type) {
* @param {(string|Array<string>)} type
* @param {String} search
* @param {Array<string>} searchFields
* @param {String} defaultSearchOperator
* @return {Object}
*/
export function getQueryParams(mappings, schema, namespace, type, search, searchFields) {
export function getQueryParams(mappings, schema, namespace, type, search, searchFields, defaultSearchOperator) {
const types = getTypes(mappings, type);
const bool = {
filter: [{
Expand All @@ -119,7 +120,8 @@ export function getQueryParams(mappings, schema, namespace, type, search, search
...getFieldsForTypes(
searchFields,
types
)
),
...(defaultSearchOperator ? { default_operator: defaultSearchOperator } : {}),
}
}
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -716,4 +716,68 @@ describe('searchDsl/queryParams', () => {
});
});
});

describe('type (plural, namespaced and global), search, defaultSearchOperator', () => {
it('supports defaultSearchOperator', () => {
expect(getQueryParams(MAPPINGS, SCHEMA, 'foo-namespace', ['saved', 'global'], 'foo', null, 'AND'))
.toEqual({
query: {
bool: {
filter: [
{
bool: {
minimum_should_match: 1,
should: [
{
bool: {
must: [
{
term: {
type: 'saved',
},
},
{
term: {
namespace: 'foo-namespace',
},
},
],
},
},
{
bool: {
must: [
{
term: {
type: 'global',
},
},
],
must_not: [
{
exists: {
field: 'namespace',
},
},
],
},
},
],
},
},
],
must: [
{
simple_query_string: {
all_fields: true,
default_operator: 'AND',
query: 'foo',
},
},
],
},
},
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export function getSearchDsl(mappings, schema, options = {}) {
const {
type,
search,
defaultSearchOperator,
searchFields,
sortField,
sortOrder,
Expand All @@ -41,7 +42,7 @@ export function getSearchDsl(mappings, schema, options = {}) {
}

return {
...getQueryParams(mappings, schema, namespace, type, search, searchFields),
...getQueryParams(mappings, schema, namespace, type, search, searchFields, defaultSearchOperator),
...getSortingParams(mappings, type, sortField, sortOrder),
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ describe('getSearchDsl', () => {
type: 'foo',
search: 'bar',
searchFields: ['baz'],
defaultSearchOperator: 'AND',
};

getSearchDsl(mappings, schema, opts);
Expand All @@ -67,6 +68,7 @@ describe('getSearchDsl', () => {
opts.type,
opts.search,
opts.searchFields,
opts.defaultSearchOperator,
);
});

Expand Down
1 change: 1 addition & 0 deletions src/server/saved_objects/service/saved_objects_client.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ export class SavedObjectsClient {
* @param {object} [options={}]
* @property {(string|Array<string>)} [options.type]
* @property {string} [options.search]
* @property {string} [options.defaultSearchOperator]
* @property {Array<string>} [options.searchFields] - see Elasticsearch Simple Query String
* Query field argument for more information
* @property {integer} [options.page=1]
Expand Down
1 change: 1 addition & 0 deletions src/ui/public/courier/saved_object/saved_object_loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ export class SavedObjectLoader {
perPage: size,
page: 1,
searchFields: ['title^3', 'description'],
defaultSearchOperator: 'AND',
fields,
}).then((resp) => {
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ class SavedObjectFinderUI extends React.Component {
search: filter ? `${filter}*` : undefined,
page: 1,
perPage: chrome.getUiSettingsClient().get('savedObjects:listingLimit'),
searchFields: ['title^3', 'description']
searchFields: ['title^3', 'description'],
defaultSearchOperator: 'AND',
});

if (this.props.savedObjectType === 'visualization'
Expand Down
1 change: 1 addition & 0 deletions src/ui/public/saved_objects/saved_objects_client.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ export class SavedObjectsClient {
* @param {object} [options={}]
* @property {string} options.type
* @property {string} options.search
* @property {string} options.defaultSearchOperator
* @property {string} options.searchFields - see Elasticsearch Simple Query String
* Query field argument for more information
* @property {integer} [options.page=1]
Expand Down
6 changes: 6 additions & 0 deletions test/functional/apps/dashboard/_dashboard_listing.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ export default function ({ getService, getPageObjects }) {
const countOfDashboards = await PageObjects.dashboard.getCountOfDashboardsInListingTable();
expect(countOfDashboards).to.equal(1);
});

it('is using AND operator', async function () {
await PageObjects.dashboard.searchForDashboardWithName('three words');
const countOfDashboards = await PageObjects.dashboard.getCountOfDashboardsInListingTable();
expect(countOfDashboards).to.equal(0);
});
});

describe('search by title', function () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ export class SpacesSavedObjectsClient implements SavedObjectsClient {
* @param {object} [options={}]
* @property {(string|Array<string>)} [options.type]
* @property {string} [options.search]
* @property {string} [options.defaultSearchOperator]
* @property {Array<string>} [options.searchFields] - see Elasticsearch Simple Query String
* Query field argument for more information
* @property {integer} [options.page=1]
Expand Down

0 comments on commit 9ba7344

Please sign in to comment.