Merge in Mahmood's caching work
8 files changed, 84 insertions(+), 5 deletions(-)

M .hgsigs
M .hgtags
M .npmignore
M package.json
M spec/model.spec.js
M src/associations.js
M src/index.js
M src/model.js
M .hgsigs +2 -0
@@ 10,3 10,5 @@ 305269d3a39697eb87e3c2a4ea9954d2553cd301
 19cac30ab3ae2abff5bddc2b3c861a3822c30656 0 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
+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

          
M .hgtags +2 -0
@@ 13,3 13,5 @@ c136410d4f3dcca229ce78e5620944d80f2cafbd
 719bd3c260b504232fc34afe4e9e449ca5407e0b v0.0.1-alpha.13
 b8a099d180c187b565d5a0a26adad1cb81245fe5 v0.2.0
 718ec6890f997587436bc9cf6d856fd6b1088081 v0.2.1
+671e76db43e9c3e08207ea525788bc6e34085571 v0.2.2
+1de93fa2c8daef2b478530a188498fefea27ccac v0.2.3

          
M .npmignore +4 -1
@@ 2,16 2,19 @@ 
 *.log
 *.map
 *.tgz
+.babelrc
 .editorconfig
 .eslintrc
 .hgignore
+.hgtags
+.hgsigs
 .idea/
 .tm_properties
+.npmignore
 coverage/
 scripts/
 docs/
 karma.conf.js
 node_modules/
 spec/
-src/
 yarn.lock

          
M package.json +1 -1
@@ 2,7 2,7 @@ 
   "name": "bailiwick",
   "description": "This is an experimental model toolkit for web applications. It's meant to allow for a model that is closer to the Domain Model pattern.",
   "homepage": "https://bitbucket.org/ged/bailiwick#readme",
-  "version": "0.2.1",
+  "version": "0.2.3",
   "scripts": {
     "build": "babel src --out-dir ./dist",
     "prepublish": "yarn build",

          
M spec/model.spec.js +72 -0
@@ 220,6 220,78 @@ describe( 'Model class', () => {
 	});
 
 
+	describe( 'replacing', () => {
+
+		let data, user;
+
+		beforeEach( () => {
+			data = {
+				id: 12,
+				firstName: "Rick",
+				lastName: "Sanchez",
+				email: "science.guy1966@realfakedoors.com",
+				removed_at: new Date()
+			};
+			user = new User( data );
+		} );
+
+
+		it( "replaces the object's data in the datastore", () => {
+			sandbox.stub( User.datastore, 'replace' ).
+				resolves( Object.assign(data, {removed_at: null}) );
+
+			return expect( user.replace() ).to.be.fulfilled.
+				then( () => {
+					expect( User.datastore.replace ).to.have.been.calledOnce;
+					expect( user.removed_at ).to.beNull;
+				});
+		} );
+
+	});
+
+
+	describe( 'deleting', () => {
+
+		let data, user;
+
+		beforeEach( () => {
+			data = {
+				id: 12,
+				firstName: "Rick",
+				lastName: "Sanchez",
+				email: "science.guy1966@realfakedoors.com",
+				removed_at: null
+			};
+			user = new User( data );
+		} );
+
+
+		it( "removes the object from the datastore", () => {
+			let removedDate = new Date();
+			sandbox.stub( User.datastore, 'remove' ).
+				resolves( Object.assign(data, {removed_at: removedDate}) );
+			return expect( user.delete() ).to.be.fulfilled.
+				then( () => {
+					expect( User.datastore.remove ).to.have.been.calledOnce;
+					expect( user.removed_at ).to.eq( removedDate );
+				});
+		} );
+
+
+		it( "is a no-op if it doesn't have an ID", () => {
+			user.id = null;
+
+			sandbox.stub( User.datastore, 'remove' );
+
+			return expect( user.delete() ).to.be.fulfilled.
+				then( () => {
+					expect( User.datastore.remove ).not.to.have.been.called;
+				});
+		} );
+
+	});
+
+
 	describe( 'validation', () => {
 
 		let data, user;

          
M src/associations.js +1 -1
@@ 83,7 83,7 @@ class Association {
 		else if ( Array.isArray(this.modelClassSpec) ) {
 			let [className, importPath] = this.modelClassSpec;
 			// System.import( importPath ).then( mod => {
-			// 	console.logger.debug( `Importing model class ${className} from module: `, mod );
+			// 	logger.debug( `Importing model class ${className} from module: `, mod );
 			// 	this.modelClassSpec = mod[ className ];
 			// });
 			throw new Error( "Imported model class not yet supported." );

          
M src/index.js +1 -1
@@ 12,7 12,7 @@ import Promise from 'bluebird';
  * The default namespace
  */
 
-export let VERSION = '0.2.1';
+export let VERSION = '0.2.3';
 
 export * from './model';
 export * from './datastore';

          
M src/model.js +1 -1
@@ 290,7 290,7 @@ export class Model {
 		if ( this.id ) {
 			return this[ DATASTORE ].remove( this.constructor, this.id ).
 				then( deletedData => {
-					console.logger.debug( "Updating ", this, " with results from deletion." );
+					logger.debug( "Updating ", this, " with results from deletion." );
 					Object.assign( this[ DATA ], deletedData );
 					this[ NEW_OBJECT ] = true;
 					this[ DIRTY_FIELDS ].clear();