diff --git a/README.md b/README.md
index 2fe6dce..9b994ca 100644
--- a/README.md
+++ b/README.md
@@ -55,6 +55,7 @@
 
 ## Changelog
 
+- v0.3.0 - Add `setHasOne` functionality (#12)
 - v0.2.1 - Several breaking changes occurred with this version due to updating `devDependencies` and `peerDependencies`:
   - Knex and Bookshelf updated their `bluebird` and `lodash` dependencies
   - Knex changed how undefined values are inserted
diff --git a/lib/manager.js b/lib/manager.js
index 53c0558..a5de2ed 100644
--- a/lib/manager.js
+++ b/lib/manager.js
@@ -46,7 +46,7 @@ Manager.prototype.initialize = function(bookshelf) {
   return this;
 };
 
-Manager.prototype.create = function(name, properties, options) {
+Manager.prototype.create = Promise.method(function(name, properties, options) {
   var Model = this.get(name);
   var model = new Model();
 
@@ -54,16 +54,16 @@ Manager.prototype.create = function(name, properties, options) {
     console.error(error.stack);
     throw error;
   });
-};
+});
 
-Manager.prototype.fetch = function(name, properties, related, options) {
+Manager.prototype.fetch = Promise.method(function(name, properties, related, options) {
   var model = this.forge(name, properties);
 
   return model.fetch({
     withRelated: related,
     transacting: options && options.transacting ? options.transacting : null
   });
-};
+});
 
 Manager.prototype.findRelated = function(properties, paths) {
   var related = [];
@@ -177,7 +177,7 @@ Manager.prototype.isCollection = function(model) {
   return model instanceof this.bookshelf.Collection || model.prototype instanceof this.bookshelf.Collection;
 };
 
-Manager.prototype.save = function(model, properties, options) {
+Manager.prototype.save = Promise.method(function(model, properties, options) {
   if (this.isModel(model)) {
     return this.saveModel(model, properties, options);
   }
@@ -187,9 +187,9 @@ Manager.prototype.save = function(model, properties, options) {
   }
 
   throw new Error('Object should be an instance of Model or Collection, not ' + typeof model);
-};
+});
 
-Manager.prototype.saveCollection = function(collection, models, options) {
+Manager.prototype.saveCollection = Promise.method(function(collection, models, options) {
   return collection.mapThen(function(model) {
     return (model.isNew() || model.hasChanged()) ? model.save(null, options) : model;
   }).then(function() {
@@ -206,18 +206,18 @@ Manager.prototype.saveCollection = function(collection, models, options) {
     console.error(error.stack);
     throw error;
   });
-};
+});
 
-Manager.prototype.saveModel = function(model, properties, options) {
+Manager.prototype.saveModel = Promise.method(function(model, properties, options) {
   return this.setModel(model, properties, options).then(function(result) {
     return (result.isNew() || result.hasChanged()) ? result.save(null, options) : result;
   }).catch(function(error) {
     console.error(error.stack);
     throw error;
   });
-};
+});
 
-Manager.prototype.set = function(model, properties, options) {
+Manager.prototype.set = Promise.method(function(model, properties, options) {
   if (this.isModel(model)) {
     return this.setModel(model, properties, options);
   }
@@ -227,9 +227,9 @@ Manager.prototype.set = function(model, properties, options) {
   }
 
   throw new Error('Object should be an instance of Model or Collection, not ' + typeof model);
-};
+});
 
-Manager.prototype.setModel = function(model, properties, options) {
+Manager.prototype.setModel = Promise.method(function(model, properties, options) {
   var promises = [];
 
   properties = (typeof properties === 'object' && !Array.isArray(properties) && properties !== null) ? properties : {};
@@ -276,9 +276,9 @@ Manager.prototype.setModel = function(model, properties, options) {
   return Promise.reduce(promises, function(result, promise) {
     return promise(result);
   }, []);
-};
+});
 
-Manager.prototype.setBelongsTo = function(model, key, value, relation, options) {
+Manager.prototype.setBelongsTo = Promise.method(function(model, key, value, relation, options) {
   var Target    = relation.relatedData.target;
   var existing  = model.related(key);
   var target    = existing.isNew() ? Target.forge() : existing.clone();
@@ -288,7 +288,7 @@ Manager.prototype.setBelongsTo = function(model, key, value, relation, options)
     if (model.get(fk)) {
       model.set(fk, null);
     }
-    return Promise.resolve((model.isNew() || model.hasChanged()) ? model.save(null, options) : model);
+    return (model.isNew() || model.hasChanged()) ? model.save(null, options) : model;
   }
 
   return this.save(target, value, options).then(function(target) {
@@ -300,12 +300,12 @@ Manager.prototype.setBelongsTo = function(model, key, value, relation, options)
 
     return (model.isNew() || model.hasChanged()) ? model.save(null, options) : model;
   });
-};
+});
 
-Manager.prototype.setBelongsToMany = function(model, key, models, relation, options) {
+Manager.prototype.setBelongsToMany = Promise.method(function(model, key, models, relation, options) {
   var existing = model.related(key);
 
-  return Promise.cast(existing.length ? existing : existing.fetch(options)).then(function() {
+  return Promise.resolve(existing.length ? existing : existing.fetch(options)).then(function() {
     return this.setCollection(existing, models, options);
   }.bind(this)).then(function(targets) {
     // Enforce attach/detach IDs
@@ -326,31 +326,25 @@ Manager.prototype.setBelongsToMany = function(model, key, models, relation, opti
   }).then(function() {
     return model;
   });
-};
+});
 
-Manager.prototype.setHasOne = function(model, key, value, relation, options) {
-  var Target    = relation.relatedData.target;
-  var existing  = Target.forge(model.related(key).attributes);
-  var target    = Target.forge(value);
+Manager.prototype.setHasOne = Promise.method(function(model, key, value, relation, options) {
+  var Target = relation.relatedData.target;
+  var existing = Target.forge(model.related(key).attributes);
+  var target = Target.forge(value);
   var fk = relation.relatedData.foreignKey;
 
-  if (value !== null) {
-    if (existing.get(fk)) {
-      existing.set(fk, null);
-    } else {
-      target.set(fk, model.id);
-      return target.save();
-    }
-
-    return existing.save()
-    .then(function() {
-      target.set(fk, model.id);
-      return target.save();
-    });
-  }
-};
+  return Promise.resolve(existing.isNew() ? null : existing.save(fk, null, options))
+  .then(function() {
+    return target.save(fk, model.id, options);
+  })
+  .then(function(target) {
+    model.relations[key] = target;
+    return model;
+  });
+});
 
-Manager.prototype.setHasMany = function(model, key, models, relation, options) {
+Manager.prototype.setHasMany = Promise.method(function(model, key, models, relation, options) {
   var existing = model.related(key);
 
   var fk = relation.relatedData.foreignKey;
@@ -380,7 +374,7 @@ Manager.prototype.setHasMany = function(model, key, models, relation, options) {
   }).then(function() {
     return model;
   });
-};
+});
 
 Manager.prototype.setScalar = Promise.method(function(model, key, value) {
   if (key.indexOf('_pivot_') === 0) {
@@ -396,7 +390,7 @@ Manager.prototype.setScalar = Promise.method(function(model, key, value) {
   return model;
 });
 
-Manager.prototype.setCollection = function(existing, models, options) {
+Manager.prototype.setCollection = Promise.method(function(existing, models, options) {
   models = models || [];
 
   return Promise.map(models, function(properties) {
@@ -406,6 +400,6 @@ Manager.prototype.setCollection = function(existing, models, options) {
   }.bind(this)).then(function(results) {
     return this.bookshelf.Collection.forge(results);
   }.bind(this));
-};
+});
 
 module.exports = Manager;
diff --git a/package.json b/package.json
index 46c5fbf..ae9c504 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "bookshelf-manager",
-  "version": "0.2.1",
+  "version": "0.3.0",
   "description": "Easily wire up models to APIs with supported for complex, nested saving.",
   "main": "index.js",
   "scripts": {
@@ -26,13 +26,13 @@
     "bluebird": "^3.4.1",
     "bookshelf": "^0.10.0",
     "deep-diff": "^0.3.4",
-    "knex": "^0.11.7",
-    "mocha": "^2.5.3",
+    "knex": "^0.12.1",
+    "mocha": "^3.0.2",
     "sqlite3": "^3.1.4"
   },
   "peerDependencies": {
     "bluebird": "3.x",
     "bookshelf": "^0.10.0",
-    "knex": "^0.11.0"
+    "knex": "^0.11.0 || ^0.12.0"
   }
 }
diff --git a/test/manager.create.js b/test/manager.create.js
index 4fc0f67..88904f9 100644
--- a/test/manager.create.js
+++ b/test/manager.create.js
@@ -29,8 +29,8 @@ describe('manager', function() {
       return manager.create('car', {
         quantity: 1
       }).then(function(car) {
-        assert.equal(1, car.id, 'Car should have ID 1');
-        assert.equal(1, car.get('quantity'), 'Car should have quantity of 1');
+        assert.equal(car.id, 1, 'Car should have ID 1');
+        assert.equal(car.get('quantity'), 1, 'Car should have quantity of 1');
       });
     });
 
@@ -41,8 +41,8 @@ describe('manager', function() {
       ]).then(function(cars) {
         cars.sortBy('quantity');
 
-        assert.equal(2, cars.length, 'Cars collection should have 2 Car models');
-        assert.equal(2, cars.pluck('quantity').length, 'Quantities should be set');
+        assert.equal(cars.length, 2, 'Cars collection should have 2 Car models');
+        assert.equal(cars.pluck('quantity').length, 2, 'Quantities should be set');
       });
     });
 
@@ -54,11 +54,27 @@ describe('manager', function() {
         },
         quantity: 1
       }).then(function(car) {
-        assert.equal(1, car.id, 'Car should have ID 1, not ' + car.id);
-        assert.equal(1, car.get('quantity'), 'Car should have quantity of 1');
-        assert.equal(1, car.related('color').id, 'Color should have ID 1, not ' + car.related('color').id);
-        assert.equal('White', car.related('color').get('name'), 'Color name should be White');
-        assert.equal('#fff', car.related('color').get('hex_value'), 'Color hex_value should be #fff');
+        assert.equal(car.id, 1, 'Car should have ID 1, not ' + car.id);
+        assert.equal(car.get('quantity'), 1, 'Car should have quantity of 1');
+        assert.equal(car.related('color').id, 1, 'Color should have ID 1, not ' + car.related('color').id);
+        assert.equal(car.related('color').get('name'), 'White', 'Color name should be White');
+        assert.equal(car.related('color').get('hex_value'), '#fff', 'Color hex_value should be #fff');
+      });
+    });
+
+    it('should create a model within a new model (hasOne)', function() {
+      return manager.create('car', {
+        title: {
+          state: 'FL',
+          issue_date: '2017-01-01'
+        },
+        quantity: 1
+      }).then(function(car) {
+        assert.equal(car.id, 1, 'Car should have ID 1, not ' + car.id);
+        assert.equal(car.get('quantity'), 1, 'Car should have quantity of 1');
+        assert.equal(car.related('title').id, 1, 'Title should have ID 1, not ' + car.related('title').id);
+        assert.equal(car.related('title').get('state'), 'FL', 'Title state should be FL');
+        assert.equal(car.related('title').get('issue_date'), '2017-01-01', 'Title issue_date should be 2017-01-01');
       });
     });
 
@@ -75,9 +91,9 @@ describe('manager', function() {
           },
           quantity: 2
         }).then(function(car) {
-          assert.equal(color.id, car.related('color').id, 'Color ID should stay the same, not ' + car.related('color').id);
-          assert.equal('Grey', car.related('color').get('name'), 'Color name should be Grey');
-          assert.equal('#666', car.related('color').get('hex_value'), 'Color hex_value should be #666');
+          assert.equal(car.related('color').id, color.id, 'Color ID should stay the same, not ' + car.related('color').id);
+          assert.equal(car.related('color').get('name'), 'Grey', 'Color name should be Grey');
+          assert.equal(car.related('color').get('hex_value'), '#666', 'Color hex_value should be #666');
         });
       });
     });
