import { SavedObjectsRawDoc , SavedObjectsSerializer , SavedObjectUnsanitizedDoc , } from '../../serialization' ; import { TransformFn } from './document_migrator' ; import { SavedObjectsMigrationLogger } from '.' ; param { TransformFn } migrateDoc param { SavedObjectsRawDoc [ ] } rawDocs returns { SavedObjectsRawDoc [ ] } export async function migrateRawDocs ( serializer , migrateDoc , rawDocs , log ) { const migrateDocWithoutBlocking = transformNonBlocking ( migrateDoc ) ; const processedDocs = [ ] ; for ( const raw of rawDocs ) { if ( serializer . isRawSavedObject ( raw ) ) { const savedObject = serializer . rawToSavedObject ( raw ) ; savedObject . migrationVersion = savedObject . migrationVersion || { } ; processedDocs . push ( serializer . savedObjectToRaw ( { references : [ ] , ... ( await migrateDocWithoutBlocking ( savedObject ) ) , } ) ) ; } else { log . error ( `Error: Unable to migrate the corrupt Saved Object document ${ raw . _id }. To prevent OpenSearch Dashboards from performing a migration on every restart, please delete or fix this document by ensuring that the namespace and type in the document's id matches the values in the namespace and type fields.` , { rawDocument : raw } ) ; processedDocs . push ( raw ) ; } } return processedDocs ; } /**
 * Migration transform functions are potentially CPU heavy e.g. doing decryption/encryption
 * or (de)/serializing large JSON payloads.
 * Executing all transforms for a batch in a synchronous loop can block the event-loop for a long time.
 * To prevent this we use setImmediate to ensure that the event-loop can process other parallel
 * work in between each transform.
 */ function transformNonBlocking ( transform ) { return ( doc ) => new Promise ( ( resolve , reject ) => { setImmediate ( ( ) => { try { resolve ( transform ( doc ) ) ; } catch ( e ) { reject ( e ) ; } } ) ; } ) ; }