Created
November 24, 2012 03:16
-
-
Save rudylattae/4138220 to your computer and use it in GitHub Desktop.
Bunch.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var Bunch = (function () { | |
// internals | |
var defaults = { | |
IDENTITY_FIELD: 'id', | |
SEQUENCE_START: 0, | |
hasIdentity: function hasIdentity( item ) { | |
return item[ this._identityField ]; | |
}, | |
ensureIdentity: function ensureIdentity( item ) { | |
var uniqueItem = clone( item ); | |
if ( !this._hasIdentity( uniqueItem ) ) { | |
uniqueItem[ this._identityField ] = this._nextId(); | |
} | |
return uniqueItem; | |
}, | |
nextId: function nextId() { | |
return this._sequence = this._sequence - 1; | |
}, | |
toModel: function toModel( item ) { | |
return item; | |
}, | |
isTransient: function isTransient( model ) { | |
var id = model[ this._identityField ]; | |
if ( typeof id === 'function' ) { | |
id = model.id(); | |
} | |
return id < 0; | |
}, | |
markDeleted: function markDeleted( model ) { | |
model._deleted = true; | |
}, | |
isDeleted: function isDeleted( model ) { | |
return model._deleted === true; | |
} | |
}; | |
// public api | |
function Bunch( options, data ) { | |
this._items = {}; | |
this._hasIdentity = options.hasIdentity || defaults.hasIdentity; | |
this._ensureIdentity = options.ensureIdentity || defaults.ensureIdentity; | |
this._nextId = options.nextId || defaults.nextId; | |
this._toModel = options.toModel || defaults.toModel; | |
this._isTransient = options.isTransient || defaults.isTransient; | |
this._markDeleted = options.markDeleted || defaults.markDeleted; | |
this._isDeleted = options.isDeleted || defaults.isDeleted; | |
this._sequence = options.sequenceStart || defaults.SEQUENCE_START; | |
this._identityField = options.identityField || defaults.IDENTITY_FIELD; | |
if ( data ) { | |
data.forEach( function( item ) { | |
this.add( item, { silent: true }); | |
}.bind( this )); | |
} | |
} | |
Bunch.prototype.add = function( item, options ) { | |
var options = options || { silent: false }, | |
id, | |
uniqueItem, | |
model; | |
uniqueItem = this._ensureIdentity( item ); | |
id = this._hasIdentity( uniqueItem ); | |
if ( !this.has( id ) ) { | |
model = this._toModel( uniqueItem ); | |
this._items[ id ] = model; | |
if ( !options.silent ) { | |
this.trigger( 'added', model ); | |
} | |
} | |
}; | |
Bunch.prototype.all = function() { | |
return this.toArray(); | |
}; | |
Bunch.prototype.get = function( id ) { | |
return this._items[ id ]; | |
}; | |
Bunch.prototype.map = function( callback, ctx ) { | |
var result = [], | |
i; | |
for ( i in this._items ) { | |
if( this._items.hasOwnProperty( i ) && !this._isDeleted( this._items[i] ) ) { | |
if ( ctx ) { | |
result.push( callback.call( ctx, this._items[i] ) ); | |
} else { | |
result.push( callback( this._items[i] ) ); | |
} | |
} | |
} | |
return result; | |
}; | |
Bunch.prototype.remove = function( id, options ) { | |
var options = options || { destroy: false }; | |
if ( this.has( id ) ) { | |
if ( options.destroy || this._isTransient(this._items[ id ]) ) { | |
this._destroy( id ); | |
} else { | |
this._softDelete( id ); | |
} | |
} | |
}; | |
Bunch.prototype.has = function( id ) { | |
return this._items[ id ]; | |
}; | |
Bunch.prototype.toArray = function() { | |
return this.map(function( o ) { | |
return o; | |
}.bind( this )); | |
}; | |
Bunch.prototype._destroy = function( id ) { | |
this.trigger( 'deleted', this._items[ id ] ); | |
this._items[ id ] = null; | |
delete this._items[ id ]; | |
}; | |
Bunch.prototype._softDelete = function( id ) { | |
this.trigger( 'deleted', this._items[ id ] ); | |
this._markDeleted( this._items[ id ] ); | |
}; | |
LucidJS.emitter( Bunch.prototype ); | |
// utils | |
function clone( obj ) { | |
return JSON.parse( JSON.stringify(obj) ); | |
} | |
return Bunch; | |
}()); | |
function ScopedStore( store, scope ) { | |
function scoped( key ) { | |
return scope + '.' + key; | |
} | |
this.set = function(key, value) { | |
return store.set( scoped(key), value ); | |
}; | |
this.get = function(key) { | |
return store.get( scoped(key) ); | |
}; | |
this.remove = function(key) { | |
store.remove( scoped(key) ); | |
}; | |
this.clear = function() { | |
store.clear(); | |
}; | |
} | |
var LocalStoragePersistenceProvider = (function() { | |
function LocalStoragePersistenceProvider( store, collection ) { | |
} | |
LocalStoragePersistenceProvider.prototype.insert = function() { | |
}; | |
LocalStoragePersistenceProvider.prototype.find = function() { | |
}; | |
LocalStoragePersistenceProvider.prototype.update = function() { | |
}; | |
LocalStoragePersistenceProvider.prototype.remove = function() { | |
}; | |
return LocalStoragePersistenceProvider; | |
}()); | |
/* | |
connect() | |
find() | |
insert() | |
update() | |
remove() | |
*/ | |
function LocaAdapter( store, collection ) { | |
var data = [], | |
index = {}, | |
nextId; | |
this.create = function( record ) { | |
record.id = nextId; | |
data.push( record ); | |
index[ nextId ] = data.indexOf( record ); | |
nextId = nextId + 1; | |
this.flush(); | |
}; | |
this.read = function( id ) { | |
return data[ index[id] ]; | |
}; | |
this.update = function( id, changes ) { | |
var record = data[ index[id] ]; | |
for( p in changes ) { | |
if ( record.hasOwnProperty(p) ) { | |
record[p] = changes[p]; | |
} | |
} | |
this.flush(); | |
}; | |
this.load = function( refresh ) { | |
if ( data && !refresh ) { | |
return data; | |
} | |
data = store.get( collection ) || []; | |
index = store.get( collection + '_index' ) || {}; | |
nextId = store.get( collection + '_nextId' ) || 1; | |
return data; | |
}; | |
this.nuke = function( confirm ) { | |
if ( confirm ) { | |
data = []; | |
index = {}; | |
nextId = 1; | |
this.flush(); | |
} | |
} | |
this.flush = function() { | |
store.set( collection, data); | |
store.set( collection + '_index', index); | |
store.set( collection + '_nextId', nextId); | |
} | |
} | |
function koRepositoryBoundObservableArray( repo ) { | |
var a = ko.observableArray( repo.all() ); | |
repo.on('added', function( item ) { | |
a.push( item ); | |
}); | |
repo.on('deleted', function( item ) { | |
a.remove( item ); | |
}); | |
return a; | |
} |
Author
rudylattae
commented
Dec 16, 2012
function Collection( options ) {
this._loader = options.loader || throw new Error('Provide a loader to fetch data');
this._mapper = options.mapper;
this._data = [];
}
Collection.prototype.all = function() {
return this._data;
};
Collection.prototype.add = function( item ) {
var model = null;
if ( this._crud.add ) {
model = this._mapper.model( this._crud.add( item ) );
}
this._data.push( model );
this.trigger( 'added', model );
};
Collection.prototype.find = function( condition, fields ) {
return this._sql.select( fields ).from( this._table ).where( condition ).execute();
};
Collection.prototype.update = function( condition, changes ) {
return this._sql.update( this._table ).set( changes ).where( condition ).execute();
};
Collection.prototype.remove = function( condition ) {
return this._sql.remove().from( this._table ).where( condition ).execute();
};
Collection.prototype.load = function( refresh ) {
if ( this._data && !refresh ) {
return;
}
var raw = this._loader();
if ( this._mapper )
this._data = this._mapper.list( raw );
else
this._data = raw;
this.trigger( 'refreshed' );
};
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment