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

Commit 3cd38910 by Simon Schick Committed by Sushant

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

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