fix #429 Multiple Models can't mixin same class

Signed-off-by: Clark Wang <clark.wangs@gmail.com>
This commit is contained in:
Clark Wang 2015-03-11 16:02:00 +08:00
parent 159be756ac
commit 90e169c1a6
2 changed files with 51 additions and 17 deletions

View File

@ -1,4 +1,5 @@
var util = require('util'); var util = require('util');
var _ = require('lodash');
/** /**
* *
* @param newClass * @param newClass
@ -61,7 +62,7 @@ exports.mixin = function (newClass, mixinClass, options) {
if (options.instanceProperties && mixinClass.prototype) { if (options.instanceProperties && mixinClass.prototype) {
mixInto(mixinClass.prototype, newClass.prototype, options); mixInto(mixinClass.prototype, newClass.prototype, options);
} }
return newClass; return newClass;
}; };
@ -75,11 +76,12 @@ function mixInto(sourceScope, targetScope, options) {
var isDelegate = isFunc && targetProperty.value._delegate; var isDelegate = isFunc && targetProperty.value._delegate;
var shouldOverride = options.override || !targetPropertyExists || isDelegate; var shouldOverride = options.override || !targetPropertyExists || isDelegate;
if (propertyName == '_mixins') {
targetScope._mixins = _.union(targetScope._mixins, sourceScope._mixins);
return;
}
if (shouldOverride) { if (shouldOverride) {
if (sourceIsFunc) {
sourceProperty.value = sourceProperty.value;
}
Object.defineProperty(targetScope, propertyName, sourceProperty); Object.defineProperty(targetScope, propertyName, sourceProperty);
} }
}); });

View File

@ -41,7 +41,7 @@ function timestamps(Model, options) {
mixins.define('TimeStamp', timestamps); mixins.define('TimeStamp', timestamps);
describe('Model class', function () { describe('Model class', function () {
it('should define mixins', function() { it('should define mixins', function() {
mixins.define('Example', function(Model, options) { mixins.define('Example', function(Model, options) {
Model.prototype.example = function() { Model.prototype.example = function() {
@ -56,7 +56,7 @@ describe('Model class', function () {
Model.multiMixin[options.key] = options.value; Model.multiMixin[options.key] = options.value;
}); });
}); });
it('should apply a mixin class', function() { it('should apply a mixin class', function() {
var Address = modelBuilder.define('Address', { var Address = modelBuilder.define('Address', {
street: { type: 'string', required: true }, street: { type: 'string', required: true },
@ -69,34 +69,34 @@ describe('Model class', function () {
}); });
var properties = Item.definition.properties; var properties = Item.definition.properties;
properties.street.should.eql({ type: String, required: true }); properties.street.should.eql({ type: String, required: true });
properties.city.should.eql({ type: String, required: true }); properties.city.should.eql({ type: String, required: true });
}); });
it('should apply mixins', function(done) { it('should apply mixins', function(done) {
var memory = new DataSource('mem', {connector: Memory}, modelBuilder); var memory = new DataSource('mem', {connector: Memory}, modelBuilder);
var Item = memory.createModel('Item', { name: 'string' }, { var Item = memory.createModel('Item', { name: 'string' }, {
mixins: { mixins: {
TimeStamp: true, Demo: { value: true }, TimeStamp: true, Demo: { value: true },
Multi: [ Multi: [
{ key: 'foo', value: 'bar' }, { key: 'foo', value: 'bar' },
{ key: 'fox', value: 'baz' } { key: 'fox', value: 'baz' }
] ]
} }
}); });
Item.mixin('Example', { foo: 'bar' }); Item.mixin('Example', { foo: 'bar' });
Item.demoMixin.should.be.true; Item.demoMixin.should.be.true;
Item.multiMixin.foo.should.equal('bar'); Item.multiMixin.foo.should.equal('bar');
Item.multiMixin.fox.should.equal('baz'); Item.multiMixin.fox.should.equal('baz');
var properties = Item.definition.properties; var properties = Item.definition.properties;
properties.createdAt.should.eql({ type: Date }); properties.createdAt.should.eql({ type: Date });
properties.updatedAt.should.eql({ type: Date }); properties.updatedAt.should.eql({ type: Date });
Item.create({ name: 'Item 1' }, function(err, inst) { Item.create({ name: 'Item 1' }, function(err, inst) {
inst.createdAt.should.be.a.date; inst.createdAt.should.be.a.date;
inst.updatedAt.should.be.a.date; inst.updatedAt.should.be.a.date;
@ -104,5 +104,37 @@ describe('Model class', function () {
done(); done();
}); });
}); });
describe('#mixin()', function () {
var Person, Author, Address;
beforeEach(function () {
Address = modelBuilder.define('Address', {
street: { type: 'string', required: true },
city: { type: 'string', required: true }
});
var memory = new DataSource('mem', {connector: Memory}, modelBuilder);
Person = memory.createModel('Person', { name: 'string' });
Author = memory.createModel('Author', { name: 'string' });
});
it('should register mixin class into _mixins', function () {
Person.mixin(Address);
Person._mixins.should.containEql(Address);
});
it('should NOT share mixins registry', function () {
Person.mixin(Address);
Author._mixins.should.not.containEql(Address);
});
it('should able to mixin same class', function () {
Person.mixin(Address);
Author.mixin(Address);
Author._mixins.should.containEql(Address);
});
});
}); });