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

Commit 5f805e3e by Sascha Depold

Merge branch 'master' into features/transactions

Conflicts:
	.gitignore
	lib/dao-factory.js
	lib/utils.js
	package.json
	test/dao-factory.test.js
	test/sequelize.test.js
2 parents 03043e2d 78e20e5c
......@@ -8,3 +8,4 @@ npm-debug.log
test/binary/tmp/*
test/tmp/*
test/sqlite/test.sqlite
coverage-*
......@@ -18,6 +18,10 @@ test:
make teaser && ./node_modules/mocha/bin/mocha --check-leaks --colors -t 10000 --reporter $(REPORTER) $(TESTS); \
fi
cover:
rm -rf coverage \
make teaser && ./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha -- -- -u exports --report lcovonly -- -R spec -- $(TESTS); \
mv coverage coverage-$(DIALECT) \
mariadb:
@DIALECT=mariadb make test
......@@ -32,6 +36,33 @@ postgres-native:
binary:
@./test/binary/sequelize.test.bats
mariadb-cover:
rm -rf coverage
@DIALECT=mariadb make cover
sqlite-cover:
rm -rf coverage
@DIALECT=sqlite make cover
mysql-cover:
rm -rf coverage
@DIALECT=mysql make cover
postgres-cover:
rm -rf coverage
@DIALECT=postgres make cover
postgres-native-cover:
rm -rf coverage
@DIALECT=postgres-native make cover
binary-cover:
rm -rf coverage
@./test/binary/sequelize.test.bats
merge-coverage:
rm -rf coverage
mkdir coverage
./node_modules/.bin/lcov-result-merger 'coverage-*/lcov.info' 'coverage/lcov.info'
coveralls-send:
cat ./coverage/lcov.info | ./node_modules/.bin/coveralls && rm -rf ./coverage
# test aliases
pgsql: postgres
......@@ -41,4 +72,7 @@ postgresn: postgres-native
all: sqlite mysql postgres postgres-native mariadb
all-cover: sqlite-cover mysql-cover postgres-cover postgres-native-cover mariadb-cover merge-coverage
coveralls: sqlite-cover mysql-cover postgres-cover postgres-native-cover mariadb-cover merge-coverage coveralls-send
.PHONY: sqlite mysql postgres pgsql postgres-native postgresn all test
......@@ -215,7 +215,7 @@ module.exports = (function() {
attributeManipulation[name][type] = fct
})
})
Object.defineProperties(this.DAO.prototype, attributeManipulation)
this.DAO.prototype.attributes = Object.keys(this.DAO.prototype.rawAttributes)
}
......@@ -622,13 +622,18 @@ module.exports = (function() {
}).run()
}
DAOFactory.prototype.findOrCreate = function (params, defaults, options) {
var self = this
DAOFactory.prototype.findOrCreate = function (where, defaults, options) {
var self = this
, params = {}
options = Utils._.extend({
transaction: null
}, options || {})
for (var attrname in where) {
params[attrname] = where[attrname]
}
return new Utils.CustomEventEmitter(function (emitter) {
self.find({
where: params
......
......@@ -188,6 +188,9 @@ module.exports = {
FLOAT: FLOAT,
NOW: 'NOW',
BLOB: BLOB,
UUID: 'CHAR(36)',
UUIDV1: 'UUIDV1',
UUIDV4: 'UUIDV4',
get ENUM() {
var result = function() {
......
......@@ -694,7 +694,7 @@ module.exports = (function() {
result.push([_key, _value].join("="))
} else {
for (var logic in value) {
var logicResult = Utils.getWhereLogic(logic)
var logicResult = Utils.getWhereLogic(logic, hash[key][logic]);
if (logic === "IN" || logic === "NOT IN") {
var values = Array.isArray(where[i][ii]) ? where[i][ii] : [where[i][ii]]
_where[_where.length] = i + ' ' + logic + ' (' + values.map(function(){ return '?' }).join(',') + ')'
......
......@@ -427,7 +427,12 @@ module.exports = (function() {
for (var attrName in row) {
if (row.hasOwnProperty(attrName) && (attrName !== calleeTableName)) {
existingEntry[attrName] = existingEntry[attrName] || []
existingEntry[attrName].push(row[attrName])
var attrRowExists = existingEntry[attrName].some(function(attrRow) {
return Utils._.isEqual(attrRow, row[attrName])
})
if (!attrRowExists) {
existingEntry[attrName].push(row[attrName])
}
}
}
})
......
......@@ -57,7 +57,7 @@ module.exports = (function() {
}
var onSuccess = function(rows, sql) {
var results = []
var results = rows
, self = this
, isTableNameQuery = (sql.indexOf('SELECT table_name FROM information_schema.tables') === 0)
, isRelNameQuery = (sql.indexOf('SELECT relname FROM pg_class WHERE oid IN') === 0)
......
var util = require("util")
, EventEmitter = require("events").EventEmitter
, Promise = require("promise")
, Promise = require("bluebird")
, proxyEventKeys = ['success', 'error', 'sql']
, Utils = require('../utils')
......
......@@ -233,7 +233,7 @@ module.exports = (function() {
// private
var getLastMigrationFromDatabase = function() {
var getLastMigrationFromDatabase = Migrator.prototype.getLastMigrationFromDatabase = function() {
var self = this
return new Utils.CustomEventEmitter(function(emitter) {
......@@ -255,7 +255,7 @@ module.exports = (function() {
}).run()
}
var getLastMigrationIdFromDatabase = function() {
var getLastMigrationIdFromDatabase = Migrator.prototype.getLastMigrationIdFromDatabase = function() {
var self = this
return new Utils.CustomEventEmitter(function(emitter) {
......@@ -270,7 +270,7 @@ module.exports = (function() {
}).run()
}
var getFormattedDateString = function(s) {
var getFormattedDateString = Migrator.prototype.getFormattedDateString = function(s) {
var result = null
try {
......@@ -282,11 +282,11 @@ module.exports = (function() {
return result
}
var stringToDate = function(s) {
var stringToDate = Migrator.prototype.stringToDate = function(s) {
return moment(getFormattedDateString(s), "YYYYMMDDHHmmss")
}
var saveSuccessfulMigration = function(from, to, callback) {
var saveSuccessfulMigration = Migrator.prototype.saveSuccessfulMigration = function(from, to, callback) {
var self = this
self.findOrCreateSequelizeMetaDAO().success(function(SequelizeMeta) {
......@@ -296,7 +296,7 @@ module.exports = (function() {
})
}
var deleteUndoneMigration = function(from, to, callback) {
var deleteUndoneMigration = Migrator.prototype.deleteUndoneMigration = function(from, to, callback) {
var self = this
self.findOrCreateSequelizeMetaDAO().success(function(SequelizeMeta) {
......
......@@ -143,7 +143,7 @@ SqlString.format = function(sql, values, timeZone, dialect) {
}
SqlString.formatNamedParameters = function(sql, values, timeZone, dialect) {
return sql.replace(/\:(\w+)/g, function (value, key) {
return sql.replace(/\:(?!\d)(\w+)/g, function (value, key) {
if (values.hasOwnProperty(key)) {
return SqlString.escape(values[key], false, timeZone, dialect)
} else {
......
......@@ -4,6 +4,7 @@ var util = require("util")
, lodash = require("lodash")
, _string = require('underscore.string')
, ParameterValidator = require('./utils/parameter-validator')
, uuid = require('node-uuid')
var Utils = module.exports = {
_: (function() {
......@@ -181,7 +182,7 @@ var Utils = module.exports = {
}
else if (type === "object") {
Object.keys(where[i]).forEach(function(ii) {
logic = self.getWhereLogic(ii)
logic = self.getWhereLogic(ii, where[i][ii]);
switch(logic) {
case 'IN':
......@@ -283,7 +284,7 @@ var Utils = module.exports = {
return Utils._.compactLite([text.join(' AND ')].concat(whereArgs))
},
getWhereLogic: function(logic) {
getWhereLogic: function(logic, val) {
switch (logic) {
case 'join':
return 'JOIN'
......@@ -298,7 +299,7 @@ var Utils = module.exports = {
case 'eq':
return '='
case 'ne':
return '!='
return val ? '!=' : 'IS NOT'
case 'between':
case '..':
return 'BETWEEN'
......@@ -376,8 +377,14 @@ var Utils = module.exports = {
toDefaultValue: function(value) {
if (lodash.isFunction(value)) {
return value()
} else if (value === DataTypes.UUIDV1) {
return uuid.v1()
} else if (value === DataTypes.UUIDV4) {
return uuid.v4()
} else if (value === DataTypes.NOW) {
return Utils.now()
} else {
return (value === DataTypes.NOW) ? Utils.now() : value
return value
}
},
......@@ -395,6 +402,8 @@ var Utils = module.exports = {
// have been normalized for this case
if (value === DataTypes.NOW) {return false}
if (value === DataTypes.UUIDV1 || value === DataTypes.UUIDV4) {return false}
if (lodash.isFunction(value)) {
return false
}
......
......@@ -45,9 +45,10 @@
"dottie": "0.0.8-0",
"toposort-class": "~0.2.0",
"generic-pool": "2.0.4",
"promise": "~3.2.0",
"sql": "~0.31.0",
"circular-json": "~0.1.5"
"circular-json": "~0.1.5",
"bluebird": "~0.11.5",
"node-uuid": "~1.4.1"
},
"devDependencies": {
"sqlite3": "~2.1.12",
......@@ -60,7 +61,10 @@
"chai-datetime": "~1.1.1",
"sinon": "~1.7.3",
"mariasql": "git://github.com/mscdex/node-mariasql.git",
"chai-spies": "~0.5.1"
"chai-spies": "~0.5.1",
"lcov-result-merger": "0.0.2",
"istanbul": "~0.1.45",
"coveralls": "~2.5.0"
},
"keywords": [
"mysql",
......
......@@ -535,7 +535,9 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
Task.hasMany(User)
expect(Task.attributes.UserId).not.to.exist
done()
setTimeout(function () {
done()
}, 50)
})
describe('setAssociations', function() {
......
......@@ -2241,6 +2241,45 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
})
})
it('including two has many relations should not result in duplicate values', function(done) {
var self = this
self.Contact = self.sequelize.define('Contact', { name: DataTypes.TEXT })
self.Photo = self.sequelize.define('Photo', { img: DataTypes.TEXT })
self.PhoneNumber = self.sequelize.define('PhoneNumber', { phone: DataTypes.TEXT })
self.Contact.hasMany(self.Photo, { as: 'Photos' })
self.Contact.hasMany(self.PhoneNumber)
self.sequelize.sync({ force: true }).success(function() {
self.Contact.create({ name: 'Boris' }).success(function(someContact) {
self.Photo.create({ img: 'img.jpg' }).success(function(somePhoto) {
self.PhoneNumber.create({ phone: '000000' }).success(function(somePhone1) {
self.PhoneNumber.create({ phone: '111111' }).success(function(somePhone2) {
someContact.setPhotos([somePhoto]).complete(function (err, data) {
expect(err).to.be.null
someContact.setPhoneNumbers([somePhone1, somePhone2]).complete(function (err, data) {
self.Contact.find({
where: {
name: 'Boris'
},
include: [self.PhoneNumber, { daoFactory: self.Photo, as: 'Photos' }]
}).complete(function (err, fetchedContact) {
expect(err).to.be.null
expect(fetchedContact).to.exist
expect(fetchedContact.photos.length).to.equal(1)
expect(fetchedContact.phoneNumbers.length).to.equal(2)
done()
})
})
})
})
})
})
})
})
})
it('eager loads with non-id primary keys', function(done) {
var self = this
self.User = self.sequelize.define('UserPKeagerone', {
......
......@@ -7,6 +7,7 @@ var chai = require('chai')
, config = require(__dirname + "/config/config")
, sinon = require('sinon')
, datetime = require('chai-datetime')
, uuid = require('node-uuid')
, _ = require('lodash')
chai.use(datetime)
......@@ -16,6 +17,8 @@ describe(Support.getTestDialectTeaser("DAO"), function () {
beforeEach(function(done) {
this.User = this.sequelize.define('User', {
username: { type: DataTypes.STRING },
uuidv1: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV1 },
uuidv4: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4 },
touchedAt: { type: DataTypes.DATE, defaultValue: DataTypes.NOW },
aNumber: { type: DataTypes.INTEGER },
bNumber: { type: DataTypes.INTEGER },
......@@ -634,6 +637,26 @@ describe(Support.getTestDialectTeaser("DAO"), function () {
})
describe('default values', function() {
describe('uuid', function() {
it('should store a string in uuidv1 and uuidv4', function(done) {
var user = this.User.build({ username: 'a user'})
expect(user.uuidv1).to.be.a('string')
expect(user.uuidv4).to.be.a('string')
done()
})
it('should store a string of length 36 in uuidv1 and uuidv4', function(done) {
var user = this.User.build({ username: 'a user'})
expect(user.uuidv1).to.have.length(36)
expect(user.uuidv4).to.have.length(36)
done()
})
it('should store a valid uuid in uuidv1 and uuidv4 that can be parsed to something of length 16', function(done) {
var user = this.User.build({ username: 'a user'})
expect(uuid.parse(user.uuidv1)).to.have.length(16)
expect(uuid.parse(user.uuidv4)).to.have.length(16)
done()
})
})
describe('current date', function() {
it('should store a date in touchedAt', function(done) {
var user = this.User.build({ username: 'a user'})
......
......@@ -25,6 +25,7 @@ describe(Support.getTestDialectTeaser('DataTypes'), function() {
[Sequelize.TEXT, 'TEXT', 'TEXT'],
[Sequelize.DATE, 'DATE', 'DATETIME'],
[Sequelize.NOW, 'NOW', 'NOW'],
[Sequelize.UUID, 'UUID', 'CHAR(36)'],
[Sequelize.BOOLEAN, 'BOOLEAN', 'TINYINT(1)'],
[Sequelize.BLOB, 'BLOB', 'BLOB'],
......
......@@ -30,7 +30,10 @@ if (dialect.match(/^postgres/)) {
Table1.hasMany(Table2, {joinTableName: 'table1_to_table2'})
Table2.hasMany(Table1, {joinTableName: 'table1_to_table2'})
done()
setTimeout(function () {
done()
}, 50)
})
it("should not use a combined name", function(done) {
......
var chai = require('chai')
, expect = chai.expect
, assert = chai.assert
, Support = require(__dirname + '/support')
, DataTypes = require(__dirname + "/../lib/data-types")
, dialect = Support.getTestDialect()
......@@ -236,6 +237,13 @@ describe(Support.getTestDialectTeaser("Sequelize"), function () {
})
})
it('replaces named parameters with the passed object and ignore those which does not qualify', function(done) {
this.sequelize.query('select :one as foo, :two as bar, \'00:00\' as baz', null, { raw: true }, { one: 1, two: 2 }).success(function(result) {
expect(result).to.deep.equal([{ foo: 1, bar: 2, baz: '00:00' }])
done()
})
})
it('replaces named parameters with the passed object using the same key twice', function(done) {
this.sequelize.query('select :one as foo, :two as bar, :one as baz', null, { raw: true }, { one: 1, two: 2 }).success(function(result) {
expect(result).to.deep.equal([{ foo: 1, bar: 2, baz: 1 }])
......@@ -296,6 +304,18 @@ describe(Support.getTestDialectTeaser("Sequelize"), function () {
done()
})
})
if (Support.getTestDialect() === 'postgres') {
it('supports WITH queries', function(done) {
this
.sequelize
.query("WITH RECURSIVE t(n) AS ( VALUES (1) UNION ALL SELECT n+1 FROM t WHERE n < 100) SELECT sum(n) FROM t")
.success(function(results) {
expect(results).to.deep.equal([ { "sum": "5050" } ])
done()
})
})
}
})
describe('define', function() {
......@@ -382,9 +402,13 @@ describe(Support.getTestDialectTeaser("Sequelize"), function () {
var User2 = this.sequelizeWithInvalidCredentials.define('User', { name: DataTypes.STRING, bio: DataTypes.TEXT })
User2.sync().complete(function(err) {
User2.sync().error(function(err) {
if (dialect === "postgres" || dialect === "postgres-native") {
expect(err.message).to.match(/(role "bar" does not exist)|(password authentication failed for user "bar")/)
assert([
'role "bar" does not exist',
'FATAL: role "bar" does not exist',
'password authentication failed for user "bar"'
].indexOf(err.message.trim()) !== -1)
} else {
expect(err.message.toString()).to.match(/.*Access\ denied.*/)
}
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!