import { IIterable , IIterator , IterableOrArrayLike , StringExt } from '@lumino/algorithm' ; import { BPlusTree } from '@lumino/collections' ; import { Datastore } from './datastore' ; import { Record } from './record' ; import { Schema } from './schema' ; /**
 * A datastore object which holds a collection of records.
 */ export class Table < S extends Schema > implements IIterable < Record < 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 ) ; } internal param table param data returns static patch < U extends Schema > ( table , data ) { let tc = { } ; let schema = table . schema ; let records = table . _records ; let cmp = Private . recordIdCmp ; for ( let id in data ) { let old = records . get ( id , cmp ) || Private . createRecord ( schema , id ) ; let { record , change } = Private . applyPatch ( schema , old , data [ id ] ) ; records . insert ( record ) ; tc [ id ] = change ; } return tc ; } internal param table param data returns static unpatch < U extends Schema > ( table , data ) { let tc = { } ; let schema = table . schema ; let records = table . _records ; let cmp = Private . recordIdCmp ; for ( let id in data ) { let old = records . get ( id , cmp ) || Private . createRecord ( schema , id ) ; let { record , change } = Private . unapplyPatch ( schema , old , data [ id ] ) ; records . insert ( record ) ; tc [ id ] = change ; } return tc ; } /**
     * The schema for the table.
     *
     * #### Complexity
     * `O(1)`
     */ readonly schema : S ; /**
     * Whether the table is empty.
     *
     * #### Complexity
     * `O(1)`
     */ get isEmpty ( ) : boolean { return this . _records . isEmpty ; } /**
     * The size of the table.
     *
     * #### Complexity
     * `O(1)`
     */ get size ( ) : number { return this . _records . size ; } returns iter ( ) { return this . _records . iter ( ) ; } param id returns has ( id ) { return this . _records . has ( id , Private . recordIdCmp ) ; } param id returns get ( id ) { return this . _records . get ( id , Private . recordIdCmp ) ; } 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 ; let cmp = Private . recordIdCmp ; for ( let id in data ) { let old = records . get ( id , cmp ) || Private . createRecord ( schema , id ) ; let record = Private . applyUpdate ( schema , old , data [ id ] , context ) ; records . insert ( record ) ; } } param schema param context private constructor ( schema , context , records ? ) { this . schema = schema ; this . _context = context ; if ( records ) { this . _records . assign ( records ) ; } } private _context : Datastore . Context ; private _records = new BPlusTree < Record < S > > ( Private . recordCmp ) ; } /**
 * The namespace for the `Table` class statics.
 */ export namespace Table { /**
     * A type alias for the table update type.
     */ export type Update < S extends Schema > = { readonly [ recordId ] : Record . Update < S > ; } ; /**
     * A type alias for the table change type.
     */ export type Change < S extends Schema > = { readonly [ recordId ] : Record . Change < S > ; } ; /**
     * A type alias for the table patch type.
     */ export type Patch < S extends Schema > = { readonly [ recordId ] : Record . Patch < S > ; } ; internal export type MutableChange < S extends Schema > = { [ recordId ] : Record . MutableChange < S > ; } ; internal export type MutablePatch < S extends Schema > = { [ recordId ] : Record . MutablePatch < S > ; } ; } /**
 * The namespace for the module implementation details.
 */ namespace Private { /**
     * A three-way record comparison function.
     */ export function recordCmp < S extends Schema > ( a , b ) { return StringExt . cmp ( a . $id , b . $id ) ; } /**
     * A three-way record id comparison function.
     */ export function recordIdCmp < S extends Schema > ( record , id ) { return StringExt . cmp ( record . $id , id ) ; } param schema param id returns export function createRecord < S extends Schema > ( schema , id ) { let record = { } ; let metadata = { } ; record . $id = id ; record [ '@@metadata' ] = metadata ; for ( let name in schema . fields ) { let field = schema . fields [ name ] ; record [ name ] = field . createValue ( ) ; metadata [ name ] = field . createMetadata ( ) ; } 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 tp = context . patch [ schema . id ] || ( context . patch [ schema . id ] = { } ) ; let rc = tc [ record . $id ] || ( tc [ record . $id ] = { } ) ; let rp = tp [ record . $id ] || ( tp [ record . $id ] = { } ) ; let previous = record as Record . Value < S > ; let metadata = record [ '@@metadata' ] ; let clone = { ... ( record as any ) } ; for ( let name in update ) { let field = schema . fields [ name ] ; let { value , change , patch } = field . applyUpdate ( { previous : previous [ name ] , update : update [ name ] ! , metadata : metadata [ name ] , version , storeId } ) ; clone [ name ] = value ; if ( name in rc ) { change = field . mergeChange ( rc [ name ] ! , change ) ; } if ( name in rp ) { patch = field . mergePatch ( rp [ name ] ! , patch ) ; } rc [ name ] = change ; rp [ name ] = patch ; } return clone ; } /**
     * A type alias for the result of a patch operation.
     */ export type PatchResult < S extends Schema > = { /**
         * The new record object.
         */ readonly record : Record < S > ; /**
         * The user-facing change object.
         */ readonly change : Record . Change < S > ; } ; param schema param record param patch return export function applyPatch < S extends Schema > ( schema , record , patch ) { let rc = { } ; let previous = record as Record . Value < S > ; let metadata = record [ '@@metadata' ] ; let clone = { ... ( record as any ) } ; for ( let name in patch ) { let field = schema . fields [ name ] ; let { value , change } = field . applyPatch ( { previous : previous [ name ] , patch : patch [ name ] ! , metadata : metadata [ name ] } ) ; clone [ name ] = value ; rc [ name ] = change ; } return { record : clone , change : rc } ; } param schema param record param patch return export function unapplyPatch < S extends Schema > ( schema , record , patch ) { let rc = { } ; let previous = record as Record . Value < S > ; let metadata = record [ '@@metadata' ] ; let clone = { ... ( record as any ) } ; for ( let name in patch ) { let field = schema . fields [ name ] ; let { value , change } = field . unapplyPatch ( { previous : previous [ name ] , patch : patch [ name ] ! , metadata : metadata [ name ] } ) ; clone [ name ] = value ; rc [ name ] = change ; } return { record : clone , change : rc } ; } }