transactional
Version:
Reactive objects with transactional updates and automatic serialization
111 lines (85 loc) • 3.59 kB
text/typescript
import { Class, ClassDefinition } from '../objectplus/index.ts'
import { begin, commit, Transactional, Transaction, TransactionOptions, Owner } from '../transactions.ts'
import { Record } from '../record/index.ts'
import { IdIndex } from './commons.ts'
let _count = 0;
export class Collection extends Transactional {
/***********************************
* Core Members
*/
// Array of the records
models : Record[]
// Index by id and cid
_byId : IdIndex
get( objOrId : string | Record | Object ) : Record {
return objOrId ? (
this._byId[ typeof objOrId === 'object' ? ( <Record> objOrId ).cid || objOrId[ this.idAttribute ] : objOrId ]
) : null;
}
each( iteratee : ( val : Record, key : number ) => void, context? : any ){
const fun = arguments.length === 2 ? ( v, k ) => iteratee.call( context, v, k ) : iteratee,
{ models } = this;
for( let i = 0; i < models.length; i++ ){
fun( models[ i ], i );
}
}
_validateNested( errors : {} ) : number {
let count = 0;
this.each( record => {
const error = record.validationError;
if( error ){
errors[ record.cid ] = error;
count++;
}
});
return count;
}
model : typeof Record
// idAttribute extracted from the model type.
idAttribute : string
constructor( records? : ( Record | {} )[], options? : TransactionOptions ){
super( _count++ );
this.models = [];
this._byId = {};
this.idAttribute = this.model.prototype.idAttribute;
}
get length() : number { return this.models.length; }
_notifyChange( options : TransactionOptions ){
// TODO: send 'changes' event
}
_notifyChangeItem( event : 'add' | 'remove' | 'change', record : Record, options : TransactionOptions ){
// TODO : send item change event
}
_notifyBulkChange( event : 'update' | 'reset' | 'sort', options : TransactionOptions ){
//TBD
}
// Deeply clone collection, optionally setting new owner.
clone( owner? : any ) : this {
return new (<any>this.constructor)( this.models, { clone : true }, owner );
}
toJSON() : Object[] {
return this.models.map( model => model.toJSON() );
}
// Apply bulk in-place object update in scope of ad-hoc transaction
set( elements : ( {} | Record )[], options? : TransactionOptions ) : this {
// Handle reset option here - no way it will be populated from the top as nested transaction.
return ( options.reset ? this.reset( elements, options ) :
this._createTransaction( elements, options ).commit( options ) );
}
reset( elements : ( {} | Record )[], options : TransactionOptions = {} ) : this {
const previousModels = dispose( this );
emptySet( this, elements, options );
return previousModels;
}
// Apply bulk object update without any notifications, and return open transaction.
// Used internally to implement two-phase commit.
_createTransaction( elements : Elements, options : TransactionOptions = {} ) : CollectionTransaction {
if( this.models.length ){
const { remove } = options;
return remove === void 0 || remove ? setTransaction( this, elements, options ) : addTransaction( this, elements, options );
}
else{
return emptySetTransaction( this, elements, options );
}
}
}