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

Commit c8a56445 by Sascha Depold

Deprecate the old references format

1 parent 48f39859
......@@ -333,11 +333,15 @@ module.exports = (function() {
}
// handle self referential constraints
if (attribute.Model && attribute.references && attribute.Model.tableName === attribute.references.model) {
this.sequelize.log('MSSQL does not support self referencial constraints, '
+ 'we will remove it but we recommend restructuring your query');
attribute.onDelete = '';
attribute.onUpdate = '';
if (attribute.references) {
attribute = Utils.formatReferences(attribute);
if (attribute.Model && attribute.Model.tableName === attribute.references.model) {
this.sequelize.log('MSSQL does not support self referencial constraints, '
+ 'we will remove it but we recommend restructuring your query');
attribute.onDelete = '';
attribute.onUpdate = '';
}
}
var template;
......@@ -410,6 +414,8 @@ module.exports = (function() {
attribute = attributes[key];
if (attribute.references) {
attribute = Utils.formatReferences(attributes[key]);
if (existingConstraints.indexOf(attribute.references.model.toString()) !== -1) {
// no cascading constraints to a table more than once
attribute.onDelete = '';
......
......@@ -292,6 +292,7 @@ module.exports = (function() {
}
if (attribute.references) {
attribute = Utils.formatReferences(attribute);
template += ' REFERENCES ' + this.quoteTable(attribute.references.model);
if (attribute.references.key) {
......
......@@ -510,6 +510,7 @@ module.exports = (function() {
}
if (attribute.references) {
attribute = Utils.formatReferences(attribute);
template += ' REFERENCES <%= referencesTable %> (<%= referencesKey %>)';
replacements.referencesTable = this.quoteTable(attribute.references.model);
......
......@@ -251,6 +251,7 @@ module.exports = (function() {
}
if(dataType.references) {
dataType = Utils.formatReferences(dataType);
template += ' REFERENCES <%= referencesTable %> (<%= referencesKey %>)';
replacements.referencesTable = this.quoteTable(dataType.references.model);
......
'use strict';
var Toposort = require('toposort-class')
, Utils = require('./utils')
, _ = require('lodash');
module.exports = (function() {
......@@ -67,13 +68,16 @@ module.exports = (function() {
for (var attrName in model.rawAttributes) {
if (model.rawAttributes.hasOwnProperty(attrName)) {
if (model.rawAttributes[attrName].references) {
dep = model.rawAttributes[attrName].references.model;
var attribute = model.rawAttributes[attrName];
if (attribute.references) {
attribute = Utils.formatReferences(attribute);
dep = attribute.references.model;
if (_.isObject(dep)) {
dep = dep.schema + '.' + dep.tableName;
}
deps.push(dep);
}
}
......
......@@ -72,10 +72,15 @@ module.exports = (function() {
if (!Utils._.isPlainObject(attribute)) {
attribute = { type: attribute };
}
attribute = this.sequelize.normalizeAttribute(attribute);
if (attribute.references && (attribute.references.model instanceof Model)) {
attribute.references.model = attribute.references.model.tableName;
if (attribute.references) {
attribute = Utils.formatReferences(attribute);
if (attribute.references.model instanceof Model) {
attribute.references.model = attribute.references.model.tableName;
}
}
if (attribute.type === undefined) {
......
......@@ -7,7 +7,8 @@ var DataTypes = require('./data-types')
, inflection = require('inflection')
, _ = require('lodash')
, dottie = require('dottie')
, uuid = require('node-uuid');
, uuid = require('node-uuid')
, deprecate = require('depd')('Utils');
var Utils = module.exports = {
inflection: inflection,
......@@ -394,24 +395,13 @@ var Utils = module.exports = {
},
formatReferences: function (obj) {
var references = {};
if (!obj || !_.isPlainObject(obj) || !obj.references) {
return obj;
}
if (_.isPlainObject(obj.references)) {
references = obj.references;
} else {
references.model = obj.references;
}
if (obj.referencesKey) {
references.key = obj.referencesKey;
delete obj.referencesKey;
if (!_.isPlainObject(obj.references)) {
deprecate('Non-object references property found. Support for that will be removed in version 4. Expected { references: { model: "value", key: "key" } } instead of { references: "value", referencesKey: "key" }.');
obj.references = { model: obj.references, key: obj.referencesKey };
obj.referencesKey = undefined;
}
return _.extend(obj, { references: references });
return obj;
}
};
......
......@@ -33,6 +33,7 @@
},
"dependencies": {
"bluebird": "~2.9.24",
"depd": "^1.0.1",
"dottie": "^0.3.1",
"generic-pool": "2.2.0",
"inflection": "^1.6.0",
......@@ -40,9 +41,9 @@
"moment": "^2.9.0",
"moment-timezone": "^0.3.1",
"node-uuid": "~1.4.1",
"shimmer": "1.0.0",
"toposort-class": "~0.3.0",
"validator": "^3.34.0",
"shimmer": "1.0.0"
"validator": "^3.34.0"
},
"devDependencies": {
"chai": "^2.1.2",
......
......@@ -43,6 +43,30 @@ if (Support.dialectIsMySQL()) {
arguments: [{id: {type: 'INTEGER', unique: true}}],
expectation: {id: 'INTEGER UNIQUE'}
},
// Old references style
{
arguments: [{id: {type: 'INTEGER', references: 'Bar'}}],
expectation: {id: 'INTEGER REFERENCES `Bar` (`id`)'}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', referencesKey: 'pk'}}],
expectation: {id: 'INTEGER REFERENCES `Bar` (`pk`)'}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', onDelete: 'CASCADE'}}],
expectation: {id: 'INTEGER REFERENCES `Bar` (`id`) ON DELETE CASCADE'}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', onUpdate: 'RESTRICT'}}],
expectation: {id: 'INTEGER REFERENCES `Bar` (`id`) ON UPDATE RESTRICT'}
},
{
arguments: [{id: {type: 'INTEGER', allowNull: false, autoIncrement: true, defaultValue: 1, references: 'Bar', onDelete: 'CASCADE', onUpdate: 'RESTRICT'}}],
expectation: {id: 'INTEGER NOT NULL auto_increment DEFAULT 1 REFERENCES `Bar` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT'}
},
// New references style
{
arguments: [{id: {type: 'INTEGER', references: { model: 'Bar' }}}],
expectation: {id: 'INTEGER REFERENCES `Bar` (`id`)'}
......@@ -62,7 +86,7 @@ if (Support.dialectIsMySQL()) {
{
arguments: [{id: {type: 'INTEGER', allowNull: false, autoIncrement: true, defaultValue: 1, references: { model: 'Bar' }, onDelete: 'CASCADE', onUpdate: 'RESTRICT'}}],
expectation: {id: 'INTEGER NOT NULL auto_increment DEFAULT 1 REFERENCES `Bar` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT'}
}
},
],
createTableQuery: [
......
......@@ -57,6 +57,57 @@ if (dialect.match(/^postgres/)) {
arguments: [{id: {type: 'INTEGER', unique: true}}],
expectation: {id: 'INTEGER UNIQUE'}
},
// Old references style
{
arguments: [{id: {type: 'INTEGER', references: 'Bar'}}],
expectation: {id: 'INTEGER REFERENCES "Bar" ("id")'}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', referencesKey: 'pk'}}],
expectation: {id: 'INTEGER REFERENCES "Bar" ("pk")'}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', onDelete: 'CASCADE'}}],
expectation: {id: 'INTEGER REFERENCES "Bar" ("id") ON DELETE CASCADE'}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', onUpdate: 'RESTRICT'}}],
expectation: {id: 'INTEGER REFERENCES "Bar" ("id") ON UPDATE RESTRICT'}
},
{
arguments: [{id: {type: 'INTEGER', allowNull: false, defaultValue: 1, references: 'Bar', onDelete: 'CASCADE', onUpdate: 'RESTRICT'}}],
expectation: {id: 'INTEGER NOT NULL DEFAULT 1 REFERENCES "Bar" ("id") ON DELETE CASCADE ON UPDATE RESTRICT'}
},
// Variants when quoteIdentifiers is false
{
arguments: [{id: {type: 'INTEGER', references: 'Bar'}}],
expectation: {id: 'INTEGER REFERENCES Bar (id)'},
context: {options: {quoteIdentifiers: false}}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', referencesKey: 'pk'}}],
expectation: {id: 'INTEGER REFERENCES Bar (pk)'},
context: {options: {quoteIdentifiers: false}}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', onDelete: 'CASCADE'}}],
expectation: {id: 'INTEGER REFERENCES Bar (id) ON DELETE CASCADE'},
context: {options: {quoteIdentifiers: false}}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', onUpdate: 'RESTRICT'}}],
expectation: {id: 'INTEGER REFERENCES Bar (id) ON UPDATE RESTRICT'},
context: {options: {quoteIdentifiers: false}}
},
{
arguments: [{id: {type: 'INTEGER', allowNull: false, defaultValue: 1, references: 'Bar', onDelete: 'CASCADE', onUpdate: 'RESTRICT'}}],
expectation: {id: 'INTEGER NOT NULL DEFAULT 1 REFERENCES Bar (id) ON DELETE CASCADE ON UPDATE RESTRICT'},
context: {options: {quoteIdentifiers: false}}
},
// New references style
{
arguments: [{id: {type: 'INTEGER', references: { model: 'Bar' }}}],
expectation: {id: 'INTEGER REFERENCES "Bar" ("id")'}
......@@ -104,7 +155,6 @@ if (dialect.match(/^postgres/)) {
expectation: {id: 'INTEGER NOT NULL DEFAULT 1 REFERENCES Bar (id) ON DELETE CASCADE ON UPDATE RESTRICT'},
context: {options: {quoteIdentifiers: false}}
}
],
createTableQuery: [
......
......@@ -53,6 +53,30 @@ if (dialect === 'sqlite') {
arguments: [{id: {type: 'INTEGER', unique: true}}],
expectation: {id: 'INTEGER UNIQUE'}
},
// Old references style
{
arguments: [{id: {type: 'INTEGER', references: 'Bar'}}],
expectation: {id: 'INTEGER REFERENCES `Bar` (`id`)'}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', referencesKey: 'pk'}}],
expectation: {id: 'INTEGER REFERENCES `Bar` (`pk`)'}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', onDelete: 'CASCADE'}}],
expectation: {id: 'INTEGER REFERENCES `Bar` (`id`) ON DELETE CASCADE'}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', onUpdate: 'RESTRICT'}}],
expectation: {id: 'INTEGER REFERENCES `Bar` (`id`) ON UPDATE RESTRICT'}
},
{
arguments: [{id: {type: 'INTEGER', allowNull: false, defaultValue: 1, references: 'Bar', onDelete: 'CASCADE', onUpdate: 'RESTRICT'}}],
expectation: {id: 'INTEGER NOT NULL DEFAULT 1 REFERENCES `Bar` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT'}
},
// New references style
{
arguments: [{id: {type: 'INTEGER', references: { model: 'Bar' }}}],
expectation: {id: 'INTEGER REFERENCES `Bar` (`id`)'}
......@@ -72,7 +96,7 @@ if (dialect === 'sqlite') {
{
arguments: [{id: {type: 'INTEGER', allowNull: false, defaultValue: 1, references: { model: 'Bar' }, onDelete: 'CASCADE', onUpdate: 'RESTRICT'}}],
expectation: {id: 'INTEGER NOT NULL DEFAULT 1 REFERENCES `Bar` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT'}
}
},
],
createTableQuery: [
......
......@@ -1212,6 +1212,7 @@ describe(Support.getTestDialectTeaser('Includes with schemas'), function() {
});
describe('findOne', function() {
([ true, false ]).forEach(function (useNewReferencesStyle) {
it('should work with schemas', function() {
var self = this;
var UserModel = this.sequelize.define('User', {
......@@ -1234,18 +1235,17 @@ describe(Support.getTestDialectTeaser('Includes with schemas'), function() {
timestamps: false
});
var UserIdColumn = useNewReferencesStyle
? { type: Sequelize.INTEGER, references: UserModel, referencesKey: 'Id' }
: { type: Sequelize.INTEGER, references: { model: UserModel, key: 'Id' } }
;
var ResumeModel = this.sequelize.define('Resume', {
Id: {
type: Sequelize.INTEGER,
primaryKey: true
},
UserId: {
type: Sequelize.INTEGER,
references: {
model: UserModel,
key: 'Id'
}
},
UserId: UserIdColumn,
Name: Sequelize.STRING,
Contact: Sequelize.STRING,
School: Sequelize.STRING,
......@@ -1285,5 +1285,6 @@ describe(Support.getTestDialectTeaser('Includes with schemas'), function() {
});
});
});
});
});
});
......@@ -2178,17 +2178,17 @@ describe(Support.getTestDialectTeaser('Model'), function() {
});
});
([ true, false ]).forEach(function (useNewReferencesStyle) {
it('uses an existing dao factory and references the author table', function() {
var authorIdColumn = useNewReferencesStyle
? { type: Sequelize.INTEGER, references: this.Author, referencesKey: 'id' }
: { type: Sequelize.INTEGER, references: { model: this.Author, key: 'id' } }
;
var Post = this.sequelize.define('post', {
title: Sequelize.STRING,
authorId: {
type: Sequelize.INTEGER,
references: {
model: this.Author,
key: 'id'
}
}
});
title: Sequelize.STRING,
authorId: authorIdColumn
});
this.Author.hasMany(Post);
Post.belongsTo(this.Author);
......@@ -2210,17 +2210,13 @@ describe(Support.getTestDialectTeaser('Model'), function() {
});
it('uses a table name as a string and references the author table', function() {
var authorIdColumn = useNewReferencesStyle
? { type: Sequelize.INTEGER, references: 'authors', referencesKey: 'id' }
: { type: Sequelize.INTEGER, references: { model: 'authors', key: 'id' } }
;
var self = this
, Post = self.sequelize.define('post', {
title: Sequelize.STRING,
authorId: {
type: Sequelize.INTEGER,
references: {
model: 'authors',
key: 'id'
}
}
});
, Post = self.sequelize.define('post', { title: Sequelize.STRING, authorId: authorIdColumn });
this.Author.hasMany(Post);
Post.belongsTo(this.Author);
......@@ -2242,16 +2238,12 @@ describe(Support.getTestDialectTeaser('Model'), function() {
});
it('emits an error event as the referenced table name is invalid', function() {
var Post = this.sequelize.define('post', {
title: Sequelize.STRING,
authorId: {
type: Sequelize.INTEGER,
references: {
model: '4uth0r5',
key: 'id'
}
}
});
var authorIdColumn = useNewReferencesStyle
? { type: Sequelize.INTEGER, references: '4uth0r5', referencesKey: 'id' }
: { type: Sequelize.INTEGER, references: { model: '4uth0r5', key: 'id' } }
;
var Post = this.sequelize.define('post', { title: Sequelize.STRING, authorId: authorIdColumn });
this.Author.hasMany(Post);
Post.belongsTo(this.Author);
......@@ -2288,23 +2280,27 @@ describe(Support.getTestDialectTeaser('Model'), function() {
it('works with comments', function() {
// Test for a case where the comment was being moved to the end of the table when there was also a reference on the column, see #1521
// jshint ignore:start
var Member = this.sequelize.define('Member', {})
, Profile = this.sequelize.define('Profile', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
references: {
model: Member,
key: 'id'
},
autoIncrement: false,
comment: 'asdf'
}
});
var Member = this.sequelize.define('Member', {});
var idColumn = {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: false,
comment: 'asdf'
};
if (useNewReferencesStyle) {
idColumn.references = { model: Member, key: 'id' };
} else {
idColumn.references = Member;
idColumn.referencesKey = 'id';
}
var Profile = this.sequelize.define('Profile', { id: idColumn });
// jshint ignore:end
return this.sequelize.sync({ force: true });
});
});
});
describe('blob', function() {
......
......@@ -189,26 +189,4 @@ describe(Support.getTestDialectTeaser('Utils'), function() {
expect(Utils.singularize('status')).to.equal('status');
});
});
describe('formatReferences', function () {
([
[undefined, undefined],
[false, false],
[null, null],
['a', 'a'],
[{}, {}],
[{a: 1}, {a: 1}],
[{referencesKey: 1}, {referencesKey: 1}],
[{references: 'a'}, {references: {model: 'a'}}],
[{references: 'a', referencesKey: 1}, {references: {model: 'a', key: 1}}],
[{references: {model: 1}}, {references: {model: 1}}]
]).forEach(function (test) {
var input = test[0];
var output = test[1];
it('converts ' + JSON.stringify(input) + ' to ' + JSON.stringify(output), function () {
expect(Utils.formatReferences(input)).to.deep.equal(output);
});
});
});
});
'use strict';
/* jshint -W030 */
/* jshint -W110 */
var chai = require('chai')
, expect = chai.expect
, Utils = require(__dirname + '/../../lib/utils')
, Support = require(__dirname + '/support');
describe(Support.getTestDialectTeaser('Utils'), function() {
describe('formatReferences', function () {
([
[{referencesKey: 1}, {references: {model: undefined, key: 1}, referencesKey: undefined}],
[{references: 'a'}, {references: {model: 'a', key: undefined}, referencesKey: undefined}],
[{references: 'a', referencesKey: 1}, {references: {model: 'a', key: 1}, referencesKey: undefined}],
[{references: {model: 1}}, {references: {model: 1}}]
]).forEach(function (test) {
var input = test[0];
var output = test[1];
it('converts ' + JSON.stringify(input) + ' to ' + JSON.stringify(output), function () {
expect(Utils.formatReferences(input)).to.deep.equal(output);
});
});
});
});
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!