From a85df6c59b79c963858d6f7e6be18ad3d2d12ee5 Mon Sep 17 00:00:00 2001 From: Vlad Balin Date: Fri, 29 Apr 2016 03:06:11 -0400 Subject: [PATCH] types --- src/record/index.ts | 8 +- .../{transactions.js => transactions.ts} | 81 +++++++++--- src/types.d.ts | 122 ++++++++++++++++++ src/types.ts | 36 ------ 4 files changed, 192 insertions(+), 55 deletions(-) rename src/record/{transactions.js => transactions.ts} (63%) create mode 100644 src/types.d.ts delete mode 100644 src/types.ts diff --git a/src/record/index.ts b/src/record/index.ts index 8608e2ea..d17326bb 100644 --- a/src/record/index.ts +++ b/src/record/index.ts @@ -4,11 +4,13 @@ import { assign, Class } from '../../tools' let _cidCount = 0; -export class Record extends Class { - static Collection(){} + +export class Record extends Class { + static Collection : Function + static define( spec ) { - const BaseModel = Object.getPrototypeOf( this.prototype ).constructor; + const BaseModel = Object.getPrototypeOf( this.prototype ).constructor; // Create collection if( this.Collection === BaseModel.Collection ) { diff --git a/src/record/transactions.js b/src/record/transactions.ts similarity index 63% rename from src/record/transactions.js rename to src/record/transactions.ts index 7342ae01..ac556f68 100644 --- a/src/record/transactions.js +++ b/src/record/transactions.ts @@ -2,7 +2,27 @@ * Everything related to record's transactional updates */ -export const RecordMixin = { +interface ITransactional { + _changing : boolean + Attributes : new ( values : {} ) => {} + _previousAttributes : {} + attributes : {} + _attributes : {} + forEachAttr : ( values : {}, iterator : ( value, key : string ) => void ) => void + _pending : boolean + _owner : any +} + +export class TransactionalMixin { + _changing : boolean + Attributes : new ( values : {} ) => {} + _previousAttributes : {} + attributes : {} + _attributes : {} + forEachAttr : ( values : {}, iterator : ( value, key : string ) => void ) => void + _pending : boolean + _owner : any + createTransaction( values, options = {} ) { const transaction = new Transaction( this ), { changes, nested } = transaction, @@ -95,7 +115,7 @@ export function setAttribute( model, name, value ) { * begin( model ) => true | false; * commit( model, options ) => void 0 */ -function begin( model ){ +function begin( model : ITransactional ) : boolean { const isRoot = !model._changing; if( isRoot ){ @@ -106,7 +126,7 @@ function begin( model ){ return isRoot; } -function commit( model, options ){ +function commit( model : ITransactional, options ){ if( !options.silent ){ while( model._pending ){ model._pending = false; @@ -126,34 +146,63 @@ function commit( model, options ){ } } -class Transaction { +export class Transaction { + isRoot : boolean + changes : string[] + nested : Transaction[] + // open transaction - constructor( model ){ + constructor( public model : ITransactional, values : {}, public options = {} ){ this.isRoot = begin( model ); - this.model = model; - this.changed = []; - this.nested = []; + + const { attributes, _attributes } = model; + const changes = this.changes = [], + nested = this.nested = []; + + model.forEachAttr( values, ( value, key ) => { + const attr = _attributes[ key ], + prev = attributes[ key ]; + + // handle deep update... + if( attr.canBeUpdated ) { + if( prev && attr.canBeUpdated( value ) ) { + nested.push( prev.createTransaction( value, options ) ); + return; + } + } + + // cast and hook... + const next = attr.transform( value, options, prev, this ); + + if( attr.isChanged( next, prev ) ) { + attributes[ key ] = next; + changes.push( key ); + + // Do the rest of the job after assignment + attr.handleChange( next, prev ); + } + } ); } // commit transaction - commit( options = {} ){ - const { nested, model } = this; + commit(){ + const { nested, model, options } = this; // Commit all nested transactions... for( let i = 0; i < nested.length; i++ ){ - nested[ i ].commit( options ); + nested[ i ].commit(); } // Notify listeners on attribute changes... if( !options.silent ){ - const { changed } = this; + const { changes } = this; - if( changed.length ){ - model._pending = options; + if( changes.length ){ + model._pending = true; } - for( let i = 0; i < changed.length; i++ ){ - model._notifyChangeAttr( changed[ i ], options ) + for( let i = 0; i < changes.length; i++ ){ + model._notifyChangeAttr( changes[ i ], options ) } } diff --git a/src/types.d.ts b/src/types.d.ts new file mode 100644 index 00000000..11c8636f --- /dev/null +++ b/src/types.d.ts @@ -0,0 +1,122 @@ +/** + * Class Types Declarations + */ + +interface ClassCtor { + new ( ...args : any[] ) : {} + define( spec? : Specification ) : this + mixins( ...mixins : Mixin[] ) : this + mixinRules( rules : MixinRules ) : this +} + +interface Specification { + properties? : PropertyDescriptorMap + mixins? : Mixin[] + mixinRules? : MixinRules + [ name : string ] : any +} + +type Mixin = Object + +interface MixinRules { + [ propName : string ] : MergeRule +} + +type MergeRule = 'merge' | 'pipe' | 'sequence' | 'reverse' | 'some' | 'every' + +/** + * Record Types declaration + */ + +interface RecordCtor extends ClassCtor { + new ( values? : {}, options? : RecordOptions ) : IRecord + prototype : IRecord + Collection : CollectionCtor +} + +interface RecordOptions { + parse? : boolean + deep? : boolean +} + +interface IRecord { + // precompiled loop through attributes function + forEachAttr( data : {}, iteratee : ( value, key : string ) => void ) : void + + // precompiled defaults function + defaults( values? : {} ) : {} + + // working structures + cid : string + + idAttribute : string + id : string | number | void + + constructor : RecordCtor + initialize( values? : {}, options? : RecordOptions ) : void + + clone( options? : { deep? : boolean } ) : this + + set( values : {}, options? : RecordOptions ) : this + + createTransaction( values : {}, options? : RecordOptions ) : ITransaction + transaction( func : ( IRecord ) => void ) : void + + parse( resp : {} ) : {} + toJSON() : {} +} + +interface IAttribute { + name : string +} + +/** + * Collection Types declaration + */ + +type CollectionArg = {} | {}[] | IRecord | IRecord[] + +interface CtorOptions { + parse? : Boolean; + deep? : Boolean; +} + +interface CollectionCtor { + new ( models? : CollectionArg, options? : CtorOptions ) : ICollection; + prototype : ICollection; +} + +interface SetOptions extends CtorOptions { + merge? : Boolean + sort? : Boolean +} + +interface AddOptions extends SetOptions { + at? : number; +} + +interface ICollection { + Record : RecordCtor; + + initialize( models? : CollectionArg, options? : CtorOptions ); + + parse( data : {} ) : {}; + toJSON() : {}; + + set( models? : CollectionArg, options? : SetOptions ) + reset( models? : CollectionArg, options? : SetOptions ) + add( models? : CollectionArg, options? : AddOptions ) + remove( models? : CollectionArg, options? : CtorOptions ) +} + +class Collection implements ICollection { + constructor( records? : CollectionArg, options? : CtorOptions ){ + + } + + Record : RecordCtor; + + initialize( records? : CollectionArg, options? : CtorOptions ){ + + } +} \ No newline at end of file diff --git a/src/types.ts b/src/types.ts deleted file mode 100644 index 05334a50..00000000 --- a/src/types.ts +++ /dev/null @@ -1,36 +0,0 @@ -type CollectionArg = {} | {}[] | IRecord | IRecord[] - -interface CtorOptions { - parse? : Boolean; - deep? : Boolean; -} - -interface CollectionCtor { - new ( models? : CollectionArg, options? : CtorOptions ); -} - - -interface RecordCtor { - new ( values? : {}, options? : CtorOptions ); - Collection : CollectionCtor -} - -interface IRecord { - constructor : RecordCtor; -} - -interface ICollection { - constructor : CollectionCtor; - Record : IRecord; - initialize( models? : CollectionArg, options? : CtorOptions ); -} - -class Collection implements ICollection { - constructor( records? : CollectionArg, options? : CtorOptions ){ - - } - - initialize( records? : CollectionArg, options? : CtorOptions ){ - - } -} \ No newline at end of file