Skip to content

Commit

Permalink
Search across spaces (elastic#67644)
Browse files Browse the repository at this point in the history
Co-authored-by: Joe Portner <[email protected]>
Co-authored-by: Elastic Machine <[email protected]>
  • Loading branch information
3 people committed Jul 14, 2020
1 parent 08e709a commit 80209be
Show file tree
Hide file tree
Showing 61 changed files with 1,209 additions and 330 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<b>Signature:</b>

```typescript
export interface SavedObjectsFindOptions extends SavedObjectsBaseOptions
export interface SavedObjectsFindOptions
```

## Properties
Expand All @@ -19,6 +19,7 @@ export interface SavedObjectsFindOptions extends SavedObjectsBaseOptions
| [fields](./kibana-plugin-core-public.savedobjectsfindoptions.fields.md) | <code>string[]</code> | An array of fields to include in the results |
| [filter](./kibana-plugin-core-public.savedobjectsfindoptions.filter.md) | <code>string</code> | |
| [hasReference](./kibana-plugin-core-public.savedobjectsfindoptions.hasreference.md) | <code>{</code><br/><code> type: string;</code><br/><code> id: string;</code><br/><code> }</code> | |
| [namespaces](./kibana-plugin-core-public.savedobjectsfindoptions.namespaces.md) | <code>string[]</code> | |
| [page](./kibana-plugin-core-public.savedobjectsfindoptions.page.md) | <code>number</code> | |
| [perPage](./kibana-plugin-core-public.savedobjectsfindoptions.perpage.md) | <code>number</code> | |
| [preference](./kibana-plugin-core-public.savedobjectsfindoptions.preference.md) | <code>string</code> | An optional ES preference value to be used for the query \* |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-core-public](./kibana-plugin-core-public.md) &gt; [SavedObjectsFindOptions](./kibana-plugin-core-public.savedobjectsfindoptions.md) &gt; [namespaces](./kibana-plugin-core-public.savedobjectsfindoptions.namespaces.md)

## SavedObjectsFindOptions.namespaces property

<b>Signature:</b>

```typescript
namespaces?: string[];
```
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<b>Signature:</b>

```typescript
export interface SavedObjectsFindOptions extends SavedObjectsBaseOptions
export interface SavedObjectsFindOptions
```

## Properties
Expand All @@ -19,6 +19,7 @@ export interface SavedObjectsFindOptions extends SavedObjectsBaseOptions
| [fields](./kibana-plugin-core-server.savedobjectsfindoptions.fields.md) | <code>string[]</code> | An array of fields to include in the results |
| [filter](./kibana-plugin-core-server.savedobjectsfindoptions.filter.md) | <code>string</code> | |
| [hasReference](./kibana-plugin-core-server.savedobjectsfindoptions.hasreference.md) | <code>{</code><br/><code> type: string;</code><br/><code> id: string;</code><br/><code> }</code> | |
| [namespaces](./kibana-plugin-core-server.savedobjectsfindoptions.namespaces.md) | <code>string[]</code> | |
| [page](./kibana-plugin-core-server.savedobjectsfindoptions.page.md) | <code>number</code> | |
| [perPage](./kibana-plugin-core-server.savedobjectsfindoptions.perpage.md) | <code>number</code> | |
| [preference](./kibana-plugin-core-server.savedobjectsfindoptions.preference.md) | <code>string</code> | An optional ES preference value to be used for the query \* |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsFindOptions](./kibana-plugin-core-server.savedobjectsfindoptions.md) &gt; [namespaces](./kibana-plugin-core-server.savedobjectsfindoptions.namespaces.md)

## SavedObjectsFindOptions.namespaces property

<b>Signature:</b>

```typescript
namespaces?: string[];
```
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
<b>Signature:</b>

