Skip to content

Commit 9119bbc

Browse files
committed
Merge remote-tracking branch 'upstream/main' into ad-hoc-management-screen-2
2 parents 7301a11 + 9e88bc9 commit 9119bbc

File tree

127 files changed

+2363
-1044
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

127 files changed

+2363
-1044
lines changed

docs/api/saved-objects/find.asciidoc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,15 @@ experimental[] Retrieve a paginated set of {kib} saved objects by various condit
5252
`has_reference`::
5353
(Optional, object) Filters to objects that have a relationship with the type and ID combination.
5454

55+
`has_reference_operator`::
56+
(Optional, string) The operator to use for the `has_reference` parameter. Either `OR` or `AND`. Defaults to `OR`.
57+
58+
`has_no_reference`::
59+
(Optional, object) Filters to objects that do not have a relationship with the type and ID combination.
60+
61+
`has_no_reference_operator`::
62+
(Optional, string) The operator to use for the `has_no_reference` parameter. Either `OR` or `AND`. Defaults to `OR`.
63+
5564
`filter`::
5665
(Optional, string) The filter is a KQL string with the caveat that if you filter with an attribute from your saved object type,
5766
it should look like that: `savedObjectType.attributes.title: "myTitle"`. However, If you use a root attribute of a saved

packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4182,6 +4182,10 @@ describe('SavedObjectsRepository', () => {
41824182
type: 'foo',
41834183
id: '1',
41844184
},
4185+
hasNoReference: {
4186+
type: 'bar',
4187+
id: '1',
4188+
},
41854189
};
41864190

41874191
it(`passes mappings, registry, and search options to getSearchDsl`, async () => {

packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,8 @@ export class SavedObjectsRepository implements ISavedObjectsRepository {
11291129
rootSearchFields,
11301130
hasReference,
11311131
hasReferenceOperator,
1132+
hasNoReference,
1133+
hasNoReferenceOperator,
11321134
page = FIND_DEFAULT_PAGE,
11331135
perPage = FIND_DEFAULT_PER_PAGE,
11341136
pit,
@@ -1235,6 +1237,8 @@ export class SavedObjectsRepository implements ISavedObjectsRepository {
12351237
typeToNamespacesMap,
12361238
hasReference,
12371239
hasReferenceOperator,
1240+
hasNoReference,
1241+
hasNoReferenceOperator,
12381242
kueryNode,
12391243
}),
12401244
},

packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/query_params.test.ts

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -195,17 +195,18 @@ describe('#getQueryParams', () => {
195195
});
196196
});
197197

