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

Commit d72b8517 by Mick Hansen

Merge pull request #3128 from v12/master

[PostgreSQL] Support for range datatype
2 parents 9612da15 1927e825
...@@ -328,7 +328,7 @@ util.inherits(JSONTYPE, ABSTRACT); ...@@ -328,7 +328,7 @@ util.inherits(JSONTYPE, ABSTRACT);
JSONTYPE.prototype.key = JSONTYPE.key = 'JSON'; JSONTYPE.prototype.key = JSONTYPE.key = 'JSON';
/* /**
* A pre-processed JSON data column. Only available in postgres. * A pre-processed JSON data column. Only available in postgres.
* @property JSONB * @property JSONB
*/ */
...@@ -382,6 +382,38 @@ BLOB.prototype.toSql = function() { ...@@ -382,6 +382,38 @@ BLOB.prototype.toSql = function() {
}; };
/** /**
* Range types are data types representing a range of values of some element type (called the range's subtype).
* Only available in postgres.
* See {@link http://www.postgresql.org/docs/9.4/static/rangetypes.html|Postgres documentation} for more details
* @property RANGE
*/
var RANGE = function (subtype) {
var options = _.isPlainObject(subtype) ? subtype : { subtype: subtype };
if (!options.subtype) options.subtype = INTEGER;
if (!(this instanceof RANGE)) return new RANGE(options);
ABSTRACT.apply(this, arguments);
this._subtype = options.subtype.key;
};
util.inherits(RANGE, ABSTRACT);
var pgRangeSubtypes = {
integer: 'int4range',
bigint: 'int8range',
decimal: 'numrange',
dateonly: 'daterange',
date: 'tstzrange'
};
RANGE.prototype.key = RANGE.key = 'RANGE';
RANGE.prototype.toSql = function() {
return pgRangeSubtypes[this._subtype.toLowerCase()];
};
/**
* A column storing a unique univeral identifier. Use with `UUIDV1` or `UUIDV4` for default values. * A column storing a unique univeral identifier. Use with `UUIDV1` or `UUIDV4` for default values.
* @property UUID * @property UUID
*/ */
...@@ -478,7 +510,7 @@ ENUM.prototype.key = ENUM.key = 'ENUM'; ...@@ -478,7 +510,7 @@ ENUM.prototype.key = ENUM.key = 'ENUM';
* @property ARRAY * @property ARRAY
*/ */
var ARRAY = function(type) { var ARRAY = function(type) {
var options = typeof type === "object" && !(type instanceof ABSTRACT) && type || { var options = _.isPlainObject(type) ? type : {
type: type type: type
}; };
if (!(this instanceof ARRAY)) return new ARRAY(options); if (!(this instanceof ARRAY)) return new ARRAY(options);
...@@ -544,5 +576,6 @@ module.exports = { ...@@ -544,5 +576,6 @@ module.exports = {
VIRTUAL: VIRTUAL, VIRTUAL: VIRTUAL,
ARRAY: ARRAY, ARRAY: ARRAY,
NONE: VIRTUAL, NONE: VIRTUAL,
ENUM: ENUM ENUM: ENUM,
RANGE: RANGE
}; };
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
var Utils = require('../../utils') var Utils = require('../../utils')
, hstore = require('./hstore') , hstore = require('./hstore')
, range = require('./range')
, util = require('util') , util = require('util')
, DataTypes = require('../../data-types') , DataTypes = require('../../data-types')
, SqlString = require('../../sql-string') , SqlString = require('../../sql-string')
...@@ -871,6 +872,13 @@ module.exports = (function() { ...@@ -871,6 +872,13 @@ module.exports = (function() {
} else if (DataTypes.ARRAY.is(field.type, DataTypes.HSTORE)) { } else if (DataTypes.ARRAY.is(field.type, DataTypes.HSTORE)) {
return "ARRAY[" + Utils._.map(value, function(v){return "'" + hstore.stringify(v) + "'::hstore";}).join(",") + "]::HSTORE[]"; return "ARRAY[" + Utils._.map(value, function(v){return "'" + hstore.stringify(v) + "'::hstore";}).join(",") + "]::HSTORE[]";
} }
} else if(Utils._.isArray(value) && field && (field.type instanceof DataTypes.RANGE || DataTypes.ARRAY.is(field.type, DataTypes.RANGE))) {
if(field.type instanceof DataTypes.RANGE) { // escape single value
return "'" + range.stringify(value) + "'";
}
else if (DataTypes.ARRAY.is(field.type, DataTypes.RANGE)) { // escape array of ranges
return "ARRAY[" + Utils._.map(value, function(v){return "'" + range.stringify(v) + "'";}).join(",") + "]::" + field.type.toString();
}
} else if (field && (field.type instanceof DataTypes.JSON || field.type instanceof DataTypes.JSONB)) { } else if (field && (field.type instanceof DataTypes.JSON || field.type instanceof DataTypes.JSONB)) {
value = JSON.stringify(value); value = JSON.stringify(value);
} else if (Array.isArray(value) && field && DataTypes.ARRAY.is(field.type, DataTypes.JSON)) { } else if (Array.isArray(value) && field && DataTypes.ARRAY.is(field.type, DataTypes.JSON)) {
......
...@@ -4,6 +4,7 @@ var Utils = require('../../utils') ...@@ -4,6 +4,7 @@ var Utils = require('../../utils')
, AbstractQuery = require('../abstract/query') , AbstractQuery = require('../abstract/query')
, DataTypes = require('../../data-types') , DataTypes = require('../../data-types')
, hstore = require('./hstore') , hstore = require('./hstore')
, range = require('./range')
, QueryTypes = require('../../query-types') , QueryTypes = require('../../query-types')
, Promise = require('../../promise') , Promise = require('../../promise')
, sequelizeErrors = require('../../errors.js'); , sequelizeErrors = require('../../errors.js');
...@@ -25,6 +26,20 @@ var parseHstoreFields = function(model, row) { ...@@ -25,6 +26,20 @@ var parseHstoreFields = function(model, row) {
}); });
}; };
var parseRangeFields = function (model, row) {
Utils._.forEach(row, function (value, key) {
if (value === null) return row[key] = null;
if (model._isRangeAttribute(key)) {
row[key] = range.parse(value, model.attributes[key].type);
} else if (model.attributes[key] && DataTypes.ARRAY.is(model.attributes[key].type, DataTypes.RANGE)) {
var array = JSON.parse('[' + value.slice(1).slice(0, -1) + ']');
row[key] = Utils._.map(array, function (v) { return range.parse(v, model.attributes[key].type.type); });
} else {
row[key] = value;
}
});
};
module.exports = (function() { module.exports = (function() {
var Query = function(client, sequelize, callee, options) { var Query = function(client, sequelize, callee, options) {
...@@ -121,7 +136,7 @@ module.exports = (function() { ...@@ -121,7 +136,7 @@ module.exports = (function() {
attribute: field, attribute: field,
collate: attribute.match(/COLLATE "(.*?)"/) ? /COLLATE "(.*?)"/.exec(attribute)[1] : undefined, collate: attribute.match(/COLLATE "(.*?)"/) ? /COLLATE "(.*?)"/.exec(attribute)[1] : undefined,
order: attribute.indexOf('DESC') !== -1 ? 'DESC' : attribute.indexOf('ASC') !== -1 ? 'ASC': undefined, order: attribute.indexOf('DESC') !== -1 ? 'DESC' : attribute.indexOf('ASC') !== -1 ? 'ASC': undefined,
length: undefined, length: undefined
}; };
}); });
delete result.columns; delete result.columns;
...@@ -168,6 +183,12 @@ module.exports = (function() { ...@@ -168,6 +183,12 @@ module.exports = (function() {
}); });
} }
if (!!self.callee && !!self.callee._hasRangeAttributes) {
rows.forEach(function (row) {
parseRangeFields(self.callee, row);
});
}
return self.handleSelectQuery(rows); return self.handleSelectQuery(rows);
} else if (QueryTypes.DESCRIBE === self.options.type) { } else if (QueryTypes.DESCRIBE === self.options.type) {
result = {}; result = {};
...@@ -214,6 +235,12 @@ module.exports = (function() { ...@@ -214,6 +235,12 @@ module.exports = (function() {
}); });
} }
if (!!self.callee && !!self.callee._hasRangeAttributes) {
rows.forEach(function (row) {
parseRangeFields(self.callee, row);
});
}
return self.handleSelectQuery(rows); return self.handleSelectQuery(rows);
} else if (QueryTypes.BULKDELETE === self.options.type) { } else if (QueryTypes.BULKDELETE === self.options.type) {
return parseInt(result.rowCount, 10); return parseInt(result.rowCount, 10);
...@@ -225,6 +252,10 @@ module.exports = (function() { ...@@ -225,6 +252,10 @@ module.exports = (function() {
parseHstoreFields(self.callee.Model, rows[0]); parseHstoreFields(self.callee.Model, rows[0]);
} }
if (!!self.callee.Model && !!self.callee.Model._hasRangeAttributes) {
parseRangeFields(self.callee.Model, rows[0]);
}
for (var key in rows[0]) { for (var key in rows[0]) {
if (rows[0].hasOwnProperty(key)) { if (rows[0].hasOwnProperty(key)) {
var record = rows[0][key]; var record = rows[0][key];
...@@ -254,7 +285,10 @@ module.exports = (function() { ...@@ -254,7 +285,10 @@ module.exports = (function() {
Query.prototype.formatError = function (err) { Query.prototype.formatError = function (err) {
var match var match
, table , table
, index; , index
, fields
, errors
, message;
var code = err.code || err.sqlState var code = err.code || err.sqlState
, errMessage = err.message || err.messagePrimary , errMessage = err.message || err.messagePrimary
...@@ -277,9 +311,9 @@ module.exports = (function() { ...@@ -277,9 +311,9 @@ module.exports = (function() {
match = errDetail.match(/Key \((.*?)\)=\((.*?)\)/); match = errDetail.match(/Key \((.*?)\)=\((.*?)\)/);
if (match) { if (match) {
var fields = Utils._.zipObject(match[1].split(', '), match[2].split(', ')) fields = Utils._.zipObject(match[1].split(', '), match[2].split(', '));
, errors = [] errors = [];
, message = 'Validation error'; message = 'Validation error';
Utils._.forOwn(fields, function(value, field) { Utils._.forOwn(fields, function(value, field) {
errors.push(new sequelizeErrors.ValidationErrorItem( errors.push(new sequelizeErrors.ValidationErrorItem(
...@@ -309,6 +343,20 @@ module.exports = (function() { ...@@ -309,6 +343,20 @@ module.exports = (function() {
} }
break; break;
case '23P01':
match = errDetail.match(/Key \((.*?)\)=\((.*?)\)/);
fields = Utils._.zipObject(match[1].split(', '), match[2].split(', '));
message = 'Exclusion constraint error';
return new sequelizeErrors.ExclusionConstraintError({
message: message,
constraint: err.constraint,
fields: fields,
table: err.table,
parent: err
});
default: default:
return new sequelizeErrors.DatabaseError(err); return new sequelizeErrors.DatabaseError(err);
} }
......
'use strict';
var Utils = require('../../utils'),
moment = require('moment');
module.exports = {
stringify: function (data) {
if (data === null) return null;
if (!Utils._.isArray(data) || data.length !== 2) return '';
if (Utils._.any(data, Utils._.isNull)) return '';
if (data.hasOwnProperty('inclusive')) {
if (!data.inclusive) data.inclusive = [false, false];
else if (data.inclusive === true) data.inclusive = [true, true];
} else {
data.inclusive = [false, false];
}
Utils._.each(data, function (value, index) {
if (Utils._.isObject(value)) {
if (value.hasOwnProperty('inclusive')) data.inclusive[index] = !!value.inclusive;
if (value.hasOwnProperty('value')) data[index] = value.value;
}
});
return (data.inclusive[0] ? '[' : '(') + JSON.stringify(data[0]) + ',' + JSON.stringify(data[1]) + (data.inclusive[1] ? ']' : ')');
},
parse: function (value, AttributeType) {
if (value === null) return null;
if(typeof AttributeType === 'function') AttributeType = new AttributeType();
AttributeType = AttributeType || ''; // if attribute is not defined, assign empty string in order to prevent
// AttributeType.toString() to fail with uncaught exception later in the code
var result = value
.slice(1, -1)
.split(',', 2);
if (result.length !== 2) return value;
result = result
.map(function (value) {
switch (AttributeType.toString()) {
case 'int4range':
return parseInt(value, 10);
case 'numrange':
return parseFloat(value);
case 'daterange':
case 'tsrange':
case 'tstzrange':
return moment(value).toDate();
}
return value;
});
result.inclusive = [(value[0] === '['), (value[value.length - 1] === ']')];
return result;
}
};
...@@ -145,6 +145,25 @@ error.ForeignKeyConstraintError = function (options) { ...@@ -145,6 +145,25 @@ error.ForeignKeyConstraintError = function (options) {
util.inherits(error.ForeignKeyConstraintError, error.DatabaseError); util.inherits(error.ForeignKeyConstraintError, error.DatabaseError);
/** /**
* Thrown when an exclusion constraint is violated in the database
* @extends DatabaseError
* @constructor
*/
error.ExclusionConstraintError = function (options) {
options = options || {};
options.parent = options.parent || { sql: '' };
error.DatabaseError.call(this, options.parent);
this.name = 'SequelizeExclusionConstraintError';
this.message = options.message;
this.constraint = options.constraint;
this.fields = options.fields;
this.table = options.table;
};
util.inherits(error.ExclusionConstraintError, error.DatabaseError);
/**
* The message from the DB. * The message from the DB.
* @property message * @property message
* @name message * @name message
......
...@@ -80,7 +80,7 @@ module.exports = (function() { ...@@ -80,7 +80,7 @@ module.exports = (function() {
if (attribute.type === undefined) { if (attribute.type === undefined) {
throw new Error('Unrecognized data type for field ' + name); throw new Error('Unrecognized data type for field ' + name);
} }
if (attribute.type instanceof DataTypes.ENUM) { if (attribute.type instanceof DataTypes.ENUM) {
if (!attribute.values.length) { if (!attribute.values.length) {
...@@ -156,7 +156,7 @@ module.exports = (function() { ...@@ -156,7 +156,7 @@ module.exports = (function() {
self.options.uniqueKeys[idxName] = { self.options.uniqueKeys[idxName] = {
name: idxName, name: idxName,
fields: [attribute], fields: [attribute],
singleField: true, singleField: true
}; };
} else if (options.unique !== false) { } else if (options.unique !== false) {
idxName = options.unique; idxName = options.unique;
...@@ -281,6 +281,7 @@ module.exports = (function() { ...@@ -281,6 +281,7 @@ module.exports = (function() {
this._booleanAttributes = []; this._booleanAttributes = [];
this._dateAttributes = []; this._dateAttributes = [];
this._hstoreAttributes = []; this._hstoreAttributes = [];
this._rangeAttributes = [];
this._jsonAttributes = []; this._jsonAttributes = [];
this._virtualAttributes = []; this._virtualAttributes = [];
this._defaultValues = {}; this._defaultValues = {};
...@@ -303,6 +304,8 @@ module.exports = (function() { ...@@ -303,6 +304,8 @@ module.exports = (function() {
self._dateAttributes.push(name); self._dateAttributes.push(name);
} else if (definition.type instanceof DataTypes.HSTORE) { } else if (definition.type instanceof DataTypes.HSTORE) {
self._hstoreAttributes.push(name); self._hstoreAttributes.push(name);
} else if (definition.type instanceof DataTypes.RANGE) {
self._rangeAttributes.push(name);
} else if (definition.type instanceof DataTypes.JSON) { } else if (definition.type instanceof DataTypes.JSON) {
self._jsonAttributes.push(name); self._jsonAttributes.push(name);
} else if (definition.type instanceof DataTypes.VIRTUAL) { } else if (definition.type instanceof DataTypes.VIRTUAL) {
...@@ -313,7 +316,7 @@ module.exports = (function() { ...@@ -313,7 +316,7 @@ module.exports = (function() {
if (typeof definition.defaultValue === "function" && ( if (typeof definition.defaultValue === "function" && (
definition.defaultValue === DataTypes.NOW || definition.defaultValue === DataTypes.NOW ||
definition.defaultValue === DataTypes.UUIDV4 || definition.defaultValue === DataTypes.UUIDV4 ||
definition.defaultValue === DataTypes.UUIDV4 definition.defaultValue === DataTypes.UUIDV4
)) { )) {
definition.defaultValue = new definition.defaultValue(); definition.defaultValue = new definition.defaultValue();
} }
...@@ -341,6 +344,11 @@ module.exports = (function() { ...@@ -341,6 +344,11 @@ module.exports = (function() {
return self._hstoreAttributes.indexOf(key) !== -1; return self._hstoreAttributes.indexOf(key) !== -1;
}); });
this._hasRangeAttributes = !!this._rangeAttributes.length;
this._isRangeAttribute = Utils._.memoize(function(key) {
return self._rangeAttributes.indexOf(key) !== -1;
});
this._hasJsonAttributes = !!this._jsonAttributes.length; this._hasJsonAttributes = !!this._jsonAttributes.length;
this._isJsonAttribute = Utils._.memoize(function(key) { this._isJsonAttribute = Utils._.memoize(function(key) {
return self._jsonAttributes.indexOf(key) !== -1; return self._jsonAttributes.indexOf(key) !== -1;
...@@ -819,7 +827,7 @@ module.exports = (function() { ...@@ -819,7 +827,7 @@ module.exports = (function() {
} }
options = paranoidClause(this, options); options = paranoidClause(this, options);
return this.QueryInterface.rawSelect(this.getTableName(options), options, aggregateFunction, this); return this.QueryInterface.rawSelect(this.getTableName(options), options, aggregateFunction, this);
}; };
...@@ -1141,7 +1149,7 @@ module.exports = (function() { ...@@ -1141,7 +1149,7 @@ module.exports = (function() {
queryOptions.transaction = transaction; queryOptions.transaction = transaction;
return self.find(options, { return self.find(options, {
transaction: transaction, transaction: transaction
}); });
}).then(function(instance) { }).then(function(instance) {
if (instance !== null) { if (instance !== null) {
...@@ -1171,7 +1179,7 @@ module.exports = (function() { ...@@ -1171,7 +1179,7 @@ module.exports = (function() {
// Someone must have created a matching instance inside the same transaction since we last did a find. Let's find it! // Someone must have created a matching instance inside the same transaction since we last did a find. Let's find it!
return self.find(options, { return self.find(options, {
transaction: internalTransaction ? null : this.transaction, transaction: internalTransaction ? null : this.transaction
}).then(function(instance) { }).then(function(instance) {
// Sanity check, ideally we caught this at the defaultFeilds/err.fields check // Sanity check, ideally we caught this at the defaultFeilds/err.fields check
// But if we didn't and instance is null, we will throw // But if we didn't and instance is null, we will throw
......
...@@ -321,6 +321,13 @@ module.exports = (function() { ...@@ -321,6 +321,13 @@ module.exports = (function() {
sequelizeErrors.UniqueConstraintError; sequelizeErrors.UniqueConstraintError;
/** /**
* Thrown when an exclusion constraint is violated in the database
* @see {Errors#ExclusionConstraintError}
*/
Sequelize.prototype.ExclusionConstraintError = Sequelize.ExclusionConstraintError =
sequelizeErrors.ExclusionConstraintError;
/**
* Thrown when a foreign key constraint is violated in the database * Thrown when a foreign key constraint is violated in the database
* @see {Errors#ForeignKeyConstraintError} * @see {Errors#ForeignKeyConstraintError}
*/ */
......
'use strict';
var chai = require('chai')
, sinon = require('sinon')
, expect = chai.expect
, DataTypes = require(__dirname + '/../../../../lib/data-types')
, Support = require(__dirname + '/../../support')
, Sequelize = Support.Sequelize
, dialect = Support.getTestDialect()
, Promise = Sequelize.Promise
, _ = require('lodash');
chai.config.includeStack = true;
if (dialect.match(/^postgres/)) {
var constraintName = 'overlap_period';
beforeEach(function () {
var self = this;
this.Booking = self.sequelize.define('Booking', {
roomNo: DataTypes.INTEGER,
period: DataTypes.RANGE(DataTypes.DATE)
});
return self.Booking
.sync({ force: true })
.then(function () {
return self.sequelize.query('ALTER TABLE "' + self.Booking.tableName + '" ADD CONSTRAINT ' + constraintName +
' EXCLUDE USING gist ("roomNo" WITH =, period WITH &&)');
});
});
describe('[POSTGRES Specific] ExclusionConstraintError', function () {
it('should contain error specific properties', function () {
var errDetails = {
message: 'Exclusion constraint error',
constraint: 'constraint_name',
fields: { 'field1': 1, 'field2': [123, 321] },
table: 'table_name',
parent: new Error('Test error')
};
var err = new Sequelize.ExclusionConstraintError(errDetails);
_.each(errDetails, function (value, key) {
expect(value).to.be.deep.equal(err[key]);
});
});
it('should throw ExclusionConstraintError when "period" value overlaps existing', function () {
var Booking = this.Booking;
return Booking
.create({
roomNo: 1,
guestName: 'Incognito Visitor',
period: [new Date(2015, 0, 1), new Date(2015, 0, 3)]
})
.then(function () {
return expect(Booking
.create({
roomNo: 1,
guestName: 'Frequent Visitor',
period: [new Date(2015, 0, 2), new Date(2015, 0, 5)]
})).to.eventually.be.rejectedWith(Sequelize.ExclusionConstraintError);
});
});
});
}
'use strict';
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/../../support')
, DataTypes = require(__dirname + '/../../../../lib/data-types')
, dialect = Support.getTestDialect()
, range = require('../../../../lib/dialects/postgres/range');
chai.config.includeStack = true;
if (dialect.match(/^postgres/)) {
describe('[POSTGRES Specific] range datatype', function () {
describe('stringify', function () {
it('should handle empty objects correctly', function () {
expect(range.stringify([])).to.equal('');
});
it('should return empty string when either of boundaries is null', function () {
expect(range.stringify([null, "test"])).to.equal('');
expect(range.stringify([123, null])).to.equal('');
});
it('should return empty string when boundaries array of invalid size', function () {
expect(range.stringify([1])).to.equal('');
expect(range.stringify([1, 2, 3])).to.equal('');
});
it('should return empty string when non-array parameter is passed', function (done) {
expect(range.stringify({})).to.equal('');
expect(range.stringify('test')).to.equal('');
expect(range.stringify(undefined)).to.equal('');
done();
});
it('should handle array of objects with `inclusive` and `value` properties', function () {
expect(range.stringify([{ inclusive: true, value: 0 }, { value: 1 }])).to.equal('[0,1)');
expect(range.stringify([{ inclusive: true, value: 0 }, { inclusive: true, value: 1 }])).to.equal('[0,1]');
expect(range.stringify([{ inclusive: false, value: 0 }, 1])).to.equal('(0,1)');
expect(range.stringify([0, { inclusive: true, value: 1 }])).to.equal('(0,1]');
});
it('should handle inclusive property of input array properly', function () {
var testRange = [1, 2];
testRange.inclusive = [true, false];
expect(range.stringify(testRange)).to.equal('[1,2)');
testRange.inclusive = [false, true];
expect(range.stringify(testRange)).to.equal('(1,2]');
testRange.inclusive = [true, true];
expect(range.stringify(testRange)).to.equal('[1,2]');
testRange.inclusive = true;
expect(range.stringify(testRange)).to.equal('[1,2]');
testRange.inclusive = false;
expect(range.stringify(testRange)).to.equal('(1,2)');
});
it('should handle date values', function () {
expect(range.stringify([new Date(2000, 1, 1),
new Date(2000, 1, 2)])).to.equal('("2000-02-01T00:00:00.000Z","2000-02-02T00:00:00.000Z")');
});
});
describe('parse', function () {
it('should handle a null object correctly', function () {
expect(range.parse(null)).to.equal(null);
});
it('should handle empty string correctly', function () {
expect(range.parse('')).to.deep.equal('');
});
it('should return raw value if not range is returned', function () {
expect(range.parse('some_non_array')).to.deep.equal('some_non_array');
});
});
describe('stringify and parse', function () {
it('should stringify then parse back the same structure', function () {
var testRange = [5,10];
testRange.inclusive = [true, true];
expect(range.parse(range.stringify(testRange), DataTypes.RANGE(DataTypes.INTEGER))).to.deep.equal(testRange);
expect(range.parse(range.stringify(range.parse(range.stringify(testRange), DataTypes.RANGE(DataTypes.INTEGER))), DataTypes.RANGE(DataTypes.INTEGER))).to.deep.equal(testRange);
});
});
});
}
...@@ -453,9 +453,9 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() { ...@@ -453,9 +453,9 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() {
describe('define', function() { describe('define', function() {
it('adds a new dao to the dao manager', function(done) { it('adds a new dao to the dao manager', function(done) {
expect(this.sequelize.daoFactoryManager.all.length).to.equal(0); var count = this.sequelize.daoFactoryManager.all.length;
this.sequelize.define('foo', { title: DataTypes.STRING }); this.sequelize.define('foo', { title: DataTypes.STRING });
expect(this.sequelize.daoFactoryManager.all.length).to.equal(1); expect(this.sequelize.daoFactoryManager.all.length).to.equal(count+1);
done(); done();
}); });
......
...@@ -10,8 +10,17 @@ before(function() { ...@@ -10,8 +10,17 @@ before(function() {
return Support.sequelize.query('CREATE EXTENSION IF NOT EXISTS hstore', null, {raw: true}); return Support.sequelize.query('CREATE EXTENSION IF NOT EXISTS hstore', null, {raw: true});
}); });
before(function() {
var dialect = Support.getTestDialect();
if (dialect !== 'postgres' && dialect !== 'postgres-native') {
return;
}
return Support.sequelize.query('CREATE EXTENSION IF NOT EXISTS btree_gist', null, {raw: true});
});
beforeEach(function() { beforeEach(function() {
return Support.clearDatabase(this.sequelize); return Support.clearDatabase(this.sequelize);
}); });
module.exports = Support; module.exports = Support;
\ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!