import * as crypto from "crypto" ; import { Knex } from "knex" ; import { keyToString } from "../keys" ; import { Todo } from "../Todo" ; export interface IdAssigner { assignNewIds ( knex , todos ) : Promise < void > ; } /**
 * Assigns all new entities an id directly from their corresponding sequence generator, instead of via INSERTs.
 *
 * This lets us avoid cyclic issues with some INSERTs having foreign keys to other rows that themselves
 * need to first be INSERTed.
 */ export class SequenceIdAssigner implements IdAssigner { async assignNewIds ( knex , todos ) { const seqStatements = [ ] ; Object . values ( todos ) . forEach ( ( todo ) => { if ( todo . inserts . length > 0 ) { const meta = todo . inserts [ 0 ] . __orm . metadata ; const sequenceName = `${ meta . tableName }_id_seq` ; const sql = `select nextval('${ sequenceName }') from generate_series(1, ${ todo . inserts . length })` ; seqStatements . push ( sql ) ; } } ) ; if ( seqStatements . length > 0 ) { const sql = seqStatements . join ( " UNION ALL " ) ; const result = await knex . raw ( sql ) ; let i = 0 ; Object . values ( todos ) . forEach ( ( todo ) => { for ( const insert of todo . inserts ) { insert . __orm . data [ "id" ] = keyToString ( todo . metadata , result . rows ! [ i ++ ] [ "nextval" ] ) ; } } ) ; } } } /**
 * Creates random UUIDs for uuid-based keys in production environments.
 *
 * See  TestUuidAssigner for creating stable-ish ids for tests
  export class RandomUuidAssigner implements IdAssigner { async assignNewIds ( knex , todos ) { Object . values ( todos ) . forEach ( ( todo ) => { for ( const insert of todo . inserts ) { insert . __orm . data [ "id" ] = keyToString ( todo . metadata , crypto . randomUUID ( ) ) ; } } ) ; } } /**
 * Creates deterministic / stable-ish UUIDs for test suites.
 *
 * These ids can technically change as test cases insert different types/numbers
 * of entities, in different orders, but otherwise will be stable.
 */ export class TestUuidAssigner implements IdAssigner { private nextId : Record < string , number > = { } ; async assignNewIds ( knex , todos ) { Object . entries ( todos ) . forEach ( ( [ type , todo ] ) => { if ( todo . inserts . length > 0 ) { let entitySpace = Object . keys ( this . nextId ) . indexOf ( type ) ; if ( entitySpace === - 1 ) { this . nextId [ type ] = 0 ; entitySpace = Object . keys ( this . nextId ) . indexOf ( type ) ; } for ( const insert of todo . inserts ) { const id = this . nextId [ type ] ++ ; const uuid = `10000000-${ String ( entitySpace ) . padStart ( 4 , "0" ) }-0000-0000-${ String ( id ) . padStart ( 12 , "0" ) }` ; insert . __orm . data [ "id" ] = keyToString ( todo . metadata , uuid ) ; } } } ) ; } reset ( ) { this . nextId = { } ; } }