198-
describe('reference filter clause', () => {
199-
describe('`hasReference` parameter', () => {
200-
it('does not call `getReferencesFilter` when `hasReference` is not specified', () => {
201-
getQueryParams({
202-
registry,
203-
hasReference: undefined,
204-
});
205-
206-
expect(getReferencesFilterMock).not.toHaveBeenCalled();
198+
describe('reference/noreference filter clause', () => {
199+
it('does not call `getReferencesFilter` when neither `hasReference` nor `hasNoReference` are specified', () => {
200+
getQueryParams({
201+
registry,
202+
hasReference: undefined,
203+
hasNoReference: undefined,
207204
});
208205

206+
expect(getReferencesFilterMock).not.toHaveBeenCalled();
207+
});
208+
209+
describe('`hasReference` parameter', () => {
209210
it('calls `getReferencesFilter` with the correct parameters', () => {
210211
const hasReference = { id: 'foo', type: 'bar' };
211212
getQueryParams({
@@ -235,6 +236,38 @@ describe('#getQueryParams', () => {
235236
expect(filters.some((filter) => filter.references_filter === true)).toBeDefined();
236237
});
237238
});
239+
240+
describe('`hasNoReference` parameter', () => {
241+
it('calls `getReferencesFilter` with the correct parameters', () => {
242+
const hasNoReference = { id: 'noFoo', type: 'bar' };
243+
getQueryParams({
244+
registry,
245+
hasNoReference,
246+
hasNoReferenceOperator: 'AND',
247+
});
248+
249+
expect(getReferencesFilterMock).toHaveBeenCalledTimes(1);
250+
expect(getReferencesFilterMock).toHaveBeenCalledWith({
251+
must: false,
252+
references: [hasNoReference],
253+
operator: 'AND',
254+
});
255+
});
256+
257+
it('includes the return of `getReferencesFilter` in the `filter` clause', () => {
258+
getReferencesFilterMock.mockReturnValue({ references_filter: true });
259+
260+
const hasNoReference = { id: 'noFoo', type: 'bar' };
261+
const result = getQueryParams({
262+
registry,
263+
hasNoReference,
264+
hasReferenceOperator: 'AND',
265+
});
266+
267+
const filters: any[] = result.query.bool.filter;
268+
expect(filters.some((filter) => filter.references_filter === true)).toBeDefined();
269+
});
270+
});
238271
});
239272

240273
describe('type filter clauses', () => {

packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/query_params.ts

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
import * as esKuery from '@kbn/es-query';
10+
import type { SavedObjectTypeIdTuple } from '@kbn/core-saved-objects-common';
1011

1112
type KueryNode = any;
1213

@@ -123,11 +124,6 @@ function getClauseForType(
123124
};
124125
}
125126

126-
export interface HasReferenceQueryParams {
127-
type: string;
128-
id: string;
129-
}
130-
131127
export type SearchOperator = 'AND' | 'OR';
132128

133129
interface QueryParams {
@@ -139,15 +135,24 @@ interface QueryParams {
139135
defaultSearchOperator?: SearchOperator;
140136
searchFields?: string[];
141137
rootSearchFields?: string[];
142-
hasReference?: HasReferenceQueryParams | HasReferenceQueryParams[];
138+
hasReference?: SavedObjectTypeIdTuple | SavedObjectTypeIdTuple[];
143139
hasReferenceOperator?: SearchOperator;
140+
hasNoReference?: SavedObjectTypeIdTuple | SavedObjectTypeIdTuple[];
141+
hasNoReferenceOperator?: SearchOperator;
144142
kueryNode?: KueryNode;
145143
}
146144

147145
// A de-duplicated set of namespaces makes for a more efficient query.
148146
const uniqNamespaces = (namespacesToNormalize?: string[]) =>
149147
namespacesToNormalize ? Array.from(new Set(namespacesToNormalize)) : undefined;
150148

149+
const toArray = (val: unknown) => {
150+
if (typeof val === 'undefined') {
151+
return val;
152+
}
153+
return !Array.isArray(val) ? [val] : val;
154+
};
155+
151156
/**
152157
* Get the "query" related keys for the search body
153158
*/
@@ -162,16 +167,17 @@ export function getQueryParams({
162167
defaultSearchOperator,
163168
hasReference,
164169
hasReferenceOperator,
170+
hasNoReference,
171+
hasNoReferenceOperator,
165172
kueryNode,
166173
}: QueryParams) {
167174
const types = getTypes(
168175
registry,
169176
typeToNamespacesMap ? Array.from(typeToNamespacesMap.keys()) : type
170177
);
171178

172-
if (hasReference && !Array.isArray(hasReference)) {
173-
hasReference = [hasReference];
174-
}
179+
hasReference = toArray(hasReference);
180+
hasNoReference = toArray(hasNoReference);
175181

176182
const bool: any = {
177183
filter: [
@@ -184,6 +190,15 @@ export function getQueryParams({
184190
}),
185191
]
186192
: []),
193+
...(hasNoReference?.length
194+
? [
195+
getReferencesFilter({
196+
references: hasNoReference,
197+
operator: hasNoReferenceOperator,
198+
must: false,
199+
}),
200+
]
201+
: []),
187202
{
188203
bool: {
189204
should: types.map((shouldType) => {

0 commit comments

Comments
 (0)