import { SavedObject , SavedObjectsClientContract , SavedObjectsImportFailure } from '../../types' ; import { extractErrors } from './extract_errors' ; import { CreatedObject } from '../types' ; import type { ImportStateMap } from './types' ; export interface CreateSavedObjectsParams < T > { objects : Array < SavedObject < T > > ; accumulatedErrors : SavedObjectsImportFailure [ ] ; savedObjectsClient : SavedObjectsClientContract ; importStateMap : ImportStateMap ; namespace ? : string ; overwrite ? : boolean ; } export interface CreateSavedObjectsResult < T > { createdObjects : Array < CreatedObject < T > > ; errors : SavedObjectsImportFailure [ ] ; } /**
 * This function abstracts the bulk creation of import objects. The main reason for this is that the import ID map should dictate the IDs of
 * the objects we create, and the create results should be mapped to the original IDs that consumers will be able to understand.
 */ export const createSavedObjects = async < T > ( { objects , accumulatedErrors , savedObjectsClient , importStateMap , namespace , overwrite , } ) : Promise < CreateSavedObjectsResult < T > > => { const errorSet = accumulatedErrors . reduce ( ( acc , { type , id } ) => acc . add ( `${ type }:${ id }` ) , new Set < string > ( ) ) ; const filteredObjects = objects . filter ( ( { type , id } ) => ! errorSet . has ( `${ type }:${ id }` ) ) ; if ( filteredObjects . length === 0 ) { return { createdObjects : [ ] , errors : [ ] } ; } const objectIdMap = filteredObjects . reduce ( ( map , object ) => map . set ( `${ object . type }:${ object . id }` , object ) , new Map < string , SavedObject < T > > ( ) ) ; const objectsToCreate = filteredObjects . map ( ( { version , ... object } ) => { const references = object . references ?. map ( ( reference ) => { const { type , id } = reference ; const importStateValue = importStateMap . get ( `${ type }:${ id }` ) ; if ( importStateValue ?. destinationId ) { return { ... reference , id : importStateValue . destinationId } ; } return reference ; } ) ; const importStateValue = importStateMap . get ( `${ object . type }:${ object . id }` ) ; if ( importStateValue ?. destinationId ) { objectIdMap . set ( `${ object . type }:${ importStateValue . destinationId }` , object ) ; const originId = importStateValue . omitOriginId ? undefined : object . originId ?? object . id ; return { ... object , id : importStateValue . destinationId , originId , ... ( references && { references } ) , } ; } return { ... object , ... ( references && { references } ) } ; } ) ; const resolvableErrors = [ 'conflict' , 'ambiguous_conflict' , 'missing_references' ] ; let expectedResults = objectsToCreate ; if ( ! accumulatedErrors . some ( ( { error : { type } } ) => resolvableErrors . includes ( type ) ) ) { const bulkCreateResponse = await savedObjectsClient . bulkCreate ( objectsToCreate , { namespace , overwrite , } ) ; expectedResults = bulkCreateResponse . saved_objects ; } const remappedResults = expectedResults . map < CreatedObject < T > > ( ( result ) => { const { id } = objectIdMap . get ( `${ result . type }:${ result . id }` ) ! ; return { ... result , id , ... ( id !== result . id && { destinationId : result . id } ) } ; } ) ; return { createdObjects : remappedResults . filter ( ( obj ) => ! obj . error ) , errors : extractErrors ( remappedResults , objects ) , } ; } ;