import { IIterator , IterableOrArrayLike , each , map } from '@lumino/algorithm' ; import { Datastore , Record , Schema , Table as LTable } from '@lumino/datastore' ; import { ITable } from '../interface' ; /**
 * A datastore object which holds a collection of records.
 */ export class Table < S extends Schema > implements ITable < S > { internal param schema param context returns static create < U extends Schema > ( schema , context ) { return new Table < U > ( schema , context ) ; } internal param schema param context returns static recreate < U extends Schema > ( schema , context , records ) { return new Table < U > ( schema , context , records ) ; } /**
     * The schema for the table.
     */ readonly schema : S ; /**
     * Whether the table is empty.
     */ get isEmpty ( ) : boolean { return Object . keys ( this . _records ) . length === 0 ; } /**
     * The size of the table.
     */ get size ( ) : number { return Object . keys ( this . _records ) . length ; } returns iter ( ) { return map ( Object . keys ( this . _records ) , key => this . _records [ key ] ) ; } param id returns has ( id ) { return this . _records . hasOwnProperty ( id ) ; } param id returns get ( id ) { return this . _records [ id ] ; } param data update ( data ) { let context = this . _context ; if ( ! context . inTransaction ) { throw new Error ( 'A table can only be updated during a transaction.' ) ; } let schema = this . schema ; let records = this . _records ; for ( let id in data ) { let old = this . get ( id ) || Private . createRecord ( schema , id ) ; let record = Private . applyUpdate ( schema , old , data [ id ] , context ) ; records [ id ] = record ; } } param schema param context private constructor ( schema , context , records ? ) { this . schema = schema ; this . _context = context ; if ( records ) { each ( records , record => { this . _records [ record . $id ] = record ; } ) ; } } private _context : Datastore . Context ; private _records : { [ key ] : Record < S > ; } = { } ; } /**
 * The namespace for the module implementation details.
 */ namespace Private { param schema param id returns export function createRecord < S extends Schema > ( schema , id ) { let record = { } ; record . $id = id ; record [ '@@metadata' ] = { } ; for ( let name in schema . fields ) { let field = schema . fields [ name ] ; record [ name ] = field . createValue ( ) ; } return record ; } param schema param record param update param context returns export function applyUpdate < S extends Schema > ( schema , record , update , context ) { let version = context . version ; let storeId = context . storeId ; let tc = context . change [ schema . id ] || ( context . change [ schema . id ] = { } ) ; let rc = tc [ record . $id ] || ( tc [ record . $id ] = { } ) ; let previous = record as Record . Value < S > ; let clone = { ... ( record as any ) } ; for ( let name in update ) { let field = schema . fields [ name ] ; let value ; let change ; switch ( field . type ) { case 'text' : value = previous [ name ] as string ; change = [ ] ; let upd = update [ name ] as any [ ] ; if ( ! Array . isArray ( upd ) ) { upd = [ upd ] ; } for ( let splice of upd ) { let { index , remove , text } = splice ; if ( index < 0 ) { index = Math . max ( 0 , index + value . length ) ; } else { index = Math . min ( index , value . length ) ; } let count = Math . min ( remove , value . length - index ) ; let removedText = value . slice ( index , index + count ) ; change . push ( { index , removed : removedText , inserted : text } ) ; value = value . slice ( 0 , index ) + text + value . slice ( index + count ) ; } break ; case 'list' : let listClone = [ ... previous [ name ] as any [ ] ] ; let up = update [ name ] as any [ ] ; change = [ ] ; if ( ! Array . isArray ( up ) ) { up = [ up ] ; } for ( let splice of up ) { let { index , remove , values } = splice ; if ( index < 0 ) { index = Math . max ( 0 , index + listClone . length ) ; } else { index = Math . min ( index , listClone . length ) ; } let count = Math . min ( remove , listClone . length - index ) ; let removedValues = spliceArray ( listClone , index , count , values ) ; change . push ( { index , removed : removedValues , inserted : values } ) ; } value = listClone ; break ; case 'map' : let mapClone = { ... ( previous [ name ] as any ) } ; let prev = { } ; let curr = { } ; for ( let key in update [ name ] ) { let v = update [ name ] [ key ] ; if ( v === null ) { delete mapClone [ key ] ; } else { mapClone [ key ] = v ; } prev [ key ] = key in previous ? previous [ key ] : null ; curr [ key ] = v ; } change = { previous : prev , current : curr } ; value = mapClone ; break ; case 'register' : value = update [ name ] ! ; change = { previous : previous [ name ] , current : value } ; break ; default : throw new Error ( `Dummystore cannot handle field type: ${ field . type }` ) ; } clone [ name ] = value ; if ( name in rc ) { change = field . mergeChange ( rc [ name ] ! , change ) ; } rc [ name ] = change ; } return clone ; } param arr param start param deleteCount param items returns function spliceArray < T > ( arr , start , deleteCount ? , items ? ) { if ( ! items ) { return arr . splice ( start , deleteCount ) ; } let size = 100000 ; if ( items . length < size ) { return arr . splice ( start , deleteCount || 0 , ... items ) ; } let deleted = arr . splice ( start , deleteCount ) ; let n = Math . floor ( items . length / size ) ; let idx = 0 ; for ( let i = 0 ; i < n ; i ++ , idx += size ) { arr . splice ( idx , 0 , ... items . slice ( idx , size ) ) ; } arr . splice ( idx , 0 , ... items . slice ( idx ) ) ; return deleted ; } }