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

Commit 876ae6c9 by Sascha Depold

Merge branch 'master' into milestones/2.0.0

2 parents 45ed5c53 df2ae8b5
......@@ -6,3 +6,4 @@ node_modules
npm-debug.log
*~
test/binary/tmp/*
test/tmp/*
[submodule "test/binary/bats"]
path = test/binary/bats
url = https://github.com/sstephenson/bats.git
......@@ -36,6 +36,6 @@ postgresn: postgres-native
# test all the dialects \o/
all: sqlite mysql postgres postgres-native binary
all: sqlite mysql postgres postgres-native
.PHONY: sqlite mysql postgres pgsql postgres-native postgresn all test binary
.PHONY: sqlite mysql postgres pgsql postgres-native postgresn all test
#!/usr/bin/env node
const path = require("path")
var path = require("path")
, fs = require("fs")
, program = require("commander")
, Sequelize = require(__dirname + '/../index')
, moment = require("moment")
, _ = Sequelize.Utils._
var configPath = process.cwd() + '/config'
, environment = process.env.NODE_ENV || 'development'
, migrationsPath = process.cwd() + '/migrations'
, packageJsonPath = __dirname + '/../package.json'
, packageJson = JSON.parse(fs.readFileSync(packageJsonPath).toString())
, configFile = configPath + '/config.json'
, configPathExists = fs.existsSync(configPath)
, configFileExists = fs.existsSync(configFile)
var configuration = {
configFile: process.cwd() + '/config/config.json',
environment: process.env.NODE_ENV || 'development',
version: require(__dirname + '/../package.json').version,
migrationsPath: process.cwd() + '/migrations'
}
var configFileExists = function() {
return fs.existsSync(configuration.configFile)
}
var writeConfig = function(config) {
!configPathExists && fs.mkdirSync(configPath)
var relativeConfigFile = function() {
return path.relative(process.cwd(), configuration.configFile)
}
var writeDefaultConfig = function(config) {
var configPath = path.dirname(configuration.configFile)
if (!fs.existsSync(configPath)) {
fs.mkdirSync(configPath)
}
config = JSON.stringify(config)
config = config.replace('{', '{\n ')
config = config.replace(/,/g, ",\n ")
config = config.replace('}', "\n}")
config = JSON.stringify({
development: {
username: "root",
password: null,
database: 'database_development',
host: '127.0.0.1'
},
test: {
username: "root",
password: null,
database: 'database_test',
host: '127.0.0.1'
},
production: {
username: "root",
password: null,
database: 'database_production',
host: '127.0.0.1'
}
}, undefined, 2) + "\n"
fs.writeFileSync(configFile, config)
fs.writeFileSync(configuration.configFile, config)
}
var createMigrationsFolder = function(force) {
if(force) {
console.log('Deleting the migrations folder.')
console.log('Deleting the migrations folder. (--force)')
try {
fs.readdirSync(migrationsPath).forEach(function(filename) {
fs.unlinkSync(migrationsPath + '/' + filename)
fs.readdirSync(configuration.migrationsPath).forEach(function(filename) {
fs.unlinkSync(configuration.migrationsPath + '/' + filename)
})
} catch(e) {}
try {
fs.rmdirSync(migrationsPath)
fs.rmdirSync(configuration.migrationsPath)
console.log('Successfully deleted the migrations folder.')
} catch(e) {}
}
console.log('Creating migrations folder.')
try {
fs.mkdirSync(migrationsPath)
console.log('Successfully create migrations folder.')
fs.mkdirSync(configuration.migrationsPath)
console.log('Successfully created migrations folder at "' + configuration.migrationsPath + '".')
} catch(e) {
console.log('Migrations folder already exist.')
}
}
var readConfig = function() {
var config
try {
config = fs.readFileSync(configFile)
config = fs.readFileSync(configuration.configFile)
} catch(e) {
throw new Error('Error reading "config/config.json".')
throw new Error('Error reading "' + relativeConfigFile() + '".')
}
try {
config = JSON.parse(config)
} catch (e) {
throw new Error('Error parsing "config/config.json" as JSON.')
throw new Error('Error parsing "' + relativeConfigFile() + '" as JSON.')
}
if (config[environment]) {
config = config[environment]
console.log('Loaded configuration file "' + relativeConfigFile() + '".')
if (config[configuration.environment]) {
console.log('Using environment "' + configuration.environment + '".')
config = config[configuration.environment]
}
return config
}
program
.version(packageJson.version)
.version(configuration.version)
.option('-i, --init', 'Initializes the project.')
.option('-e, --env <environment>', 'Specify the environment.')
.option('-m, --migrate', 'Run pending migrations.')
.option('-u, --undo', 'Undo the last migration.')
.option('-f, --force', 'Forces the action to be done.')
.option('-c, --create-migration [migration-name]', 'Creates a new migration.')
.option('--config <config_file>', 'Specifies alternate config file.')
.parse(process.argv)
if(typeof program.config === 'string') {
configuration.configFile = program.config
}
if(typeof program.env === 'string') {
environment = program.env
configuration.environment = program.env
}
console.log("Using environment '" + environment + "'.")
if(program.migrate) {
if(configFileExists) {
if (program.migrate) {
if (configFileExists()) {
var config
, options = {}
......@@ -101,8 +130,9 @@ if(program.migrate) {
if(['database', 'username', 'password'].indexOf(key) == -1) {
options[key] = value
}
if(key === "use_env_variable") {
if(process.env[value]) {
if (key === "use_env_variable") {
if (process.env[value]) {
var db_info = process.env[value].match(
/([^:]+):\/\/([^:]+):([^@]+)@([^:]+):(\d+)\/(.+)/);
config.database = db_info[6];
......@@ -121,52 +151,37 @@ if(program.migrate) {
options = _.extend(options, { logging: false })
var sequelize = new Sequelize(config.database, config.username, config.password, options)
, migratorOptions = { path: migrationsPath }
, migratorOptions = { path: configuration.migrationsPath }
, migrator = sequelize.getMigrator(migratorOptions)
if(program.undo) {
if (program.undo) {
sequelize.migrator.findOrCreateSequelizeMetaDAO().success(function(Meta) {
Meta.find({ order: 'id DESC' }).success(function(meta) {
if(meta) {
if (meta) {
migrator = sequelize.getMigrator(_.extend(migratorOptions, meta), true)
}
migrator.migrate({ method: 'down' })
migrator.migrate({ method: 'down' }).success(function() {
process.exit(0)
})
})
})
} else {
sequelize.migrate()
sequelize.migrate().success(function() {
process.exit(0)
})
}
} else {
console.log('Cannot find "config/config.json". Have you run "sequelize --init"?')
console.log('Cannot find "' + relativeConfigFile() + '". Have you run "sequelize --init"?')
process.exit(1)
}
} else if(program.init) {
if(!configFileExists || !!program.force) {
writeConfig({
development: {
username: "root",
password: null,
database: 'database_development',
host: '127.0.0.1'
},
test: {
username: "root",
password: null,
database: 'database_test',
host: '127.0.0.1'
},
production: {
username: "root",
password: null,
database: 'database_production',
host: '127.0.0.1'
}
})
if(!configFileExists() || !!program.force) {
writeDefaultConfig()
console.log('Created "config/config.json"')
console.log('Created "' + relativeConfigFile() + '"')
} else {
console.log('"config/config.json" already exists. Run "sequelize --init --force" to overwrite.')
console.log('The file "' + relativeConfigFile() + '" already exists. Run "sequelize --init --force" to overwrite it.')
process.exit(1)
}
......@@ -190,9 +205,11 @@ if(program.migrate) {
" done()",
" }",
"}"
].join('\n')
].join('\n') + "\n"
fs.writeFileSync(migrationsPath + '/' + migrationName, migrationContent)
fs.writeFileSync(configuration.migrationsPath + '/' + migrationName, migrationContent)
console.log('New migration "' + migrationName + '" was added to "' +
path.relative(process.cwd(), configuration.migrationsPath) + '/".')
} else {
console.log('Try "sequelize --help" for usage information.')
console.log('No action specified. Try "sequelize --help" for usage information.')
}
......@@ -354,14 +354,8 @@ module.exports = (function() {
DAOFactory.prototype.findAndCountAll = function(options) {
var self = this
, opts = Utils._.cloneDeep(options)
, copts = Utils._.extend({}, Utils._.cloneDeep(options) || {}, {
// no limit, offset, order or include for the options given to count()
offset : 0,
limit : 0,
order : null,
include : null
})
// no limit, offset, order, attributes or include for the options given to count()
, copts = Utils._.omit(options || {}, ['offset', 'limit', 'order', 'include', 'attributes'])
return new Utils.CustomEventEmitter(function (emitter) {
var emit = {
......@@ -383,8 +377,9 @@ module.exports = (function() {
.on('sql', emit.sql)
.error(emit.err)
.success(function(cnt) {
if (cnt === 0)
if (cnt === 0) {
return emit.okay(cnt) // no records, no need for another query
}
self.findAll(options)
.on('sql', emit.sql)
......
......@@ -183,7 +183,7 @@ module.exports = {
}
result.type = 'HSTORE'
result.toString = result.valueOf = function() { return 'TEXT' }
result.toString = result.valueOf = function() { return 'HSTORE' }
return result
}
......
......@@ -5,6 +5,7 @@ var Utils = require("../../utils")
module.exports = (function() {
var QueryGenerator = {
dialect: 'mysql',
addSchema: function(opts) {
var tableName
var schema = (!!opts && !!opts.options && !!opts.options.schema ? opts.options.schema : undefined)
......@@ -437,7 +438,7 @@ module.exports = (function() {
} else if (typeof smth === "string") {
result = smth
} else if (Array.isArray(smth)) {
result = Utils.format(smth)
result = Utils.format(smth, this.dialect)
}
return result ? result : '1=1'
......
......@@ -8,6 +8,7 @@ var Utils = require("../../utils")
module.exports = (function() {
var QueryGenerator = {
options: {},
dialect: 'postgres',
addSchema: function(opts) {
var tableName = undefined
......@@ -117,7 +118,7 @@ module.exports = (function() {
schema = 'public';
}
var query = 'SELECT c.column_name as "Field", c.column_default as "Default", c.is_nullable as "Null", c.data_type as "Type", (SELECT array_agg(e.enumlabel) FROM pg_catalog.pg_type t JOIN pg_catalog.pg_enum e ON t.oid=e.enumtypid WHERE t.typname=c.udt_name) AS "special" FROM information_schema.columns c WHERE table_name = <%= table %> AND table_schema = <%= schema %>'
var query = 'SELECT c.column_name as "Field", c.column_default as "Default", c.is_nullable as "Null", CASE WHEN c.udt_name = \'hstore\' THEN c.udt_name ELSE c.data_type END as "Type", (SELECT array_agg(e.enumlabel) FROM pg_catalog.pg_type t JOIN pg_catalog.pg_enum e ON t.oid=e.enumtypid WHERE t.typname=c.udt_name) AS "special" FROM information_schema.columns c WHERE table_name = <%= table %> AND table_schema = <%= schema %>'
return Utils._.template(query)({
table: this.escape(tableName),
......
......@@ -12,6 +12,7 @@ var hashToWhereConditions = MySqlQueryGenerator.hashToWhereConditions
module.exports = (function() {
var QueryGenerator = {
options: {},
dialect: 'sqlite',
addSchema: function(opts) {
var tableName = undefined
......
......@@ -58,8 +58,10 @@ module.exports = (function() {
} else {
self.options.logging("Running migrations...")
}
migrations.forEach(function(migration) {
var migrationTime
chainer.add(migration, 'execute', [options], {
before: function(migration) {
if (self.options.logging !== false) {
......@@ -67,6 +69,7 @@ module.exports = (function() {
}
migrationTime = process.hrtime()
},
after: function(migration) {
migrationTime = process.hrtime(migrationTime)
migrationTime = Math.round( (migrationTime[0] * 1000) + (migrationTime[1] / 1000000));
......@@ -75,6 +78,7 @@ module.exports = (function() {
self.options.logging('Completed in ' + migrationTime + 'ms')
}
},
success: function(migration, callback) {
if (options.method === 'down') {
deleteUndoneMigration.call(self, from, migration, callback)
......@@ -233,11 +237,21 @@ module.exports = (function() {
var self = this
return new Utils.CustomEventEmitter(function(emitter) {
self.findOrCreateSequelizeMetaDAO().success(function(SequelizeMeta) {
SequelizeMeta.find({ order: 'id DESC' }).success(function(meta) {
self
.findOrCreateSequelizeMetaDAO()
.success(function(SequelizeMeta) {
SequelizeMeta
.find({ order: 'id DESC' })
.success(function(meta) {
emitter.emit('success', meta ? meta : null)
}).error(function(err) { emitter.emit('error', err) })
}).error(function(err) { emitter.emit('error', err) })
})
.error(function(err) {
emitter.emit('error', err)
})
})
.error(function(err) {
emitter.emit('error', err)
})
}).run()
}
......@@ -245,7 +259,8 @@ module.exports = (function() {
var self = this
return new Utils.CustomEventEmitter(function(emitter) {
getLastMigrationFromDatabase.call(self)
getLastMigrationFromDatabase
.call(self)
.success(function(meta) {
emitter.emit('success', meta ? meta.to : null)
})
......
......@@ -210,12 +210,17 @@ module.exports = (function() {
}
Sequelize.prototype.migrate = function(options) {
this.getMigrator().migrate(options)
return this.getMigrator().migrate(options)
}
Sequelize.prototype.query = function(sql, callee, options, replacements) {
if (arguments.length === 4) {
if (Array.isArray(replacements)) {
sql = Utils.format([sql].concat(replacements), this.options.dialect)
}
else {
sql = Utils.formatNamedParameters(sql, replacements, this.options.dialect)
}
} else if (arguments.length === 3) {
options = options
} else if (arguments.length === 2) {
......
......@@ -106,6 +106,17 @@ SqlString.format = function(sql, values, timeZone, dialect) {
});
};
SqlString.formatNamedParameters = function(sql, values, timeZone, dialect) {
return sql.replace(/\:(\w+)/g, function (value, key) {
if (values.hasOwnProperty(key)) {
return SqlString.escape(values[key], false, timeZone, dialect);
}
else {
throw new Error('Named parameter "' + value + '" has no value in the given object.');
}
});
};
SqlString.dateToString = function(date, timeZone, dialect) {
var dt = new Date(date);
......
......@@ -29,6 +29,22 @@ var Utils = module.exports = {
}
return result
},
/*
* Returns an array with some falsy values removed. The values null, "", undefined and NaN are considered falsey.
*/
compactLite: function(array) {
var index = -1,
length = array ? array.length : 0,
result = [];
while (++index < length) {
var value = array[index];
if (typeof value === "boolean" || value === 0 || value) {
result.push(value);
}
}
return result;
}
})
......@@ -41,6 +57,10 @@ var Utils = module.exports = {
var timeZone = null;
return SqlString.format(arr.shift(), arr, timeZone, dialect)
},
formatNamedParameters: function(sql, parameters, dialect) {
var timeZone = null;
return SqlString.formatNamedParameters(sql, parameters, timeZone, dialect)
},
// smartWhere can accept an array of {where} objects, or a single {where} object.
// The smartWhere function breaks down the collection of where objects into a more
// centralized object for each column so we can avoid duplicates
......@@ -197,7 +217,7 @@ var Utils = module.exports = {
}
}
return lodash.compact([text.join(' AND ')].concat(whereArgs))
return Utils._.compactLite([text.join(' AND ')].concat(whereArgs))
},
getWhereLogic: function(logic) {
switch (logic) {
......
......@@ -19,7 +19,7 @@ describe(Support.getTestDialectTeaser("HasOne"), function() {
Task.create({ title: 'task', status: 'inactive' }).success(function(task) {
user.setTaskXYZ(task).success(function() {
user.getTaskXYZ({where: ['status = ?', 'active']}).success(function(task) {
expect(task).to.equal(null)
expect(task).to.be.null
done()
})
})
......
Subproject commit bc72b8587183be3f973292d6bf547adf864e7f9b
#!/usr/bin/env test/binary/bats/bin/bats
@test "no arguments prints usage instructions" {
run bin/sequelize
[ $status -eq 0 ]
[ $(expr "${lines[0]}" : "Using environment 'development'.") -ne 0 ]
[ $(expr "${lines[1]}" : "Try \"sequelize --help\" for usage information.") -ne 0 ]
}
@test "--help prints the help" {
run bin/sequelize --help
[ $status -eq 0 ]
[ "${lines[0]}" = " Usage: sequelize [options]" ]
}
@test "-h prints the help" {
run bin/sequelize -h
[ $status -eq 0 ]
[ "${lines[0]}" = " Usage: sequelize [options]" ]
}
@test "--version prints the current version" {
run bin/sequelize --version
[ $status -eq 0 ]
[ "${lines[0]}" = `cat package.json|grep version|cut -f2 -d:|cut -f2 -d\"` ]
}
@test "-V prints the current version" {
run bin/sequelize -V
[ $status -eq 0 ]
[ "${lines[0]}" = `cat package.json|grep version|cut -f2 -d:|cut -f2 -d\"` ]
}
@test "--init creates a config folder" {
cd test/binary/tmp
rm -rf ./*
../../../bin/sequelize --init
run ls -ila
[ $status -eq 0 ]
[ $(echo "${output}" | grep -b -o "config"|cut -d: -f1) -gt 0 ]
cd ../../..
}
@test "--init creates a migrations folder" {
cd test/binary/tmp
rm -rf ./*
../../../bin/sequelize --init
run ls -ila
[ $status -eq 0 ]
[ $(echo "${output}" | grep -b -o "migrations"|cut -d: -f1) -gt 0 ]
cd ../../..
}
@test "--init creates a config.json file" {
cd test/binary/tmp
rm -rf ./*
../../../bin/sequelize --init
run ls -ila config
[ $status -eq 0 ]
[ $(echo "${output}" | grep -b -o "config.json"|cut -d: -f1) -gt 0 ]
cd ../../..
}
@test "--init does not overwrite an existing config.json file" {
cd test/binary/tmp
rm -rf ./*
../../../bin/sequelize --init
echo "foo" > config/config.json
run ../../../bin/sequelize --init
[ $status -eq 1 ]
run cat config/config.json
[ $status -eq 0 ]
[ "${lines[0]}" = "foo" ]
cd ../../..
}
@test "--init does overwrite an existing config.json file if --force is added" {
cd test/binary/tmp
rm -rf ./*
../../../bin/sequelize --init
echo "foo" > config/config.json
run ../../../bin/sequelize --init -f
[ $status -eq 0 ]
run cat config/config.json
[ $status -eq 0 ]
[ "${lines[0]}" != "foo" ]
cd ../../..
}
@test "-i creates a config folder" {
cd test/binary/tmp
rm -rf ./*
../../../bin/sequelize -i
run ls -ila
[ $status -eq 0 ]
[ $(echo "${output}" | grep -b -o "config"|cut -d: -f1) -gt 0 ]
cd ../../..
}
@test "-i creates a migrations folder" {
cd test/binary/tmp
rm -rf ./*
../../../bin/sequelize -i
run ls -ila
[ $status -eq 0 ]
[ $(echo "${output}" | grep -b -o "migrations"|cut -d: -f1) -gt 0 ]
cd ../../..
}
@test "-i creates a config.json file" {
cd test/binary/tmp
rm -rf ./*
../../../bin/sequelize -i
run ls -ila config
[ $status -eq 0 ]
[ $(echo "${output}" | grep -b -o "config.json"|cut -d: -f1) -gt 0 ]
cd ../../..
}
@test "-i does not overwrite an existing config.json file" {
cd test/binary/tmp
rm -rf ./*
../../../bin/sequelize -i
echo "foo" > config/config.json
run ../../../bin/sequelize -i
[ $status -eq 1 ]
run cat config/config.json
[ $status -eq 0 ]
[ "${lines[0]}" = "foo" ]
cd ../../..
}
@test "-i does overwrite an existing config.json file if --force is added" {
cd test/binary/tmp
rm -rf ./*
../../../bin/sequelize -i
echo "foo" > config/config.json
run ../../../bin/sequelize -i -f
[ $status -eq 0 ]
run cat config/config.json
[ $status -eq 0 ]
[ "${lines[0]}" != "foo" ]
cd ../../..
}
@test "--env switches the environment" {
run bin/sequelize --env production
[ $status -eq 0 ]
[ $(expr "${lines[0]}" : "Using environment 'production'.") -ne 0 ]
}
@test "-e switches the environment" {
run bin/sequelize -e production
[ $status -eq 0 ]
[ $(expr "${lines[0]}" : "Using environment 'production'.") -ne 0 ]
}
@test "--create-migration creates a new file with the current timestamp" {
cd test/binary/tmp
rm -rf ./*
../../../bin/sequelize -i
../../../bin/sequelize --create-migration "foo"
needle=`node -e "var d=new Date(); var f=function(i){ return (parseInt(i, 10) < 10 ? '0' + i : i) }; console.log([d.getFullYear(), f(d.getMonth() + 1), f(d.getDate()), f(d.getHours()), f(d.getMinutes()), f(d.getSeconds())].join(''))"`
run ls -1 migrations
[ $status -eq 0 ]
[ $(expr "${lines[0]}" : "${needle}-foo.js") -ne 0 ]
cd ../../..
}
@test "--create-migration adds a skeleton with an up and a down method" {
cd test/binary/tmp
rm -rf ./*
../../../bin/sequelize -i
../../../bin/sequelize --create-migration "foo"
run cat migrations/*-foo.js
[ $status -eq 0 ]
[ $(expr "${lines[1]}" : " up: function(migration, DataTypes, done) {") -ne 0 ]
[ $(expr "${lines[5]}" : " down: function(migration, DataTypes, done) {") -ne 0 ]
cd ../../..
}
@test "--create-migration calls the done callback" {
cd test/binary/tmp
rm -rf ./*
../../../bin/sequelize -i
../../../bin/sequelize --create-migration "foo"
run cat migrations/*-foo.js
[ $status -eq 0 ]
[ $(expr "${lines[3]}" : " done()") -ne 0 ]
[ $(expr "${lines[7]}" : " done()") -ne 0 ]
cd ../../..
}
@test "-c creates a new file with the current timestamp" {
cd test/binary/tmp
rm -rf ./*
../../../bin/sequelize -i
../../../bin/sequelize -c "foo"
needle=`node -e "var d=new Date(); var f=function(i){ return (parseInt(i, 10) < 10 ? '0' + i : i) }; console.log([d.getFullYear(), f(d.getMonth() + 1), f(d.getDate()), f(d.getHours()), f(d.getMinutes()), f(d.getSeconds())].join(''))"`
run ls -1 migrations
[ $status -eq 0 ]
[ $(expr "${lines[0]}" : "${needle}-foo.js") -ne 0 ]
cd ../../..
}
@test "-c adds a skeleton with an up and a down method" {
cd test/binary/tmp
rm -rf ./*
../../../bin/sequelize -i
../../../bin/sequelize -c "foo"
run cat migrations/*-foo.js
[ $status -eq 0 ]
[ $(expr "${lines[1]}" : " up: function(migration, DataTypes, done) {") -ne 0 ]
[ $(expr "${lines[5]}" : " down: function(migration, DataTypes, done) {") -ne 0 ]
cd ../../..
}
@test "-c calls the done callback" {
cd test/binary/tmp
rm -rf ./*
../../../bin/sequelize -i
../../../bin/sequelize -c "foo"
run cat migrations/*-foo.js
[ $status -eq 0 ]
[ $(expr "${lines[3]}" : " done()") -ne 0 ]
[ $(expr "${lines[7]}" : " done()") -ne 0 ]
cd ../../..
}
......@@ -21,7 +21,8 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
secretValue: DataTypes.STRING,
data: DataTypes.STRING,
intVal: DataTypes.INTEGER,
theDate: DataTypes.DATE
theDate: DataTypes.DATE,
aBool: DataTypes.BOOLEAN
})
this.User.sync({ force: true }).success(function() {
done()
......@@ -999,6 +1000,72 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
})
})
it('should be able to handle false/true values just fine...', function(done) {
var User = this.User
, escapeChar = (dialect === "postgres" || dialect === "postgres-native") ? '"' : '`'
User.bulkCreate([
{username: 'boo5', aBool: false},
{username: 'boo6', aBool: true}
]).success(function() {
User.all({where: [escapeChar + 'aBool' + escapeChar + ' = ?', false]}).success(function(users) {
expect(users).to.have.length(1)
expect(users[0].username).to.equal('boo5')
User.all({where: [escapeChar + 'aBool' + escapeChar + ' = ?', true]}).success(function(_users) {
expect(_users).to.have.length(1)
expect(_users[0].username).to.equal('boo6')
done()
})
})
})
})
it('should be able to handle false/true values through associations as well...', function(done) {
var User = this.User
, escapeChar = (dialect === "postgres" || dialect === "postgres-native") ? '"' : '`'
var Passports = this.sequelize.define('Passports', {
isActive: Sequelize.BOOLEAN
})
User.hasMany(Passports)
Passports.belongsTo(User)
User.sync({ force: true }).success(function() {
Passports.sync({ force: true }).success(function() {
User.bulkCreate([
{username: 'boo5', aBool: false},
{username: 'boo6', aBool: true}
]).success(function() {
Passports.bulkCreate([
{isActive: true},
{isActive: false}
]).success(function() {
User.find(1).success(function(user) {
Passports.find(1).success(function(passport) {
user.setPassports([passport]).success(function() {
User.find(2).success(function(_user) {
Passports.find(2).success(function(_passport) {
_user.setPassports([_passport]).success(function() {
_user.getPassports({where: [escapeChar + 'isActive' + escapeChar + ' = ?', false]}).success(function(theFalsePassport) {
user.getPassports({where: [escapeChar + 'isActive' + escapeChar + ' = ?', true]}).success(function(theTruePassport) {
expect(theFalsePassport).to.have.length(1)
expect(theFalsePassport[0].isActive).to.be.false
expect(theTruePassport).to.have.length(1)
expect(theTruePassport[0].isActive).to.be.true
done()
})
})
})
})
})
})
})
})
})
})
})
})
})
it('should be able to retun a record with primaryKey being null for new inserts', function(done) {
var Session = this.sequelize.define('Session', {
token: { type: DataTypes.TEXT, allowNull: false },
......@@ -2231,6 +2298,16 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
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)
expect(Array.isArray(info.rows)).to.be.ok
expect(info.rows.length).to.equal(2)
expect(info.rows[0].selectedValues).to.not.have.property('username')
expect(info.rows[1].selectedValues).to.not.have.property('username')
done()
})
})
})
describe('all', function() {
......
......@@ -2,7 +2,6 @@ var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/../support')
, dialect = Support.getTestDialect()
, config = require(__dirname + '/../config/config')
, DataTypes = require(__dirname + "/../../lib/data-types")
chai.Assertion.includeStack = true
......@@ -26,6 +25,13 @@ if (dialect.match(/^postgres/)) {
done()
})
it('describeTable should tell me that a column is hstore and not USER-DEFINED', function(done) {
this.sequelize.queryInterface.describeTable('Users').success(function(table) {
expect(table.document.type).to.equal('HSTORE')
done()
})
})
describe('integers', function() {
describe('integer', function() {
beforeEach(function(done) {
......
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/support')
, DataTypes = require(__dirname + "/../lib/data-types")
, dialect = Support.getTestDialect()
, _ = require('lodash')
, exec = require('child_process').exec
, version = (require(__dirname + '/../package.json')).version
chai.Assertion.includeStack = true
describe(Support.getTestDialectTeaser("Executable"), function() {
describe('call without arguments', function() {
it("prints usage instructions", function(done) {
exec('bin/sequelize', function(err, stdout, stderr) {
expect(stdout).to.include("No action specified. Try \"sequelize --help\" for usage information.")
done()
})
})
})
;(function(flags) {
flags.forEach(function(flag) {
describe(flag, function() {
it("prints the help", function(done) {
exec("bin/sequelize " + flag, function(err, stdout, stderr) {
expect(stdout).to.include("Usage: sequelize [options]")
done()
})
})
})
})
})(["--help", "-h"])
;(function(flags) {
flags.forEach(function(flag) {
describe(flag, function() {
it("prints the help", function(done) {
exec("bin/sequelize " + flag, function(err, stdout, stderr) {
expect(version).to.not.be.empty
expect(stdout).to.include(version)
done()
})
})
})
})
})(['--version', '-V'])
;(function(flags) {
flags.forEach(function(flag) {
describe(flag, function() {
;(function(folders) {
folders.forEach(function(folder) {
it("creates a '" + folder + "' folder", function(done) {
exec("rm -rf ./*", { cwd: __dirname + '/tmp' }, function() {
exec("../../bin/sequelize --init", { cwd: __dirname + '/tmp' }, function() {
exec("ls -ila", { cwd: __dirname + '/tmp' }, function(err, stdout) {
expect(stdout).to.include(folder)
done()
})
})
})
})
})
})(['config', 'migrations'])
it("creates a config.json file", function(done) {
exec("rm -rf ./*", { cwd: __dirname + '/tmp' }, function() {
exec("../../bin/sequelize --init", { cwd: __dirname + '/tmp' }, function() {
exec("ls -ila config", { cwd: __dirname + '/tmp' }, function(err, stdout) {
expect(stdout).to.include('config.json')
done()
})
})
})
})
it("does not overwrite an existing config.json file", function(done) {
exec("rm -rf ./*", { cwd: __dirname + '/tmp' }, function() {
exec("../../bin/sequelize --init", { cwd: __dirname + '/tmp' }, function() {
exec("echo 'foo' > config/config.json", { cwd: __dirname + '/tmp' }, function() {
exec("../../bin/sequelize --init", { cwd: __dirname + '/tmp' }, function(err) {
expect(err.code).to.equal(1)
exec("cat config/config.json", { cwd: __dirname + '/tmp' }, function(err, stdout) {
expect(stdout).to.equal("foo\n")
done()
})
})
})
})
})
})
})
})
})(['--init', '-i'])
;(function(flags) {
flags.forEach(function(flag) {
var prepare = function(callback) {
exec("rm -rf ./*", { cwd: __dirname + '/tmp' }, function() {
exec("../../bin/sequelize --init", { cwd: __dirname + '/tmp' }, function() {
exec("../../bin/sequelize " + flag + " 'foo'", { cwd: __dirname + '/tmp' }, callback)
})
})
}
describe(flag, function() {
it("creates a new file with the current timestamp", function(done) {
prepare(function() {
exec("ls -1 migrations", { cwd: __dirname + '/tmp' }, function(err, stdout) {
var date = new Date()
, format = function(i) { return (parseInt(i, 10) < 10 ? '0' + i : i) }
, sDate = [date.getFullYear(), format(date.getMonth() + 1), format(date.getDate()), format(date.getHours()), format(date.getMinutes())].join('')
expect(stdout).to.match(new RegExp(sDate + "..-foo.js"))
done()
})
})
})
it("adds a skeleton with an up and a down method", function(done) {
prepare(function() {
exec("cat migrations/*-foo.js", { cwd: __dirname + '/tmp' }, function(err, stdout) {
expect(stdout).to.include('up: function(migration, DataTypes, done) {')
expect(stdout).to.include('down: function(migration, DataTypes, done) {')
done()
})
})
})
it("calls the done callback", function(done) {
prepare(function() {
exec("cat migrations/*-foo.js", { cwd: __dirname + '/tmp' }, function(err, stdout) {
expect(stdout).to.include('done()')
expect(stdout.match(/(done\(\))/)).to.have.length(2)
done()
})
})
})
})
})
})(['--create-migration', '-c'])
;(function(flags) {
flags.forEach(function(flag) {
var prepare = function(callback) {
exec("rm -rf ./*", { cwd: __dirname + '/tmp' }, function() {
exec("../../bin/sequelize --init", { cwd: __dirname + '/tmp' }, function() {
exec("cp ../assets/migrations/*-createPerson.js ./migrations/", { cwd: __dirname + '/tmp' }, function() {
exec("cat ../support.js|sed s,/../,/../../, > ./support.js", { cwd: __dirname + '/tmp' }, function() {
var dialect = Support.getTestDialect()
, config = require(__dirname + '/config/config.js')
config.sqlite.storage = __dirname + "/tmp/test.sqlite"
config = _.extend(config, config[dialect], { dialect: dialect })
exec("echo '" + JSON.stringify(config) + "' > config/config.json", { cwd: __dirname + '/tmp' }, function() {
exec("../../bin/sequelize " + flag, { cwd: __dirname + "/tmp" }, callback)
})
})
})
})
})
}
describe(flag, function() {
it("creates a SequelizeMeta table", function(done) {
var sequelize = this.sequelize
if (this.sequelize.options.dialect === 'sqlite') {
var options = this.sequelize.options
options.storage = __dirname + "/tmp/test.sqlite"
sequelize = new Support.Sequelize("", "", "", options)
}
prepare(function() {
sequelize.getQueryInterface().showAllTables().success(function(tables) {
tables = tables.sort()
expect(tables).to.have.length(2)
expect(tables[1]).to.equal("SequelizeMeta")
done()
})
}.bind(this))
})
it("creates the respective table", function(done) {
var sequelize = this.sequelize
if (this.sequelize.options.dialect === 'sqlite') {
var options = this.sequelize.options
options.storage = __dirname + "/tmp/test.sqlite"
sequelize = new Support.Sequelize("", "", "", options)
}
prepare(function() {
sequelize.getQueryInterface().showAllTables().success(function(tables) {
tables = tables.sort()
expect(tables).to.have.length(2)
expect(tables[0]).to.equal("Person")
done()
})
}.bind(this))
})
})
})
})(['--migrate', '-m'])
})
......@@ -177,6 +177,67 @@ describe(Support.getTestDialectTeaser("Sequelize"), function () {
})
})
it('replaces named parameters with the passed object', function(done) {
this.sequelize.query('select :one as foo, :two as bar', null, { raw: true }, { one: 1, two: 2 }).success(function(result) {
expect(result).to.deep.equal([{ foo: 1, bar: 2 }])
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 }])
done()
})
})
it('replaces named parameters with the passed object having a null property', function(done) {
this.sequelize.query('select :one as foo, :two as bar', null, { raw: true }, { one: 1, two: null }).success(function(result) {
expect(result).to.deep.equal([{ foo: 1, bar: null }])
done()
})
})
it('throw an exception when key is missing in the passed object', function(done) {
var self = this
expect(function() {
self.sequelize.query('select :one as foo, :two as bar, :three as baz', null, { raw: true }, { one: 1, two: 2 })
}).to.throw(Error, /Named parameter ":\w+" has no value in the given object\./g)
done()
})
it('throw an exception with the passed number', function(done) {
var self = this
expect(function() {
self.sequelize.query('select :one as foo, :two as bar', null, { raw: true }, 2)
}).to.throw(Error, /Named parameter ":\w+" has no value in the given object\./g)
done()
})
it('throw an exception with the passed empty object', function(done) {
var self = this
expect(function() {
self.sequelize.query('select :one as foo, :two as bar', null, { raw: true }, {})
}).to.throw(Error, /Named parameter ":\w+" has no value in the given object\./g)
done()
})
it('throw an exception with the passed string', function(done) {
var self = this
expect(function() {
self.sequelize.query('select :one as foo, :two as bar', null, { raw: true }, 'foobar')
}).to.throw(Error, /Named parameter ":\w+" has no value in the given object\./g)
done()
})
it('throw an exception with the passed date', function(done) {
var self = this
expect(function() {
self.sequelize.query('select :one as foo, :two as bar', null, { raw: true }, new Date())
}).to.throw(Error, /Named parameter ":\w+" has no value in the given object\./g)
done()
})
it('handles AS in conjunction with functions just fine', function(done) {
this.sequelize.query('SELECT ' + (dialect === "sqlite" ? 'date(\'now\')' : 'NOW()') + ' AS t').success(function(result) {
expect(moment(result[0].t).isValid()).to.be.true
......
......@@ -116,6 +116,18 @@ var Support = {
var sequelize = Support.createSequelizeInstance({ dialect: Support.getTestDialect() })
// For Postgres' HSTORE functionality and to properly execute it's commands we'll need this...
before(function(done) {
var dialect = Support.getTestDialect()
if (dialect !== "postgres" && dialect !== "postgres-native") {
return done()
}
sequelize.query('CREATE EXTENSION IF NOT EXISTS hstore', null, {raw: true}).success(function() {
done()
})
})
beforeEach(function(done) {
this.sequelize = sequelize
Support.clearDatabase(this.sequelize, function() {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!