不要怂,就是干,撸起袖子干!

Commit 4914341e by Daniel Durante

Merge branch 'master' into scopes

Conflicts:
	lib/dao-factory.js
2 parents 7484aded 346fcdb9
......@@ -39,6 +39,7 @@
- [FEATURE] Added a `findAndCountAll`, useful for pagination. [#533](https://github.com/sequelize/sequelize/pull/533). Thanks to iamjochen
- [FEATURE] Made explicit migrations possible. [#728](https://github.com/sequelize/sequelize/pull/728). Thanks to freezy
- [FEATURE] Added support for where clauses containing !=, < etc. and support for date ranges [#727](https://github.com/sequelize/sequelize/pull/727). Thanks to durango
- [FEATURE] Added support for model instances being referenced [#761](https://github.com/sequelize/sequelize/pull/761) thanks to sdepold
- [REFACTORING] hasMany now uses a single SQL statement when creating and destroying associations, instead of removing each association seperately [690](https://github.com/sequelize/sequelize/pull/690). Inspired by [#104](https://github.com/sequelize/sequelize/issues/104). janmeier
- [REFACTORING] Consistent handling of offset across dialects. Offset is now always applied, and limit is set to max table size of not limit is given [#725](https://github.com/sequelize/sequelize/pull/725). janmeier
......
var Toposort = require('toposort-class')
var Toposort = require('toposort-class')
, DaoFactory = require('./dao-factory')
module.exports = (function() {
var DAOFactoryManager = function(sequelize) {
......@@ -39,16 +40,17 @@ module.exports = (function() {
* before dependents.
*/
DAOFactoryManager.prototype.forEachDAO = function(iterator) {
var daos = {}
var daos = {}
, sorter = new Toposort()
this.daos.forEach(function(dao) {
daos[dao.tableName] = dao
var deps = []
for(var attrName in dao.rawAttributes) {
if(dao.rawAttributes.hasOwnProperty(attrName)) {
if(dao.rawAttributes[attrName].references) {
daos[dao.tableName] = dao
for (var attrName in dao.rawAttributes) {
if (dao.rawAttributes.hasOwnProperty(attrName)) {
if (dao.rawAttributes[attrName].references) {
deps.push(dao.rawAttributes[attrName].references)
}
}
......
......@@ -24,22 +24,29 @@ module.exports = (function() {
// error check options
Utils._.each(options.validate, function(validator, validatorType) {
if (Utils._.contains(Utils._.keys(attributes), validatorType))
if (Utils._.contains(Utils._.keys(attributes), validatorType)) {
throw new Error("A model validator function must not have the same name as a field. Model: " + name + ", field/validation name: " + validatorType)
if (!Utils._.isFunction(validator))
}
if (!Utils._.isFunction(validator)) {
throw new Error("Members of the validate option must be functions. Model: " + name + ", error with validate member " + validatorType)
}
})
this.name = name
if (!this.options.tableName) {
this.tableName = this.options.freezeTableName ? name : Utils.pluralize(name, this.options.language)
} else {
this.tableName = this.options.tableName
}
this.rawAttributes = attributes
attributes = replaceReferencesWithTableNames(attributes)
this.rawAttributes = attributes
this.daoFactoryManager = null // defined in init function
this.associations = {}
this.scopeObj = {}
this.associations = {}
this.scopeObj = {}
}
Object.defineProperty(DAOFactory.prototype, 'attributes', {
......@@ -60,8 +67,8 @@ module.exports = (function() {
var self = this;
this.daoFactoryManager = daoFactoryManager
this.primaryKeys = {};
this.primaryKeys = {};
Utils._.each(this.attributes, function(dataTypeString, attributeName) {
if ((attributeName !== 'id') && (dataTypeString.indexOf('PRIMARY KEY') !== -1)) {
self.primaryKeys[attributeName] = dataTypeString
......@@ -80,9 +87,11 @@ module.exports = (function() {
findAutoIncrementField.call(this)
// DAO prototype
// WTF ... ?
this.DAO = function() {
DAO.apply(this, arguments);
};
}
Util.inherits(this.DAO, DAO);
this.DAO.prototype.rawAttributes = this.rawAttributes;
......@@ -94,47 +103,48 @@ module.exports = (function() {
}
Utils._.each(['Get', 'Set'], function(type) {
var prop = type.toLowerCase(),
opt = prop + 'terMethods',
meth = '__define' + type + 'ter__',
funcs = Utils._.isObject(self.options[opt]) ? self.options[opt] : {}
;
var prop = type.toLowerCase()
, opt = prop + 'terMethods'
, meth = '__define' + type + 'ter__'
, funcs = Utils._.isObject(self.options[opt]) ? self.options[opt] : {}
Utils._.each(self.rawAttributes, function(attr, name) {
if (attr.hasOwnProperty(prop))
if (attr.hasOwnProperty(prop)) {
funcs[name] = attr[prop]
});
}
})
Utils._.each(funcs, function(fct, name) {
if (!Utils._.isFunction(fct))
if (!Utils._.isFunction(fct)) {
throw new Error(type + 'ter for "' + name + '" is not a function.')
}
self.DAO.prototype[meth](name, fct);
self.DAO.prototype[meth](name, fct)
})
})
this.DAO.prototype.attributes = Object.keys(this.DAO.prototype.rawAttributes);
this.DAO.prototype.attributes = Object.keys(this.DAO.prototype.rawAttributes);
this.DAO.prototype.booleanValues = []
this.DAO.prototype.defaultValues = {}
this.DAO.prototype.validators = {}
this.DAO.prototype.booleanValues = [];
this.DAO.prototype.defaultValues = {};
this.DAO.prototype.validators = {};
Utils._.each(this.rawAttributes, function (definition, name) {
if (((definition === DataTypes.BOOLEAN) || (definition.type === DataTypes.BOOLEAN))) {
self.DAO.prototype.booleanValues.push(name);
}
if (definition.hasOwnProperty('defaultValue')) {
self.DAO.prototype.defaultValues[name] = function() {
return Utils.toDefaultValue(definition.defaultValue);
return Utils.toDefaultValue(definition.defaultValue)
}
}
if (definition.hasOwnProperty('validate')) {
self.DAO.prototype.validators[name] = definition.validate;
}
});
})
this.DAO.prototype.__factory = this;
this.DAO.prototype.hasDefaultValues = !Utils._.isEmpty(this.DAO.prototype.defaultValues);
this.DAO.prototype.__factory = this
this.DAO.prototype.hasDefaultValues = !Utils._.isEmpty(this.DAO.prototype.defaultValues)
return this
}
......@@ -606,6 +616,10 @@ module.exports = (function() {
return this.QueryInterface.bulkUpdate(this.tableName, attrValueHash, where)
}
DAOFactory.prototype.describe = function() {
return this.QueryInterface.describeTable(this.tableName)
}
// private
var query = function() {
......@@ -713,6 +727,16 @@ module.exports = (function() {
}
}
var replaceReferencesWithTableNames = function(attributes) {
Object.keys(attributes).forEach(function(attrName) {
if (attributes[attrName].references instanceof DAOFactory) {
attributes[attrName].references = attributes[attrName].references.tableName
}
})
return attributes
}
Utils._.extend(DAOFactory.prototype, require("./associations/mixin"))
return DAOFactory
......
......@@ -514,7 +514,6 @@ module.exports = (function() {
if(dataType.references) {
template += " REFERENCES " + this.quoteIdentifier(dataType.references)
if(dataType.referencesKey) {
template += " (" + this.quoteIdentifier(dataType.referencesKey) + ")"
} else {
......
......@@ -183,11 +183,12 @@ module.exports = (function() {
// if you call "define" multiple times for the same daoName, do not clutter the factory
if(this.isDefined(daoName)) {
this.daoFactoryManager.removeDAO(this.daoFactoryManager.getDAO(daoName))
this.daoFactoryManager.removeDAO(this.daoFactoryManager.getDAO(daoName))
}
var factory = new DAOFactory(daoName, attributes, options)
this.daoFactoryManager.addDAO(factory.init(this.daoFactoryManager))
return factory
}
......
......@@ -32,24 +32,24 @@
"url": "https://github.com/sequelize/sequelize/issues"
},
"dependencies": {
"lodash": "~1.2.1",
"lodash": "~1.3.1",
"underscore.string": "~2.3.0",
"lingo": "~0.0.5",
"validator": "1.1.1",
"moment": "~1.7.0",
"commander": "~0.6.0",
"dottie": "0.0.6-1",
"toposort-class": "0.1.4",
"validator": "~1.3.0",
"moment": "~2.1.0",
"commander": "~1.3.0",
"dottie": "0.0.8-0",
"toposort-class": "~0.2.0",
"generic-pool": "2.0.3",
"promise": "~3.0.0"
"promise": "~3.2.0"
},
"devDependencies": {
"jasmine-node": "1.5.0",
"sqlite3": "~2.1.5",
"mysql": "~2.0.0-alpha7",
"pg": "~2.0.0",
"jasmine-node": "~1.10.2",
"sqlite3": "~2.1.12",
"mysql": "~2.0.0-alpha8",
"pg": "~2.1.0",
"buster": "~0.6.3",
"watchr": "~2.2.0",
"watchr": "~2.4.3",
"yuidocjs": "~0.3.36",
"semver": "~2.0.8"
},
......
......@@ -2368,4 +2368,124 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}.bind(this))
})
})
describe('references', function() {
before(function() {
this.Author = this.sequelize.define('author', { firstName: Sequelize.STRING })
})
describe("use of existing dao factory", function() {
before(function() {
this.Post = this.sequelize.define('post', {
title: Sequelize.STRING,
authorId: {
type: Sequelize.INTEGER,
references: this.Author,
referencesKey: "id"
}
})
this.Author.hasMany(this.Post)
this.Post.belongsTo(this.Author)
})
it('references the author table', function(done) {
this.Author.sync({ force: true }).success(function() {
this.Post.sync({ force: true }).on('sql', function(sql) {
if (dialect === 'postgres') {
expect(sql).toMatch(/"authorId" INTEGER REFERENCES "authors" \("id"\)/)
} else if (dialect === 'mysql') {
expect(sql).toMatch(/FOREIGN KEY \(`authorId`\) REFERENCES `authors` \(`id`\)/)
} else if (dialect === 'sqlite') {
expect(sql).toMatch(/`authorId` INTEGER REFERENCES `authors` \(`id`\)/)
} else {
throw new Error('Undefined dialect!')
}
done()
})
}.bind(this))
})
})
describe('use of table name as string', function() {
before(function() {
this.Post = this.sequelize.define('post', {
title: Sequelize.STRING,
authorId: {
type: Sequelize.INTEGER,
references: 'authors',
referencesKey: "id"
}
})
this.Author.hasMany(this.Post)
this.Post.belongsTo(this.Author)
})
it('references the author table', function(done) {
this.Author.sync({ force: true }).success(function() {
this.Post.sync({ force: true }).on('sql', function(sql) {
if (dialect === 'postgres') {
expect(sql).toMatch(/"authorId" INTEGER REFERENCES "authors" \("id"\)/)
} else if (dialect === 'mysql') {
expect(sql).toMatch(/FOREIGN KEY \(`authorId`\) REFERENCES `authors` \(`id`\)/)
} else if (dialect === 'sqlite') {
expect(sql).toMatch(/`authorId` INTEGER REFERENCES `authors` \(`id`\)/)
} else {
throw new Error('Undefined dialect!')
}
done()
})
}.bind(this))
})
})
describe('use of invalid table name', function() {
before(function() {
this.Post = this.sequelize.define('post', {
title: Sequelize.STRING,
authorId: {
type: Sequelize.INTEGER,
references: '4uth0r5',
referencesKey: "id"
}
})
this.Author.hasMany(this.Post)
this.Post.belongsTo(this.Author)
})
it("emits the error event as the referenced table name is invalid", function(done) {
this.Author.sync({ force: true }).success(function() {
this.Post
.sync({ force: true })
.success(function() {
if (dialect === 'sqlite') {
// sorry ... but sqlite is too stupid to understand whats going on ...
expect(1).toEqual(1)
done()
} else {
// the parser should not end up here ...
expect(2).toEqual(1)
}
}).error(function(err) {
if (dialect === 'mysql') {
expect(err.message).toMatch(/ER_CANT_CREATE_TABLE/)
} else if (dialect === 'sqlite') {
// the parser should not end up here ... see above
expect(1).toEqual(2)
} else if (dialect === 'postgres') {
expect(err.message).toMatch(/relation "4uth0r5" does not exist/)
} else {
throw new Error('Undefined dialect!')
}
done()
})
}.bind(this))
})
})
}) //- describe: references
})
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!