```typescript
find<T = unknown>({ search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespace, type, filter, preference, }: SavedObjectsFindOptions): Promise<SavedObjectsFindResponse<T>>;
find<T = unknown>({ search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespaces, type, filter, preference, }: SavedObjectsFindOptions): Promise<SavedObjectsFindResponse<T>>;
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| { search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespace, type, filter, preference, } | <code>SavedObjectsFindOptions</code> | |
| { search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespaces, type, filter, preference, } | <code>SavedObjectsFindOptions</code> | |

<b>Returns:</b>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export declare class SavedObjectsRepository
| [delete(type, id, options)](./kibana-plugin-core-server.savedobjectsrepository.delete.md) | | Deletes an object |
| [deleteByNamespace(namespace, options)](./kibana-plugin-core-server.savedobjectsrepository.deletebynamespace.md) | | Deletes all objects from the provided namespace. |
| [deleteFromNamespaces(type, id, namespaces, options)](./kibana-plugin-core-server.savedobjectsrepository.deletefromnamespaces.md) | | Removes one or more namespaces from a given multi-namespace saved object. If no namespaces remain, the saved object is deleted entirely. This method and \[<code>addToNamespaces</code>\][SavedObjectsRepository.addToNamespaces()](./kibana-plugin-core-server.savedobjectsrepository.addtonamespaces.md) are the only ways to change which Spaces a multi-namespace saved object is shared to. |
| [find({ search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespace, type, filter, preference, })](./kibana-plugin-core-server.savedobjectsrepository.find.md) | | |
| [find({ search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespaces, type, filter, preference, })](./kibana-plugin-core-server.savedobjectsrepository.find.md) | | |
| [get(type, id, options)](./kibana-plugin-core-server.savedobjectsrepository.get.md) | | Gets a single object |
| [incrementCounter(type, id, counterFieldName, options)](./kibana-plugin-core-server.savedobjectsrepository.incrementcounter.md) | | Increases a counter field by one. Creates the document if one doesn't exist for the given id. |
| [update(type, id, attributes, options)](./kibana-plugin-core-server.savedobjectsrepository.update.md) | | Updates an object |
Expand Down
4 changes: 3 additions & 1 deletion src/core/public/public.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1282,7 +1282,7 @@ export interface SavedObjectsCreateOptions {
}

// @public (undocumented)
export interface SavedObjectsFindOptions extends SavedObjectsBaseOptions {
export interface SavedObjectsFindOptions {
// (undocumented)
defaultSearchOperator?: 'AND' | 'OR';
fields?: string[];
Expand All @@ -1294,6 +1294,8 @@ export interface SavedObjectsFindOptions extends SavedObjectsBaseOptions {
id: string;
};
// (undocumented)
namespaces?: string[];
// (undocumented)
page?: number;
// (undocumented)
perPage?: number;
Expand Down
1 change: 1 addition & 0 deletions src/core/public/saved_objects/saved_objects_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ export class SavedObjectsClient {
sortField: 'sort_field',
type: 'type',
filter: 'filter',
namespaces: 'namespaces',
preference: 'preference',
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,97 @@ describe('getSortedObjectsForExport()', () => {
"calls": Array [
Array [
Object {
"namespace": undefined,
"namespaces": undefined,
"perPage": 500,
"search": undefined,
"type": Array [
"index-pattern",
"search",
],
},
],
],
"results": Array [
Object {
"type": "return",
"value": Promise {},
},
],
}
`);
});

