diff --git a/src/core_plugins/input_control_vis/public/control/create_search_source.js b/src/core_plugins/input_control_vis/public/control/create_search_source.js index f00125c8ba757..87cf9da28ba0a 100644 --- a/src/core_plugins/input_control_vis/public/control/create_search_source.js +++ b/src/core_plugins/input_control_vis/public/control/create_search_source.js @@ -21,16 +21,16 @@ export function createSearchSource(kbnApi, initialState, indexPattern, aggs, useTimeFilter, filters = []) { const searchSource = new kbnApi.SearchSource(initialState); // Do not not inherit from rootSearchSource to avoid picking up time and globals - searchSource.inherits(false); - searchSource.filter(() => { + searchSource.setParent(false); + searchSource.setField('filter', () => { const activeFilters = [...filters]; if (useTimeFilter) { activeFilters.push(kbnApi.timeFilter.createFilter(indexPattern)); } return activeFilters; }); - searchSource.size(0); - searchSource.index(indexPattern); - searchSource.aggs(aggs); + searchSource.setField('size', 0); + searchSource.setField('index', indexPattern); + searchSource.setField('aggs', aggs); return searchSource; } diff --git a/src/core_plugins/kibana/public/context/api/__tests__/_stubs.js b/src/core_plugins/kibana/public/context/api/__tests__/_stubs.js index 2100745f54e73..53aa102864141 100644 --- a/src/core_plugins/kibana/public/context/api/__tests__/_stubs.js +++ b/src/core_plugins/kibana/public/context/api/__tests__/_stubs.js @@ -39,18 +39,17 @@ export function createSearchSourceStubProvider(hits, timeField) { }), }; - searchSourceStub.filter = sinon.stub().returns(searchSourceStub); - searchSourceStub.inherits = sinon.stub().returns(searchSourceStub); - searchSourceStub.set = sinon.stub().returns(searchSourceStub); - searchSourceStub.get = sinon.spy(key => { - const previousSetCall = searchSourceStub.set.withArgs(key).lastCall; + searchSourceStub.setParent = sinon.stub().returns(searchSourceStub); + searchSourceStub.setField = sinon.stub().returns(searchSourceStub); + searchSourceStub.getField = sinon.spy(key => { + const previousSetCall = searchSourceStub.setField.withArgs(key).lastCall; return previousSetCall ? previousSetCall.args[1] : null; }); searchSourceStub.fetch = sinon.spy(() => { const timeField = searchSourceStub._stubTimeField; - const lastQuery = searchSourceStub.set.withArgs('query').lastCall.args[1]; + const lastQuery = searchSourceStub.setField.withArgs('query').lastCall.args[1]; const timeRange = lastQuery.query.constant_score.filter.range[timeField]; - const lastSort = searchSourceStub.set.withArgs('sort').lastCall.args[1]; + const lastSort = searchSourceStub.setField.withArgs('sort').lastCall.args[1]; const sortDirection = lastSort[0][timeField]; const sortFunction = sortDirection === 'asc' diff --git a/src/core_plugins/kibana/public/context/api/__tests__/anchor.js b/src/core_plugins/kibana/public/context/api/__tests__/anchor.js index 044e61d8608e2..1fd84edb43156 100644 --- a/src/core_plugins/kibana/public/context/api/__tests__/anchor.js +++ b/src/core_plugins/kibana/public/context/api/__tests__/anchor.js @@ -26,6 +26,24 @@ import { SearchSourceProvider } from 'ui/courier'; import { fetchAnchorProvider } from '../anchor'; +function createSearchSourceStubProvider(hits) { + const searchSourceStub = { + _stubHits: hits, + }; + + searchSourceStub.setParent = sinon.stub().returns(searchSourceStub); + searchSourceStub.setField = sinon.stub().returns(searchSourceStub); + searchSourceStub.fetch = sinon.spy(() => Promise.resolve({ + hits: { + hits: searchSourceStub._stubHits, + total: searchSourceStub._stubHits.length, + }, + })); + + return function SearchSourceStubProvider() { + return searchSourceStub; + }; +} describe('context app', function () { beforeEach(ngMock.module('kibana')); @@ -61,9 +79,9 @@ describe('context app', function () { return fetchAnchor('INDEX_PATTERN_ID', 'doc', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'asc' }]) .then(() => { - const inheritsSpy = searchSourceStub.inherits; - expect(inheritsSpy.calledOnce).to.be(true); - expect(inheritsSpy.firstCall.args[0]).to.eql(false); + const setParentSpy = searchSourceStub.setParent; + expect(setParentSpy.calledOnce).to.be(true); + expect(setParentSpy.firstCall.args[0]).to.eql(false); }); }); @@ -72,9 +90,8 @@ describe('context app', function () { return fetchAnchor('INDEX_PATTERN_ID', 'doc', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'asc' }]) .then(() => { - const setIndexSpy = searchSourceStub.set.withArgs('index'); - expect(setIndexSpy.calledOnce).to.be(true); - expect(setIndexSpy.firstCall.args[1]).to.eql({ id: 'INDEX_PATTERN_ID' }); + const setFieldSpy = searchSourceStub.setField; + expect(setFieldSpy.firstCall.args[1]).to.eql({ id: 'INDEX_PATTERN_ID' }); }); }); @@ -83,7 +100,7 @@ describe('context app', function () { return fetchAnchor('INDEX_PATTERN_ID', 'doc', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'asc' }]) .then(() => { - const setVersionSpy = searchSourceStub.set.withArgs('version'); + const setVersionSpy = searchSourceStub.setField.withArgs('version'); expect(setVersionSpy.calledOnce).to.be(true); expect(setVersionSpy.firstCall.args[1]).to.eql(true); }); @@ -94,7 +111,7 @@ describe('context app', function () { return fetchAnchor('INDEX_PATTERN_ID', 'doc', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'asc' }]) .then(() => { - const setSizeSpy = searchSourceStub.set.withArgs('size'); + const setSizeSpy = searchSourceStub.setField.withArgs('size'); expect(setSizeSpy.calledOnce).to.be(true); expect(setSizeSpy.firstCall.args[1]).to.eql(1); }); @@ -105,7 +122,7 @@ describe('context app', function () { return fetchAnchor('INDEX_PATTERN_ID', 'doc', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'asc' }]) .then(() => { - const setQuerySpy = searchSourceStub.set.withArgs('query'); + const setQuerySpy = searchSourceStub.setField.withArgs('query'); expect(setQuerySpy.calledOnce).to.be(true); expect(setQuerySpy.firstCall.args[1]).to.eql({ query: { @@ -128,7 +145,7 @@ describe('context app', function () { return fetchAnchor('INDEX_PATTERN_ID', 'doc', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'asc' }]) .then(() => { - const setSortSpy = searchSourceStub.set.withArgs('sort'); + const setSortSpy = searchSourceStub.setField.withArgs('sort'); expect(setSortSpy.calledOnce).to.be(true); expect(setSortSpy.firstCall.args[1]).to.eql([ { '@timestamp': 'desc' }, @@ -167,23 +184,3 @@ describe('context app', function () { }); }); }); - -function createSearchSourceStubProvider(hits) { - const searchSourceStub = { - _stubHits: hits, - }; - - searchSourceStub.filter = sinon.stub().returns(searchSourceStub); - searchSourceStub.inherits = sinon.stub().returns(searchSourceStub); - searchSourceStub.set = sinon.stub().returns(searchSourceStub); - searchSourceStub.fetch = sinon.spy(() => Promise.resolve({ - hits: { - hits: searchSourceStub._stubHits, - total: searchSourceStub._stubHits.length, - }, - })); - - return function SearchSourceStubProvider() { - return searchSourceStub; - }; -} diff --git a/src/core_plugins/kibana/public/context/api/__tests__/predecessors.js b/src/core_plugins/kibana/public/context/api/__tests__/predecessors.js index e940468bcbcd9..2e461ff836fe6 100644 --- a/src/core_plugins/kibana/public/context/api/__tests__/predecessors.js +++ b/src/core_plugins/kibana/public/context/api/__tests__/predecessors.js @@ -95,7 +95,7 @@ describe('context app', function () { [] ) .then((hits) => { - const intervals = searchSourceStub.set.args + const intervals = searchSourceStub.setField.args .filter(([property]) => property === 'query') .map(([, { query }]) => _.get(query, ['constant_score', 'filter', 'range', '@timestamp'])); @@ -131,7 +131,7 @@ describe('context app', function () { [] ) .then((hits) => { - const intervals = searchSourceStub.set.args + const intervals = searchSourceStub.setField.args .filter(([property]) => property === 'query') .map(([, { query }]) => _.get(query, ['constant_score', 'filter', 'range', '@timestamp'])); @@ -177,9 +177,9 @@ describe('context app', function () { [] ) .then(() => { - const inheritsSpy = searchSourceStub.inherits; - expect(inheritsSpy.alwaysCalledWith(false)).to.be(true); - expect(inheritsSpy.called).to.be(true); + const setParentSpy = searchSourceStub.setParent; + expect(setParentSpy.alwaysCalledWith(false)).to.be(true); + expect(setParentSpy.called).to.be(true); }); }); }); diff --git a/src/core_plugins/kibana/public/context/api/__tests__/successors.js b/src/core_plugins/kibana/public/context/api/__tests__/successors.js index bede78439a22f..1974d55655e25 100644 --- a/src/core_plugins/kibana/public/context/api/__tests__/successors.js +++ b/src/core_plugins/kibana/public/context/api/__tests__/successors.js @@ -95,7 +95,7 @@ describe('context app', function () { [] ) .then((hits) => { - const intervals = searchSourceStub.set.args + const intervals = searchSourceStub.setField.args .filter(([property]) => property === 'query') .map(([, { query }]) => _.get(query, ['constant_score', 'filter', 'range', '@timestamp'])); @@ -133,7 +133,7 @@ describe('context app', function () { [] ) .then((hits) => { - const intervals = searchSourceStub.set.args + const intervals = searchSourceStub.setField.args .filter(([property]) => property === 'query') .map(([, { query }]) => _.get(query, ['constant_score', 'filter', 'range', '@timestamp'])); @@ -179,9 +179,9 @@ describe('context app', function () { [] ) .then(() => { - const inheritsSpy = searchSourceStub.inherits; - expect(inheritsSpy.alwaysCalledWith(false)).to.be(true); - expect(inheritsSpy.called).to.be(true); + const setParentSpy = searchSourceStub.setParent; + expect(setParentSpy.alwaysCalledWith(false)).to.be(true); + expect(setParentSpy.called).to.be(true); }); }); }); diff --git a/src/core_plugins/kibana/public/context/api/anchor.js b/src/core_plugins/kibana/public/context/api/anchor.js index 81d88f0394504..4c541845251f6 100644 --- a/src/core_plugins/kibana/public/context/api/anchor.js +++ b/src/core_plugins/kibana/public/context/api/anchor.js @@ -32,11 +32,11 @@ export function fetchAnchorProvider(indexPatterns, Private) { ) { const indexPattern = await indexPatterns.get(indexPatternId); const searchSource = new SearchSource() - .inherits(false) - .set('index', indexPattern) - .set('version', true) - .set('size', 1) - .set('query', { + .setParent(false) + .setField('index', indexPattern) + .setField('version', true) + .setField('size', 1) + .setField('query', { query: { constant_score: { filter: { @@ -49,7 +49,7 @@ export function fetchAnchorProvider(indexPatterns, Private) { }, language: 'lucene', }) - .set('sort', sort); + .setField('sort', sort); const response = await searchSource.fetch(); diff --git a/src/core_plugins/kibana/public/context/api/context.js b/src/core_plugins/kibana/public/context/api/context.js index d9446502e8e0c..68ca81e83a20e 100644 --- a/src/core_plugins/kibana/public/context/api/context.js +++ b/src/core_plugins/kibana/public/context/api/context.js @@ -33,8 +33,8 @@ import { reverseSortDirection } from './utils/sorting'; /** * @typedef {Object} SearchSourceT * @prop {function(): Promise} fetch - * @prop {function(string, any): SearchSourceT} set - * @prop {function(any): SearchSourceT} inherits + * @prop {function(string, any): SearchSourceT} setField + * @prop {function(any): SearchSourceT} setParent */ /** @@ -162,9 +162,9 @@ function fetchContextProvider(indexPatterns, Private) { const indexPattern = await indexPatterns.get(indexPatternId); return new SearchSource() - .inherits(false) - .set('index', indexPattern) - .set('filter', filters); + .setParent(false) + .setField('index', indexPattern) + .setField('filter', filters); } /** @@ -209,8 +209,8 @@ function fetchContextProvider(indexPatterns, Private) { }; const response = await searchSource - .set('size', maxCount) - .set('query', { + .setField('size', maxCount) + .setField('query', { query: { constant_score: { filter: { @@ -225,15 +225,15 @@ function fetchContextProvider(indexPatterns, Private) { }, language: 'lucene' }) - .set('searchAfter', [ + .setField('searchAfter', [ afterTimeValue !== null ? afterTimeValue : startTimeValue, tieBreakerValue, ]) - .set('sort', [ + .setField('sort', [ { [timeField]: timeSortDirection }, { [tieBreakerField]: tieBreakerSortDirection }, ]) - .set('version', true) + .setField('version', true) .fetch(); return response.hits ? response.hits.hits : []; diff --git a/src/core_plugins/kibana/public/dashboard/__tests__/get_saved_dashboard_mock.js b/src/core_plugins/kibana/public/dashboard/__tests__/get_saved_dashboard_mock.js index 8802683cb8453..d11436dead80c 100644 --- a/src/core_plugins/kibana/public/dashboard/__tests__/get_saved_dashboard_mock.js +++ b/src/core_plugins/kibana/public/dashboard/__tests__/get_saved_dashboard_mock.js @@ -24,7 +24,7 @@ export function getSavedDashboardMock(config) { title: 'my dashboard', panelsJSON: '[]', searchSource: { - getOwn: (param) => param + getOwnField: (param) => param } }; return Object.assign(defaults, config); diff --git a/src/core_plugins/kibana/public/dashboard/dashboard_state_manager.js b/src/core_plugins/kibana/public/dashboard/dashboard_state_manager.js index ebdfb20cfaf8e..cafda9c386e68 100644 --- a/src/core_plugins/kibana/public/dashboard/dashboard_state_manager.js +++ b/src/core_plugins/kibana/public/dashboard/dashboard_state_manager.js @@ -579,8 +579,8 @@ export class DashboardStateManager { */ applyFilters(query, filters) { this.appState.query = query; - this.savedDashboard.searchSource.set('query', query); - this.savedDashboard.searchSource.set('filter', filters); + this.savedDashboard.searchSource.setField('query', query); + this.savedDashboard.searchSource.setField('filter', filters); this.saveState(); } diff --git a/src/core_plugins/kibana/public/dashboard/lib/filter_utils.js b/src/core_plugins/kibana/public/dashboard/lib/filter_utils.js index acb04a43390b0..cb5b88ca0c6e4 100644 --- a/src/core_plugins/kibana/public/dashboard/lib/filter_utils.js +++ b/src/core_plugins/kibana/public/dashboard/lib/filter_utils.js @@ -44,7 +44,7 @@ export class FilterUtils { * both query filters and filter bar filters. */ static getDashboardFilters(dashboard) { - return dashboard.searchSource.getOwn('filter'); + return dashboard.searchSource.getOwnField('filter'); } /** @@ -53,8 +53,8 @@ export class FilterUtils { * @returns {QueryFilter} */ static getQueryFilterForDashboard(dashboard) { - if (dashboard.searchSource.getOwn('query')) { - return dashboard.searchSource.getOwn('query'); + if (dashboard.searchSource.getOwnField('query')) { + return dashboard.searchSource.getOwnField('query'); } const dashboardFilters = this.getDashboardFilters(dashboard); diff --git a/src/core_plugins/kibana/public/discover/controllers/discover.js b/src/core_plugins/kibana/public/discover/controllers/discover.js index 24177f1380a58..d7c6d982eb828 100644 --- a/src/core_plugins/kibana/public/discover/controllers/discover.js +++ b/src/core_plugins/kibana/public/discover/controllers/discover.js @@ -196,18 +196,17 @@ function discoverController( $scope.searchSource = savedSearch.searchSource; $scope.indexPattern = resolveIndexPatternLoading(); $scope.searchSource - .set('index', $scope.indexPattern) - .highlightAll(true) - .version(true); + .setField('index', $scope.indexPattern) + .setField('highlightAll', true) + .setField('version', true); // searchSource which applies time range - const timeRangeSearchSource = savedSearch.searchSource.new(); - timeRangeSearchSource.set('filter', () => { + const timeRangeSearchSource = savedSearch.searchSource.create(); + timeRangeSearchSource.setField('filter', () => { return timefilter.createFilter($scope.indexPattern); }); - $scope.searchSource.inherits(timeRangeSearchSource); - + $scope.searchSource.setParent(timeRangeSearchSource); const pageTitleSuffix = savedSearch.id && savedSearch.title ? `: ${savedSearch.title}` : ''; docTitle.change(`Discover${pageTitleSuffix}`); @@ -258,26 +257,26 @@ function discoverController( }; this.getSharingData = async () => { - const searchSource = $scope.searchSource.clone(); + const searchSource = $scope.searchSource.createCopy(); const { searchFields, selectFields } = await getSharingDataFields(); - searchSource.set('fields', searchFields); - searchSource.set('sort', getSort($state.sort, $scope.indexPattern)); - searchSource.set('highlight', null); - searchSource.set('highlightAll', null); - searchSource.set('aggs', null); - searchSource.set('size', null); + searchSource.setField('fields', searchFields); + searchSource.setField('sort', getSort($state.sort, $scope.indexPattern)); + searchSource.setField('highlight', null); + searchSource.setField('highlightAll', null); + searchSource.setField('aggs', null); + searchSource.setField('size', null); const body = await searchSource.getSearchRequestBody(); return { searchRequest: { - index: searchSource.get('index').title, + index: searchSource.getField('index').title, body }, fields: selectFields, metaFields: $scope.indexPattern.metaFields, conflictedTypesFields: $scope.indexPattern.fields.filter(f => f.type === 'conflict').map(f => f.name), - indexPatternId: searchSource.get('index').id + indexPatternId: searchSource.getField('index').id }; }; @@ -293,7 +292,7 @@ function discoverController( function getStateDefaults() { return { - query: $scope.searchSource.get('query') || { + query: $scope.searchSource.getField('query') || { query: '', language: localStorage.get('kibana.userQueryLanguage') || config.get('search:queryLanguage') }, @@ -301,7 +300,7 @@ function discoverController( columns: savedSearch.columns.length > 0 ? savedSearch.columns : config.get('defaultColumns').slice(), index: $scope.indexPattern.id, interval: 'auto', - filters: _.cloneDeep($scope.searchSource.getOwn('filter')) + filters: _.cloneDeep($scope.searchSource.getOwnField('filter')) }; } @@ -344,7 +343,7 @@ function discoverController( if (!sort) return; // get the current sort from {key: val} to ["key", "val"]; - const currentSort = _.pairs($scope.searchSource.get('sort')).pop(); + const currentSort = _.pairs($scope.searchSource.getField('sort')).pop(); // if the searchSource doesn't know, tell it so if (!angular.equals(sort, currentSort)) $scope.fetch(); @@ -535,7 +534,11 @@ function discoverController( } $scope.updateTime(); - if (sort[0] === '_score') segmented.setMaxSegments(1); + + if (sort[0] === '_score') { + segmented.setMaxSegments(1); + } + segmented.setDirection(sortBy === 'time' ? (sort[1] || 'desc') : 'desc'); segmented.setSortFn(sortFn); segmented.setSize($scope.opts.sampleSize); @@ -567,14 +570,14 @@ function discoverController( .resolve(responseHandler($scope.vis, merged)) .then(resp => { $scope.visData = resp; - const visEl = $element.find('.visualization-container')[0]; + const visEl = $element.find('#discoverHistogram')[0]; visualizationLoader(visEl, $scope.vis, $scope.visData, $scope.uiState, { listenOnChange: true }); }); } $scope.hits = merged.hits.total; - const indexPattern = $scope.searchSource.get('index'); + const indexPattern = $scope.searchSource.getField('index'); // the merge rows, use a new array to help watchers $scope.rows = merged.hits.hits.slice(); @@ -646,10 +649,10 @@ function discoverController( $scope.updateDataSource = Promise.method(function updateDataSource() { $scope.searchSource - .size($scope.opts.sampleSize) - .sort(getSort($state.sort, $scope.indexPattern)) - .query(!$state.query ? null : $state.query) - .set('filter', queryFilter.getFilters()); + .setField('size', $scope.opts.sampleSize) + .setField('sort', getSort($state.sort, $scope.indexPattern)) + .setField('query', !$state.query ? null : $state.query) + .setField('filter', queryFilter.getFilters()); }); $scope.setSortOrder = function setSortOrder(columnName, direction) { @@ -731,7 +734,7 @@ function discoverController( return $scope.vis.getAggConfig().onSearchRequestStart(searchSource, searchRequest); }); - $scope.searchSource.aggs(function () { + $scope.searchSource.setField('aggs', function () { return $scope.vis.getAggConfig().toDsl(); }); } @@ -747,7 +750,7 @@ function discoverController( const stateVal = props.stateVal; const stateValFound = props.stateValFound; - const own = $scope.searchSource.getOwn('index'); + const own = $scope.searchSource.getOwnField('index'); if (own && !stateVal) return own; if (stateVal && !stateValFound) { diff --git a/src/core_plugins/kibana/public/discover/embeddable/search_embeddable.js b/src/core_plugins/kibana/public/discover/embeddable/search_embeddable.js index 47a94aa4e45ea..8b076ce825e2e 100644 --- a/src/core_plugins/kibana/public/discover/embeddable/search_embeddable.js +++ b/src/core_plugins/kibana/public/discover/embeddable/search_embeddable.js @@ -29,7 +29,7 @@ export class SearchEmbeddable extends Embeddable { metadata: { title: savedSearch.title, editUrl, - indexPattern: savedSearch.searchSource.get('index') + indexPattern: savedSearch.searchSource.getField('index') } }); this.onEmbeddableStateChanged = onEmbeddableStateChanged; @@ -58,8 +58,8 @@ export class SearchEmbeddable extends Embeddable { this.searchScope.sort = this.customization.sort || this.savedSearch.sort; this.searchScope.sharedItemTitle = this.panelTitle; - this.filtersSearchSource.set('filter', this.filters); - this.filtersSearchSource.set('query', this.query); + this.filtersSearchSource.setField('filter', this.filters); + this.filtersSearchSource.setField('query', this.query); } onContainerStateChanged(containerState) { @@ -85,15 +85,15 @@ export class SearchEmbeddable extends Embeddable { this.searchScope.description = this.savedSearch.description; this.searchScope.searchSource = this.savedSearch.searchSource; - const timeRangeSearchSource = this.searchScope.searchSource.new(); - timeRangeSearchSource.filter(() => { - return getTime(this.searchScope.searchSource.get('index'), this.timeRange); + const timeRangeSearchSource = this.searchScope.searchSource.create(); + timeRangeSearchSource.setField('filter', () => { + return getTime(this.searchScope.searchSource.getField('index'), this.timeRange); }); - this.filtersSearchSource = this.searchScope.searchSource.new(); - this.filtersSearchSource.inherits(timeRangeSearchSource); + this.filtersSearchSource = this.searchScope.searchSource.create(); + this.filtersSearchSource.setParent(timeRangeSearchSource); - this.searchScope.searchSource.inherits(this.filtersSearchSource); + this.searchScope.searchSource.setParent(this.filtersSearchSource); this.pushContainerStateParamsToScope(); @@ -103,14 +103,14 @@ export class SearchEmbeddable extends Embeddable { }; this.searchScope.addColumn = (columnName) => { - this.savedSearch.searchSource.get('index').popularizeField(columnName, 1); + this.savedSearch.searchSource.getField('index').popularizeField(columnName, 1); columnActions.addColumn(this.searchScope.columns, columnName); this.searchScope.columns = this.customization.columns = this.searchScope.columns; this.emitEmbeddableStateChange(this.getEmbeddableState()); }; this.searchScope.removeColumn = (columnName) => { - this.savedSearch.searchSource.get('index').popularizeField(columnName, 1); + this.savedSearch.searchSource.getField('index').popularizeField(columnName, 1); columnActions.removeColumn(this.searchScope.columns, columnName); this.customization.columns = this.searchScope.columns; this.emitEmbeddableStateChange(this.getEmbeddableState()); @@ -123,7 +123,7 @@ export class SearchEmbeddable extends Embeddable { }; this.searchScope.filter = (field, value, operator) => { - const index = this.savedSearch.searchSource.get('index').id; + const index = this.savedSearch.searchSource.getField('index').id; const stagedFilter = { field, value, diff --git a/src/core_plugins/kibana/public/discover/index.html b/src/core_plugins/kibana/public/discover/index.html index 589f99a66e192..a8fde71b987fb 100644 --- a/src/core_plugins/kibana/public/discover/index.html +++ b/src/core_plugins/kibana/public/discover/index.html @@ -48,7 +48,7 @@

columns="state.columns" hits="rows" field-counts="fieldCounts" - index-pattern="searchSource.get('index')" + index-pattern="searchSource.getField('index')" index-pattern-list="opts.indexPatternList" state="state" on-add-field="addColumn" @@ -129,7 +129,7 @@

Searching

-
diff --git a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__tests__/flyout.test.js b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__tests__/flyout.test.js index 0b2f03ba9801d..cd0cd57871028 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__tests__/flyout.test.js +++ b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__tests__/flyout.test.js @@ -163,7 +163,7 @@ describe('Flyout', () => { }, obj: { searchSource: { - getOwn: () => 'MyIndexPattern*', + getOwnField: () => 'MyIndexPattern*', }, }, }, diff --git a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/flyout.js b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/flyout.js index f4aa2cda9d5c5..a48623c5225cc 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/flyout.js +++ b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/flyout.js @@ -144,7 +144,7 @@ export class Flyout extends Component { ); const byId = groupBy(conflictedIndexPatterns, ({ obj }) => - obj.searchSource.getOwn('index') + obj.searchSource.getOwnField('index') ); const conflicts = Object.entries(byId).reduce( (accum, [existingIndexPatternId, list]) => { diff --git a/src/core_plugins/kibana/public/management/sections/objects/lib/__tests__/resolve_saved_objects.test.js b/src/core_plugins/kibana/public/management/sections/objects/lib/__tests__/resolve_saved_objects.test.js index b775551b234d3..acfb6d0040bb2 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/lib/__tests__/resolve_saved_objects.test.js +++ b/src/core_plugins/kibana/public/management/sections/objects/lib/__tests__/resolve_saved_objects.test.js @@ -238,7 +238,7 @@ describe('resolveSavedObjects', () => { { obj: { searchSource: { - getOwn: () => '1', + getOwnField: () => '1', }, hydrateIndexPattern, save, @@ -247,7 +247,7 @@ describe('resolveSavedObjects', () => { { obj: { searchSource: { - getOwn: () => '3', + getOwnField: () => '3', }, hydrateIndexPattern, save, diff --git a/src/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js b/src/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js index 257a1f3226052..f3976ec37e531 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js +++ b/src/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js @@ -81,7 +81,7 @@ export async function resolveIndexPatternConflicts( ) { let importCount = 0; await awaitEachItemInParallel(conflictedIndexPatterns, async ({ obj }) => { - let oldIndexId = obj.searchSource.getOwn('index'); + let oldIndexId = obj.searchSource.getOwnField('index'); // Depending on the object, this can either be the raw id or the actual index pattern object if (typeof oldIndexId !== 'string') { oldIndexId = oldIndexId.id; diff --git a/src/core_plugins/kibana/public/visualize/editor/editor.js b/src/core_plugins/kibana/public/visualize/editor/editor.js index d70d836ba4a13..b0afb15197916 100644 --- a/src/core_plugins/kibana/public/visualize/editor/editor.js +++ b/src/core_plugins/kibana/public/visualize/editor/editor.js @@ -191,11 +191,11 @@ function VisEditor( const stateDefaults = { uiState: savedVis.uiStateJSON ? JSON.parse(savedVis.uiStateJSON) : {}, linked: !!savedVis.savedSearchId, - query: searchSource.getOwn('query') || { + query: searchSource.getOwnField('query') || { query: '', language: localStorage.get('kibana.userQueryLanguage') || config.get('search:queryLanguage') }, - filters: searchSource.getOwn('filter') || [], + filters: searchSource.getOwnField('filter') || [], vis: savedVisState }; @@ -252,7 +252,7 @@ function VisEditor( }; $scope.$watchMulti([ - 'searchSource.get("index")', + 'searchSource.getField("index")', 'vis.type.options.showTimePicker', ], function ([index, requiresTimePicker]) { const showTimeFilter = Boolean((!index || index.timeFieldName) && requiresTimePicker); @@ -279,8 +279,8 @@ function VisEditor( // update the searchSource when query updates $scope.fetch = function () { $state.save(); - savedVis.searchSource.set('query', $state.query); - savedVis.searchSource.set('filter', $state.filters); + savedVis.searchSource.setField('query', $state.query); + savedVis.searchSource.setField('filter', $state.filters); $scope.vis.forceReload(); }; @@ -348,23 +348,23 @@ function VisEditor( toastNotifications.addSuccess(`Unlinked from saved search '${savedVis.savedSearch.title}'`); $state.linked = false; - const parent = searchSource.getParent(true); - const parentsParent = parent.getParent(true); + const searchSourceParent = searchSource.getParent(true); + const searchSourceGrandparent = searchSourceParent.getParent(true); delete savedVis.savedSearchId; - parent.set('filter', _.union(searchSource.getOwn('filter'), parent.getOwn('filter'))); + searchSourceParent.setField('filter', _.union(searchSource.getOwnField('filter'), searchSourceParent.getOwnField('filter'))); // copy over all state except "aggs", "query" and "filter" - _(parent.toJSON()) + _(searchSourceParent.toJSON()) .omit(['aggs', 'filter', 'query']) .forOwn(function (val, key) { - searchSource.set(key, val); + searchSource.setField(key, val); }) .commit(); - $state.query = searchSource.get('query'); - $state.filters = searchSource.get('filter'); - searchSource.inherits(parentsParent); + $state.query = searchSource.getField('query'); + $state.filters = searchSource.getField('filter'); + searchSource.setParent(searchSourceGrandparent); $scope.fetch(); }; diff --git a/src/core_plugins/kibana/public/visualize/saved_visualizations/_saved_vis.js b/src/core_plugins/kibana/public/visualize/saved_visualizations/_saved_vis.js index e8d9dc19b5cc9..8909fabb97b33 100644 --- a/src/core_plugins/kibana/public/visualize/saved_visualizations/_saved_vis.js +++ b/src/core_plugins/kibana/public/visualize/saved_visualizations/_saved_vis.js @@ -95,7 +95,7 @@ uiModules return self._getLinkedSavedSearch() .then(function () { - self.searchSource.size(0); + self.searchSource.setField('size', 0); return self.vis ? self._updateVis() : self._createVis(); }); @@ -111,7 +111,7 @@ uiModules } if (self.savedSearch) { - self.searchSource.inherits(self.savedSearch.searchSource.getParent()); + self.searchSource.setParent(self.savedSearch.searchSource.getParent()); self.savedSearch.destroy(); self.savedSearch = null; } @@ -120,7 +120,7 @@ uiModules return savedSearches.get(self.savedSearchId) .then(function (savedSearch) { self.savedSearch = savedSearch; - self.searchSource.inherits(self.savedSearch.searchSource); + self.searchSource.setParent(self.savedSearch.searchSource); }); } }); @@ -137,7 +137,7 @@ uiModules self.visState.title = self.title; } self.vis = new Vis( - self.searchSource.get('index'), + self.searchSource.getField('index'), self.visState ); @@ -147,7 +147,7 @@ uiModules SavedVis.prototype._updateVis = function () { const self = this; - self.vis.indexPattern = self.searchSource.get('index'); + self.vis.indexPattern = self.searchSource.getField('index'); self.visState.title = self.title; self.vis.setState(self.visState); }; diff --git a/src/core_plugins/kibana/server/lib/export/collect_index_patterns.js b/src/core_plugins/kibana/server/lib/export/collect_index_patterns.js index 1f1be4baf9ad2..441871208dc08 100644 --- a/src/core_plugins/kibana/server/lib/export/collect_index_patterns.js +++ b/src/core_plugins/kibana/server/lib/export/collect_index_patterns.js @@ -22,15 +22,15 @@ export async function collectIndexPatterns(savedObjectsClient, panels) { const { kibanaSavedObjectMeta, savedSearchId } = panel.attributes; if (kibanaSavedObjectMeta && kibanaSavedObjectMeta.searchSourceJSON && !savedSearchId) { - let searchSource; + let searchSourceData; try { - searchSource = JSON.parse(kibanaSavedObjectMeta.searchSourceJSON); + searchSourceData = JSON.parse(kibanaSavedObjectMeta.searchSourceJSON); } catch (err) { return acc; } - if (searchSource.index && !acc.find(s => s.id === searchSource.index)) { - acc.push({ type: 'index-pattern', id: searchSource.index }); + if (searchSourceData.index && !acc.find(s => s.id === searchSourceData.index)) { + acc.push({ type: 'index-pattern', id: searchSourceData.index }); } } return acc; diff --git a/src/core_plugins/tile_map/public/coordinate_maps_visualization.js b/src/core_plugins/tile_map/public/coordinate_maps_visualization.js index 8f8c18f9b83a0..3fec239c504c1 100644 --- a/src/core_plugins/tile_map/public/coordinate_maps_visualization.js +++ b/src/core_plugins/tile_map/public/coordinate_maps_visualization.js @@ -185,9 +185,9 @@ export function CoordinateMapsVisualizationProvider(Notifier, Private) { async getGeohashBounds() { const agg = this._getGeoHashAgg(); if (agg) { - const searchSource = this.vis.searchSource.makeChild(); - searchSource.size(0); - searchSource.aggs(function () { + const searchSource = this.vis.searchSource.createChild(); + searchSource.setField('size', 0); + searchSource.setField('aggs', function () { const geoBoundsAgg = new AggConfig(agg.vis, { type: 'geo_bounds', enabled: true, diff --git a/src/fixtures/stubbed_search_source.js b/src/fixtures/stubbed_search_source.js index 5af4f37952130..3a36b97e6757e 100644 --- a/src/fixtures/stubbed_search_source.js +++ b/src/fixtures/stubbed_search_source.js @@ -27,16 +27,15 @@ export default function stubSearchSource(Private, $q, Promise) { let onResultsCount = 0; return { - sort: sinon.spy(), - size: sinon.spy(), + setField: sinon.spy(), fetch: sinon.spy(), destroy: sinon.spy(), - get: function (param) { + getField: function (param) { switch (param) { case 'index': return indexPattern; default: - throw new Error('Param "' + param + '" is not implemented in the stubbed search source'); + throw new Error(`Param "${param}" is not implemented in the stubbed search source`); } }, crankResults: function () { diff --git a/src/ui/public/agg_types/buckets/histogram.js b/src/ui/public/agg_types/buckets/histogram.js index fd553cbb7fb55..7fda6537de79e 100644 --- a/src/ui/public/agg_types/buckets/histogram.js +++ b/src/ui/public/agg_types/buckets/histogram.js @@ -70,9 +70,9 @@ export const histogramBucketAgg = new BucketAggType({ : { field: field.name }; return searchSource - .extend() - .size(0) - .aggs({ + .createChild() + .setField('size', 0) + .setField('aggs', { maxAgg: { max: aggBody }, diff --git a/src/ui/public/agg_types/buckets/terms.js b/src/ui/public/agg_types/buckets/terms.js index 30882aa929654..0c362fa9488ba 100644 --- a/src/ui/public/agg_types/buckets/terms.js +++ b/src/ui/public/agg_types/buckets/terms.js @@ -93,10 +93,10 @@ export const termsBucketAgg = new BucketAggType({ }, createFilter: createFilterTerms, postFlightRequest: async (resp, aggConfigs, aggConfig, searchSource) => { - const nestedSearchSource = searchSource.makeChild(); + const nestedSearchSource = searchSource.createChild(); if (aggConfig.params.otherBucket) { const filterAgg = buildOtherBucketAgg(aggConfigs, aggConfig, resp); - nestedSearchSource.set('aggs', filterAgg); + nestedSearchSource.setField('aggs', filterAgg); const request = aggConfigs.vis.API.inspectorAdapters.requests.start('Other bucket', { description: `This request counts the number of documents that fall diff --git a/src/ui/public/courier/fetch/merge_duplicate_requests.js b/src/ui/public/courier/fetch/merge_duplicate_requests.js index eb4cbc29bcb09..435971ed0bbf1 100644 --- a/src/ui/public/courier/fetch/merge_duplicate_requests.js +++ b/src/ui/public/courier/fetch/merge_duplicate_requests.js @@ -30,16 +30,16 @@ export function MergeDuplicatesRequestProvider(Private) { return requests.map(function (req) { if (!isRequest(req)) return req; - const iid = req.source._instanceid; - if (!index[iid]) { + const searchSourceId = req.source.getId(); + if (!index[searchSourceId]) { // this request is unique so far - index[iid] = req; + index[searchSourceId] = req; // keep the request return req; } // the source was requested at least twice - req._uniq = index[iid]; + req._uniq = index[searchSourceId]; return DUPLICATE; }); } diff --git a/src/ui/public/courier/fetch/request/segmented_search_request/__tests__/segmented_search_request.create_queue.js b/src/ui/public/courier/fetch/request/segmented_search_request/__tests__/segmented_search_request.create_queue.js index d83a11123f013..714bbb340969d 100644 --- a/src/ui/public/courier/fetch/request/segmented_search_request/__tests__/segmented_search_request.create_queue.js +++ b/src/ui/public/courier/fetch/request/segmented_search_request/__tests__/segmented_search_request.create_queue.js @@ -55,28 +55,28 @@ describe('SegmentedSearchRequest _createQueue', () => { }); it('relies on indexPattern.toDetailedIndexList to generate queue', async function () { - const source = new MockSource(); - const ip = source.get('index'); + const searchSource = new MockSource(); + const indexPattern = searchSource.getField('index'); const indices = [1, 2, 3]; - sinon.stub(ip, 'toDetailedIndexList').returns(Promise.resolve(indices)); + sinon.stub(indexPattern, 'toDetailedIndexList').returns(Promise.resolve(indices)); - const req = new SegmentedSearchRequest({ source, errorHandler: () => {} }); + const req = new SegmentedSearchRequest({ source: searchSource, errorHandler: () => {} }); const output = await req._createQueue(); expect(output).to.equal(indices); }); it('tells the index pattern its direction', async function () { - const source = new MockSource(); - const ip = source.get('index'); - const req = new SegmentedSearchRequest({ source, errorHandler: () => {} }); - sinon.stub(ip, 'toDetailedIndexList').returns(Promise.resolve([1, 2, 3])); + const searchSource = new MockSource(); + const indexPattern = searchSource.getField('index'); + const req = new SegmentedSearchRequest({ source: searchSource, errorHandler: () => {} }); + sinon.stub(indexPattern, 'toDetailedIndexList').returns(Promise.resolve([1, 2, 3])); req.setDirection('asc'); await req._createQueue(); - expect(ip.toDetailedIndexList.lastCall.args[2]).to.be('asc'); + expect(indexPattern.toDetailedIndexList.lastCall.args[2]).to.be('asc'); req.setDirection('desc'); await req._createQueue(); - expect(ip.toDetailedIndexList.lastCall.args[2]).to.be('desc'); + expect(indexPattern.toDetailedIndexList.lastCall.args[2]).to.be('desc'); }); }); diff --git a/src/ui/public/courier/fetch/request/segmented_search_request/__tests__/segmented_search_request.index_selection.js b/src/ui/public/courier/fetch/request/segmented_search_request/__tests__/segmented_search_request.index_selection.js index c73c217c2ec65..b1cc13d057f90 100644 --- a/src/ui/public/courier/fetch/request/segmented_search_request/__tests__/segmented_search_request.index_selection.js +++ b/src/ui/public/courier/fetch/request/segmented_search_request/__tests__/segmented_search_request.index_selection.js @@ -50,8 +50,8 @@ describe('SegmentedSearchRequest index selection', function () { })); it('queries with size until all 500 docs returned', async function () { - const search = new MockSource(); - const indexPattern = search.get('index'); + const searchSource = new MockSource(); + const indexPattern = searchSource.getField('index'); sinon.stub(indexPattern, 'toDetailedIndexList').returns(Promise.resolve([ { index: 'one', min: 0, max: 1 }, { index: 'two', min: 0, max: 1 }, @@ -60,7 +60,7 @@ describe('SegmentedSearchRequest index selection', function () { { index: 'five', min: 0, max: 1 }, ])); - const req = new SegmentedSearchRequest({ source: search, errorHandler: () => {} }); + const req = new SegmentedSearchRequest({ source: searchSource, errorHandler: () => {} }); req._handle.setDirection('desc'); req._handle.setSortFn(new HitSortFn('desc')); req._handle.setSize(500); @@ -96,8 +96,8 @@ describe('SegmentedSearchRequest index selection', function () { }); it(`sets size 0 for indices that couldn't preclude hits`, async function () { - const search = new MockSource(); - const indexPattern = search.get('index'); + const searchSource = new MockSource(); + const indexPattern = searchSource.getField('index'); // the segreq is looking for 10 documents, and we will give it ten docs with time:5 in the first response. // on the second index it should still request 10 documents because it could produce documents with time:5. @@ -111,7 +111,7 @@ describe('SegmentedSearchRequest index selection', function () { { index: 'five', min: 5, max: 50 }, ])); - const req = new SegmentedSearchRequest({ source: search, errorHandler: () => {} }); + const req = new SegmentedSearchRequest({ source: searchSource, errorHandler: () => {} }); req._handle.setDirection('desc'); req._handle.setSortFn(new HitSortFn('desc')); req._handle.setSize(10); diff --git a/src/ui/public/courier/fetch/request/segmented_search_request/segmented_search_request.js b/src/ui/public/courier/fetch/request/segmented_search_request/segmented_search_request.js index 244bc03720ab1..3245a0f03dee0 100644 --- a/src/ui/public/courier/fetch/request/segmented_search_request/segmented_search_request.js +++ b/src/ui/public/courier/fetch/request/segmented_search_request/segmented_search_request.js @@ -195,7 +195,7 @@ export function SegmentedSearchRequestProvider(Private, config) { _createQueue() { const timeBounds = timefilter.getBounds(); - const indexPattern = this.source.get('index'); + const indexPattern = this.source.getField('index'); this._queueCreated = false; return indexPattern.toDetailedIndexList(timeBounds.min, timeBounds.max, this._direction) @@ -298,7 +298,7 @@ export function SegmentedSearchRequestProvider(Private, config) { _detectHitsWindow(hits) { hits = hits || []; - const indexPattern = this.source.get('index'); + const indexPattern = this.source.getField('index'); const desiredSize = this._desiredSize; const size = _.size(hits); diff --git a/src/ui/public/courier/saved_object/__tests__/saved_object.js b/src/ui/public/courier/saved_object/__tests__/saved_object.js index 62c67ee26ee3f..957269b741257 100644 --- a/src/ui/public/courier/saved_object/__tests__/saved_object.js +++ b/src/ui/public/courier/saved_object/__tests__/saved_object.js @@ -432,11 +432,11 @@ describe('Saved Object', function () { }); const savedObject = new SavedObject(config); - expect(!!savedObject.searchSource.get('index')).to.be(false); + expect(!!savedObject.searchSource.getField('index')).to.be(false); return savedObject.init().then(() => { expect(afterESRespCallback.called).to.be(true); - const index = savedObject.searchSource.get('index'); + const index = savedObject.searchSource.getField('index'); expect(index instanceof IndexPattern).to.be(true); expect(index.id).to.equal(indexPatternId); }); diff --git a/src/ui/public/courier/saved_object/saved_object.js b/src/ui/public/courier/saved_object/saved_object.js index da035b9f5e7e8..1e50c53d70a53 100644 --- a/src/ui/public/courier/saved_object/saved_object.js +++ b/src/ui/public/courier/saved_object/saved_object.js @@ -112,23 +112,23 @@ export function SavedObjectProvider(Promise, Private, Notifier, confirmModalProm const parseSearchSource = (searchSourceJson) => { if (!this.searchSource) return; - // if we have a searchSource, set its state based on the searchSourceJSON field - let state; + // if we have a searchSource, set its values based on the searchSourceJson field + let searchSourceValues; try { - state = JSON.parse(searchSourceJson); + searchSourceValues = JSON.parse(searchSourceJson); } catch (e) { - state = {}; + searchSourceValues = {}; } - const oldState = this.searchSource.toJSON(); - const fnProps = _.transform(oldState, function (dynamic, val, name) { + const searchSourceFields = this.searchSource.getFields(); + const fnProps = _.transform(searchSourceFields, function (dynamic, val, name) { if (_.isFunction(val)) dynamic[name] = val; }, {}); - this.searchSource.set(_.defaults(state, fnProps)); + this.searchSource.setFields(_.defaults(searchSourceValues, fnProps)); - if (!_.isUndefined(this.searchSource.getOwn('query'))) { - this.searchSource.set('query', migrateLegacyQuery(this.searchSource.getOwn('query'))); + if (!_.isUndefined(this.searchSource.getOwnField('query'))) { + this.searchSource.setField('query', migrateLegacyQuery(this.searchSource.getOwnField('query'))); } }; @@ -144,11 +144,11 @@ export function SavedObjectProvider(Promise, Private, Notifier, confirmModalProm } if (config.clearSavedIndexPattern) { - this.searchSource.set('index', undefined); + this.searchSource.setField('index', null); return Promise.resolve(null); } - let index = id || config.indexPattern || this.searchSource.getOwn('index'); + let index = id || config.indexPattern || this.searchSource.getOwnField('index'); if (!index) { return Promise.resolve(null); @@ -162,7 +162,7 @@ export function SavedObjectProvider(Promise, Private, Notifier, confirmModalProm // At this point index will either be an IndexPattern, if cached, or a promise that // will return an IndexPattern, if not cached. return Promise.resolve(index).then(indexPattern => { - this.searchSource.set('index', indexPattern); + this.searchSource.setField('index', indexPattern); }); }; @@ -260,8 +260,9 @@ export function SavedObjectProvider(Promise, Private, Notifier, confirmModalProm }); if (this.searchSource) { + const searchSourceFields = _.omit(this.searchSource.getFields(), ['sort', 'size']); body.kibanaSavedObjectMeta = { - searchSourceJSON: angular.toJson(_.omit(this.searchSource.toJSON(), ['sort', 'size'])) + searchSourceJSON: angular.toJson(searchSourceFields) }; } diff --git a/src/ui/public/courier/search_source/__tests__/search_source.js b/src/ui/public/courier/search_source/__tests__/search_source.js index 694b2fb2cec08..a17cebccae23f 100644 --- a/src/ui/public/courier/search_source/__tests__/search_source.js +++ b/src/ui/public/courier/search_source/__tests__/search_source.js @@ -54,18 +54,18 @@ describe('SearchSource', function () { describe('#onResults()', function () { it('adds a request to the searchRequestQueue', function () { - const source = new SearchSource(); + const searchSource = new SearchSource(); expect(searchRequestQueue.getCount()).to.be(0); - source.onResults(); + searchSource.onResults(); expect(searchRequestQueue.getCount()).to.be(1); }); it('returns a promise that is resolved with the results', function () { - const source = new SearchSource(); + const searchSource = new SearchSource(); const fakeResults = {}; - const promise = source.onResults().then((results) => { + const promise = searchSource.onResults().then((results) => { expect(results).to.be(fakeResults); }); @@ -77,106 +77,132 @@ describe('SearchSource', function () { describe('#destroy()', function () { it('aborts all startable requests', function () { - const source = new SearchSource(); - source.onResults(); + const searchSource = new SearchSource(); + searchSource.onResults(); const searchRequest = searchRequestQueue.getSearchRequestAt(0); sinon.stub(searchRequest, 'canStart').returns(true); - source.destroy(); + searchSource.destroy(); expect(searchRequestQueue.getCount()).to.be(0); }); it('aborts all non-startable requests', function () { - const source = new SearchSource(); - source.onResults(); + const searchSource = new SearchSource(); + searchSource.onResults(); const searchRequest = searchRequestQueue.getSearchRequestAt(0); sinon.stub(searchRequest, 'canStart').returns(false); - source.destroy(); + searchSource.destroy(); expect(searchRequestQueue.getCount()).to.be(0); }); }); - describe('#index()', function () { + describe('#setField()', function () { + it('sets the value for the property', function () { + const searchSource = new SearchSource(); + searchSource.setField('aggs', 5); + expect(searchSource.getField('aggs')).to.be(5); + }); + + it('throws an error if the property is not accepted', function () { + const searchSource = new SearchSource(); + expect(() => searchSource.setField('index', 5)).to.throwError(); + }); + }); + + describe('#getField()', function () { + it('gets the value for the property', function () { + const searchSource = new SearchSource(); + searchSource.setField('aggs', 5); + expect(searchSource.getField('aggs')).to.be(5); + }); + + it('throws an error if the property is not accepted', function () { + const searchSource = new SearchSource(); + expect(() => searchSource.getField('unacceptablePropName')).to.throwError(); + }); + }); + + describe(`#setField('index')`, function () { describe('auto-sourceFiltering', function () { describe('new index pattern assigned', function () { - it('generates a source filter', function () { - const source = new SearchSource(); - expect(source.get('index')).to.be(undefined); - expect(source.get('source')).to.be(undefined); - source.set('index', indexPattern); - expect(source.get('index')).to.be(indexPattern); - expect(source.get('source')).to.be.a('function'); + it('generates a searchSource filter', function () { + const searchSource = new SearchSource(); + expect(searchSource.getField('index')).to.be(undefined); + expect(searchSource.getField('source')).to.be(undefined); + searchSource.setField('index', indexPattern); + expect(searchSource.getField('index')).to.be(indexPattern); + expect(searchSource.getField('source')).to.be.a('function'); }); - it('removes created source filter on removal', function () { - const source = new SearchSource(); - source.set('index', indexPattern); - source.set('index', null); - expect(source.get('index')).to.be(undefined); - expect(source.get('source')).to.be(undefined); + it('removes created searchSource filter on removal', function () { + const searchSource = new SearchSource(); + searchSource.setField('index', indexPattern); + searchSource.setField('index', null); + expect(searchSource.getField('index')).to.be(undefined); + expect(searchSource.getField('source')).to.be(undefined); }); }); describe('new index pattern assigned over another', function () { - it('replaces source filter with new', function () { - const source = new SearchSource(); - source.set('index', indexPattern); - const sourceFilter1 = source.get('source'); - source.set('index', indexPattern2); - expect(source.get('index')).to.be(indexPattern2); - expect(source.get('source')).to.be.a('function'); - expect(source.get('source')).to.not.be(sourceFilter1); + it('replaces searchSource filter with new', function () { + const searchSource = new SearchSource(); + searchSource.setField('index', indexPattern); + const searchSourceFilter1 = searchSource.getField('source'); + searchSource.setField('index', indexPattern2); + expect(searchSource.getField('index')).to.be(indexPattern2); + expect(searchSource.getField('source')).to.be.a('function'); + expect(searchSource.getField('source')).to.not.be(searchSourceFilter1); }); - it('removes created source filter on removal', function () { - const source = new SearchSource(); - source.set('index', indexPattern); - source.set('index', indexPattern2); - source.set('index', null); - expect(source.get('index')).to.be(undefined); - expect(source.get('source')).to.be(undefined); + it('removes created searchSource filter on removal', function () { + const searchSource = new SearchSource(); + searchSource.setField('index', indexPattern); + searchSource.setField('index', indexPattern2); + searchSource.setField('index', null); + expect(searchSource.getField('index')).to.be(undefined); + expect(searchSource.getField('source')).to.be(undefined); }); }); - describe('ip assigned before custom source filter', function () { - it('custom source filter becomes new source', function () { - const source = new SearchSource(); + describe('ip assigned before custom searchSource filter', function () { + it('custom searchSource filter becomes new searchSource', function () { + const searchSource = new SearchSource(); const football = {}; - source.set('index', indexPattern); - expect(source.get('source')).to.be.a('function'); - source.set('source', football); - expect(source.get('index')).to.be(indexPattern); - expect(source.get('source')).to.be(football); + searchSource.setField('index', indexPattern); + expect(searchSource.getField('source')).to.be.a('function'); + searchSource.setField('source', football); + expect(searchSource.getField('index')).to.be(indexPattern); + expect(searchSource.getField('source')).to.be(football); }); - it('custom source stays after removal', function () { - const source = new SearchSource(); + it('custom searchSource stays after removal', function () { + const searchSource = new SearchSource(); const football = {}; - source.set('index', indexPattern); - source.set('source', football); - source.set('index', null); - expect(source.get('index')).to.be(undefined); - expect(source.get('source')).to.be(football); + searchSource.setField('index', indexPattern); + searchSource.setField('source', football); + searchSource.setField('index', null); + expect(searchSource.getField('index')).to.be(undefined); + expect(searchSource.getField('source')).to.be(football); }); }); - describe('ip assigned after custom source filter', function () { + describe('ip assigned after custom searchSource filter', function () { it('leaves the custom filter in place', function () { - const source = new SearchSource(); + const searchSource = new SearchSource(); const football = {}; - source.set('source', football); - source.set('index', indexPattern); - expect(source.get('index')).to.be(indexPattern); - expect(source.get('source')).to.be(football); + searchSource.setField('source', football); + searchSource.setField('index', indexPattern); + expect(searchSource.getField('index')).to.be(indexPattern); + expect(searchSource.getField('source')).to.be(football); }); - it('custom source stays after removal', function () { - const source = new SearchSource(); + it('custom searchSource stays after removal', function () { + const searchSource = new SearchSource(); const football = {}; - source.set('source', football); - source.set('index', indexPattern); - source.set('index', null); - expect(source.get('index')).to.be(undefined); - expect(source.get('source')).to.be(football); + searchSource.setField('source', football); + searchSource.setField('index', indexPattern); + searchSource.setField('index', null); + expect(searchSource.getField('index')).to.be(undefined); + expect(searchSource.getField('source')).to.be(football); }); }); }); @@ -184,66 +210,66 @@ describe('SearchSource', function () { describe('#onRequestStart()', () => { it('should be called when starting a request', async () => { - const source = new SearchSource(); + const searchSource = new SearchSource(); const fn = sinon.spy(); - source.onRequestStart(fn); + searchSource.onRequestStart(fn); const request = {}; - source.requestIsStarting(request); + searchSource.requestIsStarting(request); await timeout(); - expect(fn.calledWith(source, request)).to.be(true); + expect(fn.calledWith(searchSource, request)).to.be(true); }); it('should not be called on parent searchSource', async () => { const parent = new SearchSource(); - const source = new SearchSource().inherits(parent); + const searchSource = new SearchSource().setParent(parent); const fn = sinon.spy(); - source.onRequestStart(fn); + searchSource.onRequestStart(fn); const parentFn = sinon.spy(); parent.onRequestStart(parentFn); const request = {}; - source.requestIsStarting(request); + searchSource.requestIsStarting(request); await timeout(); - expect(fn.calledWith(source, request)).to.be(true); + expect(fn.calledWith(searchSource, request)).to.be(true); expect(parentFn.notCalled).to.be(true); }); it('should be called on parent searchSource if callParentStartHandlers is true', async () => { const parent = new SearchSource(); - const source = new SearchSource().inherits(parent, { callParentStartHandlers: true }); + const searchSource = new SearchSource().setParent(parent, { callParentStartHandlers: true }); const fn = sinon.spy(); - source.onRequestStart(fn); + searchSource.onRequestStart(fn); const parentFn = sinon.spy(); parent.onRequestStart(parentFn); const request = {}; - source.requestIsStarting(request); + searchSource.requestIsStarting(request); await timeout(); - expect(fn.calledWith(source, request)).to.be(true); - expect(parentFn.calledWith(source, request)).to.be(true); + expect(fn.calledWith(searchSource, request)).to.be(true); + expect(parentFn.calledWith(searchSource, request)).to.be(true); }); }); describe('#_mergeProp', function () { describe('filter', function () { - let source; + let searchSource; let state; beforeEach(function () { - source = new SearchSource(); + searchSource = new SearchSource(); state = {}; }); [null, undefined].forEach(falsyValue => { it(`ignores ${falsyValue} filter`, function () { - source._mergeProp(state, falsyValue, 'filter'); + searchSource._mergeProp(state, falsyValue, 'filter'); expect(state.filters).to.be(undefined); }); }); [false, 0, '', NaN].forEach(falsyValue => { it(`doesn't add ${falsyValue} filter`, function () { - source._mergeProp(state, falsyValue, 'filter'); + searchSource._mergeProp(state, falsyValue, 'filter'); expect(state.filters).to.be.empty(); }); }); @@ -252,7 +278,7 @@ describe('SearchSource', function () { const filter = { meta: {} }; - source._mergeProp(state, filter, 'filter'); + searchSource._mergeProp(state, filter, 'filter'); expect(state.filters).to.eql([filter]); }); @@ -262,7 +288,7 @@ describe('SearchSource', function () { disabled: false } }; - source._mergeProp(state, filter, 'filter'); + searchSource._mergeProp(state, filter, 'filter'); expect(state.filters).to.eql([filter]); }); @@ -272,7 +298,7 @@ describe('SearchSource', function () { disabled: true } }; - source._mergeProp(state, filter, 'filter'); + searchSource._mergeProp(state, filter, 'filter'); expect(state.filters).to.be.empty(); }); @@ -289,7 +315,7 @@ describe('SearchSource', function () { byName: {} } }; - source._mergeProp(state, filter, 'filter'); + searchSource._mergeProp(state, filter, 'filter'); expect(state.filters).to.eql([ filter ]); }); }); @@ -307,7 +333,7 @@ describe('SearchSource', function () { byName: {} } }; - source._mergeProp(state, filter, 'filter'); + searchSource._mergeProp(state, filter, 'filter'); expect(state.filters).to.be.empty(); }); @@ -325,20 +351,10 @@ describe('SearchSource', function () { } } }; - source._mergeProp(state, filter, 'filter'); + searchSource._mergeProp(state, filter, 'filter'); expect(state.filters).to.eql([ filter ]); }); }); - - it('uses custom filter predicate', function () { - source.addFilterPredicate(() => { - return false; - }); - - const filter = {}; - source._mergeProp(state, filter, 'filter'); - expect(state.filters).to.be.empty(); - }); }); }); }); diff --git a/src/ui/public/courier/search_source/search_source.js b/src/ui/public/courier/search_source/search_source.js index fa70082a30d1e..3a56d6a1dbf54 100644 --- a/src/ui/public/courier/search_source/search_source.js +++ b/src/ui/public/courier/search_source/search_source.js @@ -84,14 +84,31 @@ import { FieldWildcardProvider } from '../../field_wildcard'; import { getHighlightRequest } from '../../../../core_plugins/kibana/common/highlight'; import { BuildESQueryProvider } from './build_query'; -function parseInitialState(initialState) { - if (!initialState) { +const FIELDS = [ + 'type', + 'query', + 'filter', + 'sort', + 'highlight', + 'highlightAll', + 'aggs', + 'from', + 'searchAfter', + 'size', + 'source', + 'version', + 'fields', + 'index', +]; + +function parseInitialFields(initialFields) { + if (!initialFields) { return {}; } - return typeof initialState === 'string' ? - JSON.parse(initialState) - : _.cloneDeep(initialState); + return typeof initialFields === 'string' ? + JSON.parse(initialFields) + : _.cloneDeep(initialFields); } function isIndexPattern(val) { @@ -110,45 +127,11 @@ export function SearchSourceProvider(Promise, Private, config) { const forIp = Symbol('for which index pattern?'); class SearchSource { - constructor(initialState) { - this._instanceid = _.uniqueId('data_source'); + constructor(initialFields) { + this._id = _.uniqueId('data_source'); - this._state = parseInitialState(initialState); - - /** - * List of the editable state properties that turn into a - * chainable API - * - * @type {Array} - */ - this._methods = [ - 'type', - 'query', - 'filter', - 'sort', - 'highlight', - 'highlightAll', - 'aggs', - 'from', - 'searchAfter', - 'size', - 'source', - 'version', - 'fields' - ]; - - // set internal state values - this._methods.forEach(name => { - this[name] = val => { - if (val == null) { - delete this._state[name]; - } else { - this._state[name] = val; - } - - return this; - }; - }); + this._fields = parseInitialFields(initialFields); + this._parent = undefined; this.history = []; this._requestStartHandlers = []; @@ -163,13 +146,13 @@ export function SearchSourceProvider(Promise, Private, config) { const disabled = _.get(filter, 'meta.disabled'); return disabled === undefined || disabled === false; }, - (filter, state) => { + (filter, data) => { if (!config.get('courier:ignoreFilterIfFieldNotInIndex')) { return true; } - if ('meta' in filter && 'index' in state) { - const field = state.index.fields.byName[filter.meta.key]; + if ('meta' in filter && 'index' in data) { + const field = data.index.fields.byName[filter.meta.key]; if (!field) return false; } return true; @@ -181,210 +164,136 @@ export function SearchSourceProvider(Promise, Private, config) { * PUBLIC API *****/ + setFields(newFields) { + this._fields = newFields; + return this; + } - index(indexPattern) { - const state = this._state; - - const hasSource = state.source; - const sourceCameFromIp = hasSource && state.source.hasOwnProperty(forIp); - const sourceIsForOurIp = sourceCameFromIp && state.source[forIp] === state.index; - if (sourceIsForOurIp) { - delete state.source; + setField = (field, value) => { + if (!FIELDS.includes(field)) { + throw new Error(`Can't set field '${field}' on SearchSource. Acceptable fields are: ${FIELDS.join(', ')}.`); } - if (indexPattern === undefined) return state.index; - if (indexPattern === null) return delete state.index; - if (!isIndexPattern(indexPattern)) { - throw new TypeError('expected indexPattern to be an IndexPattern duck.'); + if (field === 'index') { + const fields = this._fields; + + const hasSource = fields.source; + const sourceCameFromIp = hasSource && fields.source.hasOwnProperty(forIp); + const sourceIsForOurIp = sourceCameFromIp && fields.source[forIp] === fields.index; + if (sourceIsForOurIp) { + delete fields.source; + } + + if (value === null || value === undefined) { + delete fields.index; + return this; + } + + if (!isIndexPattern(value)) { + throw new TypeError('expected indexPattern to be an IndexPattern duck.'); + } + + fields[field] = value; + if (!fields.source) { + // imply source filtering based on the index pattern, but allow overriding + // it by simply setting another field for "source". When index is changed + fields.source = function () { + return value.getSourceFiltering(); + }; + fields.source[forIp] = value; + } + + return this; } - state.index = indexPattern; - if (!state.source) { - // imply source filtering based on the index pattern, but allow overriding - // it by simply setting another value for "source". When index is changed - state.source = function () { - return indexPattern.getSourceFiltering(); - }; - state.source[forIp] = indexPattern; + if (value == null) { + delete this._fields[field]; + return this; } + this._fields[field] = value; return this; - } + }; - /** - * Set a searchSource that this source should inherit from - * @param {SearchSource} searchSource - the parent searchSource - * @return {this} - chainable - */ - inherits(parent, options = {}) { - this._parent = parent; - this._inheritOptions = options; - return this; + getId() { + return this._id; } - /** - * Get the parent of this SearchSource - * @return {undefined|searchSource} - */ - getParent() { - return this._parent || undefined; + getFields() { + return _.clone(this._fields); } /** - * Temporarily prevent this Search from being fetched... not a fan but it's easy + * Get fields from the fields */ - disable() { - this._fetchDisabled = true; - } + getField = field => { + if (!FIELDS.includes(field)) { + throw new Error(`Can't get field '${field}' from SearchSource. Acceptable fields are: ${FIELDS.join(', ')}.`); + } - /** - * Reverse of SearchSource#disable(), only need to call this if source was previously disabled - */ - enable() { - this._fetchDisabled = false; - } + let searchSource = this; - onBeginSegmentedFetch(initFunction) { - const self = this; - return new Promise((resolve, reject) => { - function addRequest() { - const defer = Promise.defer(); - const errorHandler = (request, error) => { - reject(error); - request.abort(); - }; - const req = new SegmentedSearchRequest({ source: self, defer, errorHandler, initFn: initFunction }); - - // Return promises created by the completion handler so that - // errors will bubble properly - return req.getCompletePromise().then(addRequest); + while (searchSource) { + const value = searchSource._fields[field]; + if (value !== void 0) { + return value; } - addRequest(); - }); - } - - addFilterPredicate(predicate) { - this._filterPredicates.push(predicate); - } - - clone() { - const clone = new SearchSource(this.toString()); - // when serializing the internal state with .toString() we lose the internal classes used in the index - // pattern, so we have to set it again to workaround this behavior - clone.set('index', this.get('index')); - clone.inherits(this.getParent()); - return clone; - } - - makeChild(params) { - return new SearchSource().inherits(this, params); - } - - new() { - return new SearchSource(); - } - - async getSearchRequestBody() { - const searchRequest = await this._flatten(); - return searchRequest.body; - } + searchSource = searchSource.getParent(); + } + }; /** - * Called by requests of this search source when they are done - * @param {Courier.Request} request - * @return {undefined} + * Get the field from our own fields, don't traverse up the chain */ - requestIsStopped() { - this.activeFetchCount -= 1; - } + getOwnField(field) { + if (!FIELDS.includes(field)) { + throw new Error(`Can't get field '${field}' from SearchSource. Acceptable fields are: ${FIELDS.join(', ')}.`); + } - /** - * Get values from the state - * @param {string} name - The name of the property desired - * @return {any} - the value found - */ - get(name) { - let self = this; - while (self) { - if (self._state[name] !== void 0) return self._state[name]; - self = self.getParent(); + const value = this._fields[field]; + if (value !== void 0) { + return value; } } - /** - * Get the value from our own state, don't traverse up the chain - * @param {string} name - The name of the property desired - * @return {any} - the value found - */ - getOwn(name) { - if (this._state[name] !== void 0) return this._state[name]; + create() { + return new SearchSource(); } - /** - * Change the entire state of a SearchSource - * @param {object|string} state - The SearchSource's new state, or a - * string of the state value to set - */ - set(state, val) { - const self = this; - - if (typeof state === 'string') { - // the getter and setter methods check for undefined explicitly - // to identify getters and null to identify deletion - if (val === undefined) { - val = null; - } - self[state](val); - } else { - self._state = state; - } - return self; + createCopy() { + const json = angular.toJson(this._fields); + const newSearchSource = new SearchSource(json); + // when serializing the internal fields we lose the internal classes used in the index + // pattern, so we have to set it again to workaround this behavior + newSearchSource.setField('index', this.getField('index')); + newSearchSource.setParent(this.getParent()); + return newSearchSource; } - /** - * Create a new dataSource object of the same type - * as this, which inherits this dataSource's properties - * @return {SearchSource} - */ - extend() { - return new SearchSource().inherits(this); + createChild(options = {}) { + const childSearchSource = new SearchSource(); + childSearchSource.setParent(this, options); + return childSearchSource; } /** - * return a simple, encodable object representing the state of the SearchSource - * @return {[type]} [description] - */ - toJSON = function () { - return _.clone(this._state); - }; - - /** - * Create a string representation of the object - * @return {[type]} [description] + * Set a searchSource that this source should inherit from + * @param {SearchSource} searchSource - the parent searchSource + * @return {this} - chainable */ - toString() { - return angular.toJson(this.toJSON()); + setParent(parent, options = {}) { + this._parent = parent; + this._inheritOptions = options; + return this; } /** - * Put a request in to the courier that this Source should - * be fetched on the next run of the courier - * @return {Promise} + * Get the parent of this SearchSource + * @return {undefined|searchSource} */ - onResults() { - const self = this; - - return new Promise(function (resolve, reject) { - const defer = Promise.defer(); - defer.promise.then(resolve, reject); - - const errorHandler = (request, error) => { - reject(error); - request.abort(); - }; - self._createRequest({ defer, errorHandler }); - }); + getParent() { + return this._parent || undefined; } /** @@ -417,7 +326,7 @@ export function SearchSourceProvider(Promise, Private, config) { } /** - * Cancel all pending requests for this dataSource + * Cancel all pending requests for this searchSource * @return {undefined} */ cancelQueued() { @@ -426,15 +335,6 @@ export function SearchSourceProvider(Promise, Private, config) { .forEach(req => req.abort()); } - /** - * Completely destroy the SearchSource. - * @return {undefined} - */ - destroy() { - this.cancelQueued(); - this._requestStartHandlers.length = 0; - } - /** * Add a handler that will be notified whenever requests start * @param {Function} handler @@ -469,6 +369,68 @@ export function SearchSourceProvider(Promise, Private, config) { .then(_.noop); } + /** + * Put a request in to the courier that this Source should + * be fetched on the next run of the courier + * @return {Promise} + */ + onResults() { + const self = this; + + return new Promise(function (resolve, reject) { + const defer = Promise.defer(); + defer.promise.then(resolve, reject); + + const errorHandler = (request, error) => { + reject(error); + request.abort(); + }; + self._createRequest({ defer, errorHandler }); + }); + } + + onBeginSegmentedFetch(initFunction) { + const self = this; + return new Promise((resolve, reject) => { + function addRequest() { + const defer = Promise.defer(); + const errorHandler = (request, error) => { + reject(error); + request.abort(); + }; + const req = new SegmentedSearchRequest({ source: self, defer, errorHandler, initFn: initFunction }); + + // Return promises created by the completion handler so that + // errors will bubble properly + return req.getCompletePromise().then(addRequest); + } + + addRequest(); + }); + } + + async getSearchRequestBody() { + const searchRequest = await this._flatten(); + return searchRequest.body; + } + + /** + * Called by requests of this search source when they are done + * @param {Courier.Request} request + * @return {undefined} + */ + requestIsStopped() { + this.activeFetchCount -= 1; + } + + /** + * Completely destroy the SearchSource. + * @return {undefined} + */ + destroy() { + this.cancelQueued(); + this._requestStartHandlers.length = 0; + } /****** * PRIVATE APIS @@ -480,14 +442,6 @@ export function SearchSourceProvider(Promise, Private, config) { .filter(req => req.source === this); } - /** - * Gets the type of the DataSource - * @return {string} - */ - _getType() { - return 'search'; - } - /** * Create a common search request object, which should * be put into the pending request queue, for this search @@ -502,20 +456,20 @@ export function SearchSourceProvider(Promise, Private, config) { } /** - * Used to merge properties into the state within ._flatten(). - * The state is passed in and modified by the function + * Used to merge properties into the data within ._flatten(). + * The data is passed in and modified by the function * - * @param {object} state - the current merged state + * @param {object} data - the current merged data * @param {*} val - the value at `key` * @param {*} key - The key of `val` * @return {undefined} */ - _mergeProp(state, val, key) { + _mergeProp(data, val, key) { if (typeof val === 'function') { const source = this; return Promise.cast(val(this)) .then(function (newVal) { - return source._mergeProp(state, newVal, key); + return source._mergeProp(data, newVal, key); }); } @@ -526,17 +480,17 @@ export function SearchSourceProvider(Promise, Private, config) { let filters = Array.isArray(val) ? val : [val]; filters = filters.filter(filter => { - return this._filterPredicates.every(predicate => predicate(filter, state)); + return this._filterPredicates.every(predicate => predicate(filter, data)); }); - state.filters = [...(state.filters || []), ...filters]; + data.filters = [...(data.filters || []), ...filters]; return; case 'index': case 'type': case 'id': case 'highlightAll': - if (key && state[key] == null) { - state[key] = val; + if (key && data[key] == null) { + data[key] = val; } return; case 'searchAfter': @@ -548,14 +502,14 @@ export function SearchSourceProvider(Promise, Private, config) { addToBody(); break; case 'sort': - val = normalizeSortRequest(val, this.get('index')); + val = normalizeSortRequest(val, this.getField('index')); addToBody(); break; case 'query': - state.query = (state.query || []).concat(val); + data.query = (data.query || []).concat(val); break; case 'fields': - state[key] = _.uniq([...(state[key] || []), ...val]); + data[key] = _.uniq([...(data[key] || []), ...val]); break; default: addToBody(); @@ -565,10 +519,10 @@ export function SearchSourceProvider(Promise, Private, config) { * Add the key and val to the body of the request */ function addToBody() { - state.body = state.body || {}; + data.body = data.body || {}; // ignore if we already have a value - if (state.body[key] == null) { - state.body[key] = val; + if (data.body[key] == null) { + data.body[key] = val; } } } @@ -577,15 +531,13 @@ export function SearchSourceProvider(Promise, Private, config) { * Walk the inheritance chain of a source and return it's * flat representation (taking into account merging rules) * @returns {Promise} - * @resolved {Object|null} - the flat state of the SearchSource + * @resolved {Object|null} - the flat data of the SearchSource */ _flatten() { - const type = this._getType(); + // the merged data of this dataSource and it's ancestors + const flatData = {}; - // the merged state of this dataSource and it's ancestors - const flatState = {}; - - // function used to write each property from each state object in the chain to flat state + // function used to write each property from each data object in the chain to flat data const root = this; // start the chain at this source @@ -593,17 +545,17 @@ export function SearchSourceProvider(Promise, Private, config) { // call the ittr and return it's promise return (function ittr() { - // iterate the _state object (not array) and + // iterate the _fields object (not array) and // pass each key:value pair to source._mergeProp. if _mergeProp // returns a promise, then wait for it to complete and call _mergeProp again - return Promise.all(_.map(current._state, function ittr(value, key) { + return Promise.all(_.map(current._fields, function ittr(value, key) { if (Promise.is(value)) { return value.then(function (value) { return ittr(value, key); }); } - const prom = root._mergeProp(flatState, value, key); + const prom = root._mergeProp(flatData, value, key); return Promise.is(prom) ? prom : null; })) .then(function () { @@ -617,82 +569,80 @@ export function SearchSourceProvider(Promise, Private, config) { }); }()) .then(function () { - if (type === 'search') { - // This is down here to prevent the circular dependency - flatState.body = flatState.body || {}; - - const computedFields = flatState.index.getComputedFields(); - flatState.body.stored_fields = computedFields.storedFields; - flatState.body.script_fields = flatState.body.script_fields || {}; - flatState.body.docvalue_fields = flatState.body.docvalue_fields || []; - - _.extend(flatState.body.script_fields, computedFields.scriptFields); - flatState.body.docvalue_fields = _.union(flatState.body.docvalue_fields, computedFields.docvalueFields); - - if (flatState.body._source) { - // exclude source fields for this index pattern specified by the user - const filter = fieldWildcardFilter(flatState.body._source.excludes); - flatState.body.docvalue_fields = flatState.body.docvalue_fields.filter(filter); - } + // This is down here to prevent the circular dependency + flatData.body = flatData.body || {}; - // if we only want to search for certain fields - const fields = flatState.fields; - if (fields) { - // filter out the docvalue_fields, and script_fields to only include those that we are concerned with - flatState.body.docvalue_fields = _.intersection(flatState.body.docvalue_fields, fields); - flatState.body.script_fields = _.pick(flatState.body.script_fields, fields); - - // request the remaining fields from both stored_fields and _source - const remainingFields = _.difference(fields, _.keys(flatState.body.script_fields)); - flatState.body.stored_fields = remainingFields; - _.set(flatState.body, '_source.includes', remainingFields); - } + const computedFields = flatData.index.getComputedFields(); + flatData.body.stored_fields = computedFields.storedFields; + flatData.body.script_fields = flatData.body.script_fields || {}; + flatData.body.docvalue_fields = flatData.body.docvalue_fields || []; - flatState.body.query = buildESQuery(flatState.index, flatState.query, flatState.filters); + _.extend(flatData.body.script_fields, computedFields.scriptFields); + flatData.body.docvalue_fields = _.union(flatData.body.docvalue_fields, computedFields.docvalueFields); - if (flatState.highlightAll != null) { - if (flatState.highlightAll && flatState.body.query) { - flatState.body.highlight = getHighlightRequest(flatState.body.query, getConfig); - } - delete flatState.highlightAll; + if (flatData.body._source) { + // exclude source fields for this index pattern specified by the user + const filter = fieldWildcardFilter(flatData.body._source.excludes); + flatData.body.docvalue_fields = flatData.body.docvalue_fields.filter(filter); + } + + // if we only want to search for certain fields + const fields = flatData.fields; + if (fields) { + // filter out the docvalue_fields, and script_fields to only include those that we are concerned with + flatData.body.docvalue_fields = _.intersection(flatData.body.docvalue_fields, fields); + flatData.body.script_fields = _.pick(flatData.body.script_fields, fields); + + // request the remaining fields from both stored_fields and _source + const remainingFields = _.difference(fields, _.keys(flatData.body.script_fields)); + flatData.body.stored_fields = remainingFields; + _.set(flatData.body, '_source.includes', remainingFields); + } + + flatData.body.query = buildESQuery(flatData.index, flatData.query, flatData.filters); + + if (flatData.highlightAll != null) { + if (flatData.highlightAll && flatData.body.query) { + flatData.body.highlight = getHighlightRequest(flatData.body.query, getConfig); } + delete flatData.highlightAll; + } - /** - * Translate a filter into a query to support es 3+ - * @param {Object} filter - The filter to translate - * @return {Object} the query version of that filter - */ - const translateToQuery = function (filter) { - if (!filter) return; + /** + * Translate a filter into a query to support es 3+ + * @param {Object} filter - The filter to translate + * @return {Object} the query version of that filter + */ + const translateToQuery = function (filter) { + if (!filter) return; - if (filter.query) { - return filter.query; - } + if (filter.query) { + return filter.query; + } - return filter; - }; + return filter; + }; - // re-write filters within filter aggregations - (function recurse(aggBranch) { - if (!aggBranch) return; - Object.keys(aggBranch).forEach(function (id) { - const agg = aggBranch[id]; + // re-write filters within filter aggregations + (function recurse(aggBranch) { + if (!aggBranch) return; + Object.keys(aggBranch).forEach(function (id) { + const agg = aggBranch[id]; - if (agg.filters) { - // translate filters aggregations - const filters = agg.filters.filters; + if (agg.filters) { + // translate filters aggregations + const filters = agg.filters.filters; - Object.keys(filters).forEach(function (filterId) { - filters[filterId] = translateToQuery(filters[filterId]); - }); - } + Object.keys(filters).forEach(function (filterId) { + filters[filterId] = translateToQuery(filters[filterId]); + }); + } - recurse(agg.aggs || agg.aggregations); - }); - }(flatState.body.aggs || flatState.body.aggregations)); - } + recurse(agg.aggs || agg.aggregations); + }); + }(flatData.body.aggs || flatData.body.aggregations)); - return flatState; + return flatData; }); } } diff --git a/src/ui/public/courier/utils/courier_inspector_utils.js b/src/ui/public/courier/utils/courier_inspector_utils.js index 10f5f490f68fe..30b845e27bc56 100644 --- a/src/ui/public/courier/utils/courier_inspector_utils.js +++ b/src/ui/public/courier/utils/courier_inspector_utils.js @@ -25,7 +25,7 @@ */ function getRequestInspectorStats(searchSource) { const stats = {}; - const index = searchSource.get('index'); + const index = searchSource.getField('index'); if (index) { stats['Index pattern'] = { diff --git a/src/ui/public/doc_table/__tests__/doc_table.js b/src/ui/public/doc_table/__tests__/doc_table.js index 7a00effd88f68..5395ddb4f216f 100644 --- a/src/ui/public/doc_table/__tests__/doc_table.js +++ b/src/ui/public/doc_table/__tests__/doc_table.js @@ -72,7 +72,7 @@ describe('docTable', function () { searchSource = Private(FixturesStubbedSearchSourceProvider); }); init($elem, { - searchSource: searchSource, + searchSource, columns: [], sorting: ['@timestamp', 'desc'] }); @@ -89,12 +89,12 @@ describe('docTable', function () { }); it('should set the indexPattern to that of the searchSource', function () { - expect($scope.indexPattern).to.be(searchSource.get('index')); + expect($scope.indexPattern).to.be(searchSource.getField('index')); }); it('should set size and sort on the searchSource', function () { - expect($scope.searchSource.sort.called).to.be(true); - expect($scope.searchSource.size.called).to.be(true); + expect($scope.searchSource.setField.getCall(0).args[0]).to.be('size'); + expect($scope.searchSource.setField.getCall(1).args[0]).to.be('sort'); }); it('should have an addRows function that increases the row count', function () { diff --git a/src/ui/public/doc_table/doc_table.js b/src/ui/public/doc_table/doc_table.js index c8d1efea19457..b7e47a9c9d625 100644 --- a/src/ui/public/doc_table/doc_table.js +++ b/src/ui/public/doc_table/doc_table.js @@ -94,16 +94,16 @@ uiModules.get('kibana') $scope.$watch('searchSource', function () { if (!$scope.searchSource) return; - $scope.indexPattern = $scope.searchSource.get('index'); + $scope.indexPattern = $scope.searchSource.getField('index'); - $scope.searchSource.size(config.get('discover:sampleSize')); - $scope.searchSource.sort(getSort($scope.sorting, $scope.indexPattern)); + $scope.searchSource.setField('size', config.get('discover:sampleSize')); + $scope.searchSource.setField('sort', getSort($scope.sorting, $scope.indexPattern)); // Set the watcher after initialization $scope.$watchCollection('sorting', function (newSort, oldSort) { // Don't react if sort values didn't really change if (newSort === oldSort) return; - $scope.searchSource.sort(getSort(newSort, $scope.indexPattern)); + $scope.searchSource.setField('sort', getSort(newSort, $scope.indexPattern)); $scope.searchSource.fetchQueued(); }); diff --git a/src/ui/public/vis/request_handlers/courier.js b/src/ui/public/vis/request_handlers/courier.js index 812c3e9d3f8a5..c9750f936e9b4 100644 --- a/src/ui/public/vis/request_handlers/courier.js +++ b/src/ui/public/vis/request_handlers/courier.js @@ -82,8 +82,8 @@ const CourierRequestHandlerProvider = function () { // Using callParentStartHandlers: true we make sure, that the parent searchSource // onSearchRequestStart will be called properly even though we use an inherited // search source. - const timeFilterSearchSource = searchSource.makeChild({ callParentStartHandlers: true }); - const requestSearchSource = timeFilterSearchSource.makeChild({ callParentStartHandlers: true }); + const timeFilterSearchSource = searchSource.createChild({ callParentStartHandlers: true }); + const requestSearchSource = timeFilterSearchSource.createChild({ callParentStartHandlers: true }); // For now we need to mirror the history of the passed search source, since // the spy panel wouldn't work otherwise. @@ -96,7 +96,7 @@ const CourierRequestHandlerProvider = function () { } }); - requestSearchSource.aggs(function () { + requestSearchSource.setField('aggs', function () { return aggs.toDsl(); }); @@ -104,12 +104,12 @@ const CourierRequestHandlerProvider = function () { return aggs.onSearchRequestStart(searchSource, searchRequest); }); - timeFilterSearchSource.set('filter', () => { - return getTime(searchSource.get('index'), timeRange); + timeFilterSearchSource.setField('filter', () => { + return getTime(searchSource.getField('index'), timeRange); }); - requestSearchSource.set('filter', filters); - requestSearchSource.set('query', query); + requestSearchSource.setField('filter', filters); + requestSearchSource.setField('query', query); const shouldQuery = (requestBodyHash) => { if (!searchSource.lastQuery || forceFetch) return true; diff --git a/src/ui/public/visualize/__tests__/visualize.js b/src/ui/public/visualize/__tests__/visualize.js index e98cb6598559d..cea05d50b9f17 100644 --- a/src/ui/public/visualize/__tests__/visualize.js +++ b/src/ui/public/visualize/__tests__/visualize.js @@ -64,8 +64,8 @@ describe('visualize directive', function () { $rootScope.uiState = uiState; $rootScope.searchSource = searchSource; $rootScope.savedObject = { - vis: vis, - searchSource: searchSource + vis, + searchSource, }; $rootScope.updateState = updateState; diff --git a/src/ui/public/visualize/loader/__tests__/visualize_loader.js b/src/ui/public/visualize/loader/__tests__/visualize_loader.js index fbe6f1e37120b..2b5c4b7043e0a 100644 --- a/src/ui/public/visualize/loader/__tests__/visualize_loader.js +++ b/src/ui/public/visualize/loader/__tests__/visualize_loader.js @@ -42,8 +42,8 @@ describe('visualize loader', () => { function createSavedObject() { return { - vis: vis, - searchSource: searchSource + vis, + searchSource, }; } diff --git a/x-pack/plugins/ml/public/jobs/components/custom_url_editor/custom_url_editor_directive.js b/x-pack/plugins/ml/public/jobs/components/custom_url_editor/custom_url_editor_directive.js index 8fdd222cf7d50..4cfeb6d9c0a8f 100644 --- a/x-pack/plugins/ml/public/jobs/components/custom_url_editor/custom_url_editor_directive.js +++ b/x-pack/plugins/ml/public/jobs/components/custom_url_editor/custom_url_editor_directive.js @@ -185,9 +185,9 @@ module.directive('mlCustomUrlEditor', function (Private) { const searchSourceJSON = response.get('kibanaSavedObjectMeta.searchSourceJSON'); if (searchSourceJSON !== undefined) { - const searchSource = JSON.parse(searchSourceJSON); - filters = _.get(searchSource, 'filter', []); - query = searchSource.query; + const searchSourceData = JSON.parse(searchSourceJSON); + filters = _.get(searchSourceData, 'filter', []); + query = searchSourceData.query; } // Add time settings to the global state URL parameter with $earliest$ and diff --git a/x-pack/plugins/ml/public/jobs/new_job/utils/new_job_utils.js b/x-pack/plugins/ml/public/jobs/new_job/utils/new_job_utils.js index ac5cd7789de51..23e069ea22e4c 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/utils/new_job_utils.js +++ b/x-pack/plugins/ml/public/jobs/new_job/utils/new_job_utils.js @@ -56,12 +56,12 @@ export function createSearchItems($route) { if (indexPattern.id === undefined && savedSearch.id !== undefined) { - indexPattern = searchSource.get('index'); + indexPattern = searchSource.getField('index'); // Extract the query from the searchSource // Might be as a String in q.query, or // nested inside q.query.query_string - const q = searchSource.get('query'); + const q = searchSource.getField('query'); if (q !== undefined && q.language === 'lucene' && q.query !== undefined) { if (typeof q.query === 'string' && q.query !== '') { query.query_string.query = q.query; @@ -71,7 +71,7 @@ export function createSearchItems($route) { } } - const fs = searchSource.get('filter'); + const fs = searchSource.getField('filter'); if (fs.length) { filters = fs; }