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

Commit 1ef192b9 by Mick Hansen

refactor(data-types): data types should always be functions, data types should a…

…lways be inited before use
1 parent 8d7c0703
'use strict';
var STRING = function(length, binary) {
if (this instanceof STRING) {
this._binary = !!binary;
if (typeof length === 'number') {
this._length = length;
} else {
this._length = 255;
}
} else {
return new STRING(length, binary);
}
};
var util = require('util');
var CHAR = function(length, binary) {
if (this instanceof CHAR) {
this._binary = !!binary;
if (typeof length === 'number') {
this._length = length;
} else {
this._length = 255;
}
} else {
return new CHAR(length, binary);
}
};
var ABSTRACT = function(options) {
STRING.prototype = {
get BINARY() {
this._binary = true;
return this;
},
get type() {
return this.toString();
},
toString: function() {
return 'VARCHAR(' + this._length + ')' + ((this._binary) ? ' BINARY' : '');
}
};
CHAR.prototype = {
get BINARY() {
this._binary = true;
return this;
},
get type() {
return this.toString();
},
toString: function() {
return 'CHAR(' + this._length + ')' + ((this._binary) ? ' BINARY' : '');
}
ABSTRACT.prototype.toString = function() {
return this.toSql();
};
Object.defineProperty(STRING, 'BINARY', {
get: function() {
return new STRING(undefined, true);
}
});
Object.defineProperty(CHAR, 'BINARY', {
get: function() {
return new CHAR(undefined, true);
}
});
var INTEGER = function() {
return INTEGER.prototype.construct.apply(this, [INTEGER].concat(Array.prototype.slice.apply(arguments)));
ABSTRACT.prototype.toSql = function() {
return this.key;
};
var BIGINT = function() {
return BIGINT.prototype.construct.apply(this, [BIGINT].concat(Array.prototype.slice.apply(arguments)));
};
/**
* A variable length string. Default length 255
*
* Available properties: `BINARY`
*
* @property STRING
*/
var STRING = function(length, binary) {
var options = typeof length === "object" && length || {
length: length,
binary: binary
};
var FLOAT = function() {
return FLOAT.prototype.construct.apply(this, [FLOAT].concat(Array.prototype.slice.apply(arguments)));
};
if (!(this instanceof STRING)) return new STRING(options);
var BLOB = function() {
return BLOB.prototype.construct.apply(this, [BLOB].concat(Array.prototype.slice.apply(arguments)));
this._binary = options.binary;
this._length = options.length || 255;
};
util.inherits(STRING, ABSTRACT);
var DECIMAL = function() {
return DECIMAL.prototype.construct.apply(this, [DECIMAL].concat(Array.prototype.slice.apply(arguments)));
STRING.prototype.key = 'STRING';
STRING.prototype.toSql = function() {
return 'VARCHAR(' + this._length + ')' + ((this._binary) ? ' BINARY' : '');
};
Object.defineProperty(STRING.prototype, 'BINARY', {
get: function() {
this._binary = true;
return this;
}
});
var VIRTUAL = function() {
/**
* A fixed length string. Default length 255
*
* Available properties: `BINARY`
*
* @property CHAR
*/
var CHAR = function(length, binary) {
var options = typeof length === "object" && length || {
length: length,
binary: binary
};
if (!(this instanceof CHAR)) return new CHAR(options);
STRING.apply(this, arguments);
};
util.inherits(CHAR, STRING);
FLOAT._type = FLOAT;
FLOAT._typeName = 'FLOAT';
INTEGER._type = INTEGER;
INTEGER._typeName = 'INTEGER';
BIGINT._type = BIGINT;
BIGINT._typeName = 'BIGINT';
STRING._type = STRING;
STRING._typeName = 'VARCHAR';
CHAR._type = CHAR;
CHAR._typeName = 'CHAR';
BLOB._type = BLOB;
BLOB._typeName = 'BLOB';
DECIMAL._type = DECIMAL;
DECIMAL._typeName = 'DECIMAL';
BLOB.toString = STRING.toString = CHAR.toString = INTEGER.toString = FLOAT.toString = BIGINT.toString = DECIMAL.toString = function() {
return new this._type().toString();
CHAR.prototype.key = 'CHAR';
CHAR.prototype.toSql = function() {
return 'CHAR(' + this._length + ')' + ((this._binary) ? ' BINARY' : '');
};
BLOB.prototype = {
construct: function(RealType, length) {
if (this instanceof RealType) {
this._typeName = RealType._typeName;
if (typeof length === 'string') {
this._length = length;
} else {
this._length = '';
}
} else {
return new RealType(length);
}
},
get type() {
return this.toString();
},
toString: function() {
switch (this._length.toLowerCase()) {
case 'tiny':
return 'TINYBLOB';
case 'medium':
return 'MEDIUMBLOB';
case 'long':
return 'LONGBLOB';
default:
return this._typeName;
}
}
/**
* An unlimited length text column
* @property TEXT
*/
var TEXT = function(options) {
if (!(this instanceof TEXT)) return new TEXT(options);
};
util.inherits(TEXT, ABSTRACT);
FLOAT.prototype = BIGINT.prototype = INTEGER.prototype = {
construct: function(RealType, length, decimals, unsigned, zerofill) {
if (this instanceof RealType) {
this._typeName = RealType._typeName;
this._unsigned = !!unsigned;
this._zerofill = !!zerofill;
if (typeof length === 'number') {
this._length = length;
}
if (typeof decimals === 'number') {
this._decimals = decimals;
}
} else {
return new RealType(length, decimals, unsigned, zerofill);
}
},
get type() {
return this.toString();
},
TEXT.prototype.key = 'TEXT';
get UNSIGNED() {
this._unsigned = true;
return this;
},
get ZEROFILL() {
this._zerofill = true;
return this;
},
var NUMBER = function(options) {
if (!(this instanceof NUMBER)) return new NUMBER(options);
this._length = options.length;
this._decimals = options.decimals;
this._precision = options.precision;
this._scale = options.scale;
this._unsigned = options.unsigned;
};
util.inherits(NUMBER, ABSTRACT);
toString: function() {
var result = this._typeName;
NUMBER.prototype.key = 'NUMBER';
NUMBER.prototype.toSql = function() {
var result = this.key;
if (this._length) {
result += '(' + this._length;
if (typeof this._decimals === 'number') {
......@@ -189,243 +107,283 @@ FLOAT.prototype = BIGINT.prototype = INTEGER.prototype = {
result += ' ZEROFILL';
}
return result;
}
};
DECIMAL.prototype = {
construct: function(RealType, precision, scale) {
if (this instanceof RealType) {
this._typeName = RealType._typeName;
if (typeof precision === 'number') {
this._precision = precision;
} else {
this._precision = 0;
}
if (typeof scale === 'number') {
this._scale = scale;
} else {
this._scale = 0;
}
} else {
return new RealType(precision, scale);
}
},
get type() {
return this.toString();
},
get PRECISION() {
return this._precision;
},
get SCALE() {
return this._scale;
},
toString: function() {
if (this._precision || this._scale) {
return 'DECIMAL(' + this._precision + ',' + this._scale + ')';
}
return 'DECIMAL';
}
};
var unsignedDesc = {
get: function() {
return new this._type(undefined, undefined, true);
}
};
var zerofillDesc = {
Object.defineProperty(NUMBER.prototype, 'UNSIGNED', {
get: function() {
return new this._type(undefined, undefined, undefined, true);
}
};
var typeDesc = {
get: function() {
return new this._type().toString();
this._unsigned = true;
return this;
}
};
var decimalDesc = {
});
Object.defineProperty(NUMBER.prototype, 'ZEROFILL', {
get: function() {
return new this._type(undefined, undefined, undefined);
this._zerofill = true;
return this;
}
};
Object.defineProperty(STRING, 'type', typeDesc);
Object.defineProperty(CHAR, 'type', typeDesc);
Object.defineProperty(INTEGER, 'type', typeDesc);
Object.defineProperty(BIGINT, 'type', typeDesc);
Object.defineProperty(FLOAT, 'type', typeDesc);
Object.defineProperty(BLOB, 'type', typeDesc);
Object.defineProperty(DECIMAL, 'type', typeDesc);
Object.defineProperty(INTEGER, 'UNSIGNED', unsignedDesc);
Object.defineProperty(BIGINT, 'UNSIGNED', unsignedDesc);
Object.defineProperty(FLOAT, 'UNSIGNED', unsignedDesc);
Object.defineProperty(INTEGER, 'ZEROFILL', zerofillDesc);
Object.defineProperty(BIGINT, 'ZEROFILL', zerofillDesc);
Object.defineProperty(FLOAT, 'ZEROFILL', zerofillDesc);
Object.defineProperty(DECIMAL, 'PRECISION', decimalDesc);
Object.defineProperty(DECIMAL, 'SCALE', decimalDesc);
});
/**
* A convenience class holding commonly used data types. The datatypes are used when definining a new model using `Sequelize.define`, like this:
* ```js
* sequelize.define('model', {
* column: DataTypes.INTEGER
* })
* ```
* When defining a model you can just as easily pass a string as type, but often using the types defined here is beneficial. For example, using `DataTypes.BLOB`, mean
* that that column will be returned as an instance of `Buffer` when being fetched by sequelize.
*
* Some data types have special properties that can be accessed in order to change the data type. For example, to get an unsigned integer with zerofill you can do `DataTypes.INTEGER.UNSIGNED.ZEROFILL`.
* The order you access the properties in do not matter, so `DataTypes.INTEGER.ZEROFILL.UNSIGNED` is fine as well. The available properties are listed under each data type.
*
* To provide a length for the data type, you can invoke it like a function: `INTEGER(2)`
*
* Three of the values provided here (`NOW`, `UUIDV1` and `UUIDV4`) are special default values, that should not be used to define types. Instead they are used as shorthands for
* defining default values. For example, to get a uuid field with a default value generated following v1 of the UUID standard:
* ```js
* sequelize.define('model', {
* uuid: {
* type: DataTypes.UUID,
* defaultValue: DataTypes.UUIDV1,
* primaryKey: true
* }
* })
* ```
*
* @class DataTypes
*/
module.exports = {
/**
* A variable length string. Default length 255
* A 32 bit integer.
*
* Available properties: `BINARY`
* Available properties: `UNSIGNED`, `ZEROFILL`
*
* @property STRING
* @property INTEGER
*/
STRING: STRING,
/**
* A fixed length string. Default length 255
var INTEGER = function(length) {
var options = typeof length === "object" && length || {
length: length
};
if (!(this instanceof INTEGER)) return new INTEGER(options);
NUMBER.call(this, options);
};
util.inherits(INTEGER, NUMBER);
INTEGER.prototype.key = 'INTEGER';
/**
* A 64 bit integer.
*
* Available properties: `BINARY`
* Available properties: `UNSIGNED`, `ZEROFILL`
*
* @property CHAR
*/
CHAR: CHAR,
/**
* An unlimited length text column
* @property TEXT
* @property BIGINT
*/
TEXT: 'TEXT',
/**
* A 32 bit integer.
var BIGINT = function(length) {
var options = typeof length === "object" && length || {
length: length
};
if (!(this instanceof BIGINT)) return new BIGINT(options);
NUMBER.call(this, options);
};
util.inherits(BIGINT, NUMBER);
BIGINT.prototype.key = 'BIGINT';
/**
* Floating point number. Accepts one or two arguments for precision
*
* Available properties: `UNSIGNED`, `ZEROFILL`
*
* @property INTEGER
* @property FLOAT
*/
INTEGER: INTEGER,
/**
* A 64 bit integer.
var FLOAT = function(length, decimals) {
var options = typeof length === "object" && length || {
length: length,
decimals: decimals
};
if (!(this instanceof FLOAT)) return new FLOAT(options);
NUMBER.call(this, options);
};
util.inherits(FLOAT, NUMBER);
FLOAT.prototype.key = 'FLOAT';
/**
* Decimal number. Accepts one or two arguments for precision
*
* Available properties: `UNSIGNED`, `ZEROFILL`
*
* @property BIGINT
* @property DECIMAL
*/
BIGINT: BIGINT,
/**
var DECIMAL = function(precision, scale) {
var options = typeof precision === "object" && precision || {
precision: precision,
scale: scale
};
if (!(this instanceof DECIMAL)) return new DECIMAL(options);
NUMBER.call(this, options);
};
util.inherits(DECIMAL, NUMBER);
DECIMAL.prototype.key = 'DECIMAL';
DECIMAL.prototype.toSql = function() {
if (this._precision || this._scale) {
return 'DECIMAL(' + this._precision + ',' + this._scale + ')';
}
return 'DECIMAL';
};
/**
* A boolean / tinyint column, depending on dialect
* @property BOOLEAN
*/
var BOOLEAN = function() {
if (!(this instanceof BOOLEAN)) return new BOOLEAN();
ABSTRACT.apply(this, arguments);
};
util.inherits(BOOLEAN, ABSTRACT);
BOOLEAN.prototype.key = 'BOOLEAN';
BOOLEAN.prototype.toSql = function() {
return 'TINYINT(1)';
};
/**
* A time column
* @property TIME
*/
TIME: 'TIME',
/**
var TIME = function() {
if (!(this instanceof TIME)) return new TIME();
ABSTRACT.apply(this, arguments);
};
util.inherits(TIME, ABSTRACT);
TIME.prototype.key = 'TIME';
TIME.prototype.toSql = function() {
return 'TIME';
};
/**
* A datetime column
* @property DATE
*/
DATE: 'DATETIME',
/**
var DATE = function() {
if (!(this instanceof DATE)) return new DATE();
ABSTRACT.apply(this, arguments);
};
util.inherits(DATE, ABSTRACT);
DATE.prototype.key = 'DATE';
DATE.prototype.toSql = function() {
return 'DATETIME';
};
/**
* A date only column
* @property DATEONLY
*/
DATEONLY: 'DATE',
/**
* A boolean / tinyint column, depending on dialect
* @property BOOLEAN
var DATEONLY = function() {
if (!(this instanceof DATEONLY)) return new DATEONLY();
ABSTRACT.apply(this, arguments);
};
util.inherits(DATEONLY, ABSTRACT);
DATEONLY.prototype.key = 'DATEONLY';
DATEONLY.prototype.toSql = function() {
return 'DATE';
};
/**
* A key / value column. Only available in postgres.
* @property HSTORE
*/
BOOLEAN: 'TINYINT(1)',
/**
* Floating point number. Accepts one or two arguments for precision
*
* Available properties: `UNSIGNED`, `ZEROFILL`
*
* @property FLOAT
var HSTORE = function() {
if (!(this instanceof HSTORE)) return new HSTORE();
ABSTRACT.apply(this, arguments);
};
util.inherits(HSTORE, ABSTRACT);
HSTORE.prototype.key = 'HSTORE';
/**
* A JSON string column. Only available in postgres.
* @property JSON
*/
FLOAT: FLOAT,
/**
var JSON = function() {
if (!(this instanceof JSON)) return new JSON();
ABSTRACT.apply(this, arguments);
};
util.inherits(JSON, ABSTRACT);
JSON.prototype.key = 'JSON';
/*
* A pre-processed JSON data column. Only available in postgres.
* @property JSONB
*/
var JSONB = function() {
if (!(this instanceof JSONB)) return new JSONB();
ABSTRACT.apply(this, arguments);
};
util.inherits(JSONB, ABSTRACT);
JSONB.prototype.key = 'JSONB';
/**
* A default value of the current timestamp
* @property NOW
*/
NOW: 'NOW',
/**
var NOW = function() {
if (!(this instanceof NOW)) return new NOW();
ABSTRACT.apply(this, arguments);
};
util.inherits(NOW, ABSTRACT);
NOW.prototype.key = 'NOW';
/**
* Binary storage. Available lengths: `tiny`, `medium`, `long`
*
* @property BLOB
*/
BLOB: BLOB,
/**
* Decimal number. Accepts one or two arguments for precision
*
* Available properties: `UNSIGNED`, `ZEROFILL`
*
* @property DECIMAL
*/
DECIMAL: DECIMAL,
/**
var BLOB = function(length) {
var options = typeof length === "object" && length || {
length: length
};
if (!(this instanceof BLOB)) return new BLOB(options);
this._length = options.length || '';
};
util.inherits(BLOB, ABSTRACT);
BLOB.prototype.key = 'BLOB';
BLOB.prototype.toSql = function() {
switch (this._length.toLowerCase()) {
case 'tiny':
return 'TINYBLOB';
case 'medium':
return 'MEDIUMBLOB';
case 'long':
return 'LONGBLOB';
default:
return this.key;
}
};
/**
* A column storing a unique univeral identifier. Use with `UUIDV1` or `UUIDV4` for default values.
* @property UUID
*/
UUID: 'UUID',
/**
var UUID = function() {
if (!(this instanceof UUID)) return new UUID();
ABSTRACT.apply(this, arguments);
};
util.inherits(UUID, ABSTRACT);
UUID.prototype.key = 'UUID';
/**
* A default unique universal identifier generated following the UUID v1 standard
* @property UUIDV1
*/
UUIDV1: 'UUIDV1',
/**
var UUIDV1 = function() {
if (!(this instanceof UUIDV1)) return new UUIDV1();
ABSTRACT.apply(this, arguments);
};
util.inherits(UUIDV1, ABSTRACT);
UUIDV1.prototype.key = 'UUIDV1';
/**
* A default unique universal identifier generated following the UUID v2 standard
* @property UUIDV4
*/
UUIDV4: 'UUIDV4',
/**
* A key / value column. Only available in postgres.
* @property HSTORE
*/
HSTORE: 'HSTORE',
/**
* A JSON string column. Only available in postgres.
* @property JSON
*/
JSON: 'JSON',
var UUIDV4 = function() {
if (!(this instanceof UUIDV4)) return new UUIDV4();
ABSTRACT.apply(this, arguments);
};
util.inherits(UUIDV4, ABSTRACT);
/*
* A pre-processed JSON data column. Only available in postgres.
* @property JSONB
*/
JSONB: 'JSONB',
UUIDV4.prototype.key = 'UUIDV4';
/**
/**
* A virtual value that is not stored in the DB. This could for example be useful if you want to provide a default value in your model
* that is returned to the user but not stored in the DB.
*
......@@ -453,33 +411,126 @@ module.exports = {
* @property VIRTUAL
* @alias NONE
*/
VIRTUAL: VIRTUAL,
NONE: VIRTUAL,
var VIRTUAL = function() {
if (!(this instanceof VIRTUAL)) return new VIRTUAL();
ABSTRACT.apply(this, arguments);
};
util.inherits(VIRTUAL, ABSTRACT);
VIRTUAL.prototype.key = 'VIRTUAL';
/**
/**
* An enumeration. `DataTypes.ENUM('value', 'another value')`.
*
* @property ENUM
*/
get ENUM() {
var result = function() {
return {
type: 'ENUM',
var ENUM = function(value) {
var options = typeof value === "object" && !Array.isArray(value) && value || {
values: Array.prototype.slice.call(arguments).reduce(function(result, element) {
return result.concat(Array.isArray(element) ? element : [element]);
}, []),
toString: result.toString
}, [])
};
};
result.toString = result.valueOf = function() { return 'ENUM'; };
if (!(this instanceof ENUM)) return new ENUM(options);
this.values = options.values;
};
util.inherits(ENUM, ABSTRACT);
return result;
},
ENUM.prototype.key = 'ENUM';
/**
/**
* An array of `type`, e.g. `DataTypes.ARRAY(DataTypes.DECIMAL)`. Only available in postgres.
* @property ARRAY
*/
ARRAY: function(type) { return type + '[]'; }
var ARRAY = function(type) {
var options = typeof type === "object" && type || {
type: type
};
if (!(this instanceof ARRAY)) return new ARRAY(options);
this.type = typeof options.type === "function" ? new options.type() : options.type;
};
util.inherits(ARRAY, ABSTRACT);
ARRAY.prototype.key = 'ARRAY';
ARRAY.prototype.toSql = function() {
return this.type.toSql() + '[]';
};
var helpers = {
BINARY: [STRING, CHAR],
UNSIGNED: [NUMBER, INTEGER, BIGINT, FLOAT],
ZEROFILL: [NUMBER, INTEGER, BIGINT, FLOAT],
PRECISION: [DECIMAL],
SCALE: [DECIMAL]
};
Object.keys(helpers).forEach(function (helper) {
helpers[helper].forEach(function (DataType) {
if (!DataType[helper]) {
Object.defineProperty(DataType, helper, {
get: function() {
var dataType = new DataType();
if (typeof dataType[helper] === "object") {
dataType[helper];
return dataType;
}
return dataType[helper].apply(dataType, arguments);
}
});
}
});
});
/**
* A convenience class holding commonly used data types. The datatypes are used when definining a new model using `Sequelize.define`, like this:
* ```js
* sequelize.define('model', {
* column: DataTypes.INTEGER
* })
* ```
* When defining a model you can just as easily pass a string as type, but often using the types defined here is beneficial. For example, using `DataTypes.BLOB`, mean
* that that column will be returned as an instance of `Buffer` when being fetched by sequelize.
*
* Some data types have special properties that can be accessed in order to change the data type. For example, to get an unsigned integer with zerofill you can do `DataTypes.INTEGER.UNSIGNED.ZEROFILL`.
* The order you access the properties in do not matter, so `DataTypes.INTEGER.ZEROFILL.UNSIGNED` is fine as well. The available properties are listed under each data type.
*
* To provide a length for the data type, you can invoke it like a function: `INTEGER(2)`
*
* Three of the values provided here (`NOW`, `UUIDV1` and `UUIDV4`) are special default values, that should not be used to define types. Instead they are used as shorthands for
* defining default values. For example, to get a uuid field with a default value generated following v1 of the UUID standard:
* ```js
* sequelize.define('model', {
* uuid: {
* type: DataTypes.UUID,
* defaultValue: DataTypes.UUIDV1,
* primaryKey: true
* }
* })
* ```
*
* @class DataTypes
*/
module.exports = {
ABSTRACT: ABSTRACT,
STRING: STRING,
CHAR: CHAR,
TEXT: TEXT,
INTEGER: INTEGER,
BIGINT: BIGINT,
FLOAT: FLOAT,
TIME: TIME,
DATE: DATE,
DATEONLY: DATEONLY,
BOOLEAN: BOOLEAN,
NOW: NOW,
BLOB: BLOB,
DECIMAL: DECIMAL,
UUID: UUID,
UUIDV1: UUIDV1,
UUIDV4: UUIDV4,
HSTORE: HSTORE,
JSON: JSON,
JSONB: JSONB,
VIRTUAL: VIRTUAL,
NONE: VIRTUAL,
ENUM: ENUM
};
......@@ -249,7 +249,7 @@ module.exports = (function() {
var template = "<%= type %>"
, replacements = { type: dataType.type };
if (dataType.type.toString() === DataTypes.ENUM.toString()) {
if (dataType.type instanceof DataTypes.ENUM) {
replacements.type = "TEXT";
if (!(Array.isArray(dataType.values) && (dataType.values.length > 0))) {
......
......@@ -368,7 +368,7 @@ InstanceValidator.prototype._validateSchema = function(rawAttribute, field, valu
this.errors.push(error);
}
if (rawAttribute.type === DataTypes.STRING || rawAttribute.type instanceof DataTypes.STRING || rawAttribute.type === DataTypes.TEXT) {
if (rawAttribute.type === DataTypes.STRING || rawAttribute.type instanceof DataTypes.STRING || rawAttribute.type === DataTypes.TEXT || rawAttribute.type instanceof DataTypes.TEXT) {
if (Array.isArray(value) || (_.isObject(value) && !value._isSequelizeMethod) && !Buffer.isBuffer(value)) {
error = new sequelizeError.ValidationErrorItem(field + ' cannot be an array or an object', 'string violation', field, value);
this.errors.push(error);
......
......@@ -81,22 +81,23 @@ module.exports = (function() {
throw new Error('Unrecognized data type for field ' + name);
}
if (attribute.type.toString() === DataTypes.ENUM.toString()) {
if (typeof attribute.type === "function") attribute.type = new attribute.type();
if (attribute.type instanceof DataTypes.ENUM) {
// The ENUM is a special case where the type is an object containing the values
attribute.values = attribute.type.values || attribute.values || [];
attribute.values = attribute.values || attribute.type.values || [];
if (!attribute.values.length) {
throw new Error('Values for ENUM haven\'t been defined.');
}
attributes[name].validate = attributes[name].validate || {
attribute.validate = attribute.validate || {
_checkEnum: function(value, next) {
var hasValue = value !== undefined
, isMySQL = ['mysql', 'mariadb'].indexOf(options.sequelize.options.dialect) !== -1
, ciCollation = !!options.collate && options.collate.match(/_ci$/i) !== null
, valueOutOfScope;
if (isMySQL && ciCollation && hasValue) {
var scopeIndex = (attributes[name].values || []).map(function(d) { return d.toLowerCase(); }).indexOf(value.toLowerCase());
valueOutOfScope = scopeIndex === -1;
......@@ -290,7 +291,7 @@ module.exports = (function() {
this.Instance.prototype.validators = {};
Utils._.each(this.rawAttributes, function(definition, name) {
var type = definition.type._typeName || definition.type;
if (typeof definition.type === "function") definition.type = new definition.type();
definition.Model = self;
definition.fieldName = name;
......@@ -300,21 +301,28 @@ module.exports = (function() {
definition.field = name;
}
if (type === DataTypes.BOOLEAN) {
if (definition.type instanceof DataTypes.BOOLEAN) {
self._booleanAttributes.push(name);
} else if (type === DataTypes.DATE) {
} else if (definition.type instanceof DataTypes.DATE) {
self._dateAttributes.push(name);
} else if (type === DataTypes.HSTORE) {
} else if (definition.type instanceof DataTypes.HSTORE) {
self._hstoreAttributes.push(name);
} else if (type === DataTypes.JSON) {
} else if (definition.type instanceof DataTypes.JSON) {
self._jsonAttributes.push(name);
} else if (type === DataTypes.VIRTUAL) {
} else if (definition.type instanceof DataTypes.VIRTUAL) {
self._virtualAttributes.push(name);
}
if (definition.hasOwnProperty('defaultValue')) {
self._defaultValues[name] = Utils._.partial(
Utils.toDefaultValue, definition.defaultValue);
if (typeof definition.defaultValue === "function" && (
definition.defaultValue === DataTypes.NOW ||
definition.defaultValue === DataTypes.UUIDV4 ||
definition.defaultValue === DataTypes.UUIDV4
)) {
definition.defaultValue = new definition.defaultValue();
}
self._defaultValues[name] = Utils._.partial(Utils.toDefaultValue, definition.defaultValue);
}
if (definition.hasOwnProperty('validate')) {
......@@ -808,7 +816,7 @@ module.exports = (function() {
options.dataType = this.rawAttributes[field].type;
} else {
// Use FLOAT as fallback
options.dataType = DataTypes.FLOAT;
options.dataType = new DataTypes.FLOAT();
}
}
......
......@@ -80,6 +80,27 @@ module.exports = (function() {
attribute = { type: attribute, allowNull: true };
}
if (typeof attribute.type === "function") attribute.type = new attribute.type();
if (attribute.hasOwnProperty('defaultValue')) {
if (typeof attribute.defaultValue === "function" && (
attribute.defaultValue === DataTypes.NOW ||
attribute.defaultValue === DataTypes.UUIDV4 ||
attribute.defaultValue === DataTypes.UUIDV4
)) {
attribute.defaultValue = new definition.defaultValue();
}
}
if (attribute.type instanceof DataTypes.ENUM) {
// The ENUM is a special case where the type is an object containing the values
attribute.values = attribute.values || attribute.type.values || [];
if (!attribute.values.length) {
throw new Error('Values for ENUM haven\'t been defined.');
}
}
return attribute;
});
......@@ -330,8 +351,9 @@ module.exports = (function() {
});
};
QueryInterface.prototype.addColumn = function(table, key, dataType) {
return this.sequelize.query(this.QueryGenerator.addColumnQuery(table, key, dataType), null, {logging: this.sequelize.options.logging});
QueryInterface.prototype.addColumn = function(table, key, attribute) {
if (typeof attribute.type === "function") attribute.type = new attribute.type();
return this.sequelize.query(this.QueryGenerator.addColumnQuery(table, key, attribute), null, {logging: this.sequelize.options.logging});
};
QueryInterface.prototype.removeColumn = function(tableName, attributeName) {
......@@ -353,6 +375,8 @@ module.exports = (function() {
attributes[attributeName] = dataTypeOrOptions;
}
if (typeof attributes[attributeName].type === "function") attributes[attributeName].type = new attributes[attributeName].type();
if (this.sequelize.options.dialect === 'sqlite') {
// sqlite needs some special treatment as it cannot change a column
return SQLiteQueryInterface.changeColumn.call(this, tableName, attributes);
......@@ -741,13 +765,13 @@ module.exports = (function() {
if (dataType instanceof DataTypes.DECIMAL || dataType instanceof DataTypes.FLOAT) {
result = parseFloat(result);
} else if (dataType === DataTypes.INTEGER || dataType instanceof DataTypes.BIGINT) {
} else if (dataType instanceof DataTypes.INTEGER || dataType instanceof DataTypes.BIGINT) {
result = parseInt(result, 10);
} else if (dataType === DataTypes.DATE) {
} else if (dataType instanceof DataTypes.DATE) {
if (!Utils._.isDate(result)) {
result = new Date(result);
}
} else if (dataType === DataTypes.STRING) {
} else if (dataType instanceof DataTypes.STRING) {
// Nothing to do, result is already a string.
}
}
......
......@@ -473,11 +473,11 @@ var Utils = module.exports = {
toDefaultValue: function(value) {
if (lodash.isFunction(value)) {
return value();
} else if (value === DataTypes.UUIDV1) {
} else if (value instanceof DataTypes.UUIDV1) {
return uuid.v1();
} else if (value === DataTypes.UUIDV4) {
} else if (value instanceof DataTypes.UUIDV4) {
return uuid.v4();
} else if (value === DataTypes.NOW) {
} else if (value instanceof DataTypes.NOW) {
return Utils.now();
} else {
return value;
......@@ -496,9 +496,9 @@ var Utils = module.exports = {
// TODO this will be schemable when all supported db
// have been normalized for this case
if (value === DataTypes.NOW) { return false; }
if (value instanceof DataTypes.NOW) { return false; }
if (value === DataTypes.UUIDV1 || value === DataTypes.UUIDV4) { return false; }
if (value instanceof DataTypes.UUIDV1 || value instanceof DataTypes.UUIDV4) { return false; }
if (lodash.isFunction(value)) {
return false;
......
......@@ -580,7 +580,7 @@ describe(Support.getTestDialectTeaser('BelongsTo'), function() {
User.belongsTo(Group);
self.sequelize.sync({ force: true }).success(function() {
expect(User.rawAttributes.GroupPKBTName.type.toString()).to.equal(DataTypes.STRING.toString());
expect(User.rawAttributes.GroupPKBTName.type.toString()).to.equal(DataTypes.STRING().toString());
done();
});
});
......@@ -604,7 +604,7 @@ describe(Support.getTestDialectTeaser('BelongsTo'), function() {
.success(function() {
dataTypes.forEach(function(dataType, i) {
expect(Tasks[dataType].rawAttributes.userId.type.toString())
.to.equal(dataType.toString());
.to.equal(dataType().toString());
if ((i + 1) === dataTypes.length) {
done();
......
......@@ -2607,7 +2607,7 @@ describe(Support.getTestDialectTeaser('HasMany'), function() {
User.hasMany(Tasks[dataType], { foreignKey: 'userId', keyType: dataType, constraints: false });
return Tasks[dataType].sync({ force: true }).then(function() {
expect(Tasks[dataType].rawAttributes.userId.type.toString()).to.equal(dataType.toString());
expect(Tasks[dataType].rawAttributes.userId.type instanceof dataType).to.be.ok;
});
});
});
......@@ -2624,7 +2624,7 @@ describe(Support.getTestDialectTeaser('HasMany'), function() {
User.hasMany(Task);
return this.sequelize.sync({ force: true }).then(function() {
expect(Task.rawAttributes.UserId.type).to.equal(DataTypes.STRING);
expect(Task.rawAttributes.UserId.type instanceof DataTypes.STRING).to.be.ok;
});
});
......
......@@ -515,7 +515,7 @@ describe(Support.getTestDialectTeaser('HasOne'), function() {
Group.hasOne(User);
self.sequelize.sync({ force: true }).success(function() {
expect(User.rawAttributes.GroupPKBTName.type.toString()).to.equal(Sequelize.STRING.toString());
expect(User.rawAttributes.GroupPKBTName.type.toString()).to.equal(Sequelize.STRING().toString());
done();
});
});
......@@ -536,7 +536,7 @@ describe(Support.getTestDialectTeaser('HasOne'), function() {
Tasks[dataType].sync({ force: true }).success(function() {
expect(Tasks[dataType].rawAttributes.userId.type.toString())
.to.equal(dataType.toString());
.to.equal(dataType().toString());
dataTypes.splice(dataTypes.indexOf(dataType), 1);
if (!dataTypes.length) {
......
......@@ -73,6 +73,7 @@ describe(Support.getTestDialectTeaser('DataTypes'), function() {
[Sequelize.INTEGER, 'INTEGER', 'INTEGER'],
[Sequelize.INTEGER.UNSIGNED, 'INTEGER.UNSIGNED', 'INTEGER UNSIGNED'],
[Sequelize.INTEGER.UNSIGNED.ZEROFILL, 'INTEGER.UNSIGNED', 'INTEGER UNSIGNED ZEROFILL'],
[Sequelize.INTEGER(11), 'INTEGER(11)', 'INTEGER(11)'],
[Sequelize.INTEGER(11).UNSIGNED, 'INTEGER(11).UNSIGNED', 'INTEGER(11) UNSIGNED'],
[Sequelize.INTEGER(11).UNSIGNED.ZEROFILL, 'INTEGER(11).UNSIGNED.ZEROFILL', 'INTEGER(11) UNSIGNED ZEROFILL'],
......@@ -124,7 +125,8 @@ describe(Support.getTestDialectTeaser('DataTypes'), function() {
}
}
expect(test[0].toString()).to.equal(test[2]);
if (typeof test[0] === "function") test[0] = new test[0]();
expect(test[0].toSql()).to.equal(test[2]);
done();
});
});
......
......@@ -908,8 +908,7 @@ describe(Support.getTestDialectTeaser('Model'), function() {
results.forEach(function(book, index) {
expect(book.title).to.equal(data.title);
expect(book.author).to.equal(data.author);
expect(books[index].rawAttributes.id.type.toString())
.to.equal(dataTypes[index].toString());
expect(books[index].rawAttributes.id.type instanceof dataTypes[index]).to.be.ok;
});
done();
});
......
......@@ -18,7 +18,7 @@ describe(Support.getTestDialectTeaser('CounterCache'), function() {
User.hasMany(Group, { counterCache: true });
expect(Object.keys(User.attributes)).to.contain('countGroups');
expect(User.attributes.countGroups.type).to.equal(DataTypes.INTEGER);
expect(User.attributes.countGroups.type instanceof DataTypes.INTEGER).to.be.ok;
});
it('supports `as`', function() {
......
......@@ -834,7 +834,11 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() {
Object.keys(customAttributes).forEach(function(attribute) {
Object.keys(customAttributes[attribute]).forEach(function(option) {
var optionValue = customAttributes[attribute][option];
if (typeof optionValue === "function" && optionValue() instanceof DataTypes.ABSTRACT) {
expect(Picture.rawAttributes[attribute][option] instanceof optionValue).to.be.ok;
} else {
expect(Picture.rawAttributes[attribute][option]).to.be.equal(optionValue);
}
});
});
done();
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!