Skip to content

Commit

Permalink
Improve SearchSource SearchRequest type
Browse files Browse the repository at this point in the history
  • Loading branch information
lukasolson committed Jun 24, 2024
1 parent 702442d commit 6b778cb
Show file tree
Hide file tree
Showing 12 changed files with 84 additions and 72 deletions.
8 changes: 2 additions & 6 deletions packages/kbn-generate-csv/src/lib/search_cursor_pit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@
import type { estypes } from '@elastic/elasticsearch';
import type { Logger } from '@kbn/core/server';
import { lastValueFrom } from 'rxjs';
import {
ES_SEARCH_STRATEGY,
type ISearchSource,
type SearchRequest,
} from '@kbn/data-plugin/common';
import { ES_SEARCH_STRATEGY, type ISearchSource } from '@kbn/data-plugin/common';
import { SearchCursor, type SearchCursorClients, type SearchCursorSettings } from './search_cursor';
import { i18nTexts } from './i18n_texts';

Expand Down Expand Up @@ -74,7 +70,7 @@ export class SearchCursorPit extends SearchCursor {
return pitId;
}

protected async searchWithPit(searchBody: SearchRequest) {
protected async searchWithPit(searchBody: estypes.SearchRequest) {
const { maxConcurrentShardRequests, scroll, taskInstanceFields } = this.settings;

// maxConcurrentShardRequests=0 is not supported
Expand Down
8 changes: 2 additions & 6 deletions packages/kbn-generate-csv/src/lib/search_cursor_scroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,7 @@ import type { estypes } from '@elastic/elasticsearch';
import { lastValueFrom } from 'rxjs';
import type { Logger } from '@kbn/core/server';
import type { IEsSearchResponse } from '@kbn/search-types';
import {
ES_SEARCH_STRATEGY,
type ISearchSource,
type SearchRequest,
} from '@kbn/data-plugin/common';
import { ES_SEARCH_STRATEGY, type ISearchSource } from '@kbn/data-plugin/common';
import { SearchCursor, type SearchCursorClients, type SearchCursorSettings } from './search_cursor';
import { i18nTexts } from './i18n_texts';

Expand All @@ -32,7 +28,7 @@ export class SearchCursorScroll extends SearchCursor {
// The first search query begins the scroll context in ES
public async initialize() {}

private async scan(searchBody: SearchRequest) {
private async scan(searchBody: estypes.SearchRequest) {
const { includeFrozen, maxConcurrentShardRequests, scroll, taskInstanceFields } = this.settings;

// maxConcurrentShardRequests=0 is not supported
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,15 @@ export function getSearchParamsFromRequest(
const searchParams = getSearchParams(getConfig);
// eslint-disable-next-line @typescript-eslint/naming-convention
const { track_total_hits, ...body } = searchRequest.body;
const dataView = typeof searchRequest.index !== 'string' ? searchRequest.index : undefined;
const index = dataView?.title ?? `${searchRequest.index}`;

return {
index: searchRequest.index.title || searchRequest.index,
index,
body,
// @ts-ignore
track_total_hits,
...(searchRequest.index?.allowHidden && { expand_wildcards: 'all' }),
...(dataView?.getAllowHidden() && { expand_wildcards: 'all' }),
...searchParams,
};
}
9 changes: 8 additions & 1 deletion src/plugins/data/common/search/search_source/fetch/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
* Side Public License, v 1.
*/
import type { IKibanaSearchResponse } from '@kbn/search-types';
import type { DataView } from '@kbn/data-views-plugin/common';
import type { AggregateQuery, Filter, Query } from '@kbn/es-query';
import { SearchSourceSearchOptions } from '../../..';
import { GetConfigFn } from '../../../types';

Expand All @@ -17,7 +19,12 @@ import { GetConfigFn } from '../../../types';
* where `ISearchRequestParams` is used externally instead.
* FIXME: replace with estypes.SearchRequest?
*/
export type SearchRequest = Record<string, any>;
export interface SearchRequest {
index?: DataView | string;
query?: Array<Query | AggregateQuery>;
filters?: Filter[] | (() => Filter[]);
[propName: string]: any;
}

export interface FetchHandlers {
getConfig: GetConfigFn;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import { DataViewLazy } from '@kbn/data-views-plugin/common';
import { fromKueryExpression, getKqlFieldNames } from '@kbn/es-query';
import { fromKueryExpression, getKqlFieldNames, isFilter, isOfQueryType } from '@kbn/es-query';
import type { SearchRequest } from './fetch';
import { EsQuerySortValue } from '../..';

Expand All @@ -25,21 +25,21 @@ export async function queryToFields({
const sortArr = Array.isArray(sort) ? sort : [sort];
fields.push(...sortArr.flatMap((s) => Object.keys(s)));
}
for (const query of request.query) {
for (const query of (request.query ?? []).filter(isOfQueryType)) {
if (query.query && query.language === 'kuery') {
const nodes = fromKueryExpression(query.query);
const queryFields = getKqlFieldNames(nodes);
fields = fields.concat(queryFields);
}
}
const filters = request.filters;
const { filters } = request;
if (filters) {
const filtersArr = Array.isArray(filters) ? filters : [filters];
for (const f of filtersArr) {
// unified search bar filters have meta object and key (regular filters)
// unified search bar "custom" filters ("Edit as query DSL", where meta.key is not present but meta is)
// Any other Elasticsearch query DSL filter that gets passed in by consumers (not coming from unified search, and these probably won't have a meta key at all)
if (f?.meta?.key && f.meta.disabled !== true) {
if (isFilter(f) && f?.meta?.key && f.meta.disabled !== true) {
fields.push(f.meta.key);
}
}
Expand Down
19 changes: 13 additions & 6 deletions src/plugins/data/common/search/search_source/search_source.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,14 @@ const indexPattern = {
fields: [{ name: 'foo-bar' }, { name: 'field1' }, { name: 'field2' }, { name: '_id' }],
getComputedFields,
getSourceFiltering: () => mockSource,
getAllowHidden: jest.fn(),
} as unknown as DataView;

const indexPattern2 = {
title: 'foo',
getComputedFields,
getSourceFiltering: () => mockSource2,
getAllowHidden: jest.fn(),
} as unknown as DataView;

const fields3 = [{ name: 'foo-bar' }, { name: 'field1' }, { name: 'field2' }];
Expand Down Expand Up @@ -1474,10 +1476,15 @@ describe('SearchSource', () => {
return buildExpression(ast).toString();
}

beforeEach(() => {
searchSource = new SearchSource({}, searchSourceDependencies);
searchSource.setField('index', indexPattern);
});

test('should generate an expression AST', () => {
expect(toString(searchSource.toExpressionAst())).toMatchInlineSnapshot(`
"kibana_context
| esdsl dsl=\\"{}\\""
| esdsl dsl=\\"{}\\" index=\\"1234\\""
`);
});

Expand All @@ -1486,7 +1493,7 @@ describe('SearchSource', () => {

expect(toString(searchSource.toExpressionAst())).toMatchInlineSnapshot(`
"kibana_context q={kql q=\\"something\\"}
| esdsl dsl=\\"{}\\""
| esdsl dsl=\\"{}\\" index=\\"1234\\""
`);
});

Expand All @@ -1504,7 +1511,7 @@ describe('SearchSource', () => {
expect(toString(searchSource.toExpressionAst())).toMatchInlineSnapshot(`
"kibana_context filters={kibanaFilter query=\\"{\\\\\\"query_string\\\\\\":{\\\\\\"query\\\\\\":\\\\\\"query1\\\\\\"}}\\"}
filters={kibanaFilter query=\\"{\\\\\\"query_string\\\\\\":{\\\\\\"query\\\\\\":\\\\\\"query2\\\\\\"}}\\"}
| esdsl dsl=\\"{}\\""
| esdsl dsl=\\"{}\\" index=\\"1234\\""
`);
});

Expand All @@ -1517,7 +1524,7 @@ describe('SearchSource', () => {

expect(toString(searchSource.toExpressionAst())).toMatchInlineSnapshot(`
"kibana_context filters={kibanaFilter query=\\"{\\\\\\"query_string\\\\\\":{\\\\\\"query\\\\\\":\\\\\\"query\\\\\\"}}\\"}
| esdsl dsl=\\"{}\\""
| esdsl dsl=\\"{}\\" index=\\"1234\\""
`);
});

Expand All @@ -1540,7 +1547,7 @@ describe('SearchSource', () => {
expect(toString(childSearchSource.toExpressionAst())).toMatchInlineSnapshot(`
"kibana_context q={kql q=\\"something2\\"} q={kql q=\\"something1\\"} filters={kibanaFilter query=\\"{\\\\\\"query_string\\\\\\":{\\\\\\"query\\\\\\":\\\\\\"query2\\\\\\"}}\\"}
filters={kibanaFilter query=\\"{\\\\\\"query_string\\\\\\":{\\\\\\"query\\\\\\":\\\\\\"query1\\\\\\"}}\\"}
| esdsl dsl=\\"{}\\""
| esdsl dsl=\\"{}\\" index=\\"1234\\""
`);
});

Expand All @@ -1558,7 +1565,7 @@ describe('SearchSource', () => {

expect(toString(searchSource.toExpressionAst())).toMatchInlineSnapshot(`
"kibana_context
| esdsl size=1000 dsl=\\"{}\\""
| esdsl size=1000 dsl=\\"{}\\" index=\\"1234\\""
`);
});

Expand Down
48 changes: 29 additions & 19 deletions src/plugins/data/common/search/search_source/search_source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -649,9 +649,12 @@ export class SearchSource {

switch (key) {
case 'filter':
return addToRoot('filters', (data.filters || []).concat(val));
return addToRoot(
'filters',
(typeof data.filters === 'function' ? data.filters() : data.filters || []).concat(val)
);
case 'query':
return addToRoot(key, (data[key] || []).concat(val));
return addToRoot(key, (data.query || []).concat(val));
case 'fields':
// This will pass the passed in parameters to the new fields API.
// Also if will only return scripted fields that are part of the specified
Expand All @@ -662,7 +665,7 @@ export class SearchSource {
return addToBody('fields', val);
case 'fieldsFromSource':
// preserves legacy behavior
const fields = [...new Set((data[key] || []).concat(val))];
const fields = [...new Set((data.fieldsFromSource || []).concat(val))];
return addToRoot(key, fields);
case 'index':
case 'type':
Expand Down Expand Up @@ -709,8 +712,10 @@ export class SearchSource {
return searchRequest;
}

private getIndexType(index?: DataView) {
return this.shouldOverwriteDataViewType ? this.overwriteDataViewType : index?.type;
private getIndexType(index?: DataView | string) {
return this.shouldOverwriteDataViewType
? this.overwriteDataViewType
: typeof index !== 'string' && index?.type;
}

private readonly getFieldName = (fld: SearchFieldValue): string =>
Expand Down Expand Up @@ -782,25 +787,24 @@ export class SearchSource {

private flatten() {
const { getConfig } = this.dependencies;
const metaFields = getConfig(UI_SETTINGS.META_FIELDS) ?? [];
const metaFields = getConfig<string[]>(UI_SETTINGS.META_FIELDS) ?? [];

const searchRequest = this.mergeProps();
searchRequest.body = searchRequest.body || {};
const { body, index } = searchRequest;
const dataView = typeof index !== 'string' ? index : undefined;

// get some special field types from the index pattern
const { docvalueFields, scriptFields, runtimeFields } = index
? index.getComputedFields()
: {
docvalueFields: [],
scriptFields: {},
runtimeFields: {},
};
const { docvalueFields, scriptFields, runtimeFields } = dataView?.getComputedFields() ?? {
docvalueFields: [],
scriptFields: {},
runtimeFields: {},
};
const fieldListProvided = !!body.fields;

// set defaults
const _source =
index && !body.hasOwnProperty('_source') ? index.getSourceFiltering() : body._source;
index && !body.hasOwnProperty('_source') ? dataView?.getSourceFiltering() : body._source;

// get filter if data view specified, otherwise null filter
const filter = this.getFieldFilter({ bodySourceExcludes: _source?.excludes, metaFields });
Expand Down Expand Up @@ -892,7 +896,7 @@ export class SearchSource {
runtime_mappings: runtimeFields,
script_fields: scriptedFields,
fields: this.getFieldsList({
index,
index: dataView,
fields,
docvalueFields: body.docvalue_fields,
fieldsFromSource,
Expand Down Expand Up @@ -960,7 +964,12 @@ export class SearchSource {
...getEsQueryConfig({ get: getConfig }),
filtersInMustClause,
};
return buildEsQuery(index, query, filters, esQueryConfigs);
return buildEsQuery(
typeof index !== 'string' ? index : undefined,
query,
typeof filters === 'function' ? filters() : filters,
esQueryConfigs
);
}

private getRemainingFields({
Expand Down Expand Up @@ -1157,14 +1166,15 @@ export class SearchSource {
toExpressionAst({ asDatatable = true }: ExpressionAstOptions = {}): ExpressionAstExpression {
const searchRequest = this.mergeProps();
const { body, index, query } = searchRequest;
const dataView = typeof index !== 'string' ? index : undefined;

const filters = (
typeof searchRequest.filters === 'function' ? searchRequest.filters() : searchRequest.filters
) as Filter[] | Filter | undefined;

const ast = buildExpression([
buildExpressionFunction<ExpressionFunctionKibanaContext>('kibana_context', {
q: query?.map(queryToAst),
q: query?.filter(isOfQueryType).map(queryToAst),
filters: filters && filtersToAst(filters),
}),
]).toAst();
Expand All @@ -1181,7 +1191,7 @@ export class SearchSource {
const aggConfigs =
aggs instanceof AggConfigs
? aggs
: index && aggs && this.dependencies.aggs.createAggConfigs(index, aggs);
: dataView && aggs && this.dependencies.aggs.createAggConfigs(dataView, aggs);

if (aggConfigs) {
ast.chain.push(...aggConfigs.toExpressionAst().chain);
Expand All @@ -1190,7 +1200,7 @@ export class SearchSource {
buildExpressionFunction<EsdslExpressionFunctionDefinition>('esdsl', {
size: body?.size,
dsl: JSON.stringify({}),
index: index?.id,
index: typeof index === 'string' ? index : `${dataView?.id}`,
}).toAst()
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/vis_types/vega/public/data_model/search_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export class SearchAPI {
});

return from(
extendSearchParamsWithRuntimeFields(indexPatterns, requestParams, request.index)
extendSearchParamsWithRuntimeFields(indexPatterns, requestParams, `${request.index}`)
).pipe(
tap((params) => {
/** inspect request data **/
Expand Down
3 changes: 1 addition & 2 deletions x-pack/plugins/lens/public/datasources/form_based/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { EuiLink, EuiSpacer } from '@elastic/eui';
import type { DatatableColumn } from '@kbn/expressions-plugin/common';
import { groupBy, escape, uniq, uniqBy } from 'lodash';
import type { Query } from '@kbn/data-plugin/common';
import { SearchRequest } from '@kbn/data-plugin/common';

import {
type SearchResponseWarning,
Expand Down Expand Up @@ -269,7 +268,7 @@ const accuracyModeEnabledWarning = (
export function getSearchWarningMessages(
state: FormBasedPersistedState,
warning: SearchResponseWarning,
request: SearchRequest,
request: estypes.SearchRequest,
response: estypes.SearchResponse,
theme: ThemeServiceStart
): UserMessage[] {
Expand Down
3 changes: 1 addition & 2 deletions x-pack/plugins/lens/public/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
import type { FieldFormatParams } from '@kbn/field-formats-plugin/common';
import type { SearchResponseWarning } from '@kbn/search-response-warnings';
import type { EuiButtonIconProps } from '@elastic/eui';
import { SearchRequest } from '@kbn/data-plugin/public';
import { estypes } from '@elastic/elasticsearch';
import React from 'react';
import { CellValueContext } from '@kbn/embeddable-plugin/public';
Expand Down Expand Up @@ -483,7 +482,7 @@ export interface Datasource<T = unknown, P = unknown> {
getSearchWarningMessages?: (
state: P,
warning: SearchResponseWarning,
request: SearchRequest,
request: estypes.SearchRequest,
response: estypes.SearchResponse
) => UserMessage[];

Expand Down
Loading

0 comments on commit 6b778cb

Please sign in to comment.