@@ -92,9 +108,9 @@ describe('manager', function() {
       }).then(function(car) {
         car.related('features').sortBy('name');
 
-        assert.equal(1, car.id, 'Car should have ID 1');
-        assert.equal(2, car.related('features').length, 'There should be 2 features');
-        assert.equal(2, car.related('features').pluck('name').length, 'There should be 2 names');
+        assert.equal(car.id, 1, 'Car should have ID 1');
+        assert.equal(car.related('features').length, 2, 'There should be 2 features');
+        assert.equal(car.related('features').pluck('name').length, 2, 'There should be 2 names');
       });
     });
 
@@ -107,12 +123,12 @@ describe('manager', function() {
       }).then(function(make) {
         make.related('models').sortBy('name');
 
-        assert.equal(1, make.id, 'Make should have ID 1');
-        assert.equal(2, make.related('models').length);
+        assert.equal(make.id, 1, 'Make should have ID 1');
+        assert.equal(make.related('models').length, 2);
         assert.ok(make.related('models').at(0).id, 'Model #1 should have ID, not ' + make.related('models').at(0).id);
         assert.ok(make.related('models').at(1).id, 'Model #2 should have ID, not ' + make.related('models').at(1).id);
-        assert.equal('X3', make.related('models').at(0).get('name'), 'Model #1 name should be X3, not ' + make.related('models').at(0).get('name'));
-        assert.equal('X5', make.related('models').at(1).get('name'), 'Model #2 name should be X5, not ' + make.related('models').at(1).get('name'));
+        assert.equal(make.related('models').at(0).get('name'), 'X3', 'Model #1 name should be X3, not ' + make.related('models').at(0).get('name'));
+        assert.equal(make.related('models').at(1).get('name'), 'X5', 'Model #2 name should be X5, not ' + make.related('models').at(1).get('name'));
       });
     });
 
