Skip to content

Commit b5faf41

Browse files
Manually building KueryNode for Fleet's routes (#75693)
* Simple benchmark tests for kuery * Building manually is "better" still not free * Building the KueryNode manually * Removing benchmark tests * Another query is building the KueryNode manually * Empty strings are inherently falsy * No longer reaching into the data plugin, import from the "root" indexes * Using AGENT_ACTION_SAVED_OBJECT_TYPE everywhere * Adding SavedObjectsRepository#find unit test for KueryNode * Adding KQL KueryNode test for validateConvertFilterToKueryNode * /s/KQL string/KQL expression * Updating API docs * Adding micro benchmark * Revert "Adding micro benchmark" This reverts commit 97e19c0. * Adding an empty string filters test Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
1 parent f6aa798 commit b5faf41

File tree

11 files changed

+110
-14
lines changed

11 files changed

+110
-14
lines changed

docs/development/core/public/kibana-plugin-core-public.savedobjectsfindoptions.filter.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@
77
<b>Signature:</b>
88

99
```typescript
10-
filter?: string;
10+
filter?: string | KueryNode;
1111
```

docs/development/core/public/kibana-plugin-core-public.savedobjectsfindoptions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export interface SavedObjectsFindOptions
1717
| --- | --- | --- |
1818
| [defaultSearchOperator](./kibana-plugin-core-public.savedobjectsfindoptions.defaultsearchoperator.md) | <code>'AND' &#124; 'OR'</code> | |
1919
| [fields](./kibana-plugin-core-public.savedobjectsfindoptions.fields.md) | <code>string[]</code> | An array of fields to include in the results |
20-
| [filter](./kibana-plugin-core-public.savedobjectsfindoptions.filter.md) | <code>string</code> | |
20+
| [filter](./kibana-plugin-core-public.savedobjectsfindoptions.filter.md) | <code>string &#124; KueryNode</code> | |
2121
| [hasReference](./kibana-plugin-core-public.savedobjectsfindoptions.hasreference.md) | <code>{</code><br/><code> type: string;</code><br/><code> id: string;</code><br/><code> }</code> | |
2222
| [namespaces](./kibana-plugin-core-public.savedobjectsfindoptions.namespaces.md) | <code>string[]</code> | |
2323
| [page](./kibana-plugin-core-public.savedobjectsfindoptions.page.md) | <code>number</code> | |

docs/development/core/server/kibana-plugin-core-server.savedobjectsfindoptions.filter.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@
77
<b>Signature:</b>
88

99
```typescript
10-
filter?: string;
10+
filter?: string | KueryNode;
1111
```

docs/development/core/server/kibana-plugin-core-server.savedobjectsfindoptions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export interface SavedObjectsFindOptions
1717
| --- | --- | --- |
1818
| [defaultSearchOperator](./kibana-plugin-core-server.savedobjectsfindoptions.defaultsearchoperator.md) | <code>'AND' &#124; 'OR'</code> | |
1919
| [fields](./kibana-plugin-core-server.savedobjectsfindoptions.fields.md) | <code>string[]</code> | An array of fields to include in the results |
20-
| [filter](./kibana-plugin-core-server.savedobjectsfindoptions.filter.md) | <code>string</code> | |
20+
| [filter](./kibana-plugin-core-server.savedobjectsfindoptions.filter.md) | <code>string &#124; KueryNode</code> | |
2121
| [hasReference](./kibana-plugin-core-server.savedobjectsfindoptions.hasreference.md) | <code>{</code><br/><code> type: string;</code><br/><code> id: string;</code><br/><code> }</code> | |
2222
| [namespaces](./kibana-plugin-core-server.savedobjectsfindoptions.namespaces.md) | <code>string[]</code> | |
2323
| [page](./kibana-plugin-core-server.savedobjectsfindoptions.page.md) | <code>number</code> | |

