Since the release of v1.6.0
in April 2013, many new features have
been added to Sequelize. This was mostly possible due to the great
help of the community. Furthermore Daniel Durante
joined us in May, who is a big help everyday and will be glad to help
everyone who joins our IRC channel.
This post is about the features, that have been added since April
and that are currently available in the current NPM package v1.7.0-alpha2
.
The validator
plugin has been updated to 1.1.1
. Part of the new version
is the possibility to check for proper IPv6 addresses. You can use it like this:
Sequelize.define('model', {
ip: {
type: Sequelize.STRING,
validate: {
isIPv6: true
}
}
})
In order to improve performance of the library, we replaced
underscore.js
with the faster drop-in-replacement
lodash
. You can access it via the already existing way Sequelize.Utils._
.
Many people requested, that the model needs to be validated before
it gets saved. This is now the case. So whenever the save
method gets called on an object, the model is validated and the
error
callback is triggered if the model isn't valid:
sequelize.define('user', {
username: {
type: Sequelize.STRING,
validate: {
notEmpty: true,
notNull: true
}
}
}).create({
username: ''
}).error(function(errors) {
console.log(errors) // { username: [ 'String is empty' ] }
})
It is now possible to create schemas for postgres respectively to prefix table names for sqlite and mysql. That means that you can now define tables in different scopes:
var User = sequelize.define('user', { username: Sequelize.STRING })
, wpUser = User.schema('wordpress', '_')
sequelize.createSchema('wordpress').success(function() {
sequelize.sync().success(function() {
// Sequelize will now create the following tables: `wordpress_users`
})
})
It is now possible to define foreign keys to connect tables / models
with each other. The following snippet connects the Post
model with
the Author
model.
var Author = sequelize.define('author', { first_name: Sequelize.STRING })
var Post = sequelize.define('post', {
title: Sequelize.STRING,
authorId: {
type: Sequelize.INTEGER,
references: Author,
referencesKey: "id"
}
})
Author.hasMany(Post)
Post.belongsTo(Author)
Also we can now define reactions of certain events. E.g.
what should happen to the associated objects after a
delete
operation, etc. This is the way to do it:
var Author = sequelize.define('author', { first_name: Sequelize.STRING })
var Post = sequelize.define('post', {
title: Sequelize.STRING,
authorId: {
type: Sequelize.INTEGER,
references: 'authors',
referencesKey: 'id',
onDelete: 'cascade'
}
})
Author.hasMany(Post)
Post.belongsTo(Author)
sequelize.sync().success(function() {
new Sequelize.Utils.QueryChainer()
.add(Author.create({ first_name: 'John' }))
.add(Post.create({ title: 'news' }))
.add(Post.create({ title: 'milestone reached' }))
.run()
.success(function(results) {
var author = results[0]
, news = results[1]
, milestone = results[2]
author.setPosts([ news, milestone ]).success(function() {
author.destroy()
/*
At this point, you won't find any authors and posts in the database anymore,
as we have dropped the only author and due to the cascade option every related
posts of him.
*/
})
})
})
In order to minimize the number of SQL requests while creating/updating/deleting a bunch of entries, we introduced bulk support.
This is how creation of multiple instances is possible while just triggering a single SQL statement:
var User = sequelize.define('User', { name: Sequelize.STRING })
User.sync({ force: true }).success(function() {
var userData = [
{ name: 'John' },
{ name: 'Jane' },
{ name: 'Pete' }
]
User.bulkCreate(userData).success(function() {
// We just created 3 users with just a single SQL statement <3
})
})
In order to update a bunch of entries we can utilize the update
method:
User.update({ name: 'Foo' }, '`name` LIKE "J%"').success(function() {
// All users thats name used to start with "J" is now called "Foo" :)
})
Last but not least we can delete all entries matching certain criteria:
User.bulkCreate([
{ name: 'John' },
{ name: 'Jane' },
{ name: 'Pete' }
]).success(function() {
User.destroy('`name` LIKE "J%"').success(function() {
// We just deleted all rows that have a name starting with "J"
})
})
Costent added support for advanced data types. For example, you are now able to define a column as unsigned, zerofilled integer having a length of 6:
var User = sequelize.define("user", {
streetNumber: Sequelize.INTEGER(6).ZEROFILL.UNSIGNED
})
Also we have added BIGINT
, DECIMAL
,
ENUM
, ARRAY
and some other things.
They are nicely documented over here.
Rob Fletcher made the Sequelize binary a bit more talkative, when it comes to errors or misusage.
In order to make chaining of events easier and smoother,
Sequelize now has support for Promises/A. Just call then
instead
of reacting on the usual events:
var User = sequelize.define("user", {
username: Sequelize.STRING
})
User
.sync({ force: true })
.then(function() { return User.create({ username: 'John' }) })
.then(function(john) { return User.create({ username: 'Jane' }) })
.then(function(jane) { return User.create({ username: 'Pete' }) })
.then(function(pete) {
console.log("we just created 3 users :)")
console.log("this is pete:")
console.log(pete.values)
})
Virtual attributes have been introduced and allows you, to e.g. set a first/last name based on a name respectively to do the vice versa way:
var User = sequelize.define("user", {
first_name: Sequelize.STRING,
last_name: Sequelize.STRING
}, {
setterMethods: {
name: function(s) {
this.first_name = s.split(" ")[0]
this.last_name = s.split(" ")[1]
}
},
getterMethods: {
name: function() {
return [this.first_name, this.last_name].join(" ")
}
}
})
User
.sync({ force: true })
.then(function() {
return User.create({ name: 'John Doe' })
})
.then(function(john) {
console.log("Let's welcome:", john.first_name, john.last_name)
// Let's welcome: John Doe
})
In addition to the already existing possibilities of validating certain
single attributes, the current version adds support for instance wide
validations. It utilizes the validate
option of the model definition:
var User = sequelize.define("User", {
username: {
type: Sequelize.STRING,
validate: { notEmpty: true }
},
password: Sequelize.STRING,
password_confirmation: Sequelize.STRING
}, {
validate: {
passwordEquality: function() {
if (this.password !== this.password_confirmation) {
throw new Error("Passwords aren't equal!")
}
}
}
})
User
.sync({ force: true })
.then(function() {
User.create({
username: 'john',
password: 'test',
password_confirmation: 'tst'
}).error(function(err) {
console.log(err)
// { passwordEquality: [ 'Passwords aren\'t equal!' ] }
})
})