@@ -169,7 +185,7 @@ describe('manager', function() {
       });
 
       return manager.create(ValidatedModel, { name: 'test' }).then(function(model) {
-        assert.equal('test', model.get('name'), 'Model should have a name of `test`, not `' + model.get('name') + '`');
+        assert.equal(model.get('name'), 'test', 'Model should have a name of `test`, not `' + model.get('name') + '`');
       });
     });
 
@@ -183,7 +199,7 @@ describe('manager', function() {
           },
 
           validateSave: function() {
-            assert.equal('number', typeof this.get('make_id'), 'Model make_id must be a number, not ' + typeof this.get('make_id'));
+            assert.equal(typeof this.get('make_id'), 'number', 'Model make_id must be a number, not ' + typeof this.get('make_id'));
           }
         }), 'model');
         return Bootstrap.tables(manager).then(function() {
@@ -211,7 +227,7 @@ describe('manager', function() {
           },
 
           validateSave: function() {
-            assert.equal('number', typeof this.get('make_id'), 'Model make_id must be a number, not ' + typeof this.get('make_id'));
+            assert.equal(typeof this.get('make_id'), 'number', 'Model make_id must be a number, not ' + typeof this.get('make_id'));
           }
         }), 'model');
         return Bootstrap.tables(manager).then(function() {
@@ -242,16 +258,16 @@ describe('manager', function() {
           }, {
             transacting: t
           }).then(function(car) {
-            assert.equal(color.id, car.related('color').id, 'Color ID should stay the same, not ' + car.related('color').id);
-            assert.equal('Grey', car.related('color').get('name'), 'Color name should be Grey');
-            assert.equal('#666', car.related('color').get('hex_value'), 'Color hex_value should be #666');
+            assert.equal(car.related('color').id, color.id, 'Color ID should stay the same, not ' + car.related('color').id);
+            assert.equal(car.related('color').get('name'), 'Grey', 'Color name should be Grey');
+            assert.equal(car.related('color').get('hex_value'), '#666', 'Color hex_value should be #666');
             throw new Error('test');
           });
         }).catch(function(err) {
           if (!(err instanceof assert.AssertionError)) {
             return manager.fetch('color', { id: color.id }).then(function(color) {
-              assert.equal('White', color.get('name'), 'Color name should be White');
-              assert.equal('#fff', color.get('hex_value'), 'Color hex_value should be #fff');
+              assert.equal(color.get('name'), 'White', 'Color name should be White');
+              assert.equal(color.get('hex_value'), '#fff', 'Color hex_value should be #fff');
             });
           }
           throw err;
diff --git a/test/manager.fetch.js b/test/manager.fetch.js
index 06bfe2c..c67eae4 100644
--- a/test/manager.fetch.js
+++ b/test/manager.fetch.js
@@ -21,7 +21,7 @@ describe('manager', function() {
         })
         .then(function(make) {
           assert.ok(make instanceof manager.bookshelf.Model);
-          assert.equal('BMW', make.get('name'));
+          assert.equal(make.get('name'), 'BMW');
         });
     });
 