src/core/public/public.api.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1189,8 +1189,10 @@ export interface SavedObjectsFindOptions {
11891189
// (undocumented)
11901190
defaultSearchOperator?: 'AND' | 'OR';
11911191
fields?: string[];
1192+
// Warning: (ae-forgotten-export) The symbol "KueryNode" needs to be exported by the entry point index.d.ts
1193+
//
11921194
// (undocumented)
1193-
filter?: string;
1195+
filter?: string | KueryNode;
11941196
// (undocumented)
11951197
hasReference?: {
11961198
type: string;

src/core/server/saved_objects/service/lib/filter_utils.test.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,19 @@ const mockMappings = {
8383

8484
describe('Filter Utils', () => {
8585
describe('#validateConvertFilterToKueryNode', () => {
86-
test('Validate a simple filter', () => {
86+
test('Empty string filters are ignored', () => {
87+
expect(validateConvertFilterToKueryNode(['foo'], '', mockMappings)).toBeUndefined();
88+
});
89+
test('Validate a simple KQL KueryNode filter', () => {
90+
expect(
91+
validateConvertFilterToKueryNode(
92+
['foo'],
93+
esKuery.nodeTypes.function.buildNode('is', `foo.attributes.title`, 'best', true),
94+
mockMappings
95+
)
96+
).toEqual(esKuery.fromKueryExpression('foo.title: "best"'));
97+
});
98+
test('Validate a simple KQL expression filter', () => {
8799
expect(
88100
validateConvertFilterToKueryNode(['foo'], 'foo.attributes.title: "best"', mockMappings)
89101
).toEqual(esKuery.fromKueryExpression('foo.title: "best"'));

src/core/server/saved_objects/service/lib/filter_utils.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,12 @@ const astFunctionType = ['is', 'range', 'nested'];
2828

2929
export const validateConvertFilterToKueryNode = (
3030
allowedTypes: string[],
31-
filter: string,
31+
filter: string | KueryNode,
3232
indexMapping: IndexMapping
3333
): KueryNode | undefined => {
34-
if (filter && filter.length > 0 && indexMapping) {
35-
const filterKueryNode = esKuery.fromKueryExpression(filter);
34+
if (filter && indexMapping) {
35+
const filterKueryNode =
36+
typeof filter === 'string' ? esKuery.fromKueryExpression(filter) : filter;
3637

3738
const validationFilterKuery = validateFilterKueryNode({
3839
astFilter: filterKueryNode,

src/core/server/saved_objects/service/lib/repository.test.js

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import { encodeHitVersion } from '../../version';
2525
import { SavedObjectTypeRegistry } from '../../saved_objects_type_registry';
2626
import { DocumentMigrator } from '../../migrations/core/document_migrator';
2727
import { elasticsearchClientMock } from '../../../elasticsearch/client/mocks';
28+
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
29+
import { nodeTypes } from '../../../../../plugins/data/common/es_query';
2830

2931
jest.mock('./search_dsl/search_dsl', () => ({ getSearchDsl: jest.fn() }));
3032

@@ -2529,7 +2531,7 @@ describe('SavedObjectsRepository', () => {
25292531
expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledWith(mappings, registry, relevantOpts);
25302532
});
25312533

2532-
it(`accepts KQL filter and passes kueryNode to getSearchDsl`, async () => {
2534+
it(`accepts KQL expression filter and passes KueryNode to getSearchDsl`, async () => {
25332535
const findOpts = {
25342536
namespace,
25352537
search: 'foo*',
@@ -2570,6 +2572,47 @@ describe('SavedObjectsRepository', () => {
25702572
`);
25712573
});
25722574

2575+
it(`accepts KQL KueryNode filter and passes KueryNode to getSearchDsl`, async () => {
2576+
const findOpts = {
2577+
namespace,
2578+
search: 'foo*',
2579+
searchFields: ['foo'],
2580+
type: ['dashboard'],
2581+
sortField: 'name',
2582+
sortOrder: 'desc',
2583+
defaultSearchOperator: 'AND',
2584+
hasReference: {
2585+
type: 'foo',
2586+
id: '1',
2587+
},
2588+
indexPattern: undefined,
2589+
filter: nodeTypes.function.buildNode('is', `dashboard.attributes.otherField`, '*'),
2590+
};
2591+
2592+
await findSuccess(findOpts, namespace);
2593+
const { kueryNode } = getSearchDslNS.getSearchDsl.mock.calls[0][2];
2594+
expect(kueryNode).toMatchInlineSnapshot(`
2595+
Object {
2596+
"arguments": Array [
2597+
Object {
2598+
"type": "literal",
2599+
"value": "dashboard.otherField",
2600+
},
2601+
Object {
2602+
"type": "wildcard",
2603+
"value": "@kuery-wildcard@",
2604+
},
2605+
Object {
2606+
"type": "literal",
2607+
"value": false,
2608+
},
2609+
],
2610+
"function": "is",
2611+
"type": "function",
2612+
}
2613+
`);
2614+
});
2615+
25732616
it(`supports multiple types`, async () => {
25742617
const types = ['config', 'index-pattern'];
25752618
await findSuccess({ type: types });

src/core/server/saved_objects/types.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ import { SavedObjectUnsanitizedDoc } from './serialization';
3939
import { SavedObjectsMigrationLogger } from './migrations/core/migration_logger';
4040
import { SavedObject } from '../../types';
4141

42+
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
43+
import { KueryNode } from '../../../plugins/data/common';
44+
4245
export {
4346
SavedObjectAttributes,
4447
SavedObjectAttribute,
@@ -89,7 +92,7 @@ export interface SavedObjectsFindOptions {
8992
rootSearchFields?: string[];
9093
hasReference?: { type: string; id: string };
9194
defaultSearchOperator?: 'AND' | 'OR';
92-
filter?: string;
95+
filter?: string | KueryNode;
9396
namespaces?: string[];
9497
/** An optional ES preference value to be used for the query **/
9598
preference?: string;

src/core/server/server.api.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2320,8 +2320,10 @@ export interface SavedObjectsFindOptions {
23202320
// (undocumented)
23212321
defaultSearchOperator?: 'AND' | 'OR';
23222322
fields?: string[];
2323+
// Warning: (ae-forgotten-export) The symbol "KueryNode" needs to be exported by the entry point index.d.ts
2324+
//
23232325
// (undocumented)
2324-
filter?: string;
2326+
filter?: string | KueryNode;
23252327
// (undocumented)
23262328
hasReference?: {
23272329
type: string;

0 commit comments

Comments
 (0)