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

Commit 3cd38910 by Simon Schick Committed by Sushant

refactor(data-types): move to classes (#10495)

1 parent 1b4a7bf8
...@@ -105,7 +105,8 @@ ...@@ -105,7 +105,8 @@
"camelcase": "warn", "camelcase": "warn",
"prefer-template": "error", "prefer-template": "error",
"no-else-return": ["error", { "allowElseIf": false }], "no-else-return": ["error", { "allowElseIf": false }],
"no-lonely-if": "error" "no-lonely-if": "error",
"no-this-before-super": "error"
}, },
"parserOptions": { "parserOptions": {
"ecmaVersion": 6, "ecmaVersion": 6,
......
...@@ -196,28 +196,19 @@ modules.exports = function sequelizeAdditions(Sequelize) { ...@@ -196,28 +196,19 @@ modules.exports = function sequelizeAdditions(Sequelize) {
/* /*
* Create new types * Create new types
*/ */
class NEWTYPE extends DataTypes.ABSTRACT {
// Create new type
DataTypes.NEWTYPE = function NEWTYPE() {
if (!(this instanceof DataTypes.NEWTYPE)) return new DataTypes.NEWTYPE()
}
inherits(DataTypes.NEWTYPE, DataTypes.ABSTRACT)
// Mandatory, set key
DataTypes.NEWTYPE.prototype.key = DataTypes.NEWTYPE.key = 'NEWTYPE'
// Mandatory, complete definition of the new type in the database // Mandatory, complete definition of the new type in the database
DataTypes.NEWTYPE.prototype.toSql = function toSql() { toSql() {
return 'INTEGER(11) UNSIGNED ZEROFILL' return 'INTEGER(11) UNSIGNED ZEROFILL'
} }
// Optional, validator function // Optional, validator function
DataTypes.NEWTYPE.prototype.validate = function validate(value, options) { validate(value, options) {
return (typeof value === 'number') && (! Number.isNaN(value)) return (typeof value === 'number') && (! Number.isNaN(value))
} }
// Optional, sanitizer // Optional, sanitizer
DataTypes.NEWTYPE.prototype._sanitize = function _sanitize(value) { _sanitize(value) {
// Force all numbers to be positive // Force all numbers to be positive
if (value < 0) { if (value < 0) {
value = 0 value = 0
...@@ -227,20 +218,27 @@ modules.exports = function sequelizeAdditions(Sequelize) { ...@@ -227,20 +218,27 @@ modules.exports = function sequelizeAdditions(Sequelize) {
} }
// Optional, value stringifier before sending to database // Optional, value stringifier before sending to database
DataTypes.NEWTYPE.prototype._stringify = function _stringify(value) { _stringify(value) {
return value.toString() return value.toString()
} }
// Optional, disable escaping after stringifier. Not recommended.
// Warning: disables Sequelize protection against SQL injections
//DataTypes.NEWTYPE.escape = false
// Optional, parser for values received from the database // Optional, parser for values received from the database
DataTypes.NEWTYPE.parse = function parse(value) { static parse(value) {
return Number.parseInt(value) return Number.parseInt(value)
} }
}
// Mandatory, set key
DataTypes.NEWTYPE.prototype.key = DataTypes.NEWTYPE.key = 'NEWTYPE'
// Optional, disable escaping after stringifier. Not recommended.
// Warning: disables Sequelize protection against SQL injections
//DataTypes.NEWTYPE.escape = false
// For convenience // For convenience
Sequelize.NEWTYPE = DataTypes.NEWTYPE // `inferNew` allows you to use the datatype without `new`
Sequelize.NEWTYPE = Sequelize.Utils.inferNew(DataTypes.NEWTYPE)
} }
``` ```
......
'use strict'; 'use strict';
const util = require('util'); const util = require('util');
const inherits = require('./utils/inherits');
const _ = require('lodash'); const _ = require('lodash');
const wkx = require('wkx'); const wkx = require('wkx');
const sequelizeErrors = require('./errors'); const sequelizeErrors = require('./errors');
...@@ -9,37 +8,43 @@ const Validator = require('./utils/validator-extras').validator; ...@@ -9,37 +8,43 @@ const Validator = require('./utils/validator-extras').validator;
const momentTz = require('moment-timezone'); const momentTz = require('moment-timezone');
const moment = require('moment'); const moment = require('moment');
const logger = require('./utils/logger'); const logger = require('./utils/logger');
const warnings = {}; const warnings = {};
const { classToInvokable } = require('./utils/classToInvokable');
function ABSTRACT() {} class ABSTRACT {
toString(options) {
ABSTRACT.prototype.dialectTypes = '';
ABSTRACT.prototype.toString = function toString(options) {
return this.toSql(options); return this.toSql(options);
}; }
ABSTRACT.prototype.toSql = function toSql() { toSql() {
return this.key; return this.key;
};
ABSTRACT.warn = function warn(link, text) {
if (!warnings[text]) {
warnings[text] = true;
logger.warn(`${text} \n>> Check: ${link}`);
} }
}; stringify(value, options) {
ABSTRACT.prototype.stringify = function stringify(value, options) {
if (this._stringify) { if (this._stringify) {
return this._stringify(value, options); return this._stringify(value, options);
} }
return value; return value;
}; }
ABSTRACT.prototype.bindParam = function bindParam(value, options) { bindParam(value, options) {
if (this._bindParam) { if (this._bindParam) {
return this._bindParam(value, options); return this._bindParam(value, options);
} }
return options.bindParam(this.stringify(value, options)); return options.bindParam(this.stringify(value, options));
}; }
static toString() {
return this.name;
}
static warn(link, text) {
if (!warnings[text]) {
warnings[text] = true;
logger.warn(`${text} \n>> Check: ${link}`);
}
}
static extend(oldType) {
return new this(oldType.options);
};
}
ABSTRACT.prototype.dialectTypes = '';
/** /**
* STRING A variable length string * STRING A variable length string
...@@ -50,38 +55,37 @@ ABSTRACT.prototype.bindParam = function bindParam(value, options) { ...@@ -50,38 +55,37 @@ ABSTRACT.prototype.bindParam = function bindParam(value, options) {
* @namespace DataTypes.STRING * @namespace DataTypes.STRING
* *
*/ */
function STRING(length, binary) { class STRING extends ABSTRACT {
constructor(length, binary) {
super();
const options = typeof length === 'object' && length || { length, binary }; const options = typeof length === 'object' && length || { length, binary };
if (!(this instanceof STRING)) return new STRING(options);
this.options = options; this.options = options;
this._binary = options.binary; this._binary = options.binary;
this._length = options.length || 255; this._length = options.length || 255;
} }
inherits(STRING, ABSTRACT); toSql() {
STRING.prototype.key = STRING.key = 'STRING';
STRING.prototype.toSql = function toSql() {
return `VARCHAR(${this._length})${this._binary ? ' BINARY' : ''}`; return `VARCHAR(${this._length})${this._binary ? ' BINARY' : ''}`;
}; }
STRING.prototype.validate = function validate(value) { validate(value) {
if (Object.prototype.toString.call(value) !== '[object String]') { if (Object.prototype.toString.call(value) !== '[object String]') {
if (this.options.binary && Buffer.isBuffer(value) || typeof value === 'number') { if (this.options.binary && Buffer.isBuffer(value) || typeof value === 'number') {
return true; return true;
} }
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid string', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid string', value));
} }
return true; return true;
}; }
Object.defineProperty(STRING.prototype, 'BINARY', {
get() { get BINARY() {
this._binary = true; this._binary = true;
this.options.binary = true; this.options.binary = true;
return this; return this;
} }
});
static get BINARY() {
return new this().BINARY;
}
}
/** /**
* CHAR A fixed length string * CHAR A fixed length string
...@@ -91,18 +95,14 @@ Object.defineProperty(STRING.prototype, 'BINARY', { ...@@ -91,18 +95,14 @@ Object.defineProperty(STRING.prototype, 'BINARY', {
* *
* @namespace DataTypes.CHAR * @namespace DataTypes.CHAR
*/ */
function CHAR(length, binary) { class CHAR extends STRING {
const options = typeof length === 'object' && length || { length, binary }; constructor(length, binary) {
super(typeof length === 'object' && length || { length, binary });
if (!(this instanceof CHAR)) return new CHAR(options); }
STRING.apply(this, arguments); toSql() {
}
inherits(CHAR, STRING);
CHAR.prototype.key = CHAR.key = 'CHAR';
CHAR.prototype.toSql = function toSql() {
return `CHAR(${this._length})${this._binary ? ' BINARY' : ''}`; return `CHAR(${this._length})${this._binary ? ' BINARY' : ''}`;
}; }
}
/** /**
* Unlimited length TEXT column * Unlimited length TEXT column
...@@ -111,16 +111,14 @@ CHAR.prototype.toSql = function toSql() { ...@@ -111,16 +111,14 @@ CHAR.prototype.toSql = function toSql() {
* *
* @namespace DataTypes.TEXT * @namespace DataTypes.TEXT
*/ */
function TEXT(length) { class TEXT extends ABSTRACT {
constructor(length) {
super();
const options = typeof length === 'object' && length || { length }; const options = typeof length === 'object' && length || { length };
if (!(this instanceof TEXT)) return new TEXT(options);
this.options = options; this.options = options;
this._length = options.length || ''; this._length = options.length || '';
} }
inherits(TEXT, ABSTRACT); toSql() {
TEXT.prototype.key = TEXT.key = 'TEXT';
TEXT.prototype.toSql = function toSql() {
switch (this._length.toLowerCase()) { switch (this._length.toLowerCase()) {
case 'tiny': case 'tiny':
return 'TINYTEXT'; return 'TINYTEXT';
...@@ -131,14 +129,14 @@ TEXT.prototype.toSql = function toSql() { ...@@ -131,14 +129,14 @@ TEXT.prototype.toSql = function toSql() {
default: default:
return this.key; return this.key;
} }
}; }
TEXT.prototype.validate = function validate(value) { validate(value) {
if (typeof value !== 'string') { if (typeof value !== 'string') {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid string', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid string', value));
} }
return true; return true;
}; }
}
/** /**
* An unlimited length case-insensitive text column. * An unlimited length case-insensitive text column.
...@@ -147,23 +145,17 @@ TEXT.prototype.validate = function validate(value) { ...@@ -147,23 +145,17 @@ TEXT.prototype.validate = function validate(value) {
* *
* @namespace DataTypes.CITEXT * @namespace DataTypes.CITEXT
*/ */
function CITEXT() { class CITEXT extends ABSTRACT {
if (!(this instanceof CITEXT)) return new CITEXT(); toSql() {
}
inherits(CITEXT, ABSTRACT);
CITEXT.prototype.key = CITEXT.key = 'CITEXT';
CITEXT.prototype.toSql = function toSql() {
return 'CITEXT'; return 'CITEXT';
}; }
CITEXT.prototype.validate = function validate(value) { validate(value) {
if (typeof value !== 'string') { if (typeof value !== 'string') {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid string', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid string', value));
} }
return true; return true;
}; }
}
/** /**
* Base number type which is used to build other types * Base number type which is used to build other types
...@@ -178,7 +170,14 @@ CITEXT.prototype.validate = function validate(value) { ...@@ -178,7 +170,14 @@ CITEXT.prototype.validate = function validate(value) {
* *
* @namespace DataTypes.NUMBER * @namespace DataTypes.NUMBER
*/ */
function NUMBER(options) { class NUMBER extends ABSTRACT {
constructor(options = {}) {
super();
if (typeof options === 'number') {
options = {
length: options
};
}
this.options = options; this.options = options;
this._length = options.length; this._length = options.length;
this._zerofill = options.zerofill; this._zerofill = options.zerofill;
...@@ -186,11 +185,8 @@ function NUMBER(options) { ...@@ -186,11 +185,8 @@ function NUMBER(options) {
this._precision = options.precision; this._precision = options.precision;
this._scale = options.scale; this._scale = options.scale;
this._unsigned = options.unsigned; this._unsigned = options.unsigned;
} }
inherits(NUMBER, ABSTRACT); toSql() {
NUMBER.prototype.key = NUMBER.key = 'NUMBER';
NUMBER.prototype.toSql = function toSql() {
let result = this.key; let result = this.key;
if (this._length) { if (this._length) {
result += `(${this._length}`; result += `(${this._length}`;
...@@ -206,39 +202,43 @@ NUMBER.prototype.toSql = function toSql() { ...@@ -206,39 +202,43 @@ NUMBER.prototype.toSql = function toSql() {
result += ' ZEROFILL'; result += ' ZEROFILL';
} }
return result; return result;
}; }
NUMBER.prototype.validate = function(value) { validate(value) {
if (!Validator.isFloat(String(value))) { if (!Validator.isFloat(String(value))) {
throw new sequelizeErrors.ValidationError(util.format(`%j is not a valid ${this.key.toLowerCase()}`, value)); throw new sequelizeErrors.ValidationError(util.format(`%j is not a valid ${this.key.toLowerCase()}`, value));
} }
return true; return true;
}; }
NUMBER.prototype._stringify = function _stringify(number) { _stringify(number) {
if (typeof number === 'number' || number === null || number === undefined) { if (typeof number === 'number' || number === null || number === undefined) {
return number; return number;
} }
if (typeof number.toString === 'function') { if (typeof number.toString === 'function') {
return number.toString(); return number.toString();
} }
return number; return number;
}; }
Object.defineProperty(NUMBER.prototype, 'UNSIGNED', {
get() { get UNSIGNED() {
this._unsigned = true; this._unsigned = true;
this.options.unsigned = true; this.options.unsigned = true;
return this; return this;
} }
});
Object.defineProperty(NUMBER.prototype, 'ZEROFILL', { get ZEROFILL() {
get() {
this._zerofill = true; this._zerofill = true;
this.options.zerofill = true; this.options.zerofill = true;
return this; return this;
} }
});
static get UNSIGNED() {
return new this().UNSIGNED;
}
static get ZEROFILL() {
return new this().ZEROFILL;
}
}
/** /**
* A 32 bit integer * A 32 bit integer
...@@ -247,21 +247,14 @@ Object.defineProperty(NUMBER.prototype, 'ZEROFILL', { ...@@ -247,21 +247,14 @@ Object.defineProperty(NUMBER.prototype, 'ZEROFILL', {
* *
* @namespace DataTypes.INTEGER * @namespace DataTypes.INTEGER
*/ */
function INTEGER(length) { class INTEGER extends NUMBER {
const options = typeof length === 'object' && length || { length }; validate(value) {
if (!(this instanceof INTEGER)) return new INTEGER(options);
NUMBER.call(this, options);
}
inherits(INTEGER, NUMBER);
INTEGER.prototype.key = INTEGER.key = 'INTEGER';
INTEGER.prototype.validate = function validate(value) {
if (!Validator.isInt(String(value))) { if (!Validator.isInt(String(value))) {
throw new sequelizeErrors.ValidationError(util.format(`%j is not a valid ${this.key.toLowerCase()}`, value)); throw new sequelizeErrors.ValidationError(util.format(`%j is not a valid ${this.key.toLowerCase()}`, value));
} }
return true; return true;
}; }
}
/** /**
* A 8 bit integer * A 8 bit integer
...@@ -270,14 +263,8 @@ INTEGER.prototype.validate = function validate(value) { ...@@ -270,14 +263,8 @@ INTEGER.prototype.validate = function validate(value) {
* *
* @namespace DataTypes.TINYINT * @namespace DataTypes.TINYINT
*/ */
function TINYINT(length) { class TINYINT extends INTEGER {
const options = typeof length === 'object' && length || { length };
if (!(this instanceof TINYINT)) return new TINYINT(options);
NUMBER.call(this, options);
} }
inherits(TINYINT, INTEGER);
TINYINT.prototype.key = TINYINT.key = 'TINYINT';
/** /**
* A 16 bit integer * A 16 bit integer
...@@ -286,14 +273,8 @@ TINYINT.prototype.key = TINYINT.key = 'TINYINT'; ...@@ -286,14 +273,8 @@ TINYINT.prototype.key = TINYINT.key = 'TINYINT';
* *
* @namespace DataTypes.SMALLINT * @namespace DataTypes.SMALLINT
*/ */
function SMALLINT(length) { class SMALLINT extends INTEGER {
const options = typeof length === 'object' && length || { length };
if (!(this instanceof SMALLINT)) return new SMALLINT(options);
NUMBER.call(this, options);
} }
inherits(SMALLINT, INTEGER);
SMALLINT.prototype.key = SMALLINT.key = 'SMALLINT';
/** /**
* A 24 bit integer * A 24 bit integer
...@@ -302,14 +283,8 @@ SMALLINT.prototype.key = SMALLINT.key = 'SMALLINT'; ...@@ -302,14 +283,8 @@ SMALLINT.prototype.key = SMALLINT.key = 'SMALLINT';
* *
* @namespace DataTypes.MEDIUMINT * @namespace DataTypes.MEDIUMINT
*/ */
function MEDIUMINT(length) { class MEDIUMINT extends INTEGER {
const options = typeof length === 'object' && length || { length };
if (!(this instanceof MEDIUMINT)) return new MEDIUMINT(options);
NUMBER.call(this, options);
} }
inherits(MEDIUMINT, INTEGER);
MEDIUMINT.prototype.key = MEDIUMINT.key = 'MEDIUMINT';
/** /**
* A 64 bit integer * A 64 bit integer
...@@ -318,14 +293,8 @@ MEDIUMINT.prototype.key = MEDIUMINT.key = 'MEDIUMINT'; ...@@ -318,14 +293,8 @@ MEDIUMINT.prototype.key = MEDIUMINT.key = 'MEDIUMINT';
* *
* @namespace DataTypes.BIGINT * @namespace DataTypes.BIGINT
*/ */
function BIGINT(length) { class BIGINT extends INTEGER {
const options = typeof length === 'object' && length || { length };
if (!(this instanceof BIGINT)) return new BIGINT(options);
NUMBER.call(this, options);
} }
inherits(BIGINT, INTEGER);
BIGINT.prototype.key = BIGINT.key = 'BIGINT';
/** /**
* Floating point number (4-byte precision). * Floating point number (4-byte precision).
...@@ -335,21 +304,17 @@ BIGINT.prototype.key = BIGINT.key = 'BIGINT'; ...@@ -335,21 +304,17 @@ BIGINT.prototype.key = BIGINT.key = 'BIGINT';
* *
* @namespace DataTypes.FLOAT * @namespace DataTypes.FLOAT
*/ */
function FLOAT(length, decimals) { class FLOAT extends NUMBER {
const options = typeof length === 'object' && length || { length, decimals }; constructor(length, decimals) {
if (!(this instanceof FLOAT)) return new FLOAT(options); super(typeof length === 'object' && length || { length, decimals });
NUMBER.call(this, options); }
} validate(value) {
inherits(FLOAT, NUMBER);
FLOAT.prototype.key = FLOAT.key = 'FLOAT';
FLOAT.prototype.validate = function validate(value) {
if (!Validator.isFloat(String(value))) { if (!Validator.isFloat(String(value))) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid float', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid float', value));
} }
return true; return true;
}; }
}
/** /**
* Floating point number (4-byte precision). * Floating point number (4-byte precision).
...@@ -359,14 +324,11 @@ FLOAT.prototype.validate = function validate(value) { ...@@ -359,14 +324,11 @@ FLOAT.prototype.validate = function validate(value) {
* *
* @namespace DataTypes.REAL * @namespace DataTypes.REAL
*/ */
function REAL(length, decimals) { class REAL extends NUMBER {
const options = typeof length === 'object' && length || { length, decimals }; constructor(length, decimals) {
if (!(this instanceof REAL)) return new REAL(options); super(typeof length === 'object' && length || { length, decimals });
NUMBER.call(this, options); }
} }
inherits(REAL, NUMBER);
REAL.prototype.key = REAL.key = 'REAL';
/** /**
* Floating point number (8-byte precision). * Floating point number (8-byte precision).
...@@ -376,14 +338,11 @@ REAL.prototype.key = REAL.key = 'REAL'; ...@@ -376,14 +338,11 @@ REAL.prototype.key = REAL.key = 'REAL';
* *
* @namespace DataTypes.DOUBLE * @namespace DataTypes.DOUBLE
*/ */
function DOUBLE(length, decimals) { class DOUBLE extends NUMBER {
const options = typeof length === 'object' && length || { length, decimals }; constructor(length, decimals) {
if (!(this instanceof DOUBLE)) return new DOUBLE(options); super(typeof length === 'object' && length || { length, decimals });
NUMBER.call(this, options); }
} }
inherits(DOUBLE, NUMBER);
DOUBLE.prototype.key = DOUBLE.key = 'DOUBLE PRECISION';
/** /**
* Decimal type, variable precision, take length as specified by user * Decimal type, variable precision, take length as specified by user
...@@ -393,30 +352,25 @@ DOUBLE.prototype.key = DOUBLE.key = 'DOUBLE PRECISION'; ...@@ -393,30 +352,25 @@ DOUBLE.prototype.key = DOUBLE.key = 'DOUBLE PRECISION';
* *
* @namespace DataTypes.DECIMAL * @namespace DataTypes.DECIMAL
*/ */
function DECIMAL(precision, scale) { class DECIMAL extends NUMBER {
const options = typeof precision === 'object' && precision || { precision, scale }; constructor(precision, scale) {
if (!(this instanceof DECIMAL)) return new DECIMAL(options); super(typeof precision === 'object' && precision || { precision, scale });
NUMBER.call(this, options); }
} toSql() {
inherits(DECIMAL, NUMBER);
DECIMAL.prototype.key = DECIMAL.key = 'DECIMAL';
DECIMAL.prototype.toSql = function toSql() {
if (this._precision || this._scale) { if (this._precision || this._scale) {
return `DECIMAL(${[this._precision, this._scale].filter(_.identity).join(',')})`; return `DECIMAL(${[this._precision, this._scale].filter(_.identity).join(',')})`;
} }
return 'DECIMAL'; return 'DECIMAL';
}; }
DECIMAL.prototype.validate = function validate(value) { validate(value) {
if (!Validator.isDecimal(String(value))) { if (!Validator.isDecimal(String(value))) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid decimal', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid decimal', value));
} }
return true; return true;
}; }
}
// TODO: Create intermediate class
const protoExtensions = { const protoExtensions = {
escape: false, escape: false,
_value(value) { _value(value) {
...@@ -447,30 +401,22 @@ for (const floating of [FLOAT, DOUBLE, REAL]) { ...@@ -447,30 +401,22 @@ for (const floating of [FLOAT, DOUBLE, REAL]) {
* *
* @namespace DataTypes.BOOLEAN * @namespace DataTypes.BOOLEAN
*/ */
function BOOLEAN() { class BOOLEAN extends ABSTRACT {
if (!(this instanceof BOOLEAN)) return new BOOLEAN(); toSql() {
}
inherits(BOOLEAN, ABSTRACT);
BOOLEAN.prototype.key = BOOLEAN.key = 'BOOLEAN';
BOOLEAN.prototype.toSql = function toSql() {
return 'TINYINT(1)'; return 'TINYINT(1)';
}; }
BOOLEAN.prototype.validate = function validate(value) { validate(value) {
if (!Validator.isBoolean(String(value))) { if (!Validator.isBoolean(String(value))) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid boolean', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid boolean', value));
} }
return true; return true;
}; }
_sanitize(value) {
BOOLEAN.prototype._sanitize = function _sanitize(value) {
if (value !== null && value !== undefined) { if (value !== null && value !== undefined) {
if (Buffer.isBuffer(value) && value.length === 1) { if (Buffer.isBuffer(value) && value.length === 1) {
// Bit fields are returned as buffers // Bit fields are returned as buffers
value = value[0]; value = value[0];
} }
const type = typeof value; const type = typeof value;
if (type === 'string') { if (type === 'string') {
// Only take action on valid boolean strings. // Only take action on valid boolean strings.
...@@ -481,9 +427,11 @@ BOOLEAN.prototype._sanitize = function _sanitize(value) { ...@@ -481,9 +427,11 @@ BOOLEAN.prototype._sanitize = function _sanitize(value) {
return value === 1 ? true : value === 0 ? false : value; return value === 1 ? true : value === 0 ? false : value;
} }
} }
return value; return value;
}; }
}
BOOLEAN.parse = BOOLEAN.prototype._sanitize; BOOLEAN.parse = BOOLEAN.prototype._sanitize;
/** /**
...@@ -491,15 +439,11 @@ BOOLEAN.parse = BOOLEAN.prototype._sanitize; ...@@ -491,15 +439,11 @@ BOOLEAN.parse = BOOLEAN.prototype._sanitize;
* *
* @namespace DataTypes.TIME * @namespace DataTypes.TIME
*/ */
function TIME() { class TIME extends ABSTRACT {
if (!(this instanceof TIME)) return new TIME(); toSql() {
}
inherits(TIME, ABSTRACT);
TIME.prototype.key = TIME.key = 'TIME';
TIME.prototype.toSql = function toSql() {
return 'TIME'; return 'TIME';
}; }
}
/** /**
* Date column with timezone, default is UTC * Date column with timezone, default is UTC
...@@ -508,56 +452,41 @@ TIME.prototype.toSql = function toSql() { ...@@ -508,56 +452,41 @@ TIME.prototype.toSql = function toSql() {
* *
* @namespace DataTypes.DATE * @namespace DataTypes.DATE
*/ */
function DATE(length) { class DATE extends ABSTRACT {
constructor(length) {
super();
const options = typeof length === 'object' && length || { length }; const options = typeof length === 'object' && length || { length };
if (!(this instanceof DATE)) return new DATE(options);
this.options = options; this.options = options;
this._length = options.length || ''; this._length = options.length || '';
} }
inherits(DATE, ABSTRACT); toSql() {
DATE.prototype.key = DATE.key = 'DATE';
DATE.prototype.toSql = function toSql() {
return 'DATETIME'; return 'DATETIME';
}; }
DATE.prototype.validate = function validate(value) { validate(value) {
if (!Validator.isDate(String(value))) { if (!Validator.isDate(String(value))) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid date', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid date', value));
} }
return true; return true;
}; }
_sanitize(value, options) {
DATE.prototype._sanitize = function _sanitize(value, options) {
if ((!options || options && !options.raw) && !(value instanceof Date) && !!value) { if ((!options || options && !options.raw) && !(value instanceof Date) && !!value) {
return new Date(value); return new Date(value);
} }
return value; return value;
}; }
_isChanged(value, originalValue) {
DATE.prototype._isChanged = function _isChanged(value, originalValue) { if (originalValue && !!value &&
if ( (value === originalValue ||
originalValue && !!value && value instanceof Date && originalValue instanceof Date && value.getTime() === originalValue.getTime())) {
(
value === originalValue ||
value instanceof Date && originalValue instanceof Date && value.getTime() === originalValue.getTime()
)
) {
return false; return false;
} }
// not changed when set to same empty value // not changed when set to same empty value
if (!originalValue && !value && originalValue === value) { if (!originalValue && !value && originalValue === value) {
return false; return false;
} }
return true; return true;
}; }
_applyTimezone(date, options) {
DATE.prototype._applyTimezone = function _applyTimezone(date, options) {
if (options.timezone) { if (options.timezone) {
if (momentTz.tz.zone(options.timezone)) { if (momentTz.tz.zone(options.timezone)) {
return momentTz(date).tz(options.timezone); return momentTz(date).tz(options.timezone);
...@@ -565,117 +494,87 @@ DATE.prototype._applyTimezone = function _applyTimezone(date, options) { ...@@ -565,117 +494,87 @@ DATE.prototype._applyTimezone = function _applyTimezone(date, options) {
return date = moment(date).utcOffset(options.timezone); return date = moment(date).utcOffset(options.timezone);
} }
return momentTz(date); return momentTz(date);
}; }
_stringify(date, options) {
DATE.prototype._stringify = function _stringify(date, options) {
date = this._applyTimezone(date, options); date = this._applyTimezone(date, options);
// Z here means current timezone, _not_ UTC // Z here means current timezone, _not_ UTC
return date.format('YYYY-MM-DD HH:mm:ss.SSS Z'); return date.format('YYYY-MM-DD HH:mm:ss.SSS Z');
}; }
}
/** /**
* A date only column (no timestamp) * A date only column (no timestamp)
* *
* @namespace DataTypes.DATEONLY * @namespace DataTypes.DATEONLY
*/ */
function DATEONLY() { class DATEONLY extends ABSTRACT {
if (!(this instanceof DATEONLY)) return new DATEONLY(); toSql() {
}
util.inherits(DATEONLY, ABSTRACT);
DATEONLY.prototype.key = DATEONLY.key = 'DATEONLY';
DATEONLY.prototype.toSql = function() {
return 'DATE'; return 'DATE';
}; }
_stringify(date) {
DATEONLY.prototype._stringify = function _stringify(date) {
return moment(date).format('YYYY-MM-DD'); return moment(date).format('YYYY-MM-DD');
}; }
_sanitize(value, options) {
DATEONLY.prototype._sanitize = function _sanitize(value, options) {
if ((!options || options && !options.raw) && !!value) { if ((!options || options && !options.raw) && !!value) {
return moment(value).format('YYYY-MM-DD'); return moment(value).format('YYYY-MM-DD');
} }
return value; return value;
}; }
_isChanged(value, originalValue) {
DATEONLY.prototype._isChanged = function _isChanged(value, originalValue) {
if (originalValue && !!value && originalValue === value) { if (originalValue && !!value && originalValue === value) {
return false; return false;
} }
// not changed when set to same empty value // not changed when set to same empty value
if (!originalValue && !value && originalValue === value) { if (!originalValue && !value && originalValue === value) {
return false; return false;
} }
return true; return true;
}; }
}
/** /**
* A key / value store column. Only available in Postgres. * A key / value store column. Only available in Postgres.
* *
* @namespace DataTypes.HSTORE * @namespace DataTypes.HSTORE
*/ */
function HSTORE() { class HSTORE extends ABSTRACT {
if (!(this instanceof HSTORE)) return new HSTORE(); validate(value) {
}
inherits(HSTORE, ABSTRACT);
HSTORE.prototype.key = HSTORE.key = 'HSTORE';
HSTORE.prototype.validate = function validate(value) {
if (!_.isPlainObject(value)) { if (!_.isPlainObject(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid hstore', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid hstore', value));
} }
return true; return true;
}; }
}
/** /**
* A JSON string column. Available in MySQL, Postgres and SQLite * A JSON string column. Available in MySQL, Postgres and SQLite
* *
* @namespace DataTypes.JSON * @namespace DataTypes.JSON
*/ */
function JSONTYPE() { class JSONTYPE extends ABSTRACT {
if (!(this instanceof JSONTYPE)) return new JSONTYPE(); validate() {
}
inherits(JSONTYPE, ABSTRACT);
JSONTYPE.prototype.key = JSONTYPE.key = 'JSON';
JSONTYPE.prototype.validate = function validate() {
return true; return true;
}; }
_stringify(value) {
JSONTYPE.prototype._stringify = function _stringify(value) {
return JSON.stringify(value); return JSON.stringify(value);
}; }
}
/** /**
* A binary storage JSON column. Only available in Postgres. * A binary storage JSON column. Only available in Postgres.
* *
* @namespace DataTypes.JSONB * @namespace DataTypes.JSONB
*/ */
function JSONB() { class JSONB extends JSONTYPE {
if (!(this instanceof JSONB)) return new JSONB();
JSONTYPE.call(this);
} }
inherits(JSONB, JSONTYPE);
JSONB.prototype.key = JSONB.key = 'JSONB';
/** /**
* A default value of the current timestamp * A default value of the current timestamp
* *
* @namespace DataTypes.NOW * @namespace DataTypes.NOW
*/ */
function NOW() { class NOW extends ABSTRACT {
if (!(this instanceof NOW)) return new NOW();
} }
inherits(NOW, ABSTRACT);
NOW.prototype.key = NOW.key = 'NOW';
/** /**
* Binary storage * Binary storage
...@@ -685,16 +584,14 @@ NOW.prototype.key = NOW.key = 'NOW'; ...@@ -685,16 +584,14 @@ NOW.prototype.key = NOW.key = 'NOW';
* @namespace DataTypes.BLOB * @namespace DataTypes.BLOB
* *
*/ */
function BLOB(length) { class BLOB extends ABSTRACT {
constructor(length) {
super();
const options = typeof length === 'object' && length || { length }; const options = typeof length === 'object' && length || { length };
if (!(this instanceof BLOB)) return new BLOB(options);
this.options = options; this.options = options;
this._length = options.length || ''; this._length = options.length || '';
} }
inherits(BLOB, ABSTRACT); toSql() {
BLOB.prototype.key = BLOB.key = 'BLOB';
BLOB.prototype.toSql = function toSql() {
switch (this._length.toLowerCase()) { switch (this._length.toLowerCase()) {
case 'tiny': case 'tiny':
return 'TINYBLOB'; return 'TINYBLOB';
...@@ -705,43 +602,43 @@ BLOB.prototype.toSql = function toSql() { ...@@ -705,43 +602,43 @@ BLOB.prototype.toSql = function toSql() {
default: default:
return this.key; return this.key;
} }
}; }
BLOB.prototype.validate = function validate(value) { validate(value) {
if (typeof value !== 'string' && !Buffer.isBuffer(value)) { if (typeof value !== 'string' && !Buffer.isBuffer(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid blob', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid blob', value));
} }
return true; return true;
}; }
_stringify(value) {
BLOB.prototype.escape = false;
BLOB.prototype._stringify = function _stringify(value) {
if (!Buffer.isBuffer(value)) { if (!Buffer.isBuffer(value)) {
if (Array.isArray(value)) { if (Array.isArray(value)) {
value = Buffer.from(value); value = Buffer.from(value);
} else { }
else {
value = Buffer.from(value.toString()); value = Buffer.from(value.toString());
} }
} }
const hex = value.toString('hex'); const hex = value.toString('hex');
return this._hexify(hex); return this._hexify(hex);
}; }
_hexify(hex) {
BLOB.prototype._hexify = function _hexify(hex) {
return `X'${hex}'`; return `X'${hex}'`;
}; }
_bindParam(value, options) {
BLOB.prototype._bindParam = function _bindParam(value, options) {
if (!Buffer.isBuffer(value)) { if (!Buffer.isBuffer(value)) {
if (Array.isArray(value)) { if (Array.isArray(value)) {
value = Buffer.from(value); value = Buffer.from(value);
} else { }
else {
value = Buffer.from(value.toString()); value = Buffer.from(value.toString());
} }
} }
return options.bindParam(value); return options.bindParam(value);
}; }
}
BLOB.prototype.escape = false;
/** /**
* Range types are data types representing a range of values of some element type (called the range's subtype). * Range types are data types representing a range of values of some element type (called the range's subtype).
...@@ -751,34 +648,28 @@ BLOB.prototype._bindParam = function _bindParam(value, options) { ...@@ -751,34 +648,28 @@ BLOB.prototype._bindParam = function _bindParam(value, options) {
* *
* @namespace DataTypes.RANGE * @namespace DataTypes.RANGE
*/ */
function RANGE(subtype) { class RANGE extends ABSTRACT {
constructor(subtype) {
super();
const options = _.isPlainObject(subtype) ? subtype : { subtype }; const options = _.isPlainObject(subtype) ? subtype : { subtype };
if (!options.subtype)
if (!options.subtype) options.subtype = new INTEGER(); options.subtype = new INTEGER();
if (typeof options.subtype === 'function') { if (typeof options.subtype === 'function') {
options.subtype = new options.subtype(); options.subtype = new options.subtype();
} }
if (!(this instanceof RANGE)) return new RANGE(options);
this._subtype = options.subtype.key; this._subtype = options.subtype.key;
this.options = options; this.options = options;
} }
inherits(RANGE, ABSTRACT); validate(value) {
RANGE.prototype.key = RANGE.key = 'RANGE';
RANGE.prototype.validate = function validate(value) {
if (!Array.isArray(value)) { if (!Array.isArray(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid range', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid range', value));
} }
if (value.length !== 2) { if (value.length !== 2) {
throw new sequelizeErrors.ValidationError('A range must be an array with two elements'); throw new sequelizeErrors.ValidationError('A range must be an array with two elements');
} }
return true; return true;
}; }
}
/** /**
* A column storing a unique universal identifier. * A column storing a unique universal identifier.
...@@ -786,57 +677,42 @@ RANGE.prototype.validate = function validate(value) { ...@@ -786,57 +677,42 @@ RANGE.prototype.validate = function validate(value) {
* *
* @namespace DataTypes.UUID * @namespace DataTypes.UUID
*/ */
function UUID() { class UUID extends ABSTRACT {
if (!(this instanceof UUID)) return new UUID(); validate(value, options) {
}
inherits(UUID, ABSTRACT);
UUID.prototype.key = UUID.key = 'UUID';
UUID.prototype.validate = function validate(value, options) {
if (typeof value !== 'string' || !Validator.isUUID(value) && (!options || !options.acceptStrings)) { if (typeof value !== 'string' || !Validator.isUUID(value) && (!options || !options.acceptStrings)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid uuid', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid uuid', value));
} }
return true; return true;
}; }
}
/** /**
* A default unique universal identifier generated following the UUID v1 standard * A default unique universal identifier generated following the UUID v1 standard
* *
* @namespace DataTypes.UUIDV1 * @namespace DataTypes.UUIDV1
*/ */
function UUIDV1() { class UUIDV1 extends ABSTRACT {
if (!(this instanceof UUIDV1)) return new UUIDV1(); validate(value, options) {
}
inherits(UUIDV1, ABSTRACT);
UUIDV1.prototype.key = UUIDV1.key = 'UUIDV1';
UUIDV1.prototype.validate = function validate(value, options) {
if (typeof value !== 'string' || !Validator.isUUID(value) && (!options || !options.acceptStrings)) { if (typeof value !== 'string' || !Validator.isUUID(value) && (!options || !options.acceptStrings)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid uuid', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid uuid', value));
} }
return true; return true;
}; }
}
/** /**
* A default unique universal identifier generated following the UUID v4 standard * A default unique universal identifier generated following the UUID v4 standard
* *
* @namespace DataTypes.UUIDV4 * @namespace DataTypes.UUIDV4
*/ */
function UUIDV4() { class UUIDV4 extends ABSTRACT {
if (!(this instanceof UUIDV4)) return new UUIDV4(); validate(value, options) {
}
inherits(UUIDV4, ABSTRACT);
UUIDV4.prototype.key = UUIDV4.key = 'UUIDV4';
UUIDV4.prototype.validate = function validate(value, options) {
if (typeof value !== 'string' || !Validator.isUUID(value, 4) && (!options || !options.acceptStrings)) { if (typeof value !== 'string' || !Validator.isUUID(value, 4) && (!options || !options.acceptStrings)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid uuidv4', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid uuidv4', value));
} }
return true; return true;
}; }
}
/** /**
* 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. * 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.
...@@ -883,16 +759,15 @@ UUIDV4.prototype.validate = function validate(value, options) { ...@@ -883,16 +759,15 @@ UUIDV4.prototype.validate = function validate(value, options) {
* @namespace DataTypes.VIRTUAL * @namespace DataTypes.VIRTUAL
* *
*/ */
function VIRTUAL(ReturnType, fields) { class VIRTUAL extends ABSTRACT {
if (!(this instanceof VIRTUAL)) return new VIRTUAL(ReturnType, fields); constructor(ReturnType, fields) {
if (typeof ReturnType === 'function') ReturnType = new ReturnType(); super();
if (typeof ReturnType === 'function')
ReturnType = new ReturnType();
this.returnType = ReturnType; this.returnType = ReturnType;
this.fields = fields; this.fields = fields;
}
} }
inherits(VIRTUAL, ABSTRACT);
VIRTUAL.prototype.key = VIRTUAL.key = 'VIRTUAL';
/** /**
* An enumeration, Postgres Only * An enumeration, Postgres Only
...@@ -909,27 +784,25 @@ VIRTUAL.prototype.key = VIRTUAL.key = 'VIRTUAL'; ...@@ -909,27 +784,25 @@ VIRTUAL.prototype.key = VIRTUAL.key = 'VIRTUAL';
* @namespace DataTypes.ENUM * @namespace DataTypes.ENUM
* *
*/ */
function ENUM(...args) { class ENUM extends ABSTRACT {
constructor(...args) {
super();
const value = args[0]; const value = args[0];
const options = typeof value === 'object' && !Array.isArray(value) && value || { const options = typeof value === 'object' && !Array.isArray(value) && value || {
values: args.reduce((result, element) => { values: args.reduce((result, element) => {
return result.concat(Array.isArray(element) ? element : [element]); return result.concat(Array.isArray(element) ? element : [element]);
}, []) }, [])
}; };
if (!(this instanceof ENUM)) return new ENUM(options);
this.values = options.values; this.values = options.values;
this.options = options; this.options = options;
} }
inherits(ENUM, ABSTRACT); validate(value) {
ENUM.prototype.key = ENUM.key = 'ENUM';
ENUM.prototype.validate = function validate(value) {
if (!this.values.includes(value)) { if (!this.values.includes(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid choice in %j', value, this.values)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid choice in %j', value, this.values));
} }
return true; return true;
}; }
}
/** /**
* An array of `type`. Only available in Postgres. * An array of `type`. Only available in Postgres.
...@@ -941,27 +814,25 @@ ENUM.prototype.validate = function validate(value) { ...@@ -941,27 +814,25 @@ ENUM.prototype.validate = function validate(value) {
* *
* @namespace DataTypes.ARRAY * @namespace DataTypes.ARRAY
*/ */
function ARRAY(type) { class ARRAY extends ABSTRACT {
constructor(type) {
super();
const options = _.isPlainObject(type) ? type : { type }; const options = _.isPlainObject(type) ? type : { type };
if (!(this instanceof ARRAY)) return new ARRAY(options);
this.type = typeof options.type === 'function' ? new options.type() : options.type; this.type = typeof options.type === 'function' ? new options.type() : options.type;
} }
inherits(ARRAY, ABSTRACT); toSql() {
ARRAY.prototype.key = ARRAY.key = 'ARRAY';
ARRAY.prototype.toSql = function toSql() {
return `${this.type.toSql()}[]`; return `${this.type.toSql()}[]`;
}; }
ARRAY.prototype.validate = function validate(value) { validate(value) {
if (!Array.isArray(value)) { if (!Array.isArray(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid array', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid array', value));
} }
return true; return true;
}; }
ARRAY.is = function is(obj, type) { static is(obj, type) {
return obj instanceof ARRAY && obj.type instanceof type; return obj instanceof ARRAY && obj.type instanceof type;
}; }
}
/** /**
* A column storing Geometry information. * A column storing Geometry information.
...@@ -1012,26 +883,23 @@ ARRAY.is = function is(obj, type) { ...@@ -1012,26 +883,23 @@ ARRAY.is = function is(obj, type) {
* @see {@link DataTypes.GEOGRAPHY} * @see {@link DataTypes.GEOGRAPHY}
* @namespace DataTypes.GEOMETRY * @namespace DataTypes.GEOMETRY
*/ */
function GEOMETRY(type, srid) { class GEOMETRY extends ABSTRACT {
constructor(type, srid) {
super();
const options = _.isPlainObject(type) ? type : { type, srid }; const options = _.isPlainObject(type) ? type : { type, srid };
if (!(this instanceof GEOMETRY)) return new GEOMETRY(options);
this.options = options; this.options = options;
this.type = options.type; this.type = options.type;
this.srid = options.srid; this.srid = options.srid;
}
_stringify(value, options) {
return `GeomFromText(${options.escape(wkx.Geometry.parseGeoJSON(value).toWkt())})`;
}
_bindParam(value, options) {
return `GeomFromText(${options.bindParam(wkx.Geometry.parseGeoJSON(value).toWkt())})`;
}
} }
inherits(GEOMETRY, ABSTRACT);
GEOMETRY.prototype.key = GEOMETRY.key = 'GEOMETRY';
GEOMETRY.prototype.escape = false; GEOMETRY.prototype.escape = false;
GEOMETRY.prototype._stringify = function _stringify(value, options) {
return `GeomFromText(${options.escape(wkx.Geometry.parseGeoJSON(value).toWkt())})`;
};
GEOMETRY.prototype._bindParam = function _bindParam(value, options) {
return `GeomFromText(${options.bindParam(wkx.Geometry.parseGeoJSON(value).toWkt())})`;
};
/** /**
* A geography datatype represents two dimensional spacial objects in an elliptic coord system. * A geography datatype represents two dimensional spacial objects in an elliptic coord system.
...@@ -1059,26 +927,24 @@ GEOMETRY.prototype._bindParam = function _bindParam(value, options) { ...@@ -1059,26 +927,24 @@ GEOMETRY.prototype._bindParam = function _bindParam(value, options) {
* *
* @namespace DataTypes.GEOGRAPHY * @namespace DataTypes.GEOGRAPHY
*/ */
function GEOGRAPHY(type, srid) { class GEOGRAPHY extends ABSTRACT {
constructor(type, srid) {
super();
const options = _.isPlainObject(type) ? type : { type, srid }; const options = _.isPlainObject(type) ? type : { type, srid };
if (!(this instanceof GEOGRAPHY)) return new GEOGRAPHY(options);
this.options = options; this.options = options;
this.type = options.type; this.type = options.type;
this.srid = options.srid; this.srid = options.srid;
}
_stringify(value, options) {
return `GeomFromText(${options.escape(wkx.Geometry.parseGeoJSON(value).toWkt())})`;
}
_bindParam(value, options) {
return `GeomFromText(${options.bindParam(wkx.Geometry.parseGeoJSON(value).toWkt())})`;
}
} }
inherits(GEOGRAPHY, ABSTRACT);
GEOGRAPHY.prototype.key = GEOGRAPHY.key = 'GEOGRAPHY';
GEOGRAPHY.prototype.escape = false; GEOGRAPHY.prototype.escape = false;
GEOGRAPHY.prototype._stringify = function _stringify(value, options) {
return `GeomFromText(${options.escape(wkx.Geometry.parseGeoJSON(value).toWkt())})`;
};
GEOGRAPHY.prototype._bindParam = function _bindParam(value, options) {
return `GeomFromText(${options.bindParam(wkx.Geometry.parseGeoJSON(value).toWkt())})`;
};
/** /**
* The cidr type holds an IPv4 or IPv6 network specification. Takes 7 or 19 bytes. * The cidr type holds an IPv4 or IPv6 network specification. Takes 7 or 19 bytes.
...@@ -1087,20 +953,14 @@ GEOGRAPHY.prototype._bindParam = function _bindParam(value, options) { ...@@ -1087,20 +953,14 @@ GEOGRAPHY.prototype._bindParam = function _bindParam(value, options) {
* *
* @namespace DataTypes.CIDR * @namespace DataTypes.CIDR
*/ */
function CIDR() { class CIDR extends ABSTRACT {
if (!(this instanceof CIDR)) return new CIDR(); validate(value) {
}
inherits(CIDR, ABSTRACT);
CIDR.prototype.key = CIDR.key = 'CIDR';
CIDR.prototype.validate = function validate(value) {
if (typeof value !== 'string' || !Validator.isIPRange(value)) { if (typeof value !== 'string' || !Validator.isIPRange(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid CIDR', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid CIDR', value));
} }
return true; return true;
}; }
}
/** /**
* The INET type holds an IPv4 or IPv6 host address, and optionally its subnet. Takes 7 or 19 bytes * The INET type holds an IPv4 or IPv6 host address, and optionally its subnet. Takes 7 or 19 bytes
...@@ -1109,20 +969,14 @@ CIDR.prototype.validate = function validate(value) { ...@@ -1109,20 +969,14 @@ CIDR.prototype.validate = function validate(value) {
* *
* @namespace DataTypes.INET * @namespace DataTypes.INET
*/ */
function INET() { class INET extends ABSTRACT {
if (!(this instanceof INET)) return new INET(); validate(value) {
}
inherits(INET, ABSTRACT);
INET.prototype.key = INET.key = 'INET';
INET.prototype.validate = function validate(value) {
if (typeof value !== 'string' || !Validator.isIP(value)) { if (typeof value !== 'string' || !Validator.isIP(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid INET', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid INET', value));
} }
return true; return true;
}; }
}
/** /**
* The MACADDR type stores MAC addresses. Takes 6 bytes * The MACADDR type stores MAC addresses. Takes 6 bytes
...@@ -1131,42 +985,12 @@ INET.prototype.validate = function validate(value) { ...@@ -1131,42 +985,12 @@ INET.prototype.validate = function validate(value) {
* *
* @namespace DataTypes.MACADDR * @namespace DataTypes.MACADDR
*/ */
function MACADDR() { class MACADDR extends ABSTRACT {
if (!(this instanceof MACADDR)) return new MACADDR(); validate(value) {
}
inherits(MACADDR, ABSTRACT);
MACADDR.prototype.key = MACADDR.key = 'MACADDR';
MACADDR.prototype.validate = function validate(value) {
if (typeof value !== 'string' || !Validator.isMACAddress(value)) { if (typeof value !== 'string' || !Validator.isMACAddress(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid MACADDR', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid MACADDR', value));
} }
return true; return true;
};
const helpers = {
BINARY: [STRING, CHAR],
UNSIGNED: [NUMBER, TINYINT, SMALLINT, MEDIUMINT, INTEGER, BIGINT, FLOAT, DOUBLE, REAL, DECIMAL],
ZEROFILL: [NUMBER, TINYINT, SMALLINT, MEDIUMINT, INTEGER, BIGINT, FLOAT, DOUBLE, REAL, DECIMAL],
PRECISION: [DECIMAL],
SCALE: [DECIMAL]
};
for (const helper of Object.keys(helpers)) {
for (const DataType of helpers[helper]) {
if (!DataType[helper]) {
Object.defineProperty(DataType, helper, {
get() {
const dataType = new DataType();
if (typeof dataType[helper] === 'object') {
return dataType;
}
return dataType[helper].apply(dataType, arguments);
}
});
}
} }
} }
...@@ -1248,8 +1072,8 @@ const DataTypes = module.exports = { ...@@ -1248,8 +1072,8 @@ const DataTypes = module.exports = {
ENUM, ENUM,
RANGE, RANGE,
REAL, REAL,
DOUBLE,
'DOUBLE PRECISION': DOUBLE, 'DOUBLE PRECISION': DOUBLE,
DOUBLE,
GEOMETRY, GEOMETRY,
GEOGRAPHY, GEOGRAPHY,
CIDR, CIDR,
...@@ -1258,14 +1082,35 @@ const DataTypes = module.exports = { ...@@ -1258,14 +1082,35 @@ const DataTypes = module.exports = {
CITEXT CITEXT
}; };
_.each(DataTypes, dataType => {
_.each(DataTypes, (dataType, name) => {
// guard for aliases
if (!dataType.hasOwnProperty('key')) {
dataType.types = {}; dataType.types = {};
dataType.key = dataType.prototype.key = name;
}
}); });
DataTypes.postgres = require('./dialects/postgres/data-types')(DataTypes); const dialectNames = ['postgres', 'mysql', 'mariadb', 'sqlite', 'mssql'];
DataTypes.mysql = require('./dialects/mysql/data-types')(DataTypes); const dialectMap = {};
DataTypes.mariadb = require('./dialects/mariadb/data-types')(DataTypes); for (const d of dialectNames) {
DataTypes.sqlite = require('./dialects/sqlite/data-types')(DataTypes); dialectMap[d] = require(`./dialects/${d}/data-types`)(DataTypes);
DataTypes.mssql = require('./dialects/mssql/data-types')(DataTypes); }
const dialectList = _.values(dialectMap);
for (const dataTypes of dialectList) {
_.each(dataTypes, (DataType, key) => {
if (!DataType.key) {
DataType.key = DataType.prototype.key = key;
}
});
}
// Wrap all data types to not require `new`
for (const dataTypes of [DataTypes, ...dialectList]) {
_.each(dataTypes, (DataType, key) => {
dataTypes[key] = classToInvokable(DataType);
});
}
module.exports = DataTypes; Object.assign(DataTypes, dialectMap);
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
const _ = require('lodash'); const _ = require('lodash');
const moment = require('moment-timezone'); const moment = require('moment-timezone');
const inherits = require('../../utils/inherits');
module.exports = BaseTypes => { module.exports = BaseTypes => {
BaseTypes.ABSTRACT.prototype.dialectTypes = 'https://mariadb.com/kb/en/library/resultset/#field-types'; BaseTypes.ABSTRACT.prototype.dialectTypes = 'https://mariadb.com/kb/en/library/resultset/#field-types';
...@@ -35,138 +34,83 @@ module.exports = BaseTypes => { ...@@ -35,138 +34,83 @@ module.exports = BaseTypes => {
BaseTypes.GEOMETRY.types.mariadb = ['GEOMETRY']; BaseTypes.GEOMETRY.types.mariadb = ['GEOMETRY'];
BaseTypes.JSON.types.mariadb = ['JSON']; BaseTypes.JSON.types.mariadb = ['JSON'];
function DECIMAL(precision, scale) { class DECIMAL extends BaseTypes.DECIMAL {
if (!(this instanceof DECIMAL)) { toSql() {
return new DECIMAL(precision, scale); let definition = super.toSql();
}
BaseTypes.DECIMAL.apply(this, arguments);
}
inherits(DECIMAL, BaseTypes.DECIMAL);
DECIMAL.prototype.toSql = function toSql() {
let definition = BaseTypes.DECIMAL.prototype.toSql.apply(this);
if (this._unsigned) { if (this._unsigned) {
definition += ' UNSIGNED'; definition += ' UNSIGNED';
} }
if (this._zerofill) { if (this._zerofill) {
definition += ' ZEROFILL'; definition += ' ZEROFILL';
} }
return definition; return definition;
};
function DATE(length) {
if (!(this instanceof DATE)) {
return new DATE(length);
} }
BaseTypes.DATE.apply(this, arguments);
} }
inherits(DATE, BaseTypes.DATE); class DATE extends BaseTypes.DATE {
toSql() {
DATE.prototype.toSql = function toSql() {
return `DATETIME${this._length ? `(${this._length})` : ''}`; return `DATETIME${this._length ? `(${this._length})` : ''}`;
}; }
_stringify(date, options) {
DATE.prototype._stringify = function _stringify(date, options) { date = this._applyTimezone(date, options);
date = BaseTypes.DATE.prototype._applyTimezone(date, options);
return date.format('YYYY-MM-DD HH:mm:ss.SSS'); return date.format('YYYY-MM-DD HH:mm:ss.SSS');
}; }
static parse(value, options) {
DATE.parse = function parse(value, options) {
value = value.string(); value = value.string();
if (value === null) { if (value === null) {
return value; return value;
} }
if (moment.tz.zone(options.timezone)) { if (moment.tz.zone(options.timezone)) {
value = moment.tz(value, options.timezone).toDate(); value = moment.tz(value, options.timezone).toDate();
} else { }
else {
value = new Date(`${value} ${options.timezone}`); value = new Date(`${value} ${options.timezone}`);
} }
return value; return value;
};
function DATEONLY() {
if (!(this instanceof DATEONLY)) {
return new DATEONLY();
} }
BaseTypes.DATEONLY.call(this);
} }
inherits(DATEONLY, BaseTypes.DATEONLY); class DATEONLY extends BaseTypes.DATEONLY {
static parse(value) {
DATEONLY.parse = function parse(value) {
return value.string(); return value.string();
}; };
function UUID() {
if (!(this instanceof UUID)) {
return new UUID();
}
BaseTypes.UUID.call(this);
} }
inherits(UUID, BaseTypes.UUID); class UUID extends BaseTypes.UUID {
toSql() {
UUID.prototype.toSql = function toSql() {
return 'CHAR(36) BINARY'; return 'CHAR(36) BINARY';
};
function GEOMETRY(type, srid) {
if (!(this instanceof GEOMETRY)) {
return new GEOMETRY(type, srid);
} }
BaseTypes.GEOMETRY.apply(this, arguments); }
class GEOMETRY extends BaseTypes.GEOMETRY {
constructor(type, srid) {
super(type, srid);
if (_.isEmpty(this.type)) { if (_.isEmpty(this.type)) {
this.sqlType = this.key; this.sqlType = this.key;
} else { }
else {
this.sqlType = this.type; this.sqlType = this.type;
} }
} }
toSql() {
inherits(GEOMETRY, BaseTypes.GEOMETRY);
GEOMETRY.prototype.toSql = function toSql() {
return this.sqlType; return this.sqlType;
};
function ENUM() {
if (!(this instanceof ENUM)) {
const obj = Object.create(ENUM.prototype);
ENUM.apply(obj, arguments);
return obj;
} }
BaseTypes.ENUM.apply(this, arguments);
} }
inherits(ENUM, BaseTypes.ENUM); class ENUM extends BaseTypes.ENUM {
toSql(options) {
ENUM.prototype.toSql = function toSql(options) {
return `ENUM(${this.values.map(value => options.escape(value)).join(', ')})`; return `ENUM(${this.values.map(value => options.escape(value)).join(', ')})`;
};
function JSONTYPE() {
if (!(this instanceof JSONTYPE)) {
return new JSONTYPE();
} }
BaseTypes.JSON.call(this);
} }
inherits(JSONTYPE, BaseTypes.JSON); class JSONTYPE extends BaseTypes.JSON {
_stringify(value, options) {
JSONTYPE.prototype._stringify = function _stringify(value, options) {
return options.operation === 'where' && typeof value === 'string' ? value return options.operation === 'where' && typeof value === 'string' ? value
: JSON.stringify(value); : JSON.stringify(value);
}; }
}
const exports = { return {
ENUM, ENUM,
DATE, DATE,
DATEONLY, DATEONLY,
...@@ -175,17 +119,4 @@ module.exports = BaseTypes => { ...@@ -175,17 +119,4 @@ module.exports = BaseTypes => {
DECIMAL, DECIMAL,
JSON: JSONTYPE JSON: JSONTYPE
}; };
_.forIn(exports, (DataType, key) => {
if (!DataType.key) {
DataType.key = key;
}
if (!DataType.extend) {
DataType.extend = function extend(oldType) {
return new DataType(oldType.options);
};
}
});
return exports;
}; };
'use strict'; 'use strict';
const _ = require('lodash');
const moment = require('moment'); const moment = require('moment');
const inherits = require('../../utils/inherits');
module.exports = BaseTypes => { module.exports = BaseTypes => {
const warn = BaseTypes.ABSTRACT.warn.bind(undefined, 'https://msdn.microsoft.com/en-us/library/ms187752%28v=sql.110%29.aspx'); const warn = BaseTypes.ABSTRACT.warn.bind(undefined, 'https://msdn.microsoft.com/en-us/library/ms187752%28v=sql.110%29.aspx');
...@@ -50,13 +48,8 @@ module.exports = BaseTypes => { ...@@ -50,13 +48,8 @@ module.exports = BaseTypes => {
// BaseTypes.GEOMETRY.types.mssql = [240]; // not yet supported // BaseTypes.GEOMETRY.types.mssql = [240]; // not yet supported
BaseTypes.GEOMETRY.types.mssql = false; BaseTypes.GEOMETRY.types.mssql = false;
function BLOB(length) { class BLOB extends BaseTypes.BLOB {
if (!(this instanceof BLOB)) return new BLOB(length); toSql() {
BaseTypes.BLOB.apply(this, arguments);
}
inherits(BLOB, BaseTypes.BLOB);
BLOB.prototype.toSql = function toSql() {
if (this._length) { if (this._length) {
if (this._length.toLowerCase() === 'tiny') { // tiny = 2^8 if (this._length.toLowerCase() === 'tiny') { // tiny = 2^8
warn('MSSQL does not support BLOB with the `length` = `tiny` option. `VARBINARY(256)` will be used instead.'); warn('MSSQL does not support BLOB with the `length` = `tiny` option. `VARBINARY(256)` will be used instead.');
...@@ -65,43 +58,35 @@ module.exports = BaseTypes => { ...@@ -65,43 +58,35 @@ module.exports = BaseTypes => {
warn('MSSQL does not support BLOB with the `length` option. `VARBINARY(MAX)` will be used instead.'); warn('MSSQL does not support BLOB with the `length` option. `VARBINARY(MAX)` will be used instead.');
} }
return 'VARBINARY(MAX)'; return 'VARBINARY(MAX)';
}; }
_hexify(hex) {
BLOB.prototype._hexify = function _hexify(hex) {
return `0x${hex}`; return `0x${hex}`;
};
function STRING(length, binary) {
if (!(this instanceof STRING)) return new STRING(length, binary);
BaseTypes.STRING.apply(this, arguments);
} }
inherits(STRING, BaseTypes.STRING); }
STRING.prototype.toSql = function toSql() {
class STRING extends BaseTypes.STRING {
toSql() {
if (!this._binary) { if (!this._binary) {
return `NVARCHAR(${this._length})`; return `NVARCHAR(${this._length})`;
} }
return `BINARY(${this._length})`; return `BINARY(${this._length})`;
}; }
_stringify(value, options) {
STRING.prototype.escape = false;
STRING.prototype._stringify = function _stringify(value, options) {
if (this._binary) { if (this._binary) {
return BLOB.prototype._stringify(value); return BLOB.prototype._stringify(value);
} }
return options.escape(value); return options.escape(value);
}; }
STRING.prototype._bindParam = function _bindParam(value, options) { _bindParam(value, options) {
return options.bindParam(this._binary ? Buffer.from(value) : value); return options.bindParam(this._binary ? Buffer.from(value) : value);
};
function TEXT(length) {
if (!(this instanceof TEXT)) return new TEXT(length);
BaseTypes.TEXT.apply(this, arguments);
} }
inherits(TEXT, BaseTypes.TEXT); }
STRING.prototype.escape = false;
TEXT.prototype.toSql = function toSql() { class TEXT extends BaseTypes.TEXT {
toSql() {
// TEXT is deprecated in mssql and it would normally be saved as a non-unicode string. // TEXT is deprecated in mssql and it would normally be saved as a non-unicode string.
// Using unicode is just future proof // Using unicode is just future proof
if (this._length) { if (this._length) {
...@@ -112,93 +97,66 @@ module.exports = BaseTypes => { ...@@ -112,93 +97,66 @@ module.exports = BaseTypes => {
warn('MSSQL does not support TEXT with the `length` option. `NVARCHAR(MAX)` will be used instead.'); warn('MSSQL does not support TEXT with the `length` option. `NVARCHAR(MAX)` will be used instead.');
} }
return 'NVARCHAR(MAX)'; return 'NVARCHAR(MAX)';
};
function BOOLEAN() {
if (!(this instanceof BOOLEAN)) return new BOOLEAN();
BaseTypes.BOOLEAN.call(this);
} }
inherits(BOOLEAN, BaseTypes.BOOLEAN); }
BOOLEAN.prototype.toSql = function toSql() { class BOOLEAN extends BaseTypes.BOOLEAN {
toSql() {
return 'BIT'; return 'BIT';
};
function UUID() {
if (!(this instanceof UUID)) return new UUID();
BaseTypes.UUID.call(this);
} }
inherits(UUID, BaseTypes.UUID); }
UUID.prototype.toSql = function toSql() { class UUID extends BaseTypes.UUID {
toSql() {
return 'CHAR(36)'; return 'CHAR(36)';
};
function NOW() {
if (!(this instanceof NOW)) return new NOW();
BaseTypes.NOW.call(this);
} }
inherits(NOW, BaseTypes.NOW); }
NOW.prototype.toSql = function toSql() { class NOW extends BaseTypes.NOW {
toSql() {
return 'GETDATE()'; return 'GETDATE()';
};
function DATE(length) {
if (!(this instanceof DATE)) return new DATE(length);
BaseTypes.DATE.apply(this, arguments);
} }
inherits(DATE, BaseTypes.DATE); }
DATE.prototype.toSql = function toSql() { class DATE extends BaseTypes.DATE {
toSql() {
return 'DATETIMEOFFSET'; return 'DATETIMEOFFSET';
};
function DATEONLY() {
if (!(this instanceof DATEONLY)) return new DATEONLY();
BaseTypes.DATEONLY.call(this);
} }
inherits(DATEONLY, BaseTypes.DATEONLY); }
DATEONLY.parse = function(value) { class DATEONLY extends BaseTypes.DATEONLY {
static parse(value) {
return moment(value).format('YYYY-MM-DD'); return moment(value).format('YYYY-MM-DD');
}; };
}
function INTEGER(length) { class INTEGER extends BaseTypes.INTEGER {
if (!(this instanceof INTEGER)) return new INTEGER(length); constructor(length) {
BaseTypes.INTEGER.apply(this, arguments); super(length);
removeUnsupportedIntegerOptions(this); removeUnsupportedIntegerOptions(this);
} }
inherits(INTEGER, BaseTypes.INTEGER); }
class TINYINT extends BaseTypes.TINYINT {
function TINYINT(length) { constructor(length) {
if (!(this instanceof TINYINT)) return new TINYINT(length); super(length);
BaseTypes.TINYINT.apply(this, arguments);
removeUnsupportedIntegerOptions(this); removeUnsupportedIntegerOptions(this);
} }
inherits(TINYINT, BaseTypes.TINYINT); }
class SMALLINT extends BaseTypes.SMALLINT {
function SMALLINT(length) { constructor(length) {
if (!(this instanceof SMALLINT)) return new SMALLINT(length); super(length);
BaseTypes.SMALLINT.apply(this, arguments);
removeUnsupportedIntegerOptions(this); removeUnsupportedIntegerOptions(this);
} }
inherits(SMALLINT, BaseTypes.SMALLINT); }
class BIGINT extends BaseTypes.BIGINT {
function BIGINT(length) { constructor(length) {
if (!(this instanceof BIGINT)) return new BIGINT(length); super(length);
BaseTypes.BIGINT.apply(this, arguments);
removeUnsupportedIntegerOptions(this); removeUnsupportedIntegerOptions(this);
} }
inherits(BIGINT, BaseTypes.BIGINT); }
class REAL extends BaseTypes.REAL {
function REAL(length, decimals) { constructor(length, decimals) {
if (!(this instanceof REAL)) return new REAL(length, decimals); super(length, decimals);
BaseTypes.REAL.apply(this, arguments);
// MSSQL does not support any options for real // MSSQL does not support any options for real
if (this._length || this.options.length || this._unsigned || this._zerofill) { if (this._length || this.options.length || this._unsigned || this._zerofill) {
warn('MSSQL does not support REAL with options. Plain `REAL` will be used instead.'); warn('MSSQL does not support REAL with options. Plain `REAL` will be used instead.');
...@@ -208,12 +166,10 @@ module.exports = BaseTypes => { ...@@ -208,12 +166,10 @@ module.exports = BaseTypes => {
this._zerofill = undefined; this._zerofill = undefined;
} }
} }
inherits(REAL, BaseTypes.REAL); }
class FLOAT extends BaseTypes.FLOAT {
function FLOAT(length, decimals) { constructor(length, decimals) {
if (!(this instanceof FLOAT)) return new FLOAT(length, decimals); super(length, decimals);
BaseTypes.FLOAT.apply(this, arguments);
// MSSQL does only support lengths as option. // MSSQL does only support lengths as option.
// Values between 1-24 result in 7 digits precision (4 bytes storage size) // Values between 1-24 result in 7 digits precision (4 bytes storage size)
// Values between 25-53 result in 15 digits precision (8 bytes storage size) // Values between 25-53 result in 15 digits precision (8 bytes storage size)
...@@ -232,23 +188,14 @@ module.exports = BaseTypes => { ...@@ -232,23 +188,14 @@ module.exports = BaseTypes => {
this._zerofill = undefined; this._zerofill = undefined;
} }
} }
inherits(FLOAT, BaseTypes.FLOAT);
function ENUM() {
if (!(this instanceof ENUM)) {
const obj = Object.create(ENUM.prototype);
ENUM.apply(obj, arguments);
return obj;
}
BaseTypes.ENUM.apply(this, arguments);
} }
inherits(ENUM, BaseTypes.ENUM); class ENUM extends BaseTypes.ENUM {
toSql() {
ENUM.prototype.toSql = function toSql() {
return 'VARCHAR(255)'; return 'VARCHAR(255)';
}; }
}
const exports = { return {
BLOB, BLOB,
BOOLEAN, BOOLEAN,
ENUM, ENUM,
...@@ -265,15 +212,4 @@ module.exports = BaseTypes => { ...@@ -265,15 +212,4 @@ module.exports = BaseTypes => {
FLOAT, FLOAT,
TEXT TEXT
}; };
_.forIn(exports, (DataType, key) => {
if (!DataType.key) DataType.key = key;
if (!DataType.extend) {
DataType.extend = function extend(oldType) {
return new DataType(oldType.options);
};
}
});
return exports;
}; };
...@@ -3,8 +3,6 @@ ...@@ -3,8 +3,6 @@
const wkx = require('wkx'); const wkx = require('wkx');
const _ = require('lodash'); const _ = require('lodash');
const moment = require('moment-timezone'); const moment = require('moment-timezone');
const inherits = require('../../utils/inherits');
module.exports = BaseTypes => { module.exports = BaseTypes => {
BaseTypes.ABSTRACT.prototype.dialectTypes = 'https://dev.mysql.com/doc/refman/5.7/en/data-types.html'; BaseTypes.ABSTRACT.prototype.dialectTypes = 'https://dev.mysql.com/doc/refman/5.7/en/data-types.html';
...@@ -36,143 +34,101 @@ module.exports = BaseTypes => { ...@@ -36,143 +34,101 @@ module.exports = BaseTypes => {
BaseTypes.GEOMETRY.types.mysql = ['GEOMETRY']; BaseTypes.GEOMETRY.types.mysql = ['GEOMETRY'];
BaseTypes.JSON.types.mysql = ['JSON']; BaseTypes.JSON.types.mysql = ['JSON'];
function DECIMAL(precision, scale) { class DECIMAL extends BaseTypes.DECIMAL {
if (!(this instanceof DECIMAL)) return new DECIMAL(precision, scale); toSql() {
BaseTypes.DECIMAL.apply(this, arguments); let definition = super.toSql();
}
inherits(DECIMAL, BaseTypes.DECIMAL);
DECIMAL.prototype.toSql = function toSql() {
let definition = BaseTypes.DECIMAL.prototype.toSql.apply(this);
if (this._unsigned) { if (this._unsigned) {
definition += ' UNSIGNED'; definition += ' UNSIGNED';
} }
if (this._zerofill) { if (this._zerofill) {
definition += ' ZEROFILL'; definition += ' ZEROFILL';
} }
return definition; return definition;
};
function DATE(length) {
if (!(this instanceof DATE)) return new DATE(length);
BaseTypes.DATE.apply(this, arguments);
} }
inherits(DATE, BaseTypes.DATE); }
DATE.prototype.toSql = function toSql() { class DATE extends BaseTypes.DATE {
toSql() {
return `DATETIME${this._length ? `(${this._length})` : ''}`; return `DATETIME${this._length ? `(${this._length})` : ''}`;
}; }
_stringify(date, options) {
DATE.prototype._stringify = function _stringify(date, options) { date = this._applyTimezone(date, options);
date = BaseTypes.DATE.prototype._applyTimezone(date, options);
// Fractional DATETIMEs only supported on MySQL 5.6.4+ // Fractional DATETIMEs only supported on MySQL 5.6.4+
if (this._length) { if (this._length) {
return date.format('YYYY-MM-DD HH:mm:ss.SSS'); return date.format('YYYY-MM-DD HH:mm:ss.SSS');
} }
return date.format('YYYY-MM-DD HH:mm:ss'); return date.format('YYYY-MM-DD HH:mm:ss');
}; }
static parse(value, options) {
DATE.parse = function parse(value, options) {
value = value.string(); value = value.string();
if (value === null) { if (value === null) {
return value; return value;
} }
if (moment.tz.zone(options.timezone)) { if (moment.tz.zone(options.timezone)) {
value = moment.tz(value, options.timezone).toDate(); value = moment.tz(value, options.timezone).toDate();
} else { }
else {
value = new Date(`${value} ${options.timezone}`); value = new Date(`${value} ${options.timezone}`);
} }
return value; return value;
};
function DATEONLY() {
if (!(this instanceof DATEONLY)) return new DATEONLY();
BaseTypes.DATEONLY.call(this);
} }
inherits(DATEONLY, BaseTypes.DATEONLY); }
DATEONLY.parse = function parse(value) { class DATEONLY extends BaseTypes.DATEONLY {
static parse(value) {
return value.string(); return value.string();
};
function UUID() {
if (!(this instanceof UUID)) return new UUID();
BaseTypes.UUID.call(this);
} }
inherits(UUID, BaseTypes.UUID); }
class UUID extends BaseTypes.UUID {
UUID.prototype.toSql = function toSql() { toSql() {
return 'CHAR(36) BINARY'; return 'CHAR(36) BINARY';
}; }
}
const SUPPORTED_GEOMETRY_TYPES = ['POINT', 'LINESTRING', 'POLYGON']; const SUPPORTED_GEOMETRY_TYPES = ['POINT', 'LINESTRING', 'POLYGON'];
function GEOMETRY(type, srid) { class GEOMETRY extends BaseTypes.GEOMETRY {
if (!(this instanceof GEOMETRY)) return new GEOMETRY(type, srid); constructor(type, srid) {
BaseTypes.GEOMETRY.apply(this, arguments); super(type, srid);
if (_.isEmpty(this.type)) { if (_.isEmpty(this.type)) {
this.sqlType = this.key; this.sqlType = this.key;
} else if (SUPPORTED_GEOMETRY_TYPES.includes(this.type)) { return;
}
if (SUPPORTED_GEOMETRY_TYPES.includes(this.type)) {
this.sqlType = this.type; this.sqlType = this.type;
} else { return;
throw new Error(`Supported geometry types are: ${SUPPORTED_GEOMETRY_TYPES.join(', ')}`);
} }
throw new Error(`Supported geometry types are: ${SUPPORTED_GEOMETRY_TYPES.join(', ')}`);
} }
inherits(GEOMETRY, BaseTypes.GEOMETRY); static parse(value) {
GEOMETRY.parse = GEOMETRY.prototype.parse = function parse(value) {
value = value.buffer(); value = value.buffer();
// Empty buffer, MySQL doesn't support POINT EMPTY // Empty buffer, MySQL doesn't support POINT EMPTY
// check, https://dev.mysql.com/worklog/task/?id=2381 // check, https://dev.mysql.com/worklog/task/?id=2381
if (!value || value.length === 0) { if (!value || value.length === 0) {
return null; return null;
} }
// For some reason, discard the first 4 bytes // For some reason, discard the first 4 bytes
value = value.slice(4); value = value.slice(4);
return wkx.Geometry.parse(value).toGeoJSON(); return wkx.Geometry.parse(value).toGeoJSON();
}; }
toSql() {
GEOMETRY.prototype.toSql = function toSql() {
return this.sqlType; return this.sqlType;
};
function ENUM() {
if (!(this instanceof ENUM)) {
const obj = Object.create(ENUM.prototype);
ENUM.apply(obj, arguments);
return obj;
} }
BaseTypes.ENUM.apply(this, arguments);
} }
inherits(ENUM, BaseTypes.ENUM);
ENUM.prototype.toSql = function toSql(options) { class ENUM extends BaseTypes.ENUM {
toSql(options) {
return `ENUM(${this.values.map(value => options.escape(value)).join(', ')})`; return `ENUM(${this.values.map(value => options.escape(value)).join(', ')})`;
};
function JSONTYPE() {
if (!(this instanceof JSONTYPE)) return new JSONTYPE();
BaseTypes.JSON.call(this);
} }
inherits(JSONTYPE, BaseTypes.JSON); }
JSONTYPE.prototype._stringify = function _stringify(value, options) { class JSONTYPE extends BaseTypes.JSON {
_stringify(value, options) {
return options.operation === 'where' && typeof value === 'string' ? value : JSON.stringify(value); return options.operation === 'where' && typeof value === 'string' ? value : JSON.stringify(value);
}; }
}
const exports = { return {
ENUM, ENUM,
DATE, DATE,
DATEONLY, DATEONLY,
...@@ -181,15 +137,4 @@ module.exports = BaseTypes => { ...@@ -181,15 +137,4 @@ module.exports = BaseTypes => {
DECIMAL, DECIMAL,
JSON: JSONTYPE JSON: JSONTYPE
}; };
_.forIn(exports, (DataType, key) => {
if (!DataType.key) DataType.key = key;
if (!DataType.extend) {
DataType.extend = function extend(oldType) {
return new DataType(oldType.options);
};
}
});
return exports;
}; };
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
const _ = require('lodash'); const _ = require('lodash');
const wkx = require('wkx'); const wkx = require('wkx');
const inherits = require('../../utils/inherits');
module.exports = BaseTypes => { module.exports = BaseTypes => {
const warn = BaseTypes.ABSTRACT.warn.bind(undefined, 'http://www.postgresql.org/docs/9.4/static/datatype.html'); const warn = BaseTypes.ABSTRACT.warn.bind(undefined, 'http://www.postgresql.org/docs/9.4/static/datatype.html');
...@@ -39,236 +38,184 @@ module.exports = BaseTypes => { ...@@ -39,236 +38,184 @@ module.exports = BaseTypes => {
BaseTypes.JSONB.types.postgres = ['jsonb']; BaseTypes.JSONB.types.postgres = ['jsonb'];
BaseTypes.TIME.types.postgres = ['time']; BaseTypes.TIME.types.postgres = ['time'];
function DATEONLY() { class DATEONLY extends BaseTypes.DATEONLY {
if (!(this instanceof DATEONLY)) return new DATEONLY(); _stringify(value, options) {
BaseTypes.DATEONLY.call(this);
}
inherits(DATEONLY, BaseTypes.DATEONLY);
DATEONLY.parse = function parse(value) {
if (value === 'infinity') {
return Infinity;
}
if (value === '-infinity') {
return -Infinity;
}
return value;
};
DATEONLY.prototype._stringify = function _stringify(value, options) {
if (value === Infinity) { if (value === Infinity) {
return 'Infinity'; return 'Infinity';
} }
if (value === -Infinity) { if (value === -Infinity) {
return '-Infinity'; return '-Infinity';
} }
return super._stringify(value, options);
return BaseTypes.DATEONLY.prototype._stringify.call(this, value, options); }
}; _sanitize(value, options) {
DATEONLY.prototype._sanitize = function _sanitize(value, options) {
if ((!options || options && !options.raw) && value !== Infinity && value !== -Infinity) { if ((!options || options && !options.raw) && value !== Infinity && value !== -Infinity) {
if (typeof value === 'string') { if (typeof value === 'string') {
if (value.toLowerCase() === 'infinity') { const lower = value.toLowerCase();
if (lower === 'infinity') {
return Infinity; return Infinity;
} }
if (value.toLowerCase() === '-infinity') { if (lower === '-infinity') {
return -Infinity; return -Infinity;
} }
} }
return super._sanitize(value);
return BaseTypes.DATEONLY.prototype._sanitize.call(this, value); }
return value;
}
static parse(value) {
if (value === 'infinity') {
return Infinity;
}
if (value === '-infinity') {
return -Infinity;
} }
return value; return value;
}; }
BaseTypes.DATEONLY.types.postgres = ['date'];
function DECIMAL(precision, scale) {
if (!(this instanceof DECIMAL)) return new DECIMAL(precision, scale);
BaseTypes.DECIMAL.apply(this, arguments);
} }
inherits(DECIMAL, BaseTypes.DECIMAL); BaseTypes.DATEONLY.types.postgres = ['date'];
DECIMAL.parse = function parse(value) { class DECIMAL extends BaseTypes.DECIMAL {
static parse(value) {
return value; return value;
}; }
}
// numeric // numeric
BaseTypes.DECIMAL.types.postgres = ['numeric']; BaseTypes.DECIMAL.types.postgres = ['numeric'];
function STRING(length, binary) { class STRING extends BaseTypes.STRING {
if (!(this instanceof STRING)) return new STRING(length, binary); toSql() {
BaseTypes.STRING.apply(this, arguments);
}
inherits(STRING, BaseTypes.STRING);
STRING.prototype.toSql = function toSql() {
if (this._binary) { if (this._binary) {
return 'BYTEA'; return 'BYTEA';
} }
return BaseTypes.STRING.prototype.toSql.call(this); return super.toSql();
}; }
}
BaseTypes.STRING.types.postgres = ['varchar']; BaseTypes.STRING.types.postgres = ['varchar'];
function TEXT(length) { class TEXT extends BaseTypes.TEXT {
if (!(this instanceof TEXT)) return new TEXT(length); toSql() {
BaseTypes.TEXT.apply(this, arguments);
}
inherits(TEXT, BaseTypes.TEXT);
TEXT.prototype.toSql = function toSql() {
if (this._length) { if (this._length) {
warn('PostgreSQL does not support TEXT with options. Plain `TEXT` will be used instead.'); warn('PostgreSQL does not support TEXT with options. Plain `TEXT` will be used instead.');
this._length = undefined; this._length = undefined;
} }
return 'TEXT'; return 'TEXT';
}; }
}
BaseTypes.TEXT.types.postgres = ['text']; BaseTypes.TEXT.types.postgres = ['text'];
function CITEXT() { class CITEXT extends BaseTypes.CITEXT {
if (!(this instanceof CITEXT)) return new CITEXT(); static parse(value) {
BaseTypes.CITEXT.call(this); return value;
}
} }
inherits(CITEXT, BaseTypes.CITEXT);
CITEXT.parse = value => value;
BaseTypes.CITEXT.types.postgres = ['citext']; BaseTypes.CITEXT.types.postgres = ['citext'];
function CHAR(length, binary) { class CHAR extends BaseTypes.CHAR {
if (!(this instanceof CHAR)) return new CHAR(length, binary); toSql() {
BaseTypes.CHAR.apply(this, arguments);
}
inherits(CHAR, BaseTypes.CHAR);
CHAR.prototype.toSql = function toSql() {
if (this._binary) { if (this._binary) {
return 'BYTEA'; return 'BYTEA';
} }
return BaseTypes.CHAR.prototype.toSql.call(this); return super.toSql();
}; }
}
BaseTypes.CHAR.types.postgres = ['char', 'bpchar']; BaseTypes.CHAR.types.postgres = ['char', 'bpchar'];
function BOOLEAN() { class BOOLEAN extends BaseTypes.BOOLEAN {
if (!(this instanceof BOOLEAN)) return new BOOLEAN(); toSql() {
BaseTypes.BOOLEAN.call(this);
}
inherits(BOOLEAN, BaseTypes.BOOLEAN);
BOOLEAN.prototype.toSql = function toSql() {
return 'BOOLEAN'; return 'BOOLEAN';
}; }
_sanitize(value) {
BOOLEAN.prototype._sanitize = function _sanitize(value) {
if (value !== null && value !== undefined) { if (value !== null && value !== undefined) {
if (Buffer.isBuffer(value) && value.length === 1) { if (Buffer.isBuffer(value) && value.length === 1) {
// Bit fields are returned as buffers // Bit fields are returned as buffers
value = value[0]; value = value[0];
} }
if (typeof value === 'string') { if (typeof value === 'string') {
// Only take action on valid boolean strings. // Only take action on valid boolean strings.
return value === 'true' || value === 't' ? true : value === 'false' || value === 'f' ? false : value; return value === 'true' || value === 't' ? true : value === 'false' || value === 'f' ? false : value;
} }
if (typeof value === 'number') { if (typeof value === 'number') {
// Only take action on valid boolean integers. // Only take action on valid boolean integers.
return value === 1 ? true : value === 0 ? false : value; return value === 1 ? true : value === 0 ? false : value;
} }
} }
return value; return value;
}; }
}
BOOLEAN.parse = BOOLEAN.prototype._sanitize; BOOLEAN.parse = BOOLEAN.prototype._sanitize;
BaseTypes.BOOLEAN.types.postgres = ['bool']; BaseTypes.BOOLEAN.types.postgres = ['bool'];
function DATE(length) { class DATE extends BaseTypes.DATE {
if (!(this instanceof DATE)) return new DATE(length); toSql() {
BaseTypes.DATE.apply(this, arguments);
}
inherits(DATE, BaseTypes.DATE);
DATE.prototype.toSql = function toSql() {
return 'TIMESTAMP WITH TIME ZONE'; return 'TIMESTAMP WITH TIME ZONE';
}; }
validate(value) {
DATE.prototype.validate = function validate(value) {
if (value !== Infinity && value !== -Infinity) { if (value !== Infinity && value !== -Infinity) {
return BaseTypes.DATE.prototype.validate.call(this, value); return super.validate(value);
} }
return true; return true;
}; }
_stringify(value, options) {
DATE.prototype._stringify = function _stringify(value, options) {
if (value === Infinity) { if (value === Infinity) {
return 'Infinity'; return 'Infinity';
} }
if (value === -Infinity) { if (value === -Infinity) {
return '-Infinity'; return '-Infinity';
} }
return super._stringify(value, options);
return BaseTypes.DATE.prototype._stringify.call(this, value, options); }
}; _sanitize(value, options) {
DATE.prototype._sanitize = function _sanitize(value, options) {
if ((!options || options && !options.raw) && !(value instanceof Date) && !!value && value !== Infinity && value !== -Infinity) { if ((!options || options && !options.raw) && !(value instanceof Date) && !!value && value !== Infinity && value !== -Infinity) {
if (typeof value === 'string') { if (typeof value === 'string') {
if (value.toLowerCase() === 'infinity') { const lower = value.toLowerCase();
if (lower === 'infinity') {
return Infinity; return Infinity;
} }
if (value.toLowerCase() === '-infinity') { if (lower === '-infinity') {
return -Infinity; return -Infinity;
} }
} }
return new Date(value); return new Date(value);
} }
return value; return value;
}; }
}
BaseTypes.DATE.types.postgres = ['timestamptz']; BaseTypes.DATE.types.postgres = ['timestamptz'];
function TINYINT(length) { class TINYINT extends BaseTypes.TINYINT {
if (!(this instanceof TINYINT)) return new TINYINT(length); constructor(length) {
BaseTypes.TINYINT.apply(this, arguments); super(length);
removeUnsupportedIntegerOptions(this); removeUnsupportedIntegerOptions(this);
} }
inherits(TINYINT, BaseTypes.TINYINT); }
// int2 // int2
BaseTypes.TINYINT.types.postgres = ['int2']; BaseTypes.TINYINT.types.postgres = ['int2'];
function SMALLINT(length) { class SMALLINT extends BaseTypes.SMALLINT {
if (!(this instanceof SMALLINT)) return new SMALLINT(length); constructor(length) {
BaseTypes.SMALLINT.apply(this, arguments); super(length);
removeUnsupportedIntegerOptions(this); removeUnsupportedIntegerOptions(this);
} }
inherits(SMALLINT, BaseTypes.SMALLINT); }
// int2 // int2
BaseTypes.SMALLINT.types.postgres = ['int2']; BaseTypes.SMALLINT.types.postgres = ['int2'];
function INTEGER(length) { class INTEGER extends BaseTypes.INTEGER {
if (!(this instanceof INTEGER)) return new INTEGER(length); constructor(length) {
BaseTypes.INTEGER.apply(this, arguments); super(length);
removeUnsupportedIntegerOptions(this); removeUnsupportedIntegerOptions(this);
} }
inherits(INTEGER, BaseTypes.INTEGER); }
INTEGER.parse = function parse(value) { INTEGER.parse = function parse(value) {
return parseInt(value, 10); return parseInt(value, 10);
}; };
...@@ -276,43 +223,36 @@ module.exports = BaseTypes => { ...@@ -276,43 +223,36 @@ module.exports = BaseTypes => {
// int4 // int4
BaseTypes.INTEGER.types.postgres = ['int4']; BaseTypes.INTEGER.types.postgres = ['int4'];
function BIGINT(length) { class BIGINT extends BaseTypes.BIGINT {
if (!(this instanceof BIGINT)) return new BIGINT(length); constructor(length) {
BaseTypes.BIGINT.apply(this, arguments); super(length);
removeUnsupportedIntegerOptions(this); removeUnsupportedIntegerOptions(this);
} }
inherits(BIGINT, BaseTypes.BIGINT); }
// int8 // int8
BaseTypes.BIGINT.types.postgres = ['int8']; BaseTypes.BIGINT.types.postgres = ['int8'];
function REAL(length, decimals) { class REAL extends BaseTypes.REAL {
if (!(this instanceof REAL)) return new REAL(length, decimals); constructor(length) {
BaseTypes.REAL.apply(this, arguments); super(length);
removeUnsupportedIntegerOptions(this); removeUnsupportedIntegerOptions(this);
} }
inherits(REAL, BaseTypes.REAL); }
// float4 // float4
BaseTypes.REAL.types.postgres = ['float4']; BaseTypes.REAL.types.postgres = ['float4'];
function DOUBLE(length, decimals) { class DOUBLE extends BaseTypes.DOUBLE {
if (!(this instanceof DOUBLE)) return new DOUBLE(length, decimals); constructor(length) {
BaseTypes.DOUBLE.apply(this, arguments); super(length);
removeUnsupportedIntegerOptions(this); removeUnsupportedIntegerOptions(this);
} }
inherits(DOUBLE, BaseTypes.DOUBLE); }
// float8 // float8
BaseTypes.DOUBLE.types.postgres = ['float8']; BaseTypes.DOUBLE.types.postgres = ['float8'];
function FLOAT(length, decimals) { class FLOAT extends BaseTypes.FLOAT {
if (!(this instanceof FLOAT)) return new FLOAT(length, decimals); constructor(length, decimals) {
BaseTypes.FLOAT.apply(this, arguments); super(length, decimals);
// POSTGRES does only support lengths as parameter. // POSTGRES does only support lengths as parameter.
// Values between 1-24 result in REAL // Values between 1-24 result in REAL
// Values between 25-53 result in DOUBLE PRECISION // Values between 25-53 result in DOUBLE PRECISION
...@@ -332,157 +272,119 @@ module.exports = BaseTypes => { ...@@ -332,157 +272,119 @@ module.exports = BaseTypes => {
this._zerofill = undefined; this._zerofill = undefined;
} }
} }
inherits(FLOAT, BaseTypes.FLOAT);
delete FLOAT.parse; // Float has no separate type in PG
function BLOB(length) {
if (!(this instanceof BLOB)) return new BLOB(length);
BaseTypes.BLOB.apply(this, arguments);
} }
inherits(BLOB, BaseTypes.BLOB); delete FLOAT.parse; // Float has no separate type in PG
BLOB.prototype.toSql = function toSql() { class BLOB extends BaseTypes.BLOB {
toSql() {
if (this._length) { if (this._length) {
warn('PostgreSQL does not support BLOB (BYTEA) with options. Plain `BYTEA` will be used instead.'); warn('PostgreSQL does not support BLOB (BYTEA) with options. Plain `BYTEA` will be used instead.');
this._length = undefined; this._length = undefined;
} }
return 'BYTEA'; return 'BYTEA';
}; }
_hexify(hex) {
BLOB.prototype._hexify = function _hexify(hex) {
// bytea hex format http://www.postgresql.org/docs/current/static/datatype-binary.html // bytea hex format http://www.postgresql.org/docs/current/static/datatype-binary.html
return `E'\\\\x${hex}'`; return `E'\\\\x${hex}'`;
}; }
}
BaseTypes.BLOB.types.postgres = ['bytea']; BaseTypes.BLOB.types.postgres = ['bytea'];
function GEOMETRY(type, srid) { class GEOMETRY extends BaseTypes.GEOMETRY {
if (!(this instanceof GEOMETRY)) return new GEOMETRY(type, srid); toSql() {
BaseTypes.GEOMETRY.apply(this, arguments);
}
inherits(GEOMETRY, BaseTypes.GEOMETRY);
GEOMETRY.prototype.toSql = function toSql() {
let result = this.key; let result = this.key;
if (this.type) { if (this.type) {
result += `(${this.type}`; result += `(${this.type}`;
if (this.srid) { if (this.srid) {
result += `,${this.srid}`; result += `,${this.srid}`;
} }
result += ')'; result += ')';
} }
return result; return result;
}; }
static parse(value) {
BaseTypes.GEOMETRY.types.postgres = ['geometry'];
GEOMETRY.parse = GEOMETRY.prototype.parse = function parse(value) {
const b = Buffer.from(value, 'hex'); const b = Buffer.from(value, 'hex');
return wkx.Geometry.parse(b).toGeoJSON(); return wkx.Geometry.parse(b).toGeoJSON();
}; }
_stringify(value, options) {
GEOMETRY.prototype._stringify = function _stringify(value, options) {
return `ST_GeomFromGeoJSON(${options.escape(JSON.stringify(value))})`; return `ST_GeomFromGeoJSON(${options.escape(JSON.stringify(value))})`;
}; }
GEOMETRY.prototype._bindParam = function _bindParam(value, options) { _bindParam(value, options) {
return `ST_GeomFromGeoJSON(${options.bindParam(value)})`; return `ST_GeomFromGeoJSON(${options.bindParam(value)})`;
};
function GEOGRAPHY(type, srid) {
if (!(this instanceof GEOGRAPHY)) return new GEOGRAPHY(type, srid);
BaseTypes.GEOGRAPHY.apply(this, arguments);
} }
inherits(GEOGRAPHY, BaseTypes.GEOGRAPHY); }
BaseTypes.GEOMETRY.types.postgres = ['geometry'];
GEOGRAPHY.prototype.toSql = function toSql() {
let result = 'GEOGRAPHY';
class GEOGRAPHY extends BaseTypes.GEOGRAPHY {
toSql() {
let result = 'GEOGRAPHY';
if (this.type) { if (this.type) {
result += `(${this.type}`; result += `(${this.type}`;
if (this.srid) { if (this.srid) {
result += `,${this.srid}`; result += `,${this.srid}`;
} }
result += ')'; result += ')';
} }
return result; return result;
}; }
static parse(value) {
BaseTypes.GEOGRAPHY.types.postgres = ['geography'];
GEOGRAPHY.parse = GEOGRAPHY.prototype.parse = function parse(value) {
const b = Buffer.from(value, 'hex'); const b = Buffer.from(value, 'hex');
return wkx.Geometry.parse(b).toGeoJSON(); return wkx.Geometry.parse(b).toGeoJSON();
}; }
_stringify(value, options) {
GEOGRAPHY.prototype._stringify = function _stringify(value, options) {
return `ST_GeomFromGeoJSON(${options.escape(JSON.stringify(value))})`; return `ST_GeomFromGeoJSON(${options.escape(JSON.stringify(value))})`;
}; }
GEOGRAPHY.prototype.bindParam = function bindParam(value, options) { bindParam(value, options) {
return `ST_GeomFromGeoJSON(${options.bindParam(value)})`; return `ST_GeomFromGeoJSON(${options.bindParam(value)})`;
}; }
}
let hstore; BaseTypes.GEOGRAPHY.types.postgres = ['geography'];
function HSTORE() { let hstore;
if (!(this instanceof HSTORE)) return new HSTORE();
BaseTypes.HSTORE.apply(this, arguments);
class HSTORE extends BaseTypes.HSTORE {
constructor() {
super();
if (!hstore) { if (!hstore) {
// All datatype files are loaded at import - make sure we don't load the hstore parser before a hstore is instantiated // All datatype files are loaded at import - make sure we don't load the hstore parser before a hstore is instantiated
hstore = require('./hstore'); hstore = require('./hstore');
} }
} }
inherits(HSTORE, BaseTypes.HSTORE); _value(value) {
HSTORE.parse = function parse(value) {
if (!hstore) { if (!hstore) {
// All datatype files are loaded at import - make sure we don't load the hstore parser before a hstore is instantiated // All datatype files are loaded at import - make sure we don't load the hstore parser before a hstore is instantiated
hstore = require('./hstore'); hstore = require('./hstore');
} }
return hstore.parse(value); return hstore.stringify(value);
}; }
_stringify(value) {
HSTORE.prototype.escape = false; return `'${this._value(value)}'`;
HSTORE.prototype._value = function _value(value) { }
_bindParam(value, options) {
return options.bindParam(this._value(value));
}
static parse(value) {
if (!hstore) { if (!hstore) {
// All datatype files are loaded at import - make sure we don't load the hstore parser before a hstore is instantiated // All datatype files are loaded at import - make sure we don't load the hstore parser before a hstore is instantiated
hstore = require('./hstore'); hstore = require('./hstore');
} }
return hstore.stringify(value); return hstore.parse(value);
}; }
HSTORE.prototype._stringify = function _stringify(value) {
return `'${this._value(value)}'`;
};
HSTORE.prototype._bindParam = function _bindParam(value, options) {
return options.bindParam(this._value(value));
};
BaseTypes.HSTORE.types.postgres = ['hstore'];
function RANGE(subtype) {
if (!(this instanceof RANGE)) return new RANGE(subtype);
BaseTypes.RANGE.apply(this, arguments);
} }
inherits(RANGE, BaseTypes.RANGE);
const range = require('./range'); HSTORE.prototype.escape = false;
RANGE.parse = function parse(value, options = { parser: val => val }) {
return range.parse(value, options.parser);
};
RANGE.prototype.escape = false; BaseTypes.HSTORE.types.postgres = ['hstore'];
RANGE.prototype._value = function _value(values, options) {
class RANGE extends BaseTypes.RANGE {
_value(values, options) {
if (!Array.isArray(values)) { if (!Array.isArray(values)) {
return this.options.subtype.stringify(values, options); return this.options.subtype.stringify(values, options);
} }
const valueInclusivity = [true, false]; const valueInclusivity = [true, false];
const valuesStringified = values.map((value, index) => { const valuesStringified = values.map((value, index) => {
if (_.isObject(value) && value.hasOwnProperty('value')) { if (_.isObject(value) && value.hasOwnProperty('value')) {
...@@ -500,26 +402,37 @@ module.exports = BaseTypes => { ...@@ -500,26 +402,37 @@ module.exports = BaseTypes => {
} }
return options.escape(value); return options.escape(value);
}); });
// Array.map does not preserve extra array properties // Array.map does not preserve extra array properties
valuesStringified.inclusive = valueInclusivity; valuesStringified.inclusive = valueInclusivity;
return range.stringify(valuesStringified); return range.stringify(valuesStringified);
}; }
RANGE.prototype._stringify = function _stringify(values, options) { _stringify(values, options) {
const value = this._value(values, options); const value = this._value(values, options);
if (!Array.isArray(values)) { if (!Array.isArray(values)) {
return `'${value}'::${this.toCastType()}`; return `'${value}'::${this.toCastType()}`;
} }
return `'${value}'`; return `'${value}'`;
}; }
RANGE.prototype._bindParam = function _bindParam(values, options) { _bindParam(values, options) {
const value = this._value(values, options); const value = this._value(values, options);
if (!Array.isArray(values)) { if (!Array.isArray(values)) {
return `${options.bindParam(value)}::${this.toCastType()}`; return `${options.bindParam(value)}::${this.toCastType()}`;
} }
return options.bindParam(value); return options.bindParam(value);
}; }
toSql() {
return BaseTypes.RANGE.types.postgres.subtypes[this._subtype.toLowerCase()];
}
toCastType() {
return BaseTypes.RANGE.types.postgres.castTypes[this._subtype.toLowerCase()];
}
static parse(value, options = { parser: val => val }) {
return range.parse(value, options.parser);
}
}
const range = require('./range');
RANGE.prototype.escape = false;
BaseTypes.RANGE.types.postgres = { BaseTypes.RANGE.types.postgres = {
subtypes: { subtypes: {
...@@ -538,13 +451,7 @@ module.exports = BaseTypes => { ...@@ -538,13 +451,7 @@ module.exports = BaseTypes => {
} }
}; };
RANGE.prototype.toSql = function toSql() { // TODO: Why are base types being manipulated??
return BaseTypes.RANGE.types.postgres.subtypes[this._subtype.toLowerCase()];
};
RANGE.prototype.toCastType = function toCastType() {
return BaseTypes.RANGE.types.postgres.castTypes[this._subtype.toLowerCase()];
};
BaseTypes.ARRAY.prototype.escape = false; BaseTypes.ARRAY.prototype.escape = false;
BaseTypes.ARRAY.prototype._value = function _value(values, options) { BaseTypes.ARRAY.prototype._value = function _value(values, options) {
return values.map(value => { return values.map(value => {
...@@ -584,19 +491,15 @@ module.exports = BaseTypes => { ...@@ -584,19 +491,15 @@ module.exports = BaseTypes => {
return options.bindParam(this._value(values, options)); return options.bindParam(this._value(values, options));
}; };
function ENUM(options) { class ENUM extends BaseTypes.ENUM {
if (!(this instanceof ENUM)) return new ENUM(options); static parse(value) {
BaseTypes.ENUM.apply(this, arguments);
}
inherits(ENUM, BaseTypes.ENUM);
ENUM.parse = function(value) {
return value; return value;
}; };
}
BaseTypes.ENUM.types.postgres = [null]; BaseTypes.ENUM.types.postgres = [null];
const exports = { return {
DECIMAL, DECIMAL,
BLOB, BLOB,
STRING, STRING,
...@@ -619,13 +522,4 @@ module.exports = BaseTypes => { ...@@ -619,13 +522,4 @@ module.exports = BaseTypes => {
RANGE, RANGE,
ENUM ENUM
}; };
_.forIn(exports, (DataType, key) => {
if (!DataType.key) DataType.key = key;
if (!DataType.extend) {
DataType.extend = oldType => new DataType(oldType.options);
}
});
return exports;
}; };
'use strict'; 'use strict';
const _ = require('lodash');
const inherits = require('../../utils/inherits');
module.exports = BaseTypes => { module.exports = BaseTypes => {
const warn = BaseTypes.ABSTRACT.warn.bind(undefined, 'https://www.sqlite.org/datatype3.html'); const warn = BaseTypes.ABSTRACT.warn.bind(undefined, 'https://www.sqlite.org/datatype3.html');
...@@ -45,106 +42,71 @@ module.exports = BaseTypes => { ...@@ -45,106 +42,71 @@ module.exports = BaseTypes => {
BaseTypes.GEOMETRY.types.sqlite = false; BaseTypes.GEOMETRY.types.sqlite = false;
BaseTypes.JSON.types.sqlite = ['JSON', 'JSONB']; BaseTypes.JSON.types.sqlite = ['JSON', 'JSONB'];
function JSONTYPE() { class JSONTYPE extends BaseTypes.JSON {
if (!(this instanceof JSONTYPE)) return new JSONTYPE(); static parse(data) {
BaseTypes.JSON.call(this);
}
inherits(JSONTYPE, BaseTypes.JSON);
JSONTYPE.parse = function parse(data) {
return JSON.parse(data); return JSON.parse(data);
};
function DATE(length) {
if (!(this instanceof DATE)) return new DATE(length);
BaseTypes.DATE.apply(this, arguments);
} }
inherits(DATE, BaseTypes.DATE); }
DATE.parse = function parse(date, options) { class DATE extends BaseTypes.DATE {
static parse(date, options) {
if (!date.includes('+')) { if (!date.includes('+')) {
// For backwards compat. Dates inserted by sequelize < 2.0dev12 will not have a timestamp set // For backwards compat. Dates inserted by sequelize < 2.0dev12 will not have a timestamp set
return new Date(date + options.timezone); return new Date(date + options.timezone);
} }
return new Date(date); // We already have a timezone stored in the string return new Date(date); // We already have a timezone stored in the string
};
function DATEONLY() {
if (!(this instanceof DATEONLY)) return new DATEONLY();
BaseTypes.DATEONLY.call(this);
} }
inherits(DATEONLY, BaseTypes.DATEONLY); }
DATEONLY.parse = function parse(date) { class DATEONLY extends BaseTypes.DATEONLY {
static parse(date) {
return date; return date;
};
function STRING(length, binary) {
if (!(this instanceof STRING)) return new STRING(length, binary);
BaseTypes.STRING.apply(this, arguments);
} }
inherits(STRING, BaseTypes.STRING); }
STRING.prototype.toSql = function toSql() { class STRING extends BaseTypes.STRING {
toSql() {
if (this._binary) { if (this._binary) {
return `VARCHAR BINARY(${this._length})`; return `VARCHAR BINARY(${this._length})`;
} }
return BaseTypes.STRING.prototype.toSql.call(this); return super.toSql(this);
}; }
function TEXT(length) {
if (!(this instanceof TEXT)) return new TEXT(length);
BaseTypes.TEXT.apply(this, arguments);
} }
inherits(TEXT, BaseTypes.TEXT);
TEXT.prototype.toSql = function toSql() { class TEXT extends BaseTypes.TEXT {
toSql() {
if (this._length) { if (this._length) {
warn('SQLite does not support TEXT with options. Plain `TEXT` will be used instead.'); warn('SQLite does not support TEXT with options. Plain `TEXT` will be used instead.');
this._length = undefined; this._length = undefined;
} }
return 'TEXT'; return 'TEXT';
};
function CITEXT() {
if (!(this instanceof CITEXT)) return new CITEXT();
BaseTypes.CITEXT.call(this);
} }
inherits(CITEXT, BaseTypes.CITEXT); }
CITEXT.prototype.toSql = function toSql() { class CITEXT extends BaseTypes.CITEXT {
toSql() {
return 'TEXT COLLATE NOCASE'; return 'TEXT COLLATE NOCASE';
};
function CHAR(length, binary) {
if (!(this instanceof CHAR)) return new CHAR(length, binary);
BaseTypes.CHAR.apply(this, arguments);
} }
inherits(CHAR, BaseTypes.CHAR); }
CHAR.prototype.toSql = function toSql() { class CHAR extends BaseTypes.CHAR {
toSql() {
if (this._binary) { if (this._binary) {
return `CHAR BINARY(${this._length})`; return `CHAR BINARY(${this._length})`;
} }
return BaseTypes.CHAR.prototype.toSql.call(this); return super.toSql();
}; }
function NUMBER(options) {
if (!(this instanceof NUMBER)) return new NUMBER(options);
BaseTypes.NUMBER.apply(this, arguments);
} }
inherits(NUMBER, BaseTypes.NUMBER);
NUMBER.prototype.toSql = function toSql() { class NUMBER extends BaseTypes.NUMBER {
toSql() {
let result = this.key; let result = this.key;
if (this._unsigned) { if (this._unsigned) {
result += ' UNSIGNED'; result += ' UNSIGNED';
} }
if (this._zerofill) { if (this._zerofill) {
result += ' ZEROFILL'; result += ' ZEROFILL';
} }
if (this._length) { if (this._length) {
result += `(${this._length}`; result += `(${this._length}`;
if (typeof this._decimals === 'number') { if (typeof this._decimals === 'number') {
...@@ -153,98 +115,56 @@ module.exports = BaseTypes => { ...@@ -153,98 +115,56 @@ module.exports = BaseTypes => {
result += ')'; result += ')';
} }
return result; return result;
}; }
}
function TINYINT(length) {
if (!(this instanceof TINYINT)) return new TINYINT(length);
BaseTypes.TINYINT.apply(this, arguments);
class TINYINT extends BaseTypes.TINYINT {
constructor(length) {
super(length);
removeUnsupportedIntegerOptions(this); removeUnsupportedIntegerOptions(this);
} }
inherits(TINYINT, BaseTypes.TINYINT); }
TINYINT.prototype.toSql = function toSql() {
return NUMBER.prototype.toSql.call(this);
};
function SMALLINT(length) {
if (!(this instanceof SMALLINT)) return new SMALLINT(length);
BaseTypes.SMALLINT.apply(this, arguments);
class SMALLINT extends BaseTypes.SMALLINT {
constructor(length) {
super(length);
removeUnsupportedIntegerOptions(this); removeUnsupportedIntegerOptions(this);
} }
inherits(SMALLINT, BaseTypes.SMALLINT); }
SMALLINT.prototype.toSql = function toSql() {
return NUMBER.prototype.toSql.call(this);
};
function MEDIUMINT(length) {
if (!(this instanceof MEDIUMINT)) return new MEDIUMINT(length);
BaseTypes.MEDIUMINT.apply(this, arguments);
class MEDIUMINT extends BaseTypes.MEDIUMINT {
constructor(length) {
super(length);
removeUnsupportedIntegerOptions(this); removeUnsupportedIntegerOptions(this);
} }
inherits(MEDIUMINT, BaseTypes.MEDIUMINT); }
MEDIUMINT.prototype.toSql = function toSql() {
return NUMBER.prototype.toSql.call(this);
};
function INTEGER(length) {
if (!(this instanceof INTEGER)) return new INTEGER(length);
BaseTypes.INTEGER.apply(this, arguments);
class INTEGER extends BaseTypes.INTEGER {
constructor(length) {
super(length);
removeUnsupportedIntegerOptions(this); removeUnsupportedIntegerOptions(this);
} }
inherits(INTEGER, BaseTypes.INTEGER); }
INTEGER.prototype.toSql = function toSql() {
return NUMBER.prototype.toSql.call(this);
};
function BIGINT(length) {
if (!(this instanceof BIGINT)) return new BIGINT(length);
BaseTypes.BIGINT.apply(this, arguments);
class BIGINT extends BaseTypes.BIGINT {
constructor(length) {
super(length);
removeUnsupportedIntegerOptions(this); removeUnsupportedIntegerOptions(this);
} }
inherits(BIGINT, BaseTypes.BIGINT);
BIGINT.prototype.toSql = function toSql() {
return NUMBER.prototype.toSql.call(this);
};
function FLOAT(length, decimals) {
if (!(this instanceof FLOAT)) return new FLOAT(length, decimals);
BaseTypes.FLOAT.apply(this, arguments);
} }
inherits(FLOAT, BaseTypes.FLOAT);
FLOAT.prototype.toSql = function toSql() {
return NUMBER.prototype.toSql.call(this);
};
function DOUBLE(length, decimals) { class FLOAT extends BaseTypes.FLOAT {
if (!(this instanceof DOUBLE)) return new DOUBLE(length, decimals);
BaseTypes.DOUBLE.apply(this, arguments);
} }
inherits(DOUBLE, BaseTypes.DOUBLE);
DOUBLE.prototype.toSql = function toSql() {
return NUMBER.prototype.toSql.call(this);
};
function REAL(length, decimals) { class DOUBLE extends BaseTypes.DOUBLE {
if (!(this instanceof REAL)) return new REAL(length, decimals);
BaseTypes.REAL.apply(this, arguments);
} }
inherits(REAL, BaseTypes.REAL);
REAL.prototype.toSql = function toSql() {
return NUMBER.prototype.toSql.call(this);
};
[FLOAT, DOUBLE, REAL].forEach(floating => { class REAL extends BaseTypes.REAL { }
floating.parse = function parse(value) {
if (typeof value === 'string') { function parseFloating(value) {
if (typeof value !== 'string') {
return value;
}
if (value === 'NaN') { if (value === 'NaN') {
return NaN; return NaN;
} }
...@@ -255,25 +175,22 @@ module.exports = BaseTypes => { ...@@ -255,25 +175,22 @@ module.exports = BaseTypes => {
return -Infinity; return -Infinity;
} }
} }
return value; for (const floating of [FLOAT, DOUBLE, REAL]) {
floating.parse = parseFloating;
}; };
});
function ENUM() {
if (!(this instanceof ENUM)) {
const obj = Object.create(ENUM.prototype);
ENUM.apply(obj, arguments);
return obj;
}
BaseTypes.ENUM.apply(this, arguments);
}
inherits(ENUM, BaseTypes.ENUM);
ENUM.prototype.toSql = function toSql() { for (const num of [FLOAT, DOUBLE, REAL, TINYINT, SMALLINT, MEDIUMINT, INTEGER, BIGINT]) {
return 'TEXT'; num.prototype.toSql = NUMBER.prototype.toSql;
}; };
const exports = { class ENUM extends BaseTypes.ENUM {
toSql() {
return 'TEXT';
}
}
return {
DATE, DATE,
DATEONLY, DATEONLY,
STRING, STRING,
...@@ -292,16 +209,4 @@ module.exports = BaseTypes => { ...@@ -292,16 +209,4 @@ module.exports = BaseTypes => {
JSON: JSONTYPE, JSON: JSONTYPE,
CITEXT CITEXT
}; };
_.forIn(exports, (DataType, key) => {
if (!DataType.key) DataType.key = key;
if (!DataType.extend) {
DataType.extend = oldType => {
return new DataType(oldType.options);
};
}
});
return exports;
}; };
...@@ -11,6 +11,8 @@ const operatorsArray = _.values(operators); ...@@ -11,6 +11,8 @@ const operatorsArray = _.values(operators);
let inflection = require('inflection'); let inflection = require('inflection');
exports.classToInvokable = require('./utils/classToInvokable').classToInvokable;
exports.Promise = Promise; exports.Promise = Promise;
function useInflection(_inflection) { function useInflection(_inflection) {
...@@ -595,15 +597,6 @@ function defaults(object) { ...@@ -595,15 +597,6 @@ function defaults(object) {
} }
exports.defaults = defaults; exports.defaults = defaults;
function classToInvokable(Class) {
return new Proxy(Class, {
apply(Target, thisArg, args) {
return new Target(...args);
}
});
}
exports.classToInvokable = classToInvokable;
/** /**
* *
* @param {Object} index * @param {Object} index
......
'use strict';
/**
* Wraps a constructor to not need the `new` keyword using a proxy.
* Only used for data types.
* @param {Function} ctor
* @return {Proxy}
*/
function classToInvokable(Class) {
return new Proxy(Class, {
apply(Target, thisArg, args) {
return new Target(...args);
}
});
}
exports.classToInvokable = classToInvokable;
'use strict';
const util = require('util');
/**
* like util.inherits, but also copies over static properties. Inherit child constructor
* to have properties from super constructor
*
* @param {Function} constructor the child constructor
* @param {Function} superConstructor the super constructor
*
* @private
*/
function inherits(constructor, superConstructor) {
util.inherits(constructor, superConstructor); // Instance (prototype) methods
Object.assign(constructor, superConstructor); // Static methods
}
module.exports = inherits;
module.exports.inherits = inherits;
module.exports.default = inherits;
...@@ -890,7 +890,6 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => { ...@@ -890,7 +890,6 @@ describe(Support.getTestDialectTeaser('BelongsTo'), () => {
dataTypes.forEach(dataType => { dataTypes.forEach(dataType => {
const tableName = `TaskXYZ_${dataType.key}`; const tableName = `TaskXYZ_${dataType.key}`;
Tasks[dataType] = this.sequelize.define(tableName, { title: DataTypes.STRING }); Tasks[dataType] = this.sequelize.define(tableName, { title: DataTypes.STRING });
Tasks[dataType].belongsTo(User, { foreignKey: 'userId', keyType: dataType, constraints: false }); Tasks[dataType].belongsTo(User, { foreignKey: 'userId', keyType: dataType, constraints: false });
}); });
......
...@@ -64,6 +64,14 @@ export const TICK_CHAR: string; ...@@ -64,6 +64,14 @@ export const TICK_CHAR: string;
export function addTicks(s: string, tickChar?: string): string; export function addTicks(s: string, tickChar?: string): string;
export function removeTicks(s: string, tickChar?: string): string; export function removeTicks(s: string, tickChar?: string): string;
/**
* Wraps a constructor to not need the `new` keyword using a proxy.
* Only used for data types.
*/
export function classToInvokable<T extends new (...args: any[]) => any>(ctor: T): T & {
(...args: ConstructorParameters<T>): T;
}
export class SequelizeMethod { export class SequelizeMethod {
} }
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!