@@ -30,8 +30,8 @@ describe('manager', function() {
         .fetch('makes')
         .then(function(makes) {
           assert.ok(makes instanceof manager.bookshelf.Collection);
-          assert.equal(1, makes.length);
-          assert.equal('BMW', makes.get(1).get('name'));
+          assert.equal(makes.length, 1);
+          assert.equal(makes.get(1).get('name'), 'BMW');
         });
     });
 
@@ -44,6 +44,7 @@ describe('manager', function() {
           'models.type',
           'dealers',
           'dealers.cars',
+          'dealers.cars.title',
           'dealers.cars.color',
           'dealers.cars.model',
           'dealers.cars.features',
@@ -52,14 +53,15 @@ describe('manager', function() {
         .then(function(make) {
           var json = make.toJSON();
 
-          assert.equal('BMW',       json.name);
-          assert.equal('X5',        json.models[0].name);
-          assert.equal(2,           json.models[0].specs.length);
-          assert.equal('Crossover', json.models[0].type.name);
-          assert.equal('Houston',   json.dealers[0].name);
-          assert.equal('Grey',      json.dealers[0].cars[0].color.name);
-          assert.equal('X5',        json.dealers[0].cars[0].model.name);
-          assert.equal(2,           json.dealers[0].cars[0].features.length);
+          assert.equal(json.name, 'BMW');
+          assert.equal(json.models[0].name, 'X5');
+          assert.equal(json.models[0].specs.length, 2);
+          assert.equal(json.models[0].type.name, 'Crossover');
+          assert.equal(json.dealers[0].name, 'Houston');
+          assert.equal(json.dealers[0].cars[0].title.state, 'TX');
+          assert.equal(json.dealers[0].cars[0].color.name, 'Grey');
+          assert.equal(json.dealers[0].cars[0].model.name, 'X5');
+          assert.equal(json.dealers[0].cars[0].features.length, 2);
         });
       });
     });
