Skip to content

Commit

Permalink
Fix issue with duplicate references in error object when copying save…
Browse files Browse the repository at this point in the history
…d objects to space (elastic#200053)

Closes elastic#158027

## Summary

Simply dedupes references to objects if they are part of the
missing_references in the copy saved objects to SO endpoint

### Notes
- Update forEach over SOs to a regular for loop since we had a couple of
early exit scenarios
- Checks against the set for references already added to the missing
list and adds only if not present

------

**Old response: Note the duplicate references**

<img width="400" alt="Screenshot 2024-11-14 at 01 52 54"
src="https://github.com/user-attachments/assets/67078080-e39d-43b2-bf7c-7abb76866fa4">


**New response**

<img width="800" alt="Screenshot 2024-11-14 at 01 50 41"
src="https://github.com/user-attachments/assets/776db189-af8c-4522-bb03-f8efbb7cdcd9">


### Release note
Dedupe results from copy saved objects to spaces API when object
contains references to other objects.

---------

Co-authored-by: Elastic Machine <[email protected]>
  • Loading branch information
2 people authored and jesuswr committed Nov 18, 2024
1 parent 5edb9ab commit 050550c
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -267,4 +267,36 @@ describe('validateReferences()', () => {
'Error fetching references for imported objects'
);
});

// test that when references are missing returns only deduplicated errors
test('returns only deduplicated errors when references are missing', async () => {
const params = setup({
objects: [
{
id: '2',
type: 'visualization',
attributes: { title: 'My Visualization 2' },
references: [
{ name: 'ref_0', type: 'index-pattern', id: '3' },
{ name: 'ref_0', type: 'index-pattern', id: '3' },
],
},
],
});
params.savedObjectsClient.bulkGet.mockResolvedValue({
saved_objects: [createNotFoundError({ type: 'index-pattern', id: '3' })],
});

const result = await validateReferences(params);
expect(result).toEqual([
expect.objectContaining({
type: 'visualization',
id: '2',
error: {
type: 'missing_references',
references: [{ type: 'index-pattern', id: '3' }],
},
}),
]);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -102,30 +102,35 @@ export async function validateReferences(params: ValidateReferencesParams) {
const nonExistingReferenceKeys = await getNonExistingReferenceAsKeys(params);

// Filter out objects with missing references, add to error object
objects.forEach(({ type, id, references, attributes }) => {
if (objectsToSkip.has(`${type}:${id}`)) {
for (const obj of objects) {
const { type, id, references, attributes } = obj;
const objectKey = `${type}:${id}`;
if (objectsToSkip.has(objectKey)) {
// skip objects with retries that have specified `ignoreMissingReferences`
return;
continue;
}

const missingReferences = [];
const enforcedTypeReferences = (references || []).filter(filterReferencesToValidate);
const missingReferences: Array<{ type: string; id: string }> = [];
const enforcedTypeReferences = references?.filter(filterReferencesToValidate) || [];

const seenReferences = new Set();
for (const { type: refType, id: refId } of enforcedTypeReferences) {
if (nonExistingReferenceKeys.includes(`${refType}:${refId}`)) {
const refKey = `${refType}:${refId}`;

if (nonExistingReferenceKeys.includes(refKey) && !seenReferences.has(refKey)) {
missingReferences.push({ type: refType, id: refId });
seenReferences.add(refKey);
}
}
if (missingReferences.length === 0) {
return;
if (missingReferences.length > 0) {
errorMap[objectKey] = {
id,
type,
meta: { title: attributes.title },
error: { type: 'missing_references', references: missingReferences },
};
}
const { title } = attributes;
errorMap[`${type}:${id}`] = {
id,
type,
meta: { title },
error: { type: 'missing_references', references: missingReferences },
};
});
}

return Object.values(errorMap);
}

0 comments on commit 050550c

Please sign in to comment.