import { Id } from 'ngx-tethys/types' ; import { coerceArray , isFunction , isUndefinedOrNull } from './helpers' ; export interface EntityAddOptions { prepend ? : boolean ; afterId ? : Id ; } export interface EntityMoveOptions { afterId ? : Id ; toIndex ? : number ; } export interface ProducerOptions { idKey ? : string ; } export class Producer < TEntity > { private idKey = '_id' ; private entities : TEntity [ ] ; constructor ( entities , options ? ) { this . entities = entities || [ ] ; if ( options && options . idKey ) { this . idKey = options . idKey ; } } example add ( entity , addOptions ? ) { const addEntities = coerceArray ( entity ) ; if ( addEntities . length === 0 ) { return this . entities ; } if ( addOptions && ( addOptions . afterId || addOptions . prepend ) ) { if ( addOptions . afterId ) { const entities = [ ... this . entities ] ; const index = this . entities . findIndex ( item => { return item [ this . idKey ] === addOptions . afterId ; } ) + 1 ; entities . splice ( index , 0 , ... addEntities ) ; this . entities = [ ... entities ] ; } else if ( addOptions . prepend ) { this . entities = [ ... addEntities , ... this . entities ] ; } } else { this . entities = [ ... this . entities , ... addEntities ] ; } return this . entities ; } example update ( id , newStateFn ) ; update ( id , newState ? ) ; update ( idsOrFn , newStateOrFn ? ) { const ids = coerceArray ( idsOrFn ) ; for ( let i = 0 ; i < this . entities . length ; i ++ ) { const oldEntity = this . entities [ i ] ; if ( ids . indexOf ( oldEntity [ this . idKey ] ) >= 0 ) { const newState = isFunction ( newStateOrFn ) ? ( newStateOrFn as any ) ( oldEntity ) : newStateOrFn ; this . entities [ i ] = { ... ( oldEntity as any ) , ... newState } ; } } return [ ... this . entities ] ; } example remove ( id ) ; remove ( predicate ) ; remove ( idsOrFn ? ) { if ( isFunction ( idsOrFn ) ) { this . entities = this . entities . filter ( entity => { return ! ( idsOrFn as any ) ( entity ) ; } ) ; } else { const ids = coerceArray ( idsOrFn ) ; this . entities = this . entities . filter ( entity => { return ids . indexOf ( entity [ this . idKey ] ) === - 1 ; } ) ; } return this . entities ; } example move ( id , moveOptions ? ) { const fromIndex = this . entities . findIndex ( item => item [ this . idKey ] === id ) ; let toIndex = 0 ; const newEntities = [ ... this . entities ] ; if ( ! id || fromIndex < 0 ) { return [ ... this . entities ] ; } if ( moveOptions ) { if ( ! isUndefinedOrNull ( moveOptions . afterId ) ) { toIndex = this . entities . findIndex ( item => item [ this . idKey ] === moveOptions . afterId ) ; } else if ( moveOptions . toIndex ) { toIndex = moveOptions . toIndex ; } } toIndex = Math . max ( 0 , Math . min ( this . entities . length - 1 , toIndex ) ) ; if ( toIndex === fromIndex ) { return [ ... this . entities ] ; } else { const target = this . entities [ fromIndex ] ; const delta = toIndex < fromIndex ? - 1 : 1 ; for ( let i = fromIndex ; i !== toIndex ; i += delta ) { newEntities [ i ] = newEntities [ i + delta ] ; } newEntities [ toIndex ] = target ; return [ ... newEntities ] ; } } } export function produce < TEntity > ( entities , options ? ) { return new Producer ( entities , options ) ; }