test('omits the `namespaces` property from the export', async () => {
savedObjectsClient.find.mockResolvedValueOnce({
total: 2,
saved_objects: [
{
id: '2',
type: 'search',
attributes: {},
namespaces: ['foo', 'bar'],
score: 0,
references: [
{
name: 'name',
type: 'index-pattern',
id: '1',
},
],
},
{
id: '1',
type: 'index-pattern',
attributes: {},
namespaces: ['foo', 'bar'],
score: 0,
references: [],
},
],
per_page: 1,
page: 0,
});
const exportStream = await exportSavedObjectsToStream({
savedObjectsClient,
exportSizeLimit: 500,
types: ['index-pattern', 'search'],
});

const response = await readStreamToCompletion(exportStream);

expect(response).toMatchInlineSnapshot(`
Array [
Object {
"attributes": Object {},
"id": "1",
"references": Array [],
"type": "index-pattern",
},
Object {
"attributes": Object {},
"id": "2",
"references": Array [
Object {
"id": "1",
"name": "name",
"type": "index-pattern",
},
],
"type": "search",
},
Object {
"exportedCount": 2,
"missingRefCount": 0,
"missingReferences": Array [],
},
]
`);
expect(savedObjectsClient.find).toMatchInlineSnapshot(`
[MockFunction] {
"calls": Array [
Array [
Object {
"namespaces": undefined,
"perPage": 500,
"search": undefined,
"type": Array [
Expand Down Expand Up @@ -257,7 +347,7 @@ describe('getSortedObjectsForExport()', () => {
"calls": Array [
Array [
Object {
"namespace": undefined,
"namespaces": undefined,
"perPage": 500,
"search": "foo",
"type": Array [
Expand Down Expand Up @@ -346,7 +436,9 @@ describe('getSortedObjectsForExport()', () => {
"calls": Array [
Array [
Object {
"namespace": "foo",
"namespaces": Array [
"foo",
],
"perPage": 500,
"search": undefined,
"type": Array [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ async function fetchObjectsToExport({
type: types,
search,
perPage: exportSizeLimit,
namespace,
namespaces: namespace ? [namespace] : undefined,
});
if (findResponse.total > exportSizeLimit) {
throw Boom.badRequest(`Can't export more than ${exportSizeLimit} objects`);
Expand Down Expand Up @@ -162,10 +162,15 @@ export async function exportSavedObjectsToStream({
exportedObjects = sortObjects(rootObjects);
}

// redact attributes that should not be exported
const redactedObjects = exportedObjects.map<SavedObject<unknown>>(
({ namespaces, ...object }) => object
);

const exportDetails: SavedObjectsExportResultDetails = {
exportedCount: exportedObjects.length,
missingRefCount: missingReferences.length,
missingReferences,
};
return createListStream([...exportedObjects, ...(excludeExportDetails ? [] : [exportDetails])]);
return createListStream([...redactedObjects, ...(excludeExportDetails ? [] : [exportDetails])]);
}
8 changes: 8 additions & 0 deletions src/core/server/saved_objects/routes/find.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,18 @@ export const registerFindRoute = (router: IRouter) => {
),
fields: schema.maybe(schema.oneOf([schema.string(), schema.arrayOf(schema.string())])),
filter: schema.maybe(schema.string()),
namespaces: schema.maybe(
schema.oneOf([schema.string(), schema.arrayOf(schema.string())])
),
}),
},
},
router.handleLegacyErrors(async (context, req, res) => {
const query = req.query;

const namespaces =
typeof req.query.namespaces === 'string' ? [req.query.namespaces] : req.query.namespaces;

const result = await context.core.savedObjects.client.find({
perPage: query.per_page,
page: query.page,
Expand All @@ -62,6 +69,7 @@ export const registerFindRoute = (router: IRouter) => {
hasReference: query.has_reference,
fields: typeof query.fields === 'string' ? [query.fields] : query.fields,
filter: query.filter,
namespaces,
});

return res.ok({ body: result });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ describe('GET /api/saved_objects/_find', () => {
attributes: {},
score: 1,
references: [],
namespaces: ['default'],
},
{
type: 'index-pattern',
Expand All @@ -91,6 +92,7 @@ describe('GET /api/saved_objects/_find', () => {
attributes: {},
score: 1,
references: [],
namespaces: ['default'],
},
],
};
Expand Down Expand Up @@ -241,4 +243,38 @@ describe('GET /api/saved_objects/_find', () => {
defaultSearchOperator: 'OR',
});
});

it('accepts the query parameter namespaces as a string', async () => {
await supertest(httpSetup.server.listener)
.get('/api/saved_objects/_find?type=index-pattern&namespaces=foo')
.expect(200);

expect(savedObjectsClient.find).toHaveBeenCalledTimes(1);

const options = savedObjectsClient.find.mock.calls[0][0];
expect(options).toEqual({
perPage: 20,
page: 1,
type: ['index-pattern'],
namespaces: ['foo'],
defaultSearchOperator: 'OR',
});
});

it('accepts the query parameter namespaces as an array', async () => {
await supertest(httpSetup.server.listener)
.get('/api/saved_objects/_find?type=index-pattern&namespaces=default&namespaces=foo')
.expect(200);

expect(savedObjectsClient.find).toHaveBeenCalledTimes(1);

const options = savedObjectsClient.find.mock.calls[0][0];
expect(options).toEqual({
perPage: 20,
page: 1,
type: ['index-pattern'],
namespaces: ['default', 'foo'],
defaultSearchOperator: 'OR',
});
});
});
Loading

0 comments on commit 80209be

Please sign in to comment.