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

You need to sign in or sign up before continuing.
Commit 4b1b89f3 by Mick Hansen

Merge branch 'master' into milestones/2.0.0

2 parents a952b4cf 37edaeaa
......@@ -12,8 +12,18 @@ To install 2.x.x branch - which has a unstable API and will break backwards comp
`npm install sequelize@unstable`
### Resources
### Features
- Schema definition
- Schema synchronization/dropping
- 1:1, 1:M & N:M Associations
- Through models
- Promises
- Hooks/callbacks/lifecycle events
- Prefetching/association including
### Resources
- [Changelog](https://github.com/sequelize/sequelize/blob/master/changelog.md)
- [Getting Started](http://sequelizejs.com/articles/getting-started)
- [Documentation](http://sequelizejs.com/docs)
- [API Reference](https://github.com/sequelize/sequelize/wiki/API-Reference) *Work in progress*
......@@ -21,53 +31,9 @@ To install 2.x.x branch - which has a unstable API and will break backwards comp
- [Collaboration and pull requests](https://github.com/sequelize/sequelize/wiki/Collaboration)
- [Roadmap](https://github.com/sequelize/sequelize/wiki/Roadmap)
- [Meetups](https://github.com/sequelize/sequelize/wiki/Meetups)
## Important Notes ##
### 2.0.0 ###
There is a parallel "branch" of the project, released as `2.0.0-alphaX` in NPM. All those releases are based on the master
and will get all the changes of the master. However, `2.0.0` will contain major backwards compatibility breaking changes. Check the
changelog of the branch: https://github.com/sequelize/sequelize/blob/milestones/2.0.0/changelog.md
##### 2.0.0 API should be considered unstable
### 1.6.0 ###
- We changed the way timestamps are handled. From v1.6.0 on timestamps are stored and loaded as UTC.
- Support for synchronous migrations has been dropped. `up` and `down` methods in migrations do have a third parameter which is the callback parameter. Pass an error or an error message as first parameter to the callback if something went wrong in the migration.
## Blogposts/Changes ##
- [v1.6.0](http://blog.sequelizejs.com/post/46949108134/v1-6-0-eager-loading-support-for-enums-decimals-and) Eager loading, support for enums, decimals and bigint, performance improvements …
- [v1.4.1](http://blog.sequelizejs.com/post/24403298792/changes-in-sequelize-1-4-1): deprecation of node < 0.6, logging customization, ...
- [v1.4.0](http://blog.sequelizejs.com/post/24345409723/changes-in-sequelize-1-4-0): postgresql, connection pooling, ...
- [v1.3.0](http://blog.depold.com/post/15283366633/changes-in-sequelize-1-3-0): migrations, cross-database, validations, new listener notation, ...
- [v1.2.1](http://blog.depold.com/post/12319530694/changes-in-sequelize-1-2-1): changes some defaults and some interfaces
- [v1.0.0](http://blog.depold.com/post/5936116582/changes-in-sequelize-1-0-0): complete rewrite
## Features ##
- Schema definition
- Schema synchronization/dropping
- Easy definition of class/instance methods
- Instance saving/updating/dropping
- Asynchronous library
- Associations
- Importing definitions from single files
- Promises
- Hooks/callbacks/lifecycle events
## Documentation and Updates ##
You can find the documentation and announcements of updates on the [project's website](http://sequelizejs.com).
If you want to know about latest development and releases, follow me on [Twitter](http://twitter.com/sdepold).
Also make sure to take a look at the examples in the repository. The website will contain them soon, as well.
- [Documentation](http://sequelizejs.com)
- [Twitter](http://twitter.com/sdepold)
- [IRC](http://webchat.freenode.net?channels=sequelizejs)
- [Google Groups](https://groups.google.com/forum/#!forum/sequelize)
- [XING](https://www.xing.com/net/priec1b5cx/sequelize) (pretty much inactive, but you might want to name it on your profile)
## Running Examples
Instructions for running samples are located in the [example directory](https://github.com/sequelize/sequelize/tree/master/examples). Try these samples in a live sandbox environment:
......
Notice: All 1.7.x changes are present in 2.0.x aswell
# v1.7.0-rc4
- fixes issue with postgres sync and enums [#1020](https://github.com/sequelize/sequelize/issues/1020)
- fixes various issues with limit and includes [#1322](https://github.com/sequelize/sequelize/pull/1322)
#### Backwards compatability changes
- find/findAll will not always return primary keys regardless of `attributes` settings. (Motivation was to fix various issues with eager loading)
# v1.7.0-rc3
- dropAllTables now takes an option parameter with `skip` as an option [#1280](https://github.com/sequelize/sequelize/pull/1280)
- implements .spread for eventemitters [#1277](https://github.com/sequelize/sequelize/pull/1277)
......
......@@ -545,7 +545,9 @@ module.exports = (function() {
}
options = paranoidClause.call(this, options)
options.limit = 1
if (options.limit === undefined) {
options.limit = 1
}
return this.QueryInterface.select(this, this.getTableName(), options, Utils._.defaults({
plain: true,
......@@ -582,11 +584,19 @@ module.exports = (function() {
DAOFactory.prototype.count = function(options) {
options = Utils._.clone(options || {})
return new Utils.CustomEventEmitter(function (emitter) {
var col = this.sequelize.col('*')
if (options.include) {
col = this.sequelize.col(this.tableName+'.'+(this.primaryKeyAttributes[0] || 'id'))
}
options.attributes = [
[this.sequelize.fn('COUNT', this.sequelize.col(this.tableName+'.*')), 'count']
[this.sequelize.fn('COUNT', col), 'count']
]
options.includeIgnoreAttributes = false
options.limit = null
this.find(options, {raw: true, transaction: options.transaction}).proxy(emitter, {events: ['sql', 'error']}).success(function (result) {
emitter.emit('success', parseInt(result.count, 10))
......@@ -610,18 +620,18 @@ module.exports = (function() {
}
self.count(countOptions)
.proxy(emitter, {events: ['sql', 'error']})
.success(function(count) {
if (count === 0) {
return emit.okay(count) // no records, no need for another query
}
.proxy(emitter, {events: ['sql', 'error']})
.success(function(count) {
if (count === 0) {
return emit.okay(count) // no records, no need for another query
}
self.findAll(findOptions, queryOptions)
.proxy(emitter, {events: ['sql', 'error']})
.success(function(results) {
emit.okay(count, results)
})
})
self.findAll(findOptions, queryOptions)
.proxy(emitter, {events: ['sql', 'error']})
.success(function(results) {
emit.okay(count, results)
})
})
}).run()
}
......@@ -1329,8 +1339,8 @@ module.exports = (function() {
options.includeMap[include.as] = include
options.includeNames.push(include.as)
if (include.association.isMultiAssociation) options.hasMultiAssociation = true
if (include.association.isSingleAssociation) options.hasSingleAssociation = true
if (include.association.isMultiAssociation || include.hasMultiAssociation) options.hasMultiAssociation = true
if (include.association.isSingleAssociation || include.hasSingleAssociation) options.hasSingleAssociation = true
options.hasIncludeWhere = options.hasIncludeWhere || include.hasIncludeWhere || !!include.where
options.hasIncludeRequired = options.hasIncludeRequired || include.hasIncludeRequired || !!include.required
......
......@@ -473,8 +473,8 @@ module.exports = (function() {
, mainQueryItems = []
, mainAttributes = options.attributes
, mainJoinQueries = []
// We'll use a subquery if there's a limit, if we have hasMany associations and if any of them are filtered
, subQuery = limit && options && options.hasIncludeWhere && options.hasIncludeRequired && options.hasMultiAssociation
// We'll use a subquery if we have hasMany associations and a limit and a filtered/required association
, subQuery = limit && (options.hasIncludeWhere || options.hasIncludeRequired || options.hasMultiAssociation)
, subQueryItems = []
, subQueryAttributes = null
, subJoinQueries = []
......@@ -484,6 +484,10 @@ module.exports = (function() {
return this.quoteIdentifiers(t)
}.bind(this)).join(", ")
if (subQuery && mainAttributes) {
mainAttributes = mainAttributes.concat(factory.hasPrimaryKeys ? factory.primaryKeyAttributes : ['id'])
}
// Escape attributes
mainAttributes = mainAttributes && mainAttributes.map(function(attr){
var addTable = true
......@@ -518,6 +522,7 @@ module.exports = (function() {
// If subquery, we ad the mainAttributes to the subQuery and set the mainAttributes to select * from subquery
if (subQuery) {
// We need primary keys
subQueryAttributes = mainAttributes
mainAttributes = [options.table+'.*']
}
......@@ -534,7 +539,9 @@ module.exports = (function() {
, includeWhere = {}
, whereOptions = Utils._.clone(options)
if (tableName !== parentTable) as = parentTable+'.'+include.as
if (tableName !== parentTable) {
as = parentTable+'.'+include.as
}
if (include.where) {
for (var key in include.where) {
......@@ -795,12 +802,12 @@ module.exports = (function() {
return "ROLLBACK;"
},
addLimitAndOffset: function(options, query){
addLimitAndOffset: function(options, query) {
query = query || ""
if (options.offset && !options.limit) {
query += " LIMIT " + options.offset + ", " + 10000000000000;
} else if (options.limit && !(options.include && (options.limit === 1))) {
} else if (options.limit) {
if (options.offset) {
query += " LIMIT " + options.offset + ", " + options.limit
} else {
......
......@@ -396,7 +396,7 @@ module.exports = (function() {
query = query || ""
if (options.offset && !options.limit) {
query += " LIMIT " + options.offset + ", " + 18440000000000000000;
} else if (options.limit && !(options.include && (options.limit === 1))) {
} else if (options.limit) {
if (options.offset) {
query += " LIMIT " + options.offset + ", " + options.limit
} else {
......
......@@ -410,14 +410,12 @@ module.exports = (function() {
addLimitAndOffset: function(options, query){
query = query || ""
if (!(options.include && (options.limit === 1))) {
if (options.limit) {
query += " LIMIT " + options.limit
}
if (options.limit) {
query += " LIMIT " + options.limit
}
if (options.offset) {
query += " OFFSET " + options.offset
}
if (options.offset) {
query += " OFFSET " + options.offset
}
return query;
......
......@@ -153,7 +153,7 @@ module.exports = (function() {
query = query || ""
if (options.offset && !options.limit) {
query += " LIMIT " + options.offset + ", " + 10000000000000;
} else if (options.limit && !(options.include && (options.limit === 1))) {
} else if (options.limit) {
if (options.offset) {
query += " LIMIT " + options.offset + ", " + options.limit
} else {
......
......@@ -599,10 +599,12 @@ Utils.fn.prototype.toString = function(queryGenerator) {
}
Utils.col.prototype.toString = function (queryGenerator) {
if (this.col.indexOf('*') !== -1) return '*'
if (this.col.indexOf('*') === 0) {
return '*'
}
return queryGenerator.quote(this.col)
}
Utils.CustomEventEmitter = require(__dirname + "/emitters/custom-event-emitter")
Utils.QueryChainer = require(__dirname + "/query-chainer")
Utils.Lingo = require("lingo")
Utils.Lingo = require("lingo")
\ No newline at end of file
......@@ -237,8 +237,9 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
self.User.find({
where: { username: 'JohnXOXOXO' },
attributes: ['username']
}).success(function(user) {
expect(user.selectedValues).to.have.property('username', 'JohnXOXOXO')
}).done(function(err, user) {
expect(err).not.to.be.ok
expect(_.omit(user.selectedValues, ['id'])).to.have.property('username', 'JohnXOXOXO')
done()
})
})
......@@ -262,8 +263,9 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
where: { username: 'John DOE' },
attributes: ['username'],
include: [self.Mission]
}).success(function(user) {
expect(user.selectedValues).to.deep.equal({ username: 'John DOE' })
}).done(function(err, user) {
expect(err).not.to.be.ok
expect(_.omit(user.selectedValues, ['id'])).to.deep.equal({ username: 'John DOE' })
done()
})
})
......@@ -291,7 +293,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
attributes: ['username'],
include: [{model: self.Mission, as: self.Mission.tableName, attributes: ['title']}]
}).success(function(user) {
expect(user.selectedValues).to.deep.equal({ username: 'Brain Picker' })
expect(_.omit(user.selectedValues, ['id'])).to.deep.equal({ username: 'Brain Picker' })
expect(user.missions[0].selectedValues).to.deep.equal({ id: 1, title: 'another mission!!'})
expect(user.missions[0].foo).not.to.exist
done()
......
......@@ -957,6 +957,57 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
})
})
it("handles offset with includes", function (done) {
var Election = this.sequelize.define('Election', {
name: Sequelize.STRING
})
var Citizen = this.sequelize.define('Citizen', {
name: Sequelize.STRING
})
// Associations
Election.belongsTo(Citizen)
Election.hasMany(Citizen, { as: 'Voters', through: 'ElectionsVotes' })
Citizen.hasMany(Election)
Citizen.hasMany(Election, { as: 'Votes', through: 'ElectionsVotes' })
this.sequelize.sync().done(function (err) {
expect(err).not.be.ok
// Add some data
Citizen.create({ name: 'Alice' }).done(function (err, alice) {
expect(err).not.be.ok
Citizen.create({ name: 'Bob' }).done(function (err, bob) {
expect(err).not.be.ok
Election.create({ name: 'Some election' }).done(function (err, election) {
expect(err).not.be.ok
election.setCitizen(alice).done(function (err) {
expect(err).not.be.ok
election.setVoters([alice, bob]).done(function (err) {
expect(err).not.be.ok
var criteria = {
offset: 5,
limit: 1,
include: [
Citizen, // Election creator
{ model: Citizen, as: 'Voters' } // Election voters
]
}
Election.findAndCountAll(criteria).done(function (err, elections) {
expect(err).not.be.ok
expect(elections.count).to.equal(2)
expect(elections.rows.length).to.equal(0)
done()
})
})
})
})
})
})
})
})
it("handles attributes", function(done) {
this.User.findAndCountAll({where: "id != " + this.users[0].id, attributes: ['data']}).success(function(info) {
expect(info.count).to.equal(2)
......
......@@ -895,7 +895,9 @@ describe(Support.getTestDialectTeaser("Include"), function () {
})
it('should be possible to extend the on clause with a where option on nested includes', function (done) {
var User = this.sequelize.define('User', {})
var User = this.sequelize.define('User', {
name: DataTypes.STRING
})
, Product = this.sequelize.define('Product', {
title: DataTypes.STRING
})
......@@ -984,7 +986,7 @@ describe(Support.getTestDialectTeaser("Include"), function () {
async.auto({
user: function (callback) {
User.create().done(callback)
User.create({name: 'FooBarzz'}).done(callback)
},
memberships: ['user', function (callback, results) {
GroupMember.bulkCreate([
......@@ -1123,22 +1125,26 @@ describe(Support.getTestDialectTeaser("Include"), function () {
})
})
it('should be possible use limit and a where on a belongsTo with additional hasMany includes', function (done) {
it('should be possible use limit, attributes and a where on a belongsTo with additional hasMany includes', function (done) {
var self = this
this.fixtureA(function () {
self.models.Product.findAll({
attributes: ['title'],
include: [
{model: self.models.Company, where: {name: 'NYSE'}},
{model: self.models.Tag},
{model: self.models.Price}
],
limit: 3,
order: 'id ASC'
order: [
[self.sequelize.col(self.models.Product.tableName+'.id'), 'ASC']
]
}).done(function (err, products) {
expect(err).not.to.be.ok
expect(products.length).to.equal(3)
products.forEach(function (product) {
expect(product.company.name).to.equal('NYSE')
expect(product.tags.length).to.be.ok
expect(product.prices.length).to.be.ok
})
......@@ -1151,6 +1157,7 @@ describe(Support.getTestDialectTeaser("Include"), function () {
var self = this
this.fixtureA(function () {
self.models.Product.findAll({
include: [
{model: self.models.Company},
{model: self.models.Tag},
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!