diff --git a/test/manager.forge.js b/test/manager.forge.js
index 4880060..4075785 100644
--- a/test/manager.forge.js
+++ b/test/manager.forge.js
@@ -17,8 +17,8 @@ describe('manager', function() {
       });
 
       assert.ok(manager.isModel(make), 'Expected a Model');
-      assert.equal(undefined, make.get('id'), 'ID should not be defined yet');
-      assert.equal('Ford', make.get('name'), 'Name should be set');
+      assert.equal(make.get('id'), undefined, 'ID should not be defined yet');
+      assert.equal(make.get('name'), 'Ford', 'Name should be set');
     });
   });
 });
diff --git a/test/manager.get.js b/test/manager.get.js
index f6d7867..a40c3fb 100644
--- a/test/manager.get.js
+++ b/test/manager.get.js
@@ -33,13 +33,13 @@ describe('manager', function() {
         it('should return a Model', function() {
           var Model = bookshelf.Model.extend({});
 
-          assert.equal(Model, manager.get(Model));
+          assert.equal(manager.get(Model), Model);
         });
 
         it('should return a Collection', function() {
           var Collection = bookshelf.Collection.extend();
 
-          assert.equal(Collection, manager.get(Collection));
+          assert.equal(manager.get(Collection), Collection);
         });
       });
     });
