Skip to content

Commit

Permalink
Code cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
mikecote committed Jan 9, 2019
1 parent e7ff9d3 commit f2cf1e5
Show file tree
Hide file tree
Showing 14 changed files with 106 additions and 97 deletions.
Expand Up @@ -56,12 +56,12 @@ describe('findRelationships', () => {
],
})
};
const result = await findRelationships(
const result = await findRelationships({
type,
id,
size,
savedObjectsClient
);
});
expect(result).to.eql([
{ id: '1', title: 'Foo', type: 'visualization' },
{ id: '2', title: 'Bar', type: 'visualization' },
Expand Down Expand Up @@ -114,12 +114,12 @@ describe('findRelationships', () => {
})
};

const result = await findRelationships(
const result = await findRelationships({
type,
id,
size,
savedObjectsClient
);
});
expect(result).to.eql([
{ id: '1', title: 'My Dashboard', type: 'dashboard' },
{ id: '2', title: 'Your Dashboard', type: 'dashboard' },
Expand Down Expand Up @@ -177,12 +177,12 @@ describe('findRelationships', () => {
})
};

const result = await findRelationships(
const result = await findRelationships({
type,
id,
size,
savedObjectsClient
);
});
expect(result).to.eql([
{ id: '1', title: 'Foo', type: 'visualization' },
{ id: '2', title: 'Bar', type: 'visualization' },
Expand Down Expand Up @@ -282,12 +282,12 @@ describe('findRelationships', () => {
}
};

const result = await findRelationships(
const result = await findRelationships({
type,
id,
size,
savedObjectsClient
);
});
expect(result).to.eql([
{ id: '1', type: 'visualization', title: 'Foo' },
{ id: '2', type: 'visualization', title: 'Bar' },
Expand All @@ -298,7 +298,7 @@ describe('findRelationships', () => {

it('should return an empty object for invalid types', async () => {
const type = 'invalid';
const result = await findRelationships(type);
const result = await findRelationships({ type });
expect(result).to.eql({});
});
});
Expand Up @@ -26,17 +26,13 @@ export async function collectReferencesDeep(savedObjectClient, objects) {
const itemsToGet = queue.splice(0, queue.length);
const { saved_objects: savedObjects } = await savedObjectClient.bulkGet(itemsToGet);
result.push(...savedObjects);
// All references will be replaced with references once all saved object types are migrated
const allReferences = [];
savedObjects.forEach((obj) => {
allReferences.push(...(obj.references || []));
allReferences.push(...extractLegacyReferences(obj));
});
for (const reference of allReferences) {
const isInResult = result.findIndex(obj => obj.type === reference.type && obj.id === reference.id) !== -1;
if (isInResult) continue;
const isInQueue = queue.findIndex(obj => obj.type === reference.type && obj.id === reference.id) !== -1;
if (isInQueue) continue;
const references = []
.concat(...savedObjects.map(obj => obj.references || []))
// This line below will be removed once legacy support is removed
.concat(...savedObjects.map(obj => extractLegacyReferences(obj)));
for (const reference of references) {
const isDuplicate = result.concat(queue).some(obj => obj.type === reference.type && obj.id === reference.id);
if (isDuplicate) continue;
queue.push({ type: reference.type, id: reference.id });
}
}
Expand All @@ -56,7 +52,7 @@ function extractLegacyReferences(savedObject) {
panels = [];
}
for (const panel of panels) {
if (panel.type && panel.id) {
if (panel.type === 'visualization' && panel.id) {
legacyReferences.push({ type: panel.type, id: panel.id });
}
}
Expand Down
Expand Up @@ -17,8 +17,8 @@
* under the License.
*/

async function findDashboardRelationships(id, size, savedObjectsClient) {
const dashboard = await savedObjectsClient.get('dashboard', id);
async function findDashboardRelationships({ id, size, namespace, savedObjectsClient }) {
const dashboard = await savedObjectsClient.get('dashboard', id, { namespace });
const visualizations = [];

// TODO: should we handle exceptions here or at the parent level?
Expand All @@ -29,7 +29,8 @@ async function findDashboardRelationships(id, size, savedObjectsClient) {
visualizationIds.slice(0, size).map(id => ({
id,
type: 'visualization',
}))
})),
{ namespace }
);

visualizations.push(
Expand All @@ -49,9 +50,10 @@ async function findDashboardRelationships(id, size, savedObjectsClient) {
return visualizations;
}

async function findVisualizationRelationships(id, size, savedObjectsClient) {
await savedObjectsClient.get('visualization', id);
async function findVisualizationRelationships({ id, size, namespace, savedObjectsClient }) {
await savedObjectsClient.get('visualization', id, { namespace });
const allDashboardsResponse = await savedObjectsClient.find({
namespace,
type: 'dashboard',
fields: ['title', 'panelsJSON'],
});
Expand Down Expand Up @@ -81,20 +83,21 @@ async function findVisualizationRelationships(id, size, savedObjectsClient) {
return dashboards;
}

async function findSavedSearchRelationships(id, size, savedObjectsClient) {
const search = await savedObjectsClient.get('search', id);
async function findSavedSearchRelationships({ id, namespace, savedObjectsClient }) {
const search = await savedObjectsClient.get('search', id, { namespace });

const searchSourceJSON = JSON.parse(search.attributes.kibanaSavedObjectMeta.searchSourceJSON);

const indexPatterns = [];
try {
const indexPattern = await savedObjectsClient.get('index-pattern', searchSourceJSON.index);
const indexPattern = await savedObjectsClient.get('index-pattern', searchSourceJSON.index, { namespace });
indexPatterns.push({ id: indexPattern.id, type: 'index-pattern', title: indexPattern.attributes.title });
} catch (err) {
// Do nothing
}

const allVisualizationsResponse = await savedObjectsClient.find({
namespace,
type: 'visualization',
searchFields: ['savedSearchId'],
search: id,
Expand All @@ -115,16 +118,18 @@ async function findSavedSearchRelationships(id, size, savedObjectsClient) {
return visualizations.concat(indexPatterns);
}

async function findIndexPatternRelationships(id, size, savedObjectsClient) {
await savedObjectsClient.get('index-pattern', id);
async function findIndexPatternRelationships({ id, size, namespace, savedObjectsClient }) {
await savedObjectsClient.get('index-pattern', id, { namespace });
const [allVisualizationsResponse, savedSearchResponse] = await Promise.all([
savedObjectsClient.find({
namespace,
type: 'visualization',
searchFields: ['kibanaSavedObjectMeta.searchSourceJSON'],
search: '*',
fields: [`title`, `kibanaSavedObjectMeta.searchSourceJSON`],
}),
savedObjectsClient.find({
namespace,
type: 'search',
searchFields: ['kibanaSavedObjectMeta.searchSourceJSON'],
search: '*',
Expand Down Expand Up @@ -172,16 +177,16 @@ async function findIndexPatternRelationships(id, size, savedObjectsClient) {
return visualizations.concat(searches);
}

export async function findRelationships(type, id, size, savedObjectsClient) {
export async function findRelationships({ type, id, namespace, size, savedObjectsClient }) {
switch (type) {
case 'dashboard':
return await findDashboardRelationships(id, size, savedObjectsClient);
return await findDashboardRelationships({ id, size, namespace, savedObjectsClient });
case 'visualization':
return await findVisualizationRelationships(id, size, savedObjectsClient);
return await findVisualizationRelationships({ id, size, namespace, savedObjectsClient });
case 'search':
return await findSavedSearchRelationships(id, size, savedObjectsClient);
return await findSavedSearchRelationships({ id, size, namespace, savedObjectsClient });
case 'index-pattern':
return await findIndexPatternRelationships(id, size, savedObjectsClient);
return await findIndexPatternRelationships({ id, size, namespace, savedObjectsClient });
}
return [];
}
Expand Up @@ -38,7 +38,7 @@ export function registerRelationships(server) {
handler: async (req) => {
const type = req.params.type;
const id = req.params.id;
const size = req.query.size || 10;
const size = req.query.size || 10000;
const savedObjectsClient = req.getSavedObjectsClient();

return await savedObjectsClient.findRelationships(type, id, { size });
Expand Down
Expand Up @@ -20,7 +20,7 @@
import { getRelationshipsQuery } from './relationship_query_builder';

test('Filters a targeted type for a source object', () => {
const query = getRelationshipsQuery({ type: 'search', id: '123' });
const query = getRelationshipsQuery({ type: 'search', id: '123', filterTypes: ['my-type'] });
expect(query).toMatchInlineSnapshot(`
Object {
"bool": Object {
Expand All @@ -36,6 +36,15 @@ Object {
},
},
},
Array [
Object {
"terms": Object {
"type": Array [
"my-type",
],
},
},
],
Object {
"nested": Object {
"path": "references",
Expand Down Expand Up @@ -66,7 +75,12 @@ Object {
});

test('Filters by namespace', () => {
const query = getRelationshipsQuery({ type: 'search', id: '123', namespace: 'my-namespace' });
const query = getRelationshipsQuery({
type: 'search',
id: '123',
namespace: 'my-namespace',
filterTypes: ['my-type'],
});
expect(query).toMatchInlineSnapshot(`
Object {
"bool": Object {
Expand All @@ -78,6 +92,15 @@ Object {
"namespace": "my-namespace",
},
},
Array [
Object {
"terms": Object {
"type": Array [
"my-type",
],
},
},
],
Object {
"nested": Object {
"path": "references",
Expand Down
Expand Up @@ -21,11 +21,11 @@ interface RelationshipQueryOptions {
type: string;
id: string;
namespace?: string;
searchTypes?: string[];
filterTypes: string[];
}

export function getRelationshipsQuery(options: RelationshipQueryOptions) {
const { type, id, namespace, searchTypes } = options;
const { type, id, namespace, filterTypes } = options;
return {
bool: {
filter: {
Expand All @@ -34,7 +34,7 @@ export function getRelationshipsQuery(options: RelationshipQueryOptions) {
...(namespace
? [{ term: { namespace } }]
: [{ bool: { must_not: { exists: { field: 'namespace' } } } }]),
...(searchTypes ? [{ terms: { type: searchTypes } }] : []),
[{ terms: { type: filterTypes } }],
{
nested: {
path: 'references',
Expand Down
57 changes: 26 additions & 31 deletions src/server/saved_objects/service/lib/repository.js
Expand Up @@ -608,7 +608,7 @@ export class SavedObjectsRepository {
const {
size = 10000,
namespace,
filterTypes,
filterTypes = Object.keys(getRootPropertiesObjects(this._mappings)),
} = options;

if (!id || typeof id !== 'string') {
Expand All @@ -619,42 +619,37 @@ export class SavedObjectsRepository {
throw new TypeError('type must be a string');
}

const sourceObject = await this.get(type, id, { namespace });

// This code will be removed as these types migrate to use "references"
let legacyFindRelationshipsCall;
if (['dashboard', 'visualization', 'search', 'index-pattern'].includes(type)) {
legacyFindRelationshipsCall = legacyFindRelationships(type, id, size, this);
}
const bulkGetOpts = (sourceObject.references || []).map(ref => ({ id: ref.id, type: ref.type }));
const searchTypes = Array.isArray(filterTypes)
? filterTypes
: Object.keys(getRootPropertiesObjects(this._mappings));
const { references = [] } = await this.get(type, id, { namespace });
const bulkGetOpts = references
.filter(ref => filterTypes.includes(ref.type))
.map(ref => ({ id: ref.id, type: ref.type }));
const searchOpts = {
index: this._index,
size,
from: 0,
_source: [
'type',
'namespace',
...(filterTypes.map(type => `${type}.title`)),
],
ignore: [404],
rest_total_hits_as_int: true,
body: {
version: true,
query: getRelationshipsQuery({ type, id, namespace, filterTypes })
}
};

const [{ saved_objects: referencedObjects }, referencedResponse, legacyResponse] = await Promise.all([
this.bulkGet(bulkGetOpts),
this._callCluster('search', {
index: this._index,
size,
from: 0,
_source: [
'type',
'namespace',
...(searchTypes.map(type => `${type}.title`)),
],
ignore: [404],
rest_total_hits_as_int: true,
body: {
version: true,
query: getRelationshipsQuery({ type, id, namespace, searchTypes })
}
}),
legacyFindRelationshipsCall,
this._callCluster('search', searchOpts),
// This code will be removed as these types migrate to use "references"
legacyFindRelationships({ type, size, namespace, id, savedObjectsClient: this }),
]);

const relationshipObjects = [].concat(
referencedObjects.map(obj => ({ id: obj.id, type: obj.type, ...obj.attributes })),
legacyResponse || [],
legacyResponse.filter(obj => filterTypes.includes(obj.type)),
referencedResponse.hits.hits
.map(hit => this._rawToSavedObject(hit))
.map(obj => ({ id: obj.id, type: obj.type, ...obj.attributes }))
Expand All @@ -664,7 +659,7 @@ export class SavedObjectsRepository {
const objectsForType = (result[relationshipObject.type] || []);
// Since we're supporting the legacy method until all saved objects use "references",
// remove duplicates until then.
if (objectsForType.find(obj => obj.id === relationshipObject.id)) return result;
if (objectsForType.some(obj => obj.id === relationshipObject.id)) return result;
const type = relationshipObject.type;
delete relationshipObject.type;
result[type] = objectsForType.concat(relationshipObject);
Expand Down
Expand Up @@ -38,6 +38,7 @@ const createMockClient = () => {
bulkCreate: jest.fn(),
update: jest.fn(),
delete: jest.fn(),
findRelationships: jest.fn(),
errors,
};
};
Expand Down

0 comments on commit f2cf1e5

Please sign in to comment.