Skip to content

Commit 7503fd2

Browse files
authored
support serializing nested searchsource (#91525)
1 parent dadf0e6 commit 7503fd2

File tree

8 files changed

+101
-216
lines changed

8 files changed

+101
-216
lines changed

docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.getfields.md

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,8 @@ returns all search source fields
99
<b>Signature:</b>
1010

1111
```typescript
12-
getFields(recurse?: boolean): SearchSourceFields;
12+
getFields(): SearchSourceFields;
1313
```
14-
15-
## Parameters
16-
17-
| Parameter | Type | Description |
18-
| --- | --- | --- |
19-
| recurse | <code>boolean</code> | |
20-
2114
<b>Returns:</b>
2215

2316
`SearchSourceFields`

docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export declare class SearchSource
3535
| [fetch(options)](./kibana-plugin-plugins-data-public.searchsource.fetch.md) | | Fetch this source and reject the returned Promise on error |
3636
| [fetch$(options)](./kibana-plugin-plugins-data-public.searchsource.fetch_.md) | | Fetch this source from Elasticsearch, returning an observable over the response(s) |
3737
| [getField(field, recurse)](./kibana-plugin-plugins-data-public.searchsource.getfield.md) | | Gets a single field from the fields |
38-
| [getFields(recurse)](./kibana-plugin-plugins-data-public.searchsource.getfields.md) | | returns all search source fields |
38+
| [getFields()](./kibana-plugin-plugins-data-public.searchsource.getfields.md) | | returns all search source fields |
3939
| [getId()](./kibana-plugin-plugins-data-public.searchsource.getid.md) | | returns search source id |
4040
| [getOwnField(field)](./kibana-plugin-plugins-data-public.searchsource.getownfield.md) | | Get the field from our own fields, don't traverse up the chain |
4141
| [getParent()](./kibana-plugin-plugins-data-public.searchsource.getparent.md) | | Get the parent of this SearchSource {<!-- -->undefined\|searchSource<!-- -->} |

docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsourcefields.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export interface SearchSourceFields
2424
| [highlight](./kibana-plugin-plugins-data-public.searchsourcefields.highlight.md) | <code>any</code> | |
2525
| [highlightAll](./kibana-plugin-plugins-data-public.searchsourcefields.highlightall.md) | <code>boolean</code> | |
2626
| [index](./kibana-plugin-plugins-data-public.searchsourcefields.index.md) | <code>IndexPattern</code> | |
27+
| [parent](./kibana-plugin-plugins-data-public.searchsourcefields.parent.md) | <code>SearchSourceFields</code> | |
2728
| [query](./kibana-plugin-plugins-data-public.searchsourcefields.query.md) | <code>Query</code> | [Query](./kibana-plugin-plugins-data-public.query.md) |
2829
| [searchAfter](./kibana-plugin-plugins-data-public.searchsourcefields.searchafter.md) | <code>EsQuerySearchAfter</code> | |
2930
| [size](./kibana-plugin-plugins-data-public.searchsourcefields.size.md) | <code>number</code> | |
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
2+
3+
[Home](./index.md) &gt; [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) &gt; [SearchSourceFields](./kibana-plugin-plugins-data-public.searchsourcefields.md) &gt; [parent](./kibana-plugin-plugins-data-public.searchsourcefields.parent.md)
4+
5+
## SearchSourceFields.parent property
6+
7+
<b>Signature:</b>
8+
9+
```typescript
10+
parent?: SearchSourceFields;
11+
```

src/plugins/data/common/search/search_source/search_source.test.ts

Lines changed: 70 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -95,164 +95,6 @@ describe('SearchSource', () => {
9595
}
9696
`);
9797
});
98-
99-
test('recurses parents to get the entire filters: plain object filter', () => {
100-
const RECURSE = true;
101-
102-
const parent = new SearchSource({}, searchSourceDependencies);
103-
parent.setField('filter', [
104-
{
105-
meta: {
106-
index: 'd180cae0-60c3-11eb-8569-bd1f5ed24bc9',
107-
params: {},
108-
alias: null,
109-
disabled: false,
110-
negate: false,
111-
},
112-
query: {
113-
range: {
114-
'@date': {
115-
gte: '2016-01-27T18:11:05.010Z',
116-
lte: '2021-01-27T18:11:05.010Z',
117-
format: 'strict_date_optional_time',
118-
},
119-
},
120-
},
121-
},
122-
]);
123-
searchSource.setParent(parent);
124-
searchSource.setField('aggs', 5);
125-
expect(searchSource.getFields(RECURSE)).toMatchInlineSnapshot(`
126-
Object {
127-
"aggs": 5,
128-
"filter": Array [
129-
Object {
130-
"meta": Object {
131-
"alias": null,
132-
"disabled": false,
133-
"index": "d180cae0-60c3-11eb-8569-bd1f5ed24bc9",
134-
"negate": false,
135-
"params": Object {},
136-
},
137-
"query": Object {
138-
"range": Object {
139-
"@date": Object {
140-
"format": "strict_date_optional_time",
141-
"gte": "2016-01-27T18:11:05.010Z",
142-
"lte": "2021-01-27T18:11:05.010Z",
143-
},
144-
},
145-
},
146-
},
147-
],
148-
}
149-
`);
150-
151-
// calling twice gives the same result: no searchSources in the hierarchy were modified
152-
expect(searchSource.getFields(RECURSE)).toMatchInlineSnapshot(`
153-
Object {
154-
"aggs": 5,
155-
"filter": Array [
156-
Object {
157-
"meta": Object {
158-
"alias": null,
159-
"disabled": false,
160-
"index": "d180cae0-60c3-11eb-8569-bd1f5ed24bc9",
161-
"negate": false,
162-
"params": Object {},
163-
},
164-
"query": Object {
165-
"range": Object {
166-
"@date": Object {
167-
"format": "strict_date_optional_time",
168-
"gte": "2016-01-27T18:11:05.010Z",
169-
"lte": "2021-01-27T18:11:05.010Z",
170-
},
171-
},
172-
},
173-
},
174-
],
175-
}
176-
`);
177-
});
178-
179-
test('recurses parents to get the entire filters: function filter', () => {
180-
const RECURSE = true;
181-
182-
const parent = new SearchSource({}, searchSourceDependencies);
183-
parent.setField('filter', () => ({
184-
meta: {
185-
index: 'd180cae0-60c3-11eb-8569-bd1f5ed24bc9',
186-
params: {},
187-
alias: null,
188-
disabled: false,
189-
negate: false,
190-
},
191-
query: {
192-
range: {
193-
'@date': {
194-
gte: '2016-01-27T18:11:05.010Z',
195-
lte: '2021-01-27T18:11:05.010Z',
196-
format: 'strict_date_optional_time',
197-
},
198-
},
199-
},
200-
}));
201-
searchSource.setParent(parent);
202-
searchSource.setField('aggs', 5);
203-
expect(searchSource.getFields(RECURSE)).toMatchInlineSnapshot(`
204-
Object {
205-
"aggs": 5,
206-
"filter": Array [
207-
Object {
208-
"meta": Object {
209-
"alias": null,
210-
"disabled": false,
211-
"index": "d180cae0-60c3-11eb-8569-bd1f5ed24bc9",
212-
"negate": false,
213-
"params": Object {},
214-
},
215-
"query": Object {
216-
"range": Object {
217-
"@date": Object {
218-
"format": "strict_date_optional_time",
219-
"gte": "2016-01-27T18:11:05.010Z",
220-
"lte": "2021-01-27T18:11:05.010Z",
221-
},
222-
},
223-
},
224-
},
225-
],
226-
}
227-
`);
228-
229-
// calling twice gives the same result: no double-added filters
230-
expect(searchSource.getFields(RECURSE)).toMatchInlineSnapshot(`
231-
Object {
232-
"aggs": 5,
233-
"filter": Array [
234-
Object {
235-
"meta": Object {
236-
"alias": null,
237-
"disabled": false,
238-
"index": "d180cae0-60c3-11eb-8569-bd1f5ed24bc9",
239-
"negate": false,
240-
"params": Object {},
241-
},
242-
"query": Object {
243-
"range": Object {
244-
"@date": Object {
245-
"format": "strict_date_optional_time",
246-
"gte": "2016-01-27T18:11:05.010Z",
247-
"lte": "2021-01-27T18:11:05.010Z",
248-
},
249-
},
250-
},
251-
},
252-
],
253-
}
254-
`);
255-
});
25698
});
25799

258100
describe('#removeField()', () => {
@@ -975,4 +817,74 @@ describe('SearchSource', () => {
975817
expect(request._source).toEqual(['geometry']);
976818
});
977819
});
820+
821+
describe('getSerializedFields', () => {
822+
const filter = [
823+
{
824+
query: 'query',
825+
meta: {
826+
alias: 'alias',
827+
disabled: false,
828+
negate: false,
829+
index: '456',
830+
},
831+
},
832+
];
833+
834+
test('should return serialized fields', () => {
835+
const indexPattern123 = { id: '123' } as IndexPattern;
836+
searchSource.setField('index', indexPattern123);
837+
searchSource.setField('filter', () => {
838+
return filter;
839+
});
840+
const serializedFields = searchSource.getSerializedFields();
841+
expect(serializedFields).toMatchInlineSnapshot(
842+
{ index: '123', filter },
843+
`
844+
Object {
845+
"filter": Array [
846+
Object {
847+
"meta": Object {
848+
"alias": "alias",
849+
"disabled": false,
850+
"index": "456",
851+
"negate": false,
852+
},
853+
"query": "query",
854+
},
855+
],
856+
"index": "123",
857+
}
858+
`
859+
);
860+
});
861+
862+
test('should support nested search sources', () => {
863+
const indexPattern123 = { id: '123' } as IndexPattern;
864+
searchSource.setField('index', indexPattern123);
865+
searchSource.setField('from', 123);
866+
const childSearchSource = searchSource.createChild();
867+
childSearchSource.setField('timeout', '100');
868+
const serializedFields = childSearchSource.getSerializedFields(true);
869+
expect(serializedFields).toMatchInlineSnapshot(
870+
{
871+
timeout: '100',
872+
parent: {
873+
index: '123',
874+
from: 123,
875+
},
876+
},
877+
`
878+
Object {
879+
"index": undefined,
880+
"parent": Object {
881+
"from": 123,
882+
"index": "123",
883+
},
884+
"timeout": "100",
885+
}
886+
`
887+
);
888+
});
889+
});
978890
});

src/plugins/data/common/search/search_source/search_source.ts

Lines changed: 12 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
*/
6060

6161
import { setWith } from '@elastic/safer-lodash-set';
62-
import { uniqueId, keyBy, pick, difference, omit, isFunction, isEqual, uniqWith } from 'lodash';
62+
import { uniqueId, keyBy, pick, difference, isFunction, isEqual, uniqWith } from 'lodash';
6363
import { map, switchMap, tap } from 'rxjs/operators';
6464
import { defer, from } from 'rxjs';
6565
import { isObject } from 'rxjs/internal-compatibility';
@@ -114,8 +114,13 @@ export class SearchSource {
114114
private readonly dependencies: SearchSourceDependencies;
115115

116116
constructor(fields: SearchSourceFields = {}, dependencies: SearchSourceDependencies) {
117-
this.fields = fields;
117+
const { parent, ...currentFields } = fields;
118+
this.fields = currentFields;
118119
this.dependencies = dependencies;
120+
121+
if (parent) {
122+
this.setParent(new SearchSource(parent, dependencies));
123+
}
119124
}
120125

121126
/** ***
@@ -173,49 +178,7 @@ export class SearchSource {
173178
/**
174179
* returns all search source fields
175180
*/
176-
getFields(recurse = false): SearchSourceFields {
177-
let thisFilter = this.fields.filter; // type is single value, array, or function
178-
if (thisFilter) {
179-
if (typeof thisFilter === 'function') {
180-
thisFilter = thisFilter() || []; // type is single value or array
181-
}
182-
183-
if (Array.isArray(thisFilter)) {
184-
thisFilter = [...thisFilter];
185-
} else {
186-
thisFilter = [thisFilter];
187-
}
188-
} else {
189-
thisFilter = [];
190-
}
191-
192-
if (recurse) {
193-
const parent = this.getParent();
194-
if (parent) {
195-
const parentFields = parent.getFields(recurse);
196-
197-
let parentFilter = parentFields.filter; // type is single value, array, or function
198-
if (parentFilter) {
199-
if (typeof parentFilter === 'function') {
200-
parentFilter = parentFilter() || []; // type is single value or array
201-
}
202-
203-
if (Array.isArray(parentFilter)) {
204-
thisFilter.push(...parentFilter);
205-
} else {
206-
thisFilter.push(parentFilter);
207-
}
208-
}
209-
210-
// add combined filters to the fields
211-
const thisFields = {
212-
...this.fields,
213-
filter: thisFilter,
214-
};
215-
216-
return { ...parentFields, ...thisFields };
217-
}
218-
}
181+
getFields(): SearchSourceFields {
219182
return { ...this.fields };
220183
}
221184

@@ -727,9 +690,7 @@ export class SearchSource {
727690
* serializes search source fields (which can later be passed to {@link ISearchStartSearchSource})
728691
*/
729692
public getSerializedFields(recurse = false) {
730-
const { filter: originalFilters, ...searchSourceFields } = omit(this.getFields(recurse), [
731-
'size',
732-
]);
693+
const { filter: originalFilters, size: omit, ...searchSourceFields } = this.getFields();
733694
let serializedSearchSourceFields: SearchSourceFields = {
734695
...searchSourceFields,
735696
index: (searchSourceFields.index ? searchSourceFields.index.id : undefined) as any,
@@ -741,6 +702,9 @@ export class SearchSource {
741702
filter: filters,
742703
};
743704
}
705+
if (recurse && this.getParent()) {
706+
serializedSearchSourceFields.parent = this.getParent()!.getSerializedFields(recurse);
707+
}
744708
return serializedSearchSourceFields;
745709
}
746710

src/plugins/data/common/search/search_source/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ export interface SearchSourceFields {
9999
searchAfter?: EsQuerySearchAfter;
100100
timeout?: string;
101101
terminate_after?: number;
102+
103+
parent?: SearchSourceFields;
102104
}
103105

104106
export interface SearchSourceOptions {

0 commit comments

Comments
 (0)