@@ -73,13 +73,13 @@ describe('manager', function() {
         it('should return a Model', function() {
           var Model = bookshelf.Model.extend({});
 
-          assert.equal(Model, manager.get(Model));
+          assert.equal(manager.get(Model), Model);
         });
 
         it('should return a Collection', function() {
           var Collection = bookshelf.Collection.extend();
 
-          assert.equal(Collection, manager.get(Collection));
+          assert.equal(manager.get(Collection), Collection);
         });
       });
     });
diff --git a/test/manager.register.js b/test/manager.register.js
index d8bbc6a..008af0c 100644
--- a/test/manager.register.js
+++ b/test/manager.register.js
@@ -18,8 +18,8 @@ describe('manager', function() {
   });
 
   describe('.register', function() {
-    it('should return function', function() {
-      assert.equal('function', typeof manager.register(Model, 'fake'));
+    it('should return a function', function() {
+      assert.equal(typeof manager.register(Model, 'fake'), 'function');
     });
 
     it('must be called with both a Model and a model name', function() {
diff --git a/test/manager.save.js b/test/manager.save.js
index d12f595..dff1c7f 100644
--- a/test/manager.save.js
+++ b/test/manager.save.js
@@ -27,7 +27,7 @@ describe('manager', function() {
       var car = manager.forge('car');
 
       return manager.save(car).then(function(car) {
-        assert.equal(2, car.id, 'Car should have an ID of 2, not ' + car.id);
+        assert.equal(car.id, 2, 'Car should have an ID of 2, not ' + car.id);
       });
     });
 
@@ -43,50 +43,60 @@ describe('manager', function() {
           name: 'Chevy'
         });
       }).then(function(make) {
-        assert.equal(original.id, make.id, 'Should have overriden original model ID');
+        assert.equal(make.id, original.id, 'Should have overriden original model ID');
       }).then(function() {
         return manager.fetch('makes');
       }).then(function(makes) {
-        assert.equal(2, makes.length, 'Should only have 2 makes, not ' + makes.length);
+        assert.equal(makes.length, 2, 'Should only have 2 makes, not ' + makes.length);
       });
     });
 
     it('should modify the model', function() {
       return manager.fetch('car', { id: 1 }).then(function(car) {
-        assert.equal(1, car.get('quantity'), 'Car #1 should start with quantity of 1');
+        assert.equal(car.get('quantity'), 1, 'Car #1 should start with quantity of 1');
 
         return manager.save(car, {
           quantity: 2
         });
       }).then(function(car) {
-        assert.equal(2, car.get('quantity'), 'Car #1 should end with quantity of 2');
+        assert.equal(car.get('quantity'), 2, 'Car #1 should end with quantity of 2');
       });
     });
 
-    it('should modify a nested model', function() {
-      return manager.fetch('car', { id: 1 }, 'color').then(function(car) {
-        assert.equal(1, car.related('color').id);
-        assert.equal('Grey', car.related('color').get('name'));
+    it('should modify nested models', function() {
+      return manager.fetch('car', { id: 1 }, ['color', 'title']).then(function(car) {
+        assert.equal(car.related('color').id, 1);
+        assert.equal(car.related('color').get('name'), 'Grey');
+        assert.equal(car.related('title').id, 1);
+        assert.equal(car.related('title').get('state'), 'TX');
 
         return manager.save(car, {
           color: {
             id: 1,
             name: 'Dark Grey'
+          },
+          title: {
+            id: 1,
+            state: 'FL',
+            issue_date: '2017-01-01'
           }
         });
       }).then(function(car) {
         return car.fetch({
-          withRelated: 'color'
+          withRelated: ['color', 'title']
         });
       }).then(function(car) {
-        assert.equal(1, car.related('color').id);
-        assert.equal('Dark Grey', car.related('color').get('name'));
+        assert.equal(car.related('color').id, 1);
+        assert.equal(car.related('color').get('name'), 'Dark Grey');
+        assert.equal(car.related('title').id, 1);
+        assert.equal(car.related('title').get('state'), 'FL');
+        assert.equal(car.related('title').get('issue_date'), '2017-01-01');
       });
     });
 
     it('should modify a deep nested model', function() {
       return manager.fetch('car', { id: 1 }, 'model.type').then(function(car) {
-        assert.equal('Crossover', car.related('model').related('type').get('name'));
+        assert.equal(car.related('model').related('type').get('name'), 'Crossover');
 
         return manager.save(car, {
           model: {
@@ -102,7 +112,7 @@ describe('manager', function() {
           withRelated: 'model.type'
         });
       }).then(function(car) {
-        assert.equal('SUV', car.related('model').related('type').get('name'));
+        assert.equal(car.related('model').related('type').get('name'), 'SUV');
       });
     });
 
@@ -115,19 +125,19 @@ describe('manager', function() {
 
         return manager.save(feature, json);
       }).then(function(feature) {
-        assert.equal('GPSv2', feature.get('name'));
+        assert.equal(feature.get('name'), 'GPSv2');
       });
     });
 
     it('should orphan models in collection', function() {
       return manager.fetch('car', { id: 1 }, 'features').then(function(car) {
-        assert.equal(2, car.related('features').length, 'Car should have 2 existing features');
+        assert.equal(car.related('features').length, 2, 'Car should have 2 existing features');
 
         return manager.save(car, {
           id: 1,
           features: []
         }).then(function(car) {
-          assert.equal(0, car.related('features').length, 'Car should have all features removed, found: ' + car.related('features').toJSON());
+          assert.equal(car.related('features').length, 0, 'Car should have all features removed, found: ' + car.related('features').toJSON());
         });
       });
     });
@@ -142,6 +152,7 @@ describe('manager', function() {
           'models.type',
           'dealers',
           'dealers.cars',
+          'dealers.cars.title',
           'dealers.cars.color',
           'dealers.cars.model',
           'dealers.cars.features',
@@ -153,11 +164,11 @@ describe('manager', function() {
         }).then(function(make) {
           var diffs = deep.diff(expected, make.toJSON()) || [];
 
-          assert.equal(0, diffs.length, diffs);
+          assert.equal(diffs.length, 0, diffs);
 
           return manager.knex('models_specs').select();
         }).then(function(results) {
-          assert.equal(2, results.length, 'Expected only 2 rows in `models_specs`, not ' + results.length);
+          assert.equal(results.length, 2, 'Expected only 2 rows in `models_specs`, not ' + results.length);
         });
     });
 
@@ -171,16 +182,16 @@ describe('manager', function() {
           }, {
             transacting: t
           }).then(function(car) {
-            assert.equal(2, car.get('quantity', 'Car should have quantity 2, got: ' + car.get('quantity')));
-            assert.equal(0, car.related('features').length, 'Car should have all features removed, found: ' + car.related('features').toJSON());
+            assert.equal(car.get('quantity'), 2, 'Car should have quantity 2, got: ' + car.get('quantity'));
+            assert.equal(car.related('features').length, 0, 'Car should have all features removed, found: ' + car.related('features').toJSON());
             throw new Error('test');
           });
         });
       }).catch(function(err) {
         if (!(err instanceof assert.AssertionError)) {
           return manager.fetch('car', { id: 1 }, 'features').then(function(car) {
-            assert.equal(1, car.get('quantity', 'Car should have quantity 1, got: ' + car.get('quantity')));
-            assert.equal(2, car.related('features').length, 'Car should have 2 existing features');
+            assert.equal(car.get('quantity'), 1, 'Car should have quantity 1, got: ' + car.get('quantity'));
+            assert.equal(car.related('features').length, 2, 'Car should have 2 existing features');
           });
         }
         throw err;
@@ -194,7 +205,33 @@ describe('manager', function() {
           name: 'X5',
           type: null
         }).then(function(model) {
-          assert.equal(null, model.get('type_id'));
+          assert.equal(model.get('type_id'), null);
+        });
+      });
+    });
+
+    it('should save a new hasOne model and orphan any existing one if its id is unspecified', function() {
+      return manager.fetch('car', { id: 1 }, 'title').then(function(car) {
+        assert.equal(car.related('title').get('state'), 'TX');
+        return manager.save(car, {
+          title: {
+            state: 'FL',
+            issue_date: '2017-01-01'
+          }
+        });
+      })
+      .then(function() {
+        return manager.fetch('car', { id: 1 }, 'title').then(function(car) {
+          assert.equal(car.related('title').get('id'), 2);
+          assert.equal(car.related('title').get('state'), 'FL');
+          assert.equal(car.related('title').get('issue_date'), '2017-01-01');
+        });
+      })
+      .then(function() {
+        return manager.fetch('title', { id: 1 }).then(function(title) {
+          assert.equal(title.get('car_id'), null);
+          assert.equal(title.get('state'), 'TX');
+          assert.equal(title.get('issue_date'), '2016-09-19');
         });
       });
     });
diff --git a/test/models/car.js b/test/models/car.js
index a2dde46..5f84cc0 100644
--- a/test/models/car.js
+++ b/test/models/car.js
@@ -6,6 +6,10 @@ var Car = function(Bookshelf) {
       quantity: 0
     },
 
+    title: function() {
+      return this.hasOne('title', 'car_id');
+    },
+
     color: function() {
       return this.belongsTo('color');
     },
diff --git a/test/models/title.js b/test/models/title.js
new file mode 100644
index 0000000..4a9651a
--- /dev/null
+++ b/test/models/title.js
@@ -0,0 +1,11 @@
+var Title = function(Bookshelf) {
+  return Bookshelf.Model.extend({
+    tableName: 'titles',
+
+    car: function() {
+      return this.belongsTo('car');
+    }
+  });
+};
+
+module.exports = Title;
diff --git a/test/support/bootstrap.fixtures.js b/test/support/bootstrap.fixtures.js
index 135f871..87cd81c 100644
--- a/test/support/bootstrap.fixtures.js
+++ b/test/support/bootstrap.fixtures.js
@@ -8,6 +8,7 @@ module.exports = function(manager) {
   var specs     = manager.forge('specs',   [ { name: '4 door' }, { name: 'v6' } ]);
   var color     = manager.forge('color',   { name: 'Grey', hex_value: '#666' });
   var dealer    = manager.forge('dealer',  { name: 'Houston', zip_code: '77002' });
+  var title     = manager.forge('title',   { state: 'TX', issue_date: '2016-09-19'});
   var features  = manager.forge('features', [ { name: 'GPS', cost: '500' }, { name: 'ABS', cost: '1250' }]);
   var car       = manager.forge('car');
 
@@ -47,6 +48,10 @@ module.exports = function(manager) {
 
       return car.save();
     })
+    .then(function() {
+      return title.set('car_id', car.get('id'))
+      .save();
+    })
     .then(function() {
       return car.features().attach(features.toArray());
     })
diff --git a/test/support/bootstrap.tables.js b/test/support/bootstrap.tables.js
index 3b3c5ec..862c624 100644
--- a/test/support/bootstrap.tables.js
+++ b/test/support/bootstrap.tables.js
@@ -71,6 +71,14 @@ module.exports = function(manager) {
         table.increments('id');
         table.string('name');
       });
+    })
+    .then(function() {
+      return schema.createTableIfNotExists('titles', function(table) {
+        table.increments('id');
+        table.integer('car_id');
+        table.text('state');
+        table.text('issue_date');
+      });
     });
   });
 };