mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Fix SO export sorting algorithm (#142078)
* Fix SO export sorting algorithm * improve var name * adapt another unit test Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
5d31e88c5d
commit
4cdd74dfcd
3 changed files with 53 additions and 11 deletions
|
@ -146,16 +146,18 @@ describe('getSortedObjectsForExport()', () => {
|
|||
attributes = {},
|
||||
sort = [],
|
||||
type = 'index-pattern',
|
||||
idPrefix = '',
|
||||
}: {
|
||||
attributes?: Record<string, unknown>;
|
||||
sort?: string[];
|
||||
type?: string;
|
||||
idPrefix?: string;
|
||||
} = {}
|
||||
) {
|
||||
const hits = [];
|
||||
for (let i = 1; i <= hitCount; i++) {
|
||||
hits.push({
|
||||
id: `${i}`,
|
||||
id: `${idPrefix}${i}`,
|
||||
type,
|
||||
attributes,
|
||||
sort,
|
||||
|
@ -247,7 +249,7 @@ describe('getSortedObjectsForExport()', () => {
|
|||
|
||||
describe('>1k hits', () => {
|
||||
const firstMockHits = generateHits(1000, { sort: ['a', 'b'] });
|
||||
const secondMockHits = generateHits(500);
|
||||
const secondMockHits = generateHits(500, { idPrefix: 'second-hit-' });
|
||||
|
||||
test('requests multiple pages', async () => {
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { range } from 'lodash';
|
||||
import { sortObjects } from './sort_objects';
|
||||
import type { SavedObject } from '@kbn/core-saved-objects-common';
|
||||
|
||||
describe('sortObjects()', () => {
|
||||
test('should return on empty array', () => {
|
||||
|
@ -309,6 +311,7 @@ describe('sortObjects()', () => {
|
|||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('should not fail on complex circular dependencies', () => {
|
||||
const docs = [
|
||||
{
|
||||
|
@ -424,4 +427,38 @@ describe('sortObjects()', () => {
|
|||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('should not fail on large graph of objects', () => {
|
||||
// create an object that references all objects with a higher `index` up to `depth`.
|
||||
const createComplexNode = (index: number, depth: number): SavedObject => {
|
||||
return {
|
||||
type: 'test',
|
||||
id: `${index}`,
|
||||
attributes: {},
|
||||
references: range(index + 1, depth).map((refIndex) => ({
|
||||
type: 'test',
|
||||
id: `${refIndex}`,
|
||||
name: `test-${refIndex}`,
|
||||
})),
|
||||
};
|
||||
};
|
||||
|
||||
const createComplexGraph = (depth: number): SavedObject[] => {
|
||||
const nodes: SavedObject[] = [];
|
||||
for (let i = 0; i < depth; i++) {
|
||||
nodes.push(createComplexNode(i, depth));
|
||||
}
|
||||
return nodes;
|
||||
};
|
||||
|
||||
const depth = 100;
|
||||
const graph = createComplexGraph(depth);
|
||||
const sorted = sortObjects(graph);
|
||||
|
||||
expect(sorted.map(({ type, id }) => `${type}:${id}`)).toEqual(
|
||||
range(depth)
|
||||
.reverse()
|
||||
.map((index) => `test:${index}`)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,27 +8,29 @@
|
|||
|
||||
import type { SavedObject } from '@kbn/core-saved-objects-common';
|
||||
|
||||
const getId = (object: { type: string; id: string }) => `${object.type}:${object.id}`;
|
||||
|
||||
export function sortObjects(savedObjects: SavedObject[]): SavedObject[] {
|
||||
const path = new Set<SavedObject>();
|
||||
const traversed = new Set<string>();
|
||||
const sorted = new Set<SavedObject>();
|
||||
const objectsByTypeId = new Map(
|
||||
savedObjects.map((object) => [`${object.type}:${object.id}`, object] as [string, SavedObject])
|
||||
savedObjects.map((object) => [getId(object), object] as [string, SavedObject])
|
||||
);
|
||||
|
||||
function includeObjects(objects: SavedObject[]) {
|
||||
for (const object of objects) {
|
||||
if (path.has(object)) {
|
||||
const objectId = getId(object);
|
||||
if (traversed.has(objectId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const refdObjects = object.references
|
||||
.map((ref) => objectsByTypeId.get(`${ref.type}:${ref.id}`))
|
||||
const objectRefs = object.references
|
||||
.map((ref) => objectsByTypeId.get(getId(ref)))
|
||||
.filter((ref): ref is SavedObject => !!ref);
|
||||
|
||||
if (refdObjects.length) {
|
||||
path.add(object);
|
||||
includeObjects(refdObjects);
|
||||
path.delete(object);
|
||||
traversed.add(objectId);
|
||||
if (objectRefs.length) {
|
||||
includeObjects(objectRefs);
|
||||
}
|
||||
|
||||
sorted.add(object);
|
||||
|
@ -36,5 +38,6 @@ export function sortObjects(savedObjects: SavedObject[]): SavedObject[] {
|
|||
}
|
||||
|
||||
includeObjects(savedObjects);
|
||||
|
||||
return [...sorted];
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue