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

Commit 209069e1 by Jan Aagaard Meier

Pleasing code climate, abstracting duplicated code

1 parent 82b29168
...@@ -65,9 +65,7 @@ module.exports = (function() { ...@@ -65,9 +65,7 @@ module.exports = (function() {
// Sync attributes and setters/getters to DAO prototype // Sync attributes and setters/getters to DAO prototype
this.source.refreshAttributes(); this.source.refreshAttributes();
if (this.source.rawAttributes.hasOwnProperty(this.as)) { Helpers.checkNamingCollision(this);
throw new Error("Naming collision between attribute '" + this.as + "' and association '" + this.as + "' on model " + this.source.name + '. To remedy this, change either foreignKey or as in your association definition');
}
return this; return this;
}; };
......
...@@ -261,9 +261,7 @@ module.exports = (function() { ...@@ -261,9 +261,7 @@ module.exports = (function() {
this.target.refreshAttributes(); this.target.refreshAttributes();
this.source.refreshAttributes(); this.source.refreshAttributes();
if (this.source.rawAttributes.hasOwnProperty(this.as)) { Helpers.checkNamingCollision(this);
throw new Error("Naming collision between attribute '" + this.as + "' and association '" + this.as + "' on model " + this.source.name + '. To remedy this, change either foreignKey or as in your association definition');
}
return this; return this;
}; };
......
...@@ -67,9 +67,7 @@ module.exports = (function() { ...@@ -67,9 +67,7 @@ module.exports = (function() {
// Sync attributes and setters/getters to DAO prototype // Sync attributes and setters/getters to DAO prototype
this.target.refreshAttributes(); this.target.refreshAttributes();
if (this.source.rawAttributes.hasOwnProperty(this.as)) { Helpers.checkNamingCollision(this);
throw new Error("Naming collision between attribute '" + this.as + "' and association '" + this.as + "' on model " + this.source.name + '. To remedy this, change either foreignKey or as in your association definition');
}
return this; return this;
}; };
...@@ -112,11 +110,11 @@ module.exports = (function() { ...@@ -112,11 +110,11 @@ module.exports = (function() {
}).then(function() { }).then(function() {
if (associatedInstance) { if (associatedInstance) {
if (!(associatedInstance instanceof association.target.Instance)) { if (!(associatedInstance instanceof association.target.Instance)) {
var tmpInstance = {}; var tmpInstance = {};
tmpInstance[association.target.primaryKeyAttribute] = associatedInstance; tmpInstance[association.target.primaryKeyAttribute] = associatedInstance;
associatedInstance = association.target.build(tmpInstance, { associatedInstance = association.target.build(tmpInstance, {
isNewRecord: false isNewRecord: false
}); });
} }
associatedInstance.set(association.identifier, instance.get(association.sourceIdentifier)); associatedInstance.set(association.identifier, instance.get(association.sourceIdentifier));
return associatedInstance.save(options); return associatedInstance.save(options);
......
...@@ -3,6 +3,11 @@ ...@@ -3,6 +3,11 @@
var Utils = require('./../utils'); var Utils = require('./../utils');
module.exports = { module.exports = {
checkNamingCollision: function (assocition) {
if (assocition.source.rawAttributes.hasOwnProperty(assocition.as)) {
throw new Error("Naming collision between attribute '" + assocition.as + "' and association '" + assocition.as + "' on model " + assocition.source.name + '. To remedy this, change either foreignKey or as in your association definition');
}
},
addForeignKeyConstraints: function(newAttribute, source, target, options) { addForeignKeyConstraints: function(newAttribute, source, target, options) {
// FK constraints are opt-in: users must either set `foreignKeyConstraints` // FK constraints are opt-in: users must either set `foreignKeyConstraints`
......
...@@ -36,25 +36,25 @@ var Utils = require('./../utils') ...@@ -36,25 +36,25 @@ var Utils = require('./../utils')
* ] * ]
* }) * })
* ``` * ```
* To get full control over the foreign key column added by sequelize, you can use the `foreignKey` option. It can either be a string, that specifies the name, or and object type definition, * To get full control over the foreign key column added by sequelize, you can use the `foreignKey` option. It can either be a string, that specifies the name, or and object type definition,
* equivalent to those passed to `sequelize.define`. * equivalent to those passed to `sequelize.define`.
* *
* ```js * ```js
* User.hasMany(Picture, { foreignKey: 'uid' }) * User.hasMany(Picture, { foreignKey: 'uid' })
* ``` * ```
* *
* The foreign key column in Picture will now be called `uid` instead of the default `userId`. * The foreign key column in Picture will now be called `uid` instead of the default `userId`.
* *
* ```js * ```js
* User.hasMany(Picture, { * User.hasMany(Picture, {
* foreignKey: { * foreignKey: {
* fieldName: 'uid' * fieldName: 'uid'
* allowNull: false * allowNull: false
* } * }
* }) * })
* ``` * ```
* *
* This specifies that the `uid` column can not be null. In most cases this will already be covered by the foreign key costraints, which sequelize creates automatically, * This specifies that the `uid` column can not be null. In most cases this will already be covered by the foreign key costraints, which sequelize creates automatically,
* but can be usefull in case where the foreign keys are disabled, e.g. due to circular references (see `constraints: false` below). * but can be usefull in case where the foreign keys are disabled, e.g. due to circular references (see `constraints: false` below).
* *
* When fetching associated models, you can limit your query to only load some models. These queries are written in the same way as queries to `find`/`findAll`. To only get pictures in JPG, you can do: * When fetching associated models, you can limit your query to only load some models. These queries are written in the same way as queries to `find`/`findAll`. To only get pictures in JPG, you can do:
...@@ -93,6 +93,31 @@ var Utils = require('./../utils') ...@@ -93,6 +93,31 @@ var Utils = require('./../utils')
*/ */
var Mixin = module.exports = function() {}; var Mixin = module.exports = function() {};
// The logic for hasOne and belongsTo is exactly the same
var singleLinked = function (Type) {
return function(targetModel, options) {
if (!(targetModel instanceof this.sequelize.Model)) {
throw new Error(this.name + "." + Utils._.lowercaseFirst(Type.toString()) + " called with something that's not an instance of Sequelize.Model");
}
var sourceModel = this;
// Since this is a mixin, we'll need a unique variable name for hooks (since Model will override our hooks option)
options = options || {};
options.hooks = options.hooks === undefined ? false : Boolean(options.hooks);
options.useHooks = options.hooks;
// the id is in the foreign table
var association = new Type(sourceModel, targetModel, Utils._.extend(options, sourceModel.options));
sourceModel.associations[association.associationAccessor] = association.injectAttributes();
association.injectGetter(sourceModel.Instance.prototype);
association.injectSetter(sourceModel.Instance.prototype);
association.injectCreator(sourceModel.Instance.prototype);
return association;
};
};
/** /**
* Creates an association between this (the source) and the provided target. The foreign key is added on the target. * Creates an association between this (the source) and the provided target. The foreign key is added on the target.
* *
...@@ -115,28 +140,7 @@ var Mixin = module.exports = function() {}; ...@@ -115,28 +140,7 @@ var Mixin = module.exports = function() {};
* @param {string} [options.onUpdate='CASCADE'] * @param {string} [options.onUpdate='CASCADE']
* @param {boolean} [options.constraints=true] Should on update and on delete constraints be enabled on the foreign key. * @param {boolean} [options.constraints=true] Should on update and on delete constraints be enabled on the foreign key.
*/ */
Mixin.hasOne = function(targetModel, options) { Mixin.hasOne = singleLinked(HasOne);
if (!(targetModel instanceof this.sequelize.Model)) {
throw new Error(this.name + ".hasOne called with something that's not an instance of Sequelize.Model");
}
var sourceModel = this;
// Since this is a mixin, we'll need a unique variable name for hooks (since Model will override our hooks option)
options = options || {};
options.hooks = options.hooks === undefined ? false : Boolean(options.hooks);
options.useHooks = options.hooks;
// the id is in the foreign table
var association = new HasOne(sourceModel, targetModel, Utils._.extend(options, sourceModel.options));
sourceModel.associations[association.associationAccessor] = association.injectAttributes();
association.injectGetter(sourceModel.Instance.prototype);
association.injectSetter(sourceModel.Instance.prototype);
association.injectCreator(sourceModel.Instance.prototype);
return association;
};
/** /**
* Creates an association between this (the source) and the provided target. The foreign key is added on the source. * Creates an association between this (the source) and the provided target. The foreign key is added on the source.
...@@ -160,28 +164,7 @@ Mixin.hasOne = function(targetModel, options) { ...@@ -160,28 +164,7 @@ Mixin.hasOne = function(targetModel, options) {
* @param {string} [options.onUpdate='CASCADE'] * @param {string} [options.onUpdate='CASCADE']
* @param {boolean} [options.constraints=true] Should on update and on delete constraints be enabled on the foreign key. * @param {boolean} [options.constraints=true] Should on update and on delete constraints be enabled on the foreign key.
*/ */
Mixin.belongsTo = function(targetModel, options) { Mixin.belongsTo = singleLinked(BelongsTo);
if (!(targetModel instanceof this.sequelize.Model)) {
throw new Error(this.name + ".belongsTo called with something that's not an instance of Sequelize.Model");
}
var sourceModel = this;
// Since this is a mixin, we'll need a unique variable name for hooks (since Model will override our hooks option)
options = options || {};
options.hooks = options.hooks === undefined ? false : Boolean(options.hooks);
options.useHooks = options.hooks;
// the id is in this table
var association = new BelongsTo(sourceModel, targetModel, Utils._.extend(options, sourceModel.options));
sourceModel.associations[association.associationAccessor] = association.injectAttributes();
association.injectGetter(sourceModel.Instance.prototype);
association.injectSetter(sourceModel.Instance.prototype);
association.injectCreator(sourceModel.Instance.prototype);
return association;
};
/** /**
* Create an association that is either 1:m or n:m. * Create an association that is either 1:m or n:m.
......
...@@ -881,7 +881,7 @@ module.exports = (function() { ...@@ -881,7 +881,7 @@ module.exports = (function() {
if (childJoinQueries.mainQuery) { if (childJoinQueries.mainQuery) {
joinQueries.mainQuery = joinQueries.mainQuery.concat(childJoinQueries.mainQuery); joinQueries.mainQuery = joinQueries.mainQuery.concat(childJoinQueries.mainQuery);
} }
}.bind(this)); }.bind(this));
} }
...@@ -1338,11 +1338,11 @@ module.exports = (function() { ...@@ -1338,11 +1338,11 @@ module.exports = (function() {
}, },
arrayValue: function(value, key, _key, factory, logicResult) { arrayValue: function(value, key, _key, factory, logicResult) {
var _value = null; var _value = null;
if (value.length === 0) { value = [null]; } if (value.length === 0) { value = [null]; }
_value = '(' + value.map(function(v) { return this.escape(v); }.bind(this)).join(',') + ')'; _value = '(' + value.map(function(v) { return this.escape(v); }.bind(this)).join(',') + ')';
return [_key, _value].join(' ' + logicResult + ' '); return [_key, _value].join(' ' + logicResult + ' ');
}, },
/* /*
......
...@@ -399,7 +399,7 @@ module.exports = (function() { ...@@ -399,7 +399,7 @@ module.exports = (function() {
includeMap[key] = $current = $current.includeMap[piece]; includeMap[key] = $current = $current.includeMap[piece];
if (previousPiece) { if (previousPiece) {
previousPiece = previousPiece+'.'+piece; previousPiece = previousPiece+'.'+piece;
} else { } else {
previousPiece = piece; previousPiece = piece;
} }
includeMap[previousPiece] = $current; includeMap[previousPiece] = $current;
......
...@@ -198,7 +198,7 @@ module.exports = (function() { ...@@ -198,7 +198,7 @@ module.exports = (function() {
}, },
deleteQuery: function(tableName, where, options) { deleteQuery: function(tableName, where, options) {
options = options ||  {}; options = options || {};
var table = this.quoteTable(tableName); var table = this.quoteTable(tableName);
if (options.truncate === true) { if (options.truncate === true) {
......
...@@ -206,7 +206,7 @@ module.exports = (function() { ...@@ -206,7 +206,7 @@ module.exports = (function() {
}, },
deleteQuery: function(tableName, where, options) { deleteQuery: function(tableName, where, options) {
options = options || {}; options = options || {};
var query = "DELETE FROM <%= table %> WHERE <%= where %>"; var query = "DELETE FROM <%= table %> WHERE <%= where %>";
var replacements = { var replacements = {
......
...@@ -152,7 +152,7 @@ SequelizePromise.prototype.proxy = function(promise, options) { ...@@ -152,7 +152,7 @@ SequelizePromise.prototype.proxy = function(promise, options) {
options = Utils._.extend({ options = Utils._.extend({
events: proxyEventKeys, events: proxyEventKeys,
skipEvents: [] skipEvents: []
}, options ||  {}); }, options || {});
options.events = Utils._.difference(options.events, options.skipEvents); options.events = Utils._.difference(options.events, options.skipEvents);
......
...@@ -9,7 +9,7 @@ var Utils = require('./utils') ...@@ -9,7 +9,7 @@ var Utils = require('./utils')
* To run a query under a transaction, you should pass the transaction in the options object. * To run a query under a transaction, you should pass the transaction in the options object.
* @class Transaction * @class Transaction
*/ */
var Transaction = module.exports = function(sequelize, options) { var Transaction = module.exports = function(sequelize, options) {
this.sequelize = sequelize; this.sequelize = sequelize;
this.options = Utils._.extend({ this.options = Utils._.extend({
autocommit: true, autocommit: true,
......
...@@ -16,6 +16,9 @@ var Utils = module.exports = { ...@@ -16,6 +16,9 @@ var Utils = module.exports = {
_.mixin(_s.exports()); _.mixin(_s.exports());
_.mixin({ _.mixin({
includes: _s.include, includes: _s.include,
lowercaseFirst: function (s) {
return s[0].toLowerCase() + s.slice(1);
},
camelizeIf: function(string, condition) { camelizeIf: function(string, condition) {
var result = string; var result = string;
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!