import { Context } from '../context' ; import { Converter , KeysAndAttributes , Key } from 'aws-sdk/clients/dynamodb' ; import { InvalidFindDescriptorException , InternalProcessingException , } from '../base/exceptions' ; import { getChildCollection , getRootCollection , assemblePrimaryKeyValue , unwrap , getCollection , } from '../base/util' ; import { DocumentWithId , WrappedDocument } from '../base/common' ; import { CollectionLayout } from '../base/layout' ; import debugDynamo from '../debug/debugDynamo' ; import { parseKey } from './batch_utils' ; /**
 * The collection and ID of a root or child
 * item to retrieve with #transactFindByIds
 */ export type BatchFindByIdDescriptor = { /** The collection containing the item */ collection : string ; id : string ; parentId ? : string ; } ; internal export type TableKeyTuple = [ string , Key ] ; /**
 * The response to a [[batchFindByIds]] request. The
 * retrieved documents are stored in a map, organised by
 * collection name.
 *
 * Any unprocessed request keys are included in the
 * unprocessedDescriptors list. You will need to submit
 * another request to obtain these.
 */ export type BatchFindByIdsResponse = { documentsByCollection : { [ collection ] : DocumentWithId [ ] ; } ; unprocessedDescriptors : BatchFindByIdDescriptor [ ] ; } ; export const batchFindByIds = async ( ctx , items , options ? ) : Promise < BatchFindByIdsResponse > => { if ( items . length === 0 ) { throw new InvalidFindDescriptorException ( 'At least one find descriptor must be specified' ) ; } else if ( items . length > 100 ) { throw new InvalidFindDescriptorException ( 'No more than 100 find descriptors can be specified to batchFindByIds' ) ; } const tableLayoutMapping = new Map < string , CollectionLayout > ( ) ; const tableRequestItemTuples = items . map ( ( { collection , id , parentId } ) => { const collectionDefinition = parentId ? getChildCollection ( ctx , collection ) : getRootCollection ( ctx , collection ) ; tableLayoutMapping . set ( collectionDefinition . layout . tableName , collectionDefinition . layout ) ; const { layout : { tableName , primaryKey , indexKeySeparator } , } = collectionDefinition ; return [ tableName , { [ primaryKey . partitionKey ] : Converter . input ( assemblePrimaryKeyValue ( collectionDefinition . type === 'child' ? collectionDefinition . parentCollectionName : collectionDefinition . name , parentId ? parentId : id , indexKeySeparator ) ) , [ primaryKey . sortKey ] : Converter . input ( assemblePrimaryKeyValue ( collection , id , indexKeySeparator ) ) , } , ] ; } ) ; const requestItems = tableRequestItemTuples . reduce ( ( req , tuple ) => { const keyAndsAttrs = req [ tuple [ 0 ] ] ?? { ConsistentRead : ( options ?. consistentReadTableNames ?? [ ] ) . includes ( tuple [ 0 ] ) , Keys : [ ] , } ; req [ tuple [ 0 ] ] = keyAndsAttrs ; keyAndsAttrs . Keys . push ( tuple [ 1 ] ) ; return req ; } , { } as { [ collection ] : KeysAndAttributes ; } ) ; const request = { RequestItems : requestItems } ; debugDynamo ( 'batchGetItem' , request ) ; const { Responses = { } , UnprocessedKeys = { } } = await ctx . ddb . batchGetItem ( request ) . promise ( ) ; const response = { documentsByCollection : { } , unprocessedDescriptors : [ ] , } ; for ( const items of Object . values ( Responses ) ) { for ( const item of items ) { const unmarshalled = Converter . unmarshall ( item ) as WrappedDocument < DocumentWithId > ; const collection = getCollection ( ctx , unmarshalled . type ) ; const document = unwrap ( unmarshalled ) ; const collectionMap = response . documentsByCollection [ collection . name ] ?? [ ] ; response . documentsByCollection [ collection . name ] = collectionMap ; collectionMap . push ( document ) ; } } for ( const [ tableName , unprocessed ] of Object . entries ( UnprocessedKeys ) ) { const tableMapping = tableLayoutMapping . get ( tableName ) ; if ( ! tableMapping ) { throw new InternalProcessingException ( `Could not find table mapping for ${ tableName } while parsing UnprocessedKeys` ) ; } for ( const key of unprocessed . Keys ) { const descriptor = parseKey ( tableMapping , key ) ; response . unprocessedDescriptors . push ( descriptor ) ; } } return response ; } ;