@type-r/models
Version:
The serializable type system for JS and TypeScript
114 lines (90 loc) • 3.45 kB
text/typescript
/*************
* Remove items from collections.
*
* Cannot be a part of two-phase transaction on object tree.
* Can be executed in the scope of ad-hoc transaction or from the trigger, though.
*
* Implemented with low-level API.
* Most frequent operation - single element remove. Thus, it have the fast-path.
*/
import { eventsApi } from '@type-r/mixture';
import { Model } from '../model';
import { transactionApi, TransactionOptions } from '../transactions';
import { CollectionCore, CollectionTransaction, free, removeIndex } from './commons';
const { trigger2, trigger3 } = eventsApi,
{ markAsDirty, begin, commit } = transactionApi;
/** @private */
export function removeOne( collection : CollectionCore, el : Model | {} | string, options : TransactionOptions ) : Model {
var model : Model = collection.get( el );
if( model ){
const isRoot = begin( collection ),
models = collection.models;
// Remove model form the collection.
models.splice( models.indexOf( model ), 1 );
removeIndex( collection._byId, model );
// Mark transaction as dirty.
const notify = markAsDirty( collection, options );
// Send out events.
if( notify ){
trigger3( model, 'remove', model, collection, options );
trigger3( collection, 'remove', model, collection, options );
}
free( collection, model, options.unset );
notify && trigger2( collection, 'update', collection, options );
// Commit transaction.
isRoot && commit( collection );
return model;
}
};
/** Optimized for removing many elements
* 1. Remove elements from the index, checking for duplicates
* 2. Create new models array matching index
* 3. Send notifications and remove references
*/
/** @private */
export function removeMany( collection : CollectionCore, toRemove : any[], options ){
const removed = _removeFromIndex( collection, toRemove, options.unset );
if( removed.length ){
const isRoot = begin( collection );
_reallocate( collection, removed.length );
if( markAsDirty( collection, options ) ){
const transaction = new CollectionTransaction( collection, isRoot, [], removed, [], false );
transaction.commit();
}
else{
// Commit transaction.
isRoot && commit( collection );
}
}
return removed;
};
// remove models from the index...
/** @private */
function _removeFromIndex( collection, toRemove, unset : boolean ){
var removed = Array( toRemove.length ),
_byId = collection._byId;
for( var i = 0, j = 0; i < toRemove.length; i++ ){
var model = collection.get( toRemove[ i ] );
if( model ){
removed[ j++ ] = model;
removeIndex( _byId, model );
free( collection, model, unset );
}
}
removed.length = j;
return removed;
}
// Allocate new models array removing models not present in the index.
/** @private */
function _reallocate( collection, removed ){
var prev = collection.models,
models = collection.models = Array( prev.length - removed ),
_byId = collection._byId;
for( var i = 0, j = 0; i < prev.length; i++ ){
var model = prev[ i ];
if( _byId[ model.cid ] ){
models[ j++ ] = model;
}
}
models.length = j;
}