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

Commit 719f95b7 by Sushant Committed by GitHub

v5-beta (#9212)

1 parent 3fd065ca
---
verifyConditions:
- "@semantic-release/npm"
- "@semantic-release/github"
publish:
- "@semantic-release/npm"
- "@semantic-release/github"
prepare:
- "@semantic-release/npm"
...@@ -7,6 +7,7 @@ branches: ...@@ -7,6 +7,7 @@ branches:
only: only:
- master - master
- v3 - v3
- v5
- /^greenkeeper/.*$/ - /^greenkeeper/.*$/
except: except:
- /^v\d+\.\d+\.\d+$/ - /^v\d+\.\d+\.\d+$/
...@@ -43,50 +44,42 @@ before_script: ...@@ -43,50 +44,42 @@ before_script:
- "if [ $POSTGRES_VER ]; then docker run --link ${POSTGRES_VER}:db -e CHECK_PORT=5432 -e CHECK_HOST=db --net sequelize_default giorgos/takis; fi" - "if [ $POSTGRES_VER ]; then docker run --link ${POSTGRES_VER}:db -e CHECK_PORT=5432 -e CHECK_HOST=db --net sequelize_default giorgos/takis; fi"
script: script:
- 'if [ "$INSTALL_MODULE" ]; then npm install ${INSTALL_MODULE}; fi'
- npm run lint - npm run lint
- "if [ $COVERAGE ]; then npm run cover && bash <(curl -s https://codecov.io/bash) -f coverage/lcov.info; else npm run test; fi" - "if [ $COVERAGE ]; then npm run cover && bash <(curl -s https://codecov.io/bash) -f coverage/lcov.info; else npm run test; fi"
jobs: jobs:
include: include:
- stage: test - stage: test
node_js: '4' node_js: '6'
env: DIALECT=sqlite COVERAGE=true env: DIALECT=sqlite COVERAGE=true
- stage: test - stage: test
node_js: '4' node_js: '6'
sudo: required sudo: required
env: MYSQL_VER=mysql-57 DIALECT=mysql COVERAGE=true env: MYSQL_VER=mysql-57 DIALECT=mysql COVERAGE=true
- stage: test - stage: test
node_js: '4' node_js: '6'
sudo: required sudo: required
env: POSTGRES_VER=postgres-95 DIALECT=postgres COVERAGE=true env: POSTGRES_VER=postgres-95 DIALECT=postgres COVERAGE=true
- stage: test - stage: test
node_js: '4' node_js: '6'
sudo: required sudo: required
env: POSTGRES_VER=postgres-95 DIALECT=postgres-native COVERAGE=true env: POSTGRES_VER=postgres-95 DIALECT=postgres-native COVERAGE=true
- stage: test - stage: test
node_js: '8' node_js: '8'
env: DIALECT=sqlite env: DIALECT=sqlite
- stage: test # - stage: release
node_js: '4' # node_js: '8'
sudo: required # script:
env: POSTGRES_VER=postgres-95 DIALECT=postgres COVERAGE=true INSTALL_MODULE="pg@6.x pg-native@1.x" # - npm run semantic-release
- stage: test # before_deploy:
node_js: '6' # - npm run docs
env: DIALECT=sqlite # deploy:
- stage: release # provider: surge
node_js: '8' # project: ./esdoc/
script: # domain: docs.sequelizejs.com
- npm run semantic-release # skip_cleanup: true
before_deploy:
- npm run docs
deploy:
provider: surge
project: ./esdoc/
domain: docs.sequelizejs.com
skip_cleanup: true
stages: stages:
- test - test
- name: release # - name: release
if: branch = master AND type = push AND fork = false # if: branch = master AND type = push AND fork = false
...@@ -13,7 +13,7 @@ cache: ...@@ -13,7 +13,7 @@ cache:
environment: environment:
matrix: matrix:
- {NODE_VERSION: 4, DIALECT: mssql, COVERAGE: true} - {NODE_VERSION: 6, DIALECT: mssql, COVERAGE: true}
install: install:
- ps: Install-Product node $env:NODE_VERSION x64 - ps: Install-Product node $env:NODE_VERSION x64
...@@ -43,3 +43,4 @@ after_test: ...@@ -43,3 +43,4 @@ after_test:
branches: branches:
only: only:
- master - master
- v5
# Upgrade to v5
Sequelize v5 is the next major release after v4
## Breaking Changes
### Support for Node 6 and up
Sequelize v5 will only support Node 6 and up [#9015](https://github.com/sequelize/sequelize/issues/9015)
__DEV__: _Done, no deprecation_
### Secure Operators
With v4 you started to get a deprecation warning `String based operators are now deprecated`. Also concept of operators was introduced. These operators are Symbols which prevent hash injection attacks.
Please check these threads to know more
- (Issue) https://github.com/sequelize/sequelize/issues/7310
- (Fix) https://github.com/sequelize/sequelize/pull/8240
- (Explanation) https://github.com/sequelize/sequelize/issues/8417#issuecomment-334056048
- (Official Docs) http://docs.sequelizejs.com/manual/tutorial/querying.html#operators-security
With v5
- Operators are now enabled by default.
- You can still use string operators by passing an operators map in `operatorsAliases`
- Op.$raw is removed
__DEV__: _Incomplete, deprecated_
### Model
**Attributes**
`Model.attributes` now removed, use `Model.rawAttributes`. [#5320](https://github.com/sequelize/sequelize/issues/5320)
__Note__: _Please dont confuse this with `options.attributes`, they are still valid_
__DEV__: _Done, no deprecation_
**Paranoid Mode**
With v5 if `deletedAt` is set, record will be considered as deleted. So `paranoid` option will only use `deletedAt` as flag.
In v4 it used to compare current time with `deletedAt`. [#8496](https://github.com/sequelize/sequelize/issues/8496)
__DEV__: _Done, no deprecation_
/**
* Quote helpers implement quote ability for all dialects.
* These are basic block of query building
*
* Its better to implement all dialect implementation together here. Which will allow
* even abstract generator to use them by just specifying dialect type.
*
* Defining these helpers in each query dialect will leave
* code in dual dependency of abstract <-> specific dialect
*/
'use strict';
const Utils = require('../../../../utils');
/**
*
* @param {String} dialect Dialect name
* @param {String} identifier Identifier to quote
* @param {Object} [options]
* @param {Boolean} [options.force=false]
* @param {Boolean} [options.quoteIdentifiers=true]
*
* @returns {String}
*/
function quoteIdentifier(dialect, identifier, options) {
if (identifier === '*') return identifier;
options = Utils.defaults(options || {}, {
force: false,
quoteIdentifiers: true
});
switch (dialect) {
case 'sqlite':
return Utils.addTicks(Utils.removeTicks(identifier, '`'), '`');
case 'mysql':
return Utils.addTicks(Utils.removeTicks(identifier, '`'), '`');
case 'postgres':
if (
options.force !== true &&
options.quoteIdentifiers === false &&
identifier.indexOf('.') === -1 &&
identifier.indexOf('->') === -1
) {
// In Postgres, if tables or attributes are created double-quoted,
// they are also case sensitive. If they contain any uppercase
// characters, they must always be double-quoted. This makes it
// impossible to write queries in portable SQL if tables are created in
// this way. Hence, we strip quotes if we don't want case sensitivity.
return Utils.removeTicks(identifier, '"');
} else {
return Utils.addTicks(Utils.removeTicks(identifier, '"'), '"');
}
case 'mssql':
return '[' + identifier.replace(/[\[\]']+/g, '') + ']';
default:
throw new Error(`Dialect "${dialect}" is not supported`);
}
}
module.exports.quoteIdentifier = quoteIdentifier;
/**
* Test if a give string is already quoted
*
* @param {String} identifier
*
* @return Boolean
*/
function isIdentifierQuoted(identifier) {
return /^\s*(?:([`"'])(?:(?!\1).|\1{2})*\1\.?)+\s*$/i.test(identifier);
}
module.exports.isIdentifierQuoted = isIdentifierQuoted;
\ No newline at end of file
'use strict';
const _ = require('lodash');
const Op = require('../../../operators');
const Utils = require('../../../utils');
const OperatorHelpers = {
OperatorMap: {
[Op.eq]: '=',
[Op.ne]: '!=',
[Op.gte]: '>=',
[Op.gt]: '>',
[Op.lte]: '<=',
[Op.lt]: '<',
[Op.not]: 'IS NOT',
[Op.is]: 'IS',
[Op.in]: 'IN',
[Op.notIn]: 'NOT IN',
[Op.like]: 'LIKE',
[Op.notLike]: 'NOT LIKE',
[Op.iLike]: 'ILIKE',
[Op.notILike]: 'NOT ILIKE',
[Op.regexp]: '~',
[Op.notRegexp]: '!~',
[Op.iRegexp]: '~*',
[Op.notIRegexp]: '!~*',
[Op.between]: 'BETWEEN',
[Op.notBetween]: 'NOT BETWEEN',
[Op.overlap]: '&&',
[Op.contains]: '@>',
[Op.contained]: '<@',
[Op.adjacent]: '-|-',
[Op.strictLeft]: '<<',
[Op.strictRight]: '>>',
[Op.noExtendRight]: '&<',
[Op.noExtendLeft]: '&>',
[Op.any]: 'ANY',
[Op.all]: 'ALL',
[Op.and]: ' AND ',
[Op.or]: ' OR ',
[Op.col]: 'COL',
[Op.placeholder]: '$$PLACEHOLDER$$'
},
OperatorsAliasMap: {},
setOperatorsAliases(aliases) {
if (!aliases || _.isEmpty(aliases)) {
this.OperatorsAliasMap = false;
} else {
this.OperatorsAliasMap = _.assign({}, aliases);
}
},
_replaceAliases(orig) {
const obj = {};
if (!this.OperatorsAliasMap) {
return orig;
}
Utils.getOperators(orig).forEach(op => {
const item = orig[op];
if (_.isPlainObject(item)) {
obj[op] = this._replaceAliases(item);
} else {
obj[op] = item;
}
});
_.forOwn(orig, (item, prop) => {
prop = this.OperatorsAliasMap[prop] || prop;
if (_.isPlainObject(item)) {
item = this._replaceAliases(item);
}
obj[prop] = item;
});
return obj;
}
};
module.exports = OperatorHelpers;
\ No newline at end of file
'use strict';
const uuid = require('uuid');
const TransactionQueries = {
/**
* Returns a query that starts a transaction.
*
* @param {Boolean} value A boolean that states whether autocommit shall be done or not.
* @param {Object} options An object with options.
* @return {String} The generated sql query.
* @private
*/
setAutocommitQuery(value, options) {
if (options.parent) {
return;
}
// no query when value is not explicitly set
if (typeof value === 'undefined' || value === null) {
return;
}
return `SET autocommit = ${(value ? 1 : 0)};`;
},
/**
* Returns a query that sets the transaction isolation level.
*
* @param {String} value The isolation level.
* @param {Object} options An object with options.
* @return {String} The generated sql query.
* @private
*/
setIsolationLevelQuery(value, options) {
if (options.parent) {
return;
}
return `SET SESSION TRANSACTION ISOLATION LEVEL ${value};`;
},
generateTransactionId() {
return uuid.v4();
},
/**
* Returns a query that starts a transaction.
*
* @param {Transaction} transaction
* @param {Object} options An object with options.
* @return {String} The generated sql query.
* @private
*/
startTransactionQuery(transaction) {
if (transaction.parent) {
// force quoting of savepoint identifiers for postgres
return `SAVEPOINT ${this.quoteIdentifier(transaction.name, true)};`;
}
return 'START TRANSACTION;';
},
/**
* Returns a query that defers the constraints. Only works for postgres.
*
* @param {Transaction} transaction
* @param {Object} options An object with options.
* @return {String} The generated sql query.
* @private
*/
deferConstraintsQuery() {},
setConstraintQuery() {},
setDeferredQuery() {},
setImmediateQuery() {},
/**
* Returns a query that commits a transaction.
*
* @param {Object} options An object with options.
* @return {String} The generated sql query.
* @private
*/
commitTransactionQuery(transaction) {
if (transaction.parent) {
return;
}
return 'COMMIT;';
},
/**
* Returns a query that rollbacks a transaction.
*
* @param {Transaction} transaction
* @param {Object} options An object with options.
* @return {String} The generated sql query.
* @private
*/
rollbackTransactionQuery(transaction) {
if (transaction.parent) {
// force quoting of savepoint identifiers for postgres
return `ROLLBACK TO SAVEPOINT ${this.quoteIdentifier(transaction.name, true)};`;
}
return 'ROLLBACK;';
}
};
module.exports = TransactionQueries;
\ No newline at end of file
...@@ -12,8 +12,7 @@ class MssqlDialect extends AbstractDialect { ...@@ -12,8 +12,7 @@ class MssqlDialect extends AbstractDialect {
super(); super();
this.sequelize = sequelize; this.sequelize = sequelize;
this.connectionManager = new ConnectionManager(this, sequelize); this.connectionManager = new ConnectionManager(this, sequelize);
this.QueryGenerator = _.extend({}, QueryGenerator, { this.QueryGenerator = new QueryGenerator({
options: sequelize.options,
_dialect: this, _dialect: this,
sequelize sequelize
}); });
......
...@@ -7,7 +7,6 @@ const TableHints = require('../../table-hints'); ...@@ -7,7 +7,6 @@ const TableHints = require('../../table-hints');
const AbstractQueryGenerator = require('../abstract/query-generator'); const AbstractQueryGenerator = require('../abstract/query-generator');
const randomBytes = require('crypto').randomBytes; const randomBytes = require('crypto').randomBytes;
const semver = require('semver'); const semver = require('semver');
const Op = require('../../operators'); const Op = require('../../operators');
/* istanbul ignore next */ /* istanbul ignore next */
...@@ -15,11 +14,7 @@ const throwMethodUndefined = function(methodName) { ...@@ -15,11 +14,7 @@ const throwMethodUndefined = function(methodName) {
throw new Error('The method "' + methodName + '" is not defined! Please add it to your sql dialect.'); throw new Error('The method "' + methodName + '" is not defined! Please add it to your sql dialect.');
}; };
const QueryGenerator = { class MSSQLQueryGenerator extends AbstractQueryGenerator {
__proto__: AbstractQueryGenerator,
options: {},
dialect: 'mssql',
createSchema(schema) { createSchema(schema) {
return [ return [
'IF NOT EXISTS (SELECT schema_name', 'IF NOT EXISTS (SELECT schema_name',
...@@ -31,7 +26,7 @@ const QueryGenerator = { ...@@ -31,7 +26,7 @@ const QueryGenerator = {
";'", ";'",
'END;' 'END;'
].join(' '); ].join(' ');
}, }
dropSchema(schema) { dropSchema(schema) {
// Mimics Postgres CASCADE, will drop objects belonging to the schema // Mimics Postgres CASCADE, will drop objects belonging to the schema
...@@ -66,7 +61,7 @@ const QueryGenerator = { ...@@ -66,7 +61,7 @@ const QueryGenerator = {
"EXEC sp_executesql N'DROP SCHEMA", this.quoteIdentifier(schema), ";'", "EXEC sp_executesql N'DROP SCHEMA", this.quoteIdentifier(schema), ";'",
'END;' 'END;'
].join(' '); ].join(' ');
}, }
showSchemasQuery() { showSchemasQuery() {
return [ return [
...@@ -75,7 +70,7 @@ const QueryGenerator = { ...@@ -75,7 +70,7 @@ const QueryGenerator = {
"'INFORMATION_SCHEMA', 'dbo', 'guest', 'sys', 'archive'", "'INFORMATION_SCHEMA', 'dbo', 'guest', 'sys', 'archive'",
')', 'AND', '"s"."name" NOT LIKE', "'db_%'" ')', 'AND', '"s"."name" NOT LIKE', "'db_%'"
].join(' '); ].join(' ');
}, }
versionQuery() { versionQuery() {
// Uses string manipulation to convert the MS Maj.Min.Patch.Build to semver Maj.Min.Patch // Uses string manipulation to convert the MS Maj.Min.Patch.Build to semver Maj.Min.Patch
...@@ -84,7 +79,7 @@ const QueryGenerator = { ...@@ -84,7 +79,7 @@ const QueryGenerator = {
"SET @ms_ver = REVERSE(CONVERT(NVARCHAR(20), SERVERPROPERTY('ProductVersion')));", "SET @ms_ver = REVERSE(CONVERT(NVARCHAR(20), SERVERPROPERTY('ProductVersion')));",
"SELECT REVERSE(SUBSTRING(@ms_ver, CHARINDEX('.', @ms_ver)+1, 20)) AS 'version'" "SELECT REVERSE(SUBSTRING(@ms_ver, CHARINDEX('.', @ms_ver)+1, 20)) AS 'version'"
].join(' '); ].join(' ');
}, }
createTableQuery(tableName, attributes, options) { createTableQuery(tableName, attributes, options) {
const query = "IF OBJECT_ID('<%= table %>', 'U') IS NULL CREATE TABLE <%= table %> (<%= attributes %>)", const query = "IF OBJECT_ID('<%= table %>', 'U') IS NULL CREATE TABLE <%= table %> (<%= attributes %>)",
...@@ -147,7 +142,7 @@ const QueryGenerator = { ...@@ -147,7 +142,7 @@ const QueryGenerator = {
} }
return _.template(query, this._templateSettings)(values).trim() + ';'; return _.template(query, this._templateSettings)(values).trim() + ';';
}, }
describeTableQuery(tableName, schema) { describeTableQuery(tableName, schema) {
let sql = [ let sql = [
...@@ -181,7 +176,7 @@ const QueryGenerator = { ...@@ -181,7 +176,7 @@ const QueryGenerator = {
} }
return sql; return sql;
}, }
renameTableQuery(before, after) { renameTableQuery(before, after) {
const query = 'EXEC sp_rename <%= before %>, <%= after %>;'; const query = 'EXEC sp_rename <%= before %>, <%= after %>;';
...@@ -189,11 +184,11 @@ const QueryGenerator = { ...@@ -189,11 +184,11 @@ const QueryGenerator = {
before: this.quoteTable(before), before: this.quoteTable(before),
after: this.quoteTable(after) after: this.quoteTable(after)
}); });
}, }
showTablesQuery() { showTablesQuery() {
return 'SELECT TABLE_NAME, TABLE_SCHEMA FROM INFORMATION_SCHEMA.TABLES;'; return 'SELECT TABLE_NAME, TABLE_SCHEMA FROM INFORMATION_SCHEMA.TABLES;';
}, }
dropTableQuery(tableName) { dropTableQuery(tableName) {
const query = "IF OBJECT_ID('<%= table %>', 'U') IS NOT NULL DROP TABLE <%= table %>"; const query = "IF OBJECT_ID('<%= table %>', 'U') IS NOT NULL DROP TABLE <%= table %>";
...@@ -202,7 +197,7 @@ const QueryGenerator = { ...@@ -202,7 +197,7 @@ const QueryGenerator = {
}; };
return _.template(query, this._templateSettings)(values).trim() + ';'; return _.template(query, this._templateSettings)(values).trim() + ';';
}, }
addColumnQuery(table, key, dataType) { addColumnQuery(table, key, dataType) {
// FIXME: attributeToSQL SHOULD be using attributes in addColumnQuery // FIXME: attributeToSQL SHOULD be using attributes in addColumnQuery
...@@ -221,7 +216,7 @@ const QueryGenerator = { ...@@ -221,7 +216,7 @@ const QueryGenerator = {
table: this.quoteTable(table), table: this.quoteTable(table),
attribute attribute
}); });
}, }
removeColumnQuery(tableName, attributeName) { removeColumnQuery(tableName, attributeName) {
const query = 'ALTER TABLE <%= tableName %> DROP COLUMN <%= attributeName %>;'; const query = 'ALTER TABLE <%= tableName %> DROP COLUMN <%= attributeName %>;';
...@@ -229,7 +224,7 @@ const QueryGenerator = { ...@@ -229,7 +224,7 @@ const QueryGenerator = {
tableName: this.quoteTable(tableName), tableName: this.quoteTable(tableName),
attributeName: this.quoteIdentifier(attributeName) attributeName: this.quoteIdentifier(attributeName)
}); });
}, }
changeColumnQuery(tableName, attributes) { changeColumnQuery(tableName, attributes) {
const query = 'ALTER TABLE <%= tableName %> <%= query %>;'; const query = 'ALTER TABLE <%= tableName %> <%= query %>;';
...@@ -265,7 +260,7 @@ const QueryGenerator = { ...@@ -265,7 +260,7 @@ const QueryGenerator = {
tableName: this.quoteTable(tableName), tableName: this.quoteTable(tableName),
query: finalQuery query: finalQuery
}); });
}, }
renameColumnQuery(tableName, attrBefore, attributes) { renameColumnQuery(tableName, attrBefore, attributes) {
const query = "EXEC sp_rename '<%= tableName %>.<%= before %>', '<%= after %>', 'COLUMN';", const query = "EXEC sp_rename '<%= tableName %>.<%= before %>', '<%= after %>', 'COLUMN';",
...@@ -276,7 +271,7 @@ const QueryGenerator = { ...@@ -276,7 +271,7 @@ const QueryGenerator = {
before: attrBefore, before: attrBefore,
after: newName after: newName
}); });
}, }
bulkInsertQuery(tableName, attrValueHashes, options, attributes) { bulkInsertQuery(tableName, attrValueHashes, options, attributes) {
options = options || {}; options = options || {};
...@@ -352,7 +347,7 @@ const QueryGenerator = { ...@@ -352,7 +347,7 @@ const QueryGenerator = {
offset += batch; offset += batch;
} }
return commands.join(';'); return commands.join(';');
}, }
updateQuery(tableName, attrValueHash, where, options, attributes) { updateQuery(tableName, attrValueHash, where, options, attributes) {
let sql = super.updateQuery(tableName, attrValueHash, where, options, attributes); let sql = super.updateQuery(tableName, attrValueHash, where, options, attributes);
...@@ -361,7 +356,7 @@ const QueryGenerator = { ...@@ -361,7 +356,7 @@ const QueryGenerator = {
sql = sql.replace('UPDATE', updateArgs); sql = sql.replace('UPDATE', updateArgs);
} }
return sql; return sql;
}, }
upsertQuery(tableName, insertValues, updateValues, where, model) { upsertQuery(tableName, insertValues, updateValues, where, model) {
const targetTableAlias = this.quoteTable(`${tableName}_target`); const targetTableAlias = this.quoteTable(`${tableName}_target`);
...@@ -478,7 +473,7 @@ const QueryGenerator = { ...@@ -478,7 +473,7 @@ const QueryGenerator = {
query = `SET IDENTITY_INSERT ${tableNameQuoted} ON; ${query} SET IDENTITY_INSERT ${tableNameQuoted} OFF;`; query = `SET IDENTITY_INSERT ${tableNameQuoted} ON; ${query} SET IDENTITY_INSERT ${tableNameQuoted} OFF;`;
} }
return query; return query;
}, }
deleteQuery(tableName, where, options) { deleteQuery(tableName, where, options) {
options = options || {}; options = options || {};
...@@ -513,18 +508,18 @@ const QueryGenerator = { ...@@ -513,18 +508,18 @@ const QueryGenerator = {
} }
return _.template(query, this._templateSettings)(replacements); return _.template(query, this._templateSettings)(replacements);
}, }
showIndexesQuery(tableName) { showIndexesQuery(tableName) {
const sql = "EXEC sys.sp_helpindex @objname = N'<%= tableName %>';"; const sql = "EXEC sys.sp_helpindex @objname = N'<%= tableName %>';";
return _.template(sql, this._templateSettings)({ return _.template(sql, this._templateSettings)({
tableName: this.quoteTable(tableName) tableName: this.quoteTable(tableName)
}); });
}, }
showConstraintsQuery(tableName) { showConstraintsQuery(tableName) {
return `EXEC sp_helpconstraint @objname = ${this.escape(this.quoteTable(tableName))};`; return `EXEC sp_helpconstraint @objname = ${this.escape(this.quoteTable(tableName))};`;
}, }
removeIndexQuery(tableName, indexNameOrAttributes) { removeIndexQuery(tableName, indexNameOrAttributes) {
const sql = 'DROP INDEX <%= indexName %> ON <%= tableName %>'; const sql = 'DROP INDEX <%= indexName %> ON <%= tableName %>';
...@@ -540,7 +535,7 @@ const QueryGenerator = { ...@@ -540,7 +535,7 @@ const QueryGenerator = {
}; };
return _.template(sql, this._templateSettings)(values); return _.template(sql, this._templateSettings)(values);
}, }
attributeToSQL(attribute) { attributeToSQL(attribute) {
if (!_.isPlainObject(attribute)) { if (!_.isPlainObject(attribute)) {
...@@ -618,7 +613,7 @@ const QueryGenerator = { ...@@ -618,7 +613,7 @@ const QueryGenerator = {
} }
return template; return template;
}, }
attributesToSQL(attributes, options) { attributesToSQL(attributes, options) {
const result = {}, const result = {},
...@@ -651,36 +646,31 @@ const QueryGenerator = { ...@@ -651,36 +646,31 @@ const QueryGenerator = {
} }
return result; return result;
}, }
createTrigger() { createTrigger() {
throwMethodUndefined('createTrigger'); throwMethodUndefined('createTrigger');
}, }
dropTrigger() { dropTrigger() {
throwMethodUndefined('dropTrigger'); throwMethodUndefined('dropTrigger');
}, }
renameTrigger() { renameTrigger() {
throwMethodUndefined('renameTrigger'); throwMethodUndefined('renameTrigger');
}, }
createFunction() { createFunction() {
throwMethodUndefined('createFunction'); throwMethodUndefined('createFunction');
}, }
dropFunction() { dropFunction() {
throwMethodUndefined('dropFunction'); throwMethodUndefined('dropFunction');
}, }
renameFunction() { renameFunction() {
throwMethodUndefined('renameFunction'); throwMethodUndefined('renameFunction');
}, }
quoteIdentifier(identifier) {
if (identifier === '*') return identifier;
return '[' + identifier.replace(/[\[\]']+/g, '') + ']';
},
/** /**
* Generate common SQL prefix for ForeignKeysQuery. * Generate common SQL prefix for ForeignKeysQuery.
...@@ -706,7 +696,7 @@ const QueryGenerator = { ...@@ -706,7 +696,7 @@ const QueryGenerator = {
'INNER JOIN SYS.COLUMNS COL ON COL.COLUMN_ID = PARENT_COLUMN_ID AND COL.OBJECT_ID = TB.OBJECT_ID ' + 'INNER JOIN SYS.COLUMNS COL ON COL.COLUMN_ID = PARENT_COLUMN_ID AND COL.OBJECT_ID = TB.OBJECT_ID ' +
'INNER JOIN SYS.TABLES RTB ON RTB.OBJECT_ID = FKC.REFERENCED_OBJECT_ID ' + 'INNER JOIN SYS.TABLES RTB ON RTB.OBJECT_ID = FKC.REFERENCED_OBJECT_ID ' +
'INNER JOIN SYS.COLUMNS RCOL ON RCOL.COLUMN_ID = REFERENCED_COLUMN_ID AND RCOL.OBJECT_ID = RTB.OBJECT_ID'; 'INNER JOIN SYS.COLUMNS RCOL ON RCOL.COLUMN_ID = REFERENCED_COLUMN_ID AND RCOL.OBJECT_ID = RTB.OBJECT_ID';
}, }
/** /**
* Generates an SQL query that returns all foreign keys details of a table. * Generates an SQL query that returns all foreign keys details of a table.
...@@ -723,7 +713,7 @@ const QueryGenerator = { ...@@ -723,7 +713,7 @@ const QueryGenerator = {
sql += ' AND SCHEMA_NAME(TB.SCHEMA_ID) =' + wrapSingleQuote(table.schema); sql += ' AND SCHEMA_NAME(TB.SCHEMA_ID) =' + wrapSingleQuote(table.schema);
} }
return sql; return sql;
}, }
getForeignKeyQuery(table, attributeName) { getForeignKeyQuery(table, attributeName) {
const tableName = table.tableName || table; const tableName = table.tableName || table;
...@@ -736,7 +726,7 @@ const QueryGenerator = { ...@@ -736,7 +726,7 @@ const QueryGenerator = {
} }
return sql; return sql;
}, }
getPrimaryKeyConstraintQuery(table, attributeName) { getPrimaryKeyConstraintQuery(table, attributeName) {
const tableName = wrapSingleQuote(table.tableName || table); const tableName = wrapSingleQuote(table.tableName || table);
...@@ -754,14 +744,14 @@ const QueryGenerator = { ...@@ -754,14 +744,14 @@ const QueryGenerator = {
`AND K.COLUMN_NAME = ${wrapSingleQuote(attributeName)}`, `AND K.COLUMN_NAME = ${wrapSingleQuote(attributeName)}`,
`AND K.TABLE_NAME = ${tableName};` `AND K.TABLE_NAME = ${tableName};`
].join(' '); ].join(' ');
}, }
dropForeignKeyQuery(tableName, foreignKey) { dropForeignKeyQuery(tableName, foreignKey) {
return _.template('ALTER TABLE <%= table %> DROP <%= key %>', this._templateSettings)({ return _.template('ALTER TABLE <%= table %> DROP <%= key %>', this._templateSettings)({
table: this.quoteTable(tableName), table: this.quoteTable(tableName),
key: this.quoteIdentifier(foreignKey) key: this.quoteIdentifier(foreignKey)
}); });
}, }
getDefaultConstraintQuery(tableName, attributeName) { getDefaultConstraintQuery(tableName, attributeName) {
const sql = 'SELECT name FROM SYS.DEFAULT_CONSTRAINTS ' + const sql = 'SELECT name FROM SYS.DEFAULT_CONSTRAINTS ' +
...@@ -772,7 +762,7 @@ const QueryGenerator = { ...@@ -772,7 +762,7 @@ const QueryGenerator = {
table: this.quoteTable(tableName), table: this.quoteTable(tableName),
column: attributeName column: attributeName
}); });
}, }
dropConstraintQuery(tableName, constraintName) { dropConstraintQuery(tableName, constraintName) {
const sql = 'ALTER TABLE <%= table %> DROP CONSTRAINT <%= constraint %>;'; const sql = 'ALTER TABLE <%= table %> DROP CONSTRAINT <%= constraint %>;';
...@@ -780,19 +770,19 @@ const QueryGenerator = { ...@@ -780,19 +770,19 @@ const QueryGenerator = {
table: this.quoteTable(tableName), table: this.quoteTable(tableName),
constraint: this.quoteIdentifier(constraintName) constraint: this.quoteIdentifier(constraintName)
}); });
}, }
setAutocommitQuery() { setAutocommitQuery() {
return ''; return '';
}, }
setIsolationLevelQuery() { setIsolationLevelQuery() {
}, }
generateTransactionId() { generateTransactionId() {
return randomBytes(10).toString('hex'); return randomBytes(10).toString('hex');
}, }
startTransactionQuery(transaction) { startTransactionQuery(transaction) {
if (transaction.parent) { if (transaction.parent) {
...@@ -800,7 +790,7 @@ const QueryGenerator = { ...@@ -800,7 +790,7 @@ const QueryGenerator = {
} }
return 'BEGIN TRANSACTION;'; return 'BEGIN TRANSACTION;';
}, }
commitTransactionQuery(transaction) { commitTransactionQuery(transaction) {
if (transaction.parent) { if (transaction.parent) {
...@@ -808,7 +798,7 @@ const QueryGenerator = { ...@@ -808,7 +798,7 @@ const QueryGenerator = {
} }
return 'COMMIT TRANSACTION;'; return 'COMMIT TRANSACTION;';
}, }
rollbackTransactionQuery(transaction) { rollbackTransactionQuery(transaction) {
if (transaction.parent) { if (transaction.parent) {
...@@ -816,7 +806,7 @@ const QueryGenerator = { ...@@ -816,7 +806,7 @@ const QueryGenerator = {
} }
return 'ROLLBACK TRANSACTION;'; return 'ROLLBACK TRANSACTION;';
}, }
selectFromTableFragment(options, model, attributes, tables, mainTableAs, where) { selectFromTableFragment(options, model, attributes, tables, mainTableAs, where) {
let topFragment = ''; let topFragment = '';
...@@ -874,7 +864,7 @@ const QueryGenerator = { ...@@ -874,7 +864,7 @@ const QueryGenerator = {
} }
return mainFragment; return mainFragment;
}, }
addLimitAndOffset(options, model) { addLimitAndOffset(options, model) {
// Skip handling of limit and offset as postfixes for older SQL Server versions // Skip handling of limit and offset as postfixes for older SQL Server versions
...@@ -907,7 +897,7 @@ const QueryGenerator = { ...@@ -907,7 +897,7 @@ const QueryGenerator = {
} }
return fragment; return fragment;
}, }
booleanValue(value) { booleanValue(value) {
return value ? 1 : 0; return value ? 1 : 0;
...@@ -919,4 +909,4 @@ function wrapSingleQuote(identifier) { ...@@ -919,4 +909,4 @@ function wrapSingleQuote(identifier) {
return Utils.addTicks(Utils.removeTicks(identifier, "'"), "'"); return Utils.addTicks(Utils.removeTicks(identifier, "'"), "'");
} }
module.exports = QueryGenerator; module.exports = MSSQLQueryGenerator;
\ No newline at end of file
...@@ -12,8 +12,7 @@ class MysqlDialect extends AbstractDialect { ...@@ -12,8 +12,7 @@ class MysqlDialect extends AbstractDialect {
super(); super();
this.sequelize = sequelize; this.sequelize = sequelize;
this.connectionManager = new ConnectionManager(this, sequelize); this.connectionManager = new ConnectionManager(this, sequelize);
this.QueryGenerator = _.extend({}, QueryGenerator, { this.QueryGenerator = new QueryGenerator({
options: sequelize.options,
_dialect: this, _dialect: this,
sequelize sequelize
}); });
......
...@@ -6,26 +6,27 @@ const AbstractQueryGenerator = require('../abstract/query-generator'); ...@@ -6,26 +6,27 @@ const AbstractQueryGenerator = require('../abstract/query-generator');
const util = require('util'); const util = require('util');
const Op = require('../../operators'); const Op = require('../../operators');
const QueryGenerator = { class MySQLQueryGenerator extends AbstractQueryGenerator {
__proto__: AbstractQueryGenerator, constructor(options) {
dialect: 'mysql', super(options);
OperatorMap: Object.assign({}, AbstractQueryGenerator.OperatorMap, { this.OperatorMap = Object.assign({}, this.OperatorMap, {
[Op.regexp]: 'REGEXP', [Op.regexp]: 'REGEXP',
[Op.notRegexp]: 'NOT REGEXP' [Op.notRegexp]: 'NOT REGEXP'
}), });
}
createSchema() { createSchema() {
return 'SHOW TABLES'; return 'SHOW TABLES';
}, }
showSchemasQuery() { showSchemasQuery() {
return 'SHOW TABLES'; return 'SHOW TABLES';
}, }
versionQuery() { versionQuery() {
return 'SELECT VERSION() as `version`'; return 'SELECT VERSION() as `version`';
}, }
createTableQuery(tableName, attributes, options) { createTableQuery(tableName, attributes, options) {
options = _.extend({ options = _.extend({
...@@ -100,11 +101,11 @@ const QueryGenerator = { ...@@ -100,11 +101,11 @@ const QueryGenerator = {
} }
return _.template(query, this._templateSettings)(values).trim() + ';'; return _.template(query, this._templateSettings)(values).trim() + ';';
}, }
showTablesQuery() { showTablesQuery() {
return 'SHOW TABLES;'; return 'SHOW TABLES;';
}, }
addColumnQuery(table, key, dataType) { addColumnQuery(table, key, dataType) {
const definition = this.attributeToSQL(dataType, { const definition = this.attributeToSQL(dataType, {
...@@ -114,11 +115,11 @@ const QueryGenerator = { ...@@ -114,11 +115,11 @@ const QueryGenerator = {
}); });
return `ALTER TABLE ${this.quoteTable(table)} ADD ${this.quoteIdentifier(key)} ${definition};`; return `ALTER TABLE ${this.quoteTable(table)} ADD ${this.quoteIdentifier(key)} ${definition};`;
}, }
removeColumnQuery(tableName, attributeName) { removeColumnQuery(tableName, attributeName) {
return `ALTER TABLE ${this.quoteTable(tableName)} DROP ${this.quoteIdentifier(attributeName)};`; return `ALTER TABLE ${this.quoteTable(tableName)} DROP ${this.quoteIdentifier(attributeName)};`;
}, }
changeColumnQuery(tableName, attributes) { changeColumnQuery(tableName, attributes) {
const attrString = []; const attrString = [];
...@@ -146,7 +147,7 @@ const QueryGenerator = { ...@@ -146,7 +147,7 @@ const QueryGenerator = {
} }
return `ALTER TABLE ${this.quoteTable(tableName)} ${finalQuery};`; return `ALTER TABLE ${this.quoteTable(tableName)} ${finalQuery};`;
}, }
renameColumnQuery(tableName, attrBefore, attributes) { renameColumnQuery(tableName, attrBefore, attributes) {
const attrString = []; const attrString = [];
...@@ -157,7 +158,7 @@ const QueryGenerator = { ...@@ -157,7 +158,7 @@ const QueryGenerator = {
} }
return `ALTER TABLE ${this.quoteTable(tableName)} CHANGE ${attrString.join(', ')};`; return `ALTER TABLE ${this.quoteTable(tableName)} CHANGE ${attrString.join(', ')};`;
}, }
handleSequelizeMethod(smth, tableName, factory, options, prepend) { handleSequelizeMethod(smth, tableName, factory, options, prepend) {
if (smth instanceof Utils.Json) { if (smth instanceof Utils.Json) {
...@@ -218,7 +219,7 @@ const QueryGenerator = { ...@@ -218,7 +219,7 @@ const QueryGenerator = {
} }
return super.handleSequelizeMethod(smth, tableName, factory, options, prepend); return super.handleSequelizeMethod(smth, tableName, factory, options, prepend);
}, }
_toJSONValue(value) { _toJSONValue(value) {
// true/false are stored as strings in mysql // true/false are stored as strings in mysql
...@@ -230,7 +231,7 @@ const QueryGenerator = { ...@@ -230,7 +231,7 @@ const QueryGenerator = {
return 'null'; return 'null';
} }
return value; return value;
}, }
upsertQuery(tableName, insertValues, updateValues, where, model, options) { upsertQuery(tableName, insertValues, updateValues, where, model, options) {
options.onDuplicate = 'UPDATE '; options.onDuplicate = 'UPDATE ';
...@@ -241,7 +242,7 @@ const QueryGenerator = { ...@@ -241,7 +242,7 @@ const QueryGenerator = {
}).join(', '); }).join(', ');
return this.insertQuery(tableName, insertValues, model.rawAttributes, options); return this.insertQuery(tableName, insertValues, model.rawAttributes, options);
}, }
deleteQuery(tableName, where, options, model) { deleteQuery(tableName, where, options, model) {
options = options || {}; options = options || {};
...@@ -268,11 +269,11 @@ const QueryGenerator = { ...@@ -268,11 +269,11 @@ const QueryGenerator = {
query += limit; query += limit;
return query; return query;
}, }
showIndexesQuery(tableName, options) { showIndexesQuery(tableName, options) {
return 'SHOW INDEX FROM ' + this.quoteTable(tableName) + ((options || {}).database ? ' FROM `' + options.database + '`' : ''); return 'SHOW INDEX FROM ' + this.quoteTable(tableName) + ((options || {}).database ? ' FROM `' + options.database + '`' : '');
}, }
showConstraintsQuery(table, constraintName) { showConstraintsQuery(table, constraintName) {
const tableName = table.tableName || table; const tableName = table.tableName || table;
...@@ -298,7 +299,7 @@ const QueryGenerator = { ...@@ -298,7 +299,7 @@ const QueryGenerator = {
} }
return sql + ';'; return sql + ';';
}, }
removeIndexQuery(tableName, indexNameOrAttributes) { removeIndexQuery(tableName, indexNameOrAttributes) {
let indexName = indexNameOrAttributes; let indexName = indexNameOrAttributes;
...@@ -308,7 +309,7 @@ const QueryGenerator = { ...@@ -308,7 +309,7 @@ const QueryGenerator = {
} }
return `DROP INDEX ${this.quoteIdentifier(indexName)} ON ${this.quoteTable(tableName)}`; return `DROP INDEX ${this.quoteIdentifier(indexName)} ON ${this.quoteTable(tableName)}`;
}, }
attributeToSQL(attribute, options) { attributeToSQL(attribute, options) {
if (!_.isPlainObject(attribute)) { if (!_.isPlainObject(attribute)) {
...@@ -375,7 +376,7 @@ const QueryGenerator = { ...@@ -375,7 +376,7 @@ const QueryGenerator = {
} }
return template; return template;
}, }
attributesToSQL(attributes, options) { attributesToSQL(attributes, options) {
const result = {}; const result = {};
...@@ -386,12 +387,7 @@ const QueryGenerator = { ...@@ -386,12 +387,7 @@ const QueryGenerator = {
} }
return result; return result;
}, }
quoteIdentifier(identifier) {
if (identifier === '*') return identifier;
return Utils.addTicks(Utils.removeTicks(identifier, '`'), '`');
},
/** /**
* Check whether the statmement is json function or simple path * Check whether the statmement is json function or simple path
...@@ -458,27 +454,7 @@ const QueryGenerator = { ...@@ -458,27 +454,7 @@ const QueryGenerator = {
// return true if the statement has valid json function // return true if the statement has valid json function
return hasJsonFunction; return hasJsonFunction;
}, }
/**
* Generates an SQL query that extract JSON property of given path.
*
* @param {String} column The JSON column
* @param {String|Array<String>} [path] The path to extract (optional)
* @returns {String} The generated sql query
* @private
*/
jsonPathExtractionQuery(column, path) {
/**
* Sub paths need to be quoted as ECMAScript identifiers
*
* https://bugs.mysql.com/bug.php?id=81896
*/
const paths = _.toPath(path).map(subPath => Utils.addTicks(subPath, '"'));
const pathStr = `${['$'].concat(paths).join('.')}`;
const quotedColumn = this.isIdentifierQuoted(column) ? column : this.quoteIdentifier(column);
return `(${quotedColumn}->>'${pathStr}')`;
},
/** /**
* Generates fields for getForeignKeysQuery * Generates fields for getForeignKeysQuery
...@@ -500,7 +476,7 @@ const QueryGenerator = { ...@@ -500,7 +476,7 @@ const QueryGenerator = {
'REFERENCED_TABLE_NAME as referencedTableName', 'REFERENCED_TABLE_NAME as referencedTableName',
'REFERENCED_COLUMN_NAME as referencedColumnName', 'REFERENCED_COLUMN_NAME as referencedColumnName',
].join(','); ].join(',');
}, }
/** /**
* Generates an SQL query that returns all foreign keys of a table. * Generates an SQL query that returns all foreign keys of a table.
...@@ -513,7 +489,7 @@ const QueryGenerator = { ...@@ -513,7 +489,7 @@ const QueryGenerator = {
getForeignKeysQuery(tableName, schemaName) { getForeignKeysQuery(tableName, schemaName) {
return 'SELECT ' + this._getForeignKeysQueryFields() + ' FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE where TABLE_NAME = \'' + tableName + /* jshint ignore: line */ return 'SELECT ' + this._getForeignKeysQueryFields() + ' FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE where TABLE_NAME = \'' + tableName + /* jshint ignore: line */
'\' AND CONSTRAINT_NAME!=\'PRIMARY\' AND CONSTRAINT_SCHEMA=\'' + schemaName + '\' AND REFERENCED_TABLE_NAME IS NOT NULL;'; /* jshint ignore: line */ '\' AND CONSTRAINT_NAME!=\'PRIMARY\' AND CONSTRAINT_SCHEMA=\'' + schemaName + '\' AND REFERENCED_TABLE_NAME IS NOT NULL;'; /* jshint ignore: line */
}, }
/** /**
* Generates an SQL query that returns the foreign key constraint of a given column. * Generates an SQL query that returns the foreign key constraint of a given column.
...@@ -537,7 +513,7 @@ const QueryGenerator = { ...@@ -537,7 +513,7 @@ const QueryGenerator = {
+ ' AND COLUMN_NAME = ' + wrapSingleQuote(columnName) + ' AND COLUMN_NAME = ' + wrapSingleQuote(columnName)
+ ' AND REFERENCED_TABLE_NAME IS NOT NULL' + ' AND REFERENCED_TABLE_NAME IS NOT NULL'
+ ')'; + ')';
}, }
/** /**
* Generates an SQL query that removes a foreign key from a table. * Generates an SQL query that removes a foreign key from a table.
...@@ -557,4 +533,4 @@ function wrapSingleQuote(identifier) { ...@@ -557,4 +533,4 @@ function wrapSingleQuote(identifier) {
return Utils.addTicks(identifier, '\''); return Utils.addTicks(identifier, '\'');
} }
module.exports = QueryGenerator; module.exports = MySQLQueryGenerator;
...@@ -12,8 +12,7 @@ class PostgresDialect extends AbstractDialect { ...@@ -12,8 +12,7 @@ class PostgresDialect extends AbstractDialect {
super(); super();
this.sequelize = sequelize; this.sequelize = sequelize;
this.connectionManager = new ConnectionManager(this, sequelize); this.connectionManager = new ConnectionManager(this, sequelize);
this.QueryGenerator = _.extend({}, QueryGenerator, { this.QueryGenerator = new QueryGenerator({
options: sequelize.options,
_dialect: this, _dialect: this,
sequelize sequelize
}); });
......
...@@ -12,8 +12,7 @@ class SqliteDialect extends AbstractDialect { ...@@ -12,8 +12,7 @@ class SqliteDialect extends AbstractDialect {
super(); super();
this.sequelize = sequelize; this.sequelize = sequelize;
this.connectionManager = new ConnectionManager(this, sequelize); this.connectionManager = new ConnectionManager(this, sequelize);
this.QueryGenerator = _.extend({}, QueryGenerator, { this.QueryGenerator = new QueryGenerator({
options: sequelize.options,
_dialect: this, _dialect: this,
sequelize sequelize
}); });
......
...@@ -7,22 +7,18 @@ const _ = require('lodash'); ...@@ -7,22 +7,18 @@ const _ = require('lodash');
const MySqlQueryGenerator = require('../mysql/query-generator'); const MySqlQueryGenerator = require('../mysql/query-generator');
const AbstractQueryGenerator = require('../abstract/query-generator'); const AbstractQueryGenerator = require('../abstract/query-generator');
const QueryGenerator = { class SQLiteQueryGenerator extends MySqlQueryGenerator {
__proto__: MySqlQueryGenerator,
options: {},
dialect: 'sqlite',
createSchema() { createSchema() {
return "SELECT name FROM `sqlite_master` WHERE type='table' and name!='sqlite_sequence';"; return "SELECT name FROM `sqlite_master` WHERE type='table' and name!='sqlite_sequence';";
}, }
showSchemasQuery() { showSchemasQuery() {
return "SELECT name FROM `sqlite_master` WHERE type='table' and name!='sqlite_sequence';"; return "SELECT name FROM `sqlite_master` WHERE type='table' and name!='sqlite_sequence';";
}, }
versionQuery() { versionQuery() {
return 'SELECT sqlite_version() as `version`'; return 'SELECT sqlite_version() as `version`';
}, }
createTableQuery(tableName, attributes, options) { createTableQuery(tableName, attributes, options) {
options = options || {}; options = options || {};
...@@ -73,11 +69,11 @@ const QueryGenerator = { ...@@ -73,11 +69,11 @@ const QueryGenerator = {
const sql = `CREATE TABLE IF NOT EXISTS ${table} (${attrStr});`; const sql = `CREATE TABLE IF NOT EXISTS ${table} (${attrStr});`;
return this.replaceBooleanDefaults(sql); return this.replaceBooleanDefaults(sql);
}, }
booleanValue(value) { booleanValue(value) {
return value ? 1 : 0; return value ? 1 : 0;
}, }
/** /**
* Check whether the statmement is json function or simple path * Check whether the statmement is json function or simple path
...@@ -136,26 +132,7 @@ const QueryGenerator = { ...@@ -136,26 +132,7 @@ const QueryGenerator = {
// return true if the statement has valid json function // return true if the statement has valid json function
return hasJsonFunction; return hasJsonFunction;
}, }
/**
* Generates an SQL query that extract JSON property of given path.
*
* @param {String} column The JSON column
* @param {String|Array<String>} [path] The path to extract (optional)
* @returns {String} The generated sql query
* @private
*/
jsonPathExtractionQuery(column, path) {
const paths = _.toPath(path);
const pathStr = this.escape(['$']
.concat(paths)
.join('.')
.replace(/\.(\d+)(?:(?=\.)|$)/g, (_, digit) => `[${digit}]`));
const quotedColumn = this.isIdentifierQuoted(column) ? column : this.quoteIdentifier(column);
return `json_extract(${quotedColumn}, ${pathStr})`;
},
//sqlite can't cast to datetime so we need to convert date values to their ISO strings //sqlite can't cast to datetime so we need to convert date values to their ISO strings
_toJSONValue(value) { _toJSONValue(value) {
...@@ -165,7 +142,7 @@ const QueryGenerator = { ...@@ -165,7 +142,7 @@ const QueryGenerator = {
return value.map(val => val.toISOString()); return value.map(val => val.toISOString());
} }
return value; return value;
}, }
handleSequelizeMethod(smth, tableName, factory, options, prepend) { handleSequelizeMethod(smth, tableName, factory, options, prepend) {
...@@ -202,8 +179,8 @@ const QueryGenerator = { ...@@ -202,8 +179,8 @@ const QueryGenerator = {
} }
} }
return AbstractQueryGenerator.handleSequelizeMethod.call(this, smth, tableName, factory, options, prepend); return AbstractQueryGenerator.prototype.handleSequelizeMethod.call(this, smth, tableName, factory, options, prepend);
}, }
addColumnQuery(table, key, dataType) { addColumnQuery(table, key, dataType) {
const attributes = {}; const attributes = {};
...@@ -214,11 +191,11 @@ const QueryGenerator = { ...@@ -214,11 +191,11 @@ const QueryGenerator = {
const sql = `ALTER TABLE ${this.quoteTable(table)} ADD ${attribute};`; const sql = `ALTER TABLE ${this.quoteTable(table)} ADD ${attribute};`;
return this.replaceBooleanDefaults(sql); return this.replaceBooleanDefaults(sql);
}, }
showTablesQuery() { showTablesQuery() {
return "SELECT name FROM `sqlite_master` WHERE type='table' and name!='sqlite_sequence';"; return "SELECT name FROM `sqlite_master` WHERE type='table' and name!='sqlite_sequence';";
}, }
upsertQuery(tableName, insertValues, updateValues, where, model, options) { upsertQuery(tableName, insertValues, updateValues, where, model, options) {
options.ignoreDuplicates = true; options.ignoreDuplicates = true;
...@@ -226,7 +203,7 @@ const QueryGenerator = { ...@@ -226,7 +203,7 @@ const QueryGenerator = {
const sql = this.insertQuery(tableName, insertValues, model.rawAttributes, options) + ' ' + this.updateQuery(tableName, updateValues, where, options, model.rawAttributes); const sql = this.insertQuery(tableName, insertValues, model.rawAttributes, options) + ' ' + this.updateQuery(tableName, updateValues, where, options, model.rawAttributes);
return sql; return sql;
}, }
updateQuery(tableName, attrValueHash, where, options, attributes) { updateQuery(tableName, attrValueHash, where, options, attributes) {
options = options || {}; options = options || {};
...@@ -256,7 +233,7 @@ const QueryGenerator = { ...@@ -256,7 +233,7 @@ const QueryGenerator = {
} else { } else {
return `UPDATE ${this.quoteTable(tableName)} SET ${values.join(',')} ${this.whereQuery(where, options)}`; return `UPDATE ${this.quoteTable(tableName)} SET ${values.join(',')} ${this.whereQuery(where, options)}`;
} }
}, }
deleteQuery(tableName, where, options, model) { deleteQuery(tableName, where, options, model) {
options = options || {}; options = options || {};
...@@ -281,7 +258,7 @@ const QueryGenerator = { ...@@ -281,7 +258,7 @@ const QueryGenerator = {
} }
return `DELETE FROM ${this.quoteTable(tableName)} ${whereClause}`; return `DELETE FROM ${this.quoteTable(tableName)} ${whereClause}`;
}, }
attributesToSQL(attributes) { attributesToSQL(attributes) {
const result = {}; const result = {};
...@@ -345,11 +322,11 @@ const QueryGenerator = { ...@@ -345,11 +322,11 @@ const QueryGenerator = {
} }
return result; return result;
}, }
showIndexesQuery(tableName) { showIndexesQuery(tableName) {
return `PRAGMA INDEX_LIST(${this.quoteTable(tableName)})`; return `PRAGMA INDEX_LIST(${this.quoteTable(tableName)})`;
}, }
showConstraintsQuery(tableName, constraintName) { showConstraintsQuery(tableName, constraintName) {
let sql = `SELECT sql FROM sqlite_master WHERE tbl_name='${tableName}'`; let sql = `SELECT sql FROM sqlite_master WHERE tbl_name='${tableName}'`;
...@@ -359,7 +336,7 @@ const QueryGenerator = { ...@@ -359,7 +336,7 @@ const QueryGenerator = {
} }
return sql + ';'; return sql + ';';
}, }
removeIndexQuery(tableName, indexNameOrAttributes) { removeIndexQuery(tableName, indexNameOrAttributes) {
let indexName = indexNameOrAttributes; let indexName = indexNameOrAttributes;
...@@ -369,7 +346,7 @@ const QueryGenerator = { ...@@ -369,7 +346,7 @@ const QueryGenerator = {
} }
return `DROP INDEX IF EXISTS ${this.quoteIdentifier(indexName)}`; return `DROP INDEX IF EXISTS ${this.quoteIdentifier(indexName)}`;
}, }
describeTableQuery(tableName, schema, schemaDelimiter) { describeTableQuery(tableName, schema, schemaDelimiter) {
const table = { const table = {
...@@ -378,11 +355,11 @@ const QueryGenerator = { ...@@ -378,11 +355,11 @@ const QueryGenerator = {
tableName tableName
}; };
return `PRAGMA TABLE_INFO(${this.quoteTable(this.addSchema(table))});`; return `PRAGMA TABLE_INFO(${this.quoteTable(this.addSchema(table))});`;
}, }
describeCreateTableQuery(tableName) { describeCreateTableQuery(tableName) {
return `SELECT sql FROM sqlite_master WHERE tbl_name='${tableName}';`; return `SELECT sql FROM sqlite_master WHERE tbl_name='${tableName}';`;
}, }
removeColumnQuery(tableName, attributes) { removeColumnQuery(tableName, attributes) {
...@@ -409,7 +386,7 @@ const QueryGenerator = { ...@@ -409,7 +386,7 @@ const QueryGenerator = {
+ this.createTableQuery(tableName, attributes) + this.createTableQuery(tableName, attributes)
+ `INSERT INTO ${quotedTableName} SELECT ${attributeNames} FROM ${quotedBackupTableName};` + `INSERT INTO ${quotedTableName} SELECT ${attributeNames} FROM ${quotedBackupTableName};`
+ `DROP TABLE ${quotedBackupTableName};`; + `DROP TABLE ${quotedBackupTableName};`;
}, }
_alterConstraintQuery(tableName, attributes, createTableSql) { _alterConstraintQuery(tableName, attributes, createTableSql) {
let backupTableName; let backupTableName;
...@@ -432,7 +409,7 @@ const QueryGenerator = { ...@@ -432,7 +409,7 @@ const QueryGenerator = {
+ `INSERT INTO ${quotedBackupTableName} SELECT ${attributeNames} FROM ${quotedTableName};` + `INSERT INTO ${quotedBackupTableName} SELECT ${attributeNames} FROM ${quotedTableName};`
+ `DROP TABLE ${quotedTableName};` + `DROP TABLE ${quotedTableName};`
+ `ALTER TABLE ${quotedBackupTableName} RENAME TO ${quotedTableName};`; + `ALTER TABLE ${quotedBackupTableName} RENAME TO ${quotedTableName};`;
}, }
renameColumnQuery(tableName, attrNameBefore, attrNameAfter, attributes) { renameColumnQuery(tableName, attrNameBefore, attrNameAfter, attributes) {
...@@ -462,7 +439,7 @@ const QueryGenerator = { ...@@ -462,7 +439,7 @@ const QueryGenerator = {
+ this.createTableQuery(tableName, attributes) + this.createTableQuery(tableName, attributes)
+ `INSERT INTO ${quotedTableName} SELECT ${attributeNamesExport} FROM ${quotedBackupTableName};` + `INSERT INTO ${quotedTableName} SELECT ${attributeNamesExport} FROM ${quotedBackupTableName};`
+ `DROP TABLE ${quotedBackupTableName};`; + `DROP TABLE ${quotedBackupTableName};`;
}, }
startTransactionQuery(transaction) { startTransactionQuery(transaction) {
if (transaction.parent) { if (transaction.parent) {
...@@ -470,12 +447,12 @@ const QueryGenerator = { ...@@ -470,12 +447,12 @@ const QueryGenerator = {
} }
return 'BEGIN ' + transaction.options.type + ' TRANSACTION;'; return 'BEGIN ' + transaction.options.type + ' TRANSACTION;';
}, }
setAutocommitQuery() { setAutocommitQuery() {
// SQLite does not support SET autocommit // SQLite does not support SET autocommit
return null; return null;
}, }
setIsolationLevelQuery(value) { setIsolationLevelQuery(value) {
switch (value) { switch (value) {
...@@ -490,16 +467,11 @@ const QueryGenerator = { ...@@ -490,16 +467,11 @@ const QueryGenerator = {
default: default:
throw new Error('Unknown isolation level: ' + value); throw new Error('Unknown isolation level: ' + value);
} }
}, }
replaceBooleanDefaults(sql) { replaceBooleanDefaults(sql) {
return sql.replace(/DEFAULT '?false'?/g, 'DEFAULT 0').replace(/DEFAULT '?true'?/g, 'DEFAULT 1'); return sql.replace(/DEFAULT '?false'?/g, 'DEFAULT 0').replace(/DEFAULT '?true'?/g, 'DEFAULT 1');
}, }
quoteIdentifier(identifier) {
if (identifier === '*') return identifier;
return Utils.addTicks(Utils.removeTicks(identifier, '`'), '`');
},
/** /**
* Generates an SQL query that returns all foreign keys of a table. * Generates an SQL query that returns all foreign keys of a table.
...@@ -513,4 +485,4 @@ const QueryGenerator = { ...@@ -513,4 +485,4 @@ const QueryGenerator = {
} }
}; };
module.exports = QueryGenerator; module.exports = SQLiteQueryGenerator;
\ No newline at end of file
...@@ -77,15 +77,11 @@ class Model { ...@@ -77,15 +77,11 @@ class Model {
const deletedAtCol = model._timestampAttributes.deletedAt; const deletedAtCol = model._timestampAttributes.deletedAt;
const deletedAtAttribute = model.rawAttributes[deletedAtCol]; const deletedAtAttribute = model.rawAttributes[deletedAtCol];
const deletedAtObject = {}; const deletedAtObject = {};
const now = Utils.now(this.sequelize.options.dialect);
let deletedAtDefaultValue = deletedAtAttribute.hasOwnProperty('defaultValue') ? deletedAtAttribute.defaultValue : null; let deletedAtDefaultValue = deletedAtAttribute.hasOwnProperty('defaultValue') ? deletedAtAttribute.defaultValue : null;
deletedAtDefaultValue = deletedAtDefaultValue || { deletedAtDefaultValue = deletedAtDefaultValue || {
[Op.or]: { [Op.eq]: null
[Op.gt]: now,
[Op.eq]: null
}
}; };
deletedAtObject[deletedAtAttribute.field || deletedAtCol] = deletedAtDefaultValue; deletedAtObject[deletedAtAttribute.field || deletedAtCol] = deletedAtDefaultValue;
...@@ -1064,10 +1060,6 @@ class Model { ...@@ -1064,10 +1060,6 @@ class Model {
this._hasDefaultValues = !_.isEmpty(this._defaultValues); this._hasDefaultValues = !_.isEmpty(this._defaultValues);
// DEPRECATE: All code base is free from this.attributes now
// This should be removed in v5
this.attributes = this.rawAttributes;
this.tableAttributes = _.omit(this.rawAttributes, this._virtualAttributes); this.tableAttributes = _.omit(this.rawAttributes, this._virtualAttributes);
this.prototype._hasCustomGetters = Object.keys(this.prototype._customGetters).length; this.prototype._hasCustomGetters = Object.keys(this.prototype._customGetters).length;
...@@ -4204,9 +4196,6 @@ class Model { ...@@ -4204,9 +4196,6 @@ class Model {
// Aliases // Aliases
Model.prototype.updateAttributes = Model.prototype.update; Model.prototype.updateAttributes = Model.prototype.update;
Model._conformOptions = Model._conformOptions;
Model._validateIncludedElements = Model._validateIncludedElements;
Model._expandIncludeAll = Model._expandIncludeAll;
Model.findByPrimary = Model.findById; Model.findByPrimary = Model.findById;
Model.find = Model.findOne; Model.find = Model.findOne;
Model.findAndCountAll = Model.findAndCount; Model.findAndCountAll = Model.findAndCount;
......
...@@ -78,8 +78,7 @@ const Op = { ...@@ -78,8 +78,7 @@ const Op = {
values: Symbol.for('values'), values: Symbol.for('values'),
col: Symbol.for('col'), col: Symbol.for('col'),
placeholder: Symbol.for('placeholder'), placeholder: Symbol.for('placeholder'),
join: Symbol.for('join'), join: Symbol.for('join')
raw: Symbol.for('raw') //deprecated remove by v5.0
}; };
const Aliases = { const Aliases = {
...@@ -117,7 +116,6 @@ const Aliases = { ...@@ -117,7 +116,6 @@ const Aliases = {
$all: Op.all, $all: Op.all,
$values: Op.values, $values: Op.values,
$col: Op.col, $col: Op.col,
$raw: Op.raw //deprecated remove by v5.0
}; };
const LegacyAliases = { //deprecated remove by v5.0 const LegacyAliases = { //deprecated remove by v5.0
......
...@@ -4,29 +4,11 @@ ...@@ -4,29 +4,11 @@
"version": "0.0.0-development", "version": "0.0.0-development",
"author": "Sascha Depold <sascha@depold.com>", "author": "Sascha Depold <sascha@depold.com>",
"contributors": [ "contributors": [
{ "Sascha Depold <sascha@depold.com>",
"name": "Sascha Depold", "Jan Aagaard Meier <janzeh@gmail.com>",
"email": "sascha@depold.com" "Daniel Durante <me@danieldurante.com>",
}, "Mick Hansen <mick.kasper.hansen@gmail.com>",
{ "Sushant Dhiman <sushantdhiman@outlook.com>"
"name": "Jan Aagaard Meier",
"email": [
"janzeh@gmail.com",
"jmei@itu.dk"
]
},
{
"name": "Daniel Durante",
"email": "me@danieldurante.com"
},
{
"name": "Mick Hansen",
"email": "mick.kasper.hansen@gmail.com"
},
{
"name": "Sushant Dhiman",
"email": "sushantdhiman@outlook.com"
}
], ],
"repository": { "repository": {
"type": "git", "type": "git",
...@@ -55,6 +37,8 @@ ...@@ -55,6 +37,8 @@
"wkx": "^0.4.1" "wkx": "^0.4.1"
}, },
"devDependencies": { "devDependencies": {
"@semantic-release/github": "^4.2.6",
"@semantic-release/npm": "^3.2.2",
"chai": "^4.1.2", "chai": "^4.1.2",
"chai-as-promised": "^7.1.1", "chai-as-promised": "^7.1.1",
"chai-datetime": "^1.5.0", "chai-datetime": "^1.5.0",
...@@ -144,18 +128,12 @@ ...@@ -144,18 +128,12 @@
"semantic-release": "semantic-release" "semantic-release": "semantic-release"
}, },
"engines": { "engines": {
"node": ">=4.0.0" "node": ">=6.0.0"
}, },
"license": "MIT", "license": "MIT",
"config": { "config": {
"commitizen": { "commitizen": {
"path": "./node_modules/cz-conventional-changelog" "path": "./node_modules/cz-conventional-changelog"
} }
},
"release": {
"verifyConditions": [
"@semantic-release/npm",
"@semantic-release/github"
]
} }
} }
...@@ -15,56 +15,56 @@ if (dialect === 'mysql') { ...@@ -15,56 +15,56 @@ if (dialect === 'mysql') {
username: { type: DataTypes.STRING, unique: true } username: { type: DataTypes.STRING, unique: true }
}, { timestamps: false }); }, { timestamps: false });
expect(this.sequelize.getQueryInterface().QueryGenerator.attributesToSQL(User.attributes)).to.deep.equal({username: 'VARCHAR(255) UNIQUE', id: 'INTEGER NOT NULL auto_increment PRIMARY KEY'}); expect(this.sequelize.getQueryInterface().QueryGenerator.attributesToSQL(User.rawAttributes)).to.deep.equal({username: 'VARCHAR(255) UNIQUE', id: 'INTEGER NOT NULL auto_increment PRIMARY KEY'});
}); });
it('handles extended attributes (default)', function() { it('handles extended attributes (default)', function() {
const User = this.sequelize.define('User' + config.rand(), { const User = this.sequelize.define('User' + config.rand(), {
username: {type: DataTypes.STRING, defaultValue: 'foo'} username: {type: DataTypes.STRING, defaultValue: 'foo'}
}, { timestamps: false }); }, { timestamps: false });
expect(this.sequelize.getQueryInterface().QueryGenerator.attributesToSQL(User.attributes)).to.deep.equal({username: "VARCHAR(255) DEFAULT 'foo'", id: 'INTEGER NOT NULL auto_increment PRIMARY KEY'}); expect(this.sequelize.getQueryInterface().QueryGenerator.attributesToSQL(User.rawAttributes)).to.deep.equal({username: "VARCHAR(255) DEFAULT 'foo'", id: 'INTEGER NOT NULL auto_increment PRIMARY KEY'});
}); });
it('handles extended attributes (null)', function() { it('handles extended attributes (null)', function() {
const User = this.sequelize.define('User' + config.rand(), { const User = this.sequelize.define('User' + config.rand(), {
username: {type: DataTypes.STRING, allowNull: false} username: {type: DataTypes.STRING, allowNull: false}
}, { timestamps: false }); }, { timestamps: false });
expect(this.sequelize.getQueryInterface().QueryGenerator.attributesToSQL(User.attributes)).to.deep.equal({username: 'VARCHAR(255) NOT NULL', id: 'INTEGER NOT NULL auto_increment PRIMARY KEY'}); expect(this.sequelize.getQueryInterface().QueryGenerator.attributesToSQL(User.rawAttributes)).to.deep.equal({username: 'VARCHAR(255) NOT NULL', id: 'INTEGER NOT NULL auto_increment PRIMARY KEY'});
}); });
it('handles extended attributes (primaryKey)', function() { it('handles extended attributes (primaryKey)', function() {
const User = this.sequelize.define('User' + config.rand(), { const User = this.sequelize.define('User' + config.rand(), {
username: {type: DataTypes.STRING, primaryKey: true} username: {type: DataTypes.STRING, primaryKey: true}
}, { timestamps: false }); }, { timestamps: false });
expect(this.sequelize.getQueryInterface().QueryGenerator.attributesToSQL(User.attributes)).to.deep.equal({username: 'VARCHAR(255) PRIMARY KEY'}); expect(this.sequelize.getQueryInterface().QueryGenerator.attributesToSQL(User.rawAttributes)).to.deep.equal({username: 'VARCHAR(255) PRIMARY KEY'});
}); });
it('adds timestamps', function() { it('adds timestamps', function() {
const User1 = this.sequelize.define('User' + config.rand(), {}); const User1 = this.sequelize.define('User' + config.rand(), {});
const User2 = this.sequelize.define('User' + config.rand(), {}, { timestamps: true }); const User2 = this.sequelize.define('User' + config.rand(), {}, { timestamps: true });
expect(this.sequelize.getQueryInterface().QueryGenerator.attributesToSQL(User1.attributes)).to.deep.equal({id: 'INTEGER NOT NULL auto_increment PRIMARY KEY', updatedAt: 'DATETIME NOT NULL', createdAt: 'DATETIME NOT NULL'}); expect(this.sequelize.getQueryInterface().QueryGenerator.attributesToSQL(User1.rawAttributes)).to.deep.equal({id: 'INTEGER NOT NULL auto_increment PRIMARY KEY', updatedAt: 'DATETIME NOT NULL', createdAt: 'DATETIME NOT NULL'});
expect(this.sequelize.getQueryInterface().QueryGenerator.attributesToSQL(User2.attributes)).to.deep.equal({id: 'INTEGER NOT NULL auto_increment PRIMARY KEY', updatedAt: 'DATETIME NOT NULL', createdAt: 'DATETIME NOT NULL'}); expect(this.sequelize.getQueryInterface().QueryGenerator.attributesToSQL(User2.rawAttributes)).to.deep.equal({id: 'INTEGER NOT NULL auto_increment PRIMARY KEY', updatedAt: 'DATETIME NOT NULL', createdAt: 'DATETIME NOT NULL'});
}); });
it('adds deletedAt if paranoid', function() { it('adds deletedAt if paranoid', function() {
const User = this.sequelize.define('User' + config.rand(), {}, { paranoid: true }); const User = this.sequelize.define('User' + config.rand(), {}, { paranoid: true });
expect(this.sequelize.getQueryInterface().QueryGenerator.attributesToSQL(User.attributes)).to.deep.equal({id: 'INTEGER NOT NULL auto_increment PRIMARY KEY', deletedAt: 'DATETIME', updatedAt: 'DATETIME NOT NULL', createdAt: 'DATETIME NOT NULL'}); expect(this.sequelize.getQueryInterface().QueryGenerator.attributesToSQL(User.rawAttributes)).to.deep.equal({id: 'INTEGER NOT NULL auto_increment PRIMARY KEY', deletedAt: 'DATETIME', updatedAt: 'DATETIME NOT NULL', createdAt: 'DATETIME NOT NULL'});
}); });
it('underscores timestamps if underscored', function() { it('underscores timestamps if underscored', function() {
const User = this.sequelize.define('User' + config.rand(), {}, { paranoid: true, underscored: true }); const User = this.sequelize.define('User' + config.rand(), {}, { paranoid: true, underscored: true });
expect(this.sequelize.getQueryInterface().QueryGenerator.attributesToSQL(User.attributes)).to.deep.equal({id: 'INTEGER NOT NULL auto_increment PRIMARY KEY', deleted_at: 'DATETIME', updated_at: 'DATETIME NOT NULL', created_at: 'DATETIME NOT NULL'}); expect(this.sequelize.getQueryInterface().QueryGenerator.attributesToSQL(User.rawAttributes)).to.deep.equal({id: 'INTEGER NOT NULL auto_increment PRIMARY KEY', deleted_at: 'DATETIME', updated_at: 'DATETIME NOT NULL', created_at: 'DATETIME NOT NULL'});
}); });
it('omits text fields with defaultValues', function() { it('omits text fields with defaultValues', function() {
const User = this.sequelize.define('User' + config.rand(), {name: {type: DataTypes.TEXT, defaultValue: 'helloworld'}}); const User = this.sequelize.define('User' + config.rand(), {name: {type: DataTypes.TEXT, defaultValue: 'helloworld'}});
expect(User.attributes.name.type.toString()).to.equal('TEXT'); expect(User.rawAttributes.name.type.toString()).to.equal('TEXT');
}); });
it('omits blobs fields with defaultValues', function() { it('omits blobs fields with defaultValues', function() {
const User = this.sequelize.define('User' + config.rand(), {name: {type: DataTypes.STRING.BINARY, defaultValue: 'helloworld'}}); const User = this.sequelize.define('User' + config.rand(), {name: {type: DataTypes.STRING.BINARY, defaultValue: 'helloworld'}});
expect(User.attributes.name.type.toString()).to.equal('VARCHAR(255) BINARY'); expect(User.rawAttributes.name.type.toString()).to.equal('VARCHAR(255) BINARY');
}); });
}); });
......
...@@ -2198,8 +2198,6 @@ describe(Support.getTestDialectTeaser('Model'), () => { ...@@ -2198,8 +2198,6 @@ describe(Support.getTestDialectTeaser('Model'), () => {
describe('schematic support', () => { describe('schematic support', () => {
beforeEach(function() { beforeEach(function() {
const self = this;
this.UserPublic = this.sequelize.define('UserPublic', { this.UserPublic = this.sequelize.define('UserPublic', {
age: Sequelize.INTEGER age: Sequelize.INTEGER
}); });
...@@ -2208,11 +2206,11 @@ describe(Support.getTestDialectTeaser('Model'), () => { ...@@ -2208,11 +2206,11 @@ describe(Support.getTestDialectTeaser('Model'), () => {
age: Sequelize.INTEGER age: Sequelize.INTEGER
}); });
return self.sequelize.dropAllSchemas().then(() => { return this.sequelize.dropAllSchemas().then(() => {
return self.sequelize.createSchema('schema_test').then(() => { return this.sequelize.createSchema('schema_test').then(() => {
return self.sequelize.createSchema('special').then(() => { return this.sequelize.createSchema('special').then(() => {
return self.UserSpecial.schema('special').sync({force: true}).then(UserSpecialSync => { return this.UserSpecial.schema('special').sync({force: true}).then(UserSpecialSync => {
self.UserSpecialSync = UserSpecialSync; this.UserSpecialSync = UserSpecialSync;
}); });
}); });
}); });
......
...@@ -5,7 +5,6 @@ const chai = require('chai'), ...@@ -5,7 +5,6 @@ const chai = require('chai'),
Sequelize = require('../../../index'), Sequelize = require('../../../index'),
Promise = Sequelize.Promise, Promise = Sequelize.Promise,
expect = chai.expect, expect = chai.expect,
moment = require('moment'),
Support = require(__dirname + '/../support'), Support = require(__dirname + '/../support'),
dialect = Support.getTestDialect(), dialect = Support.getTestDialect(),
DataTypes = require(__dirname + '/../../../lib/data-types'), DataTypes = require(__dirname + '/../../../lib/data-types'),
...@@ -991,31 +990,6 @@ describe(Support.getTestDialectTeaser('Model'), () => { ...@@ -991,31 +990,6 @@ describe(Support.getTestDialectTeaser('Model'), () => {
})).to.eventually.be.equal(null); })).to.eventually.be.equal(null);
}); });
}); });
}); });
it('should find records where deletedAt set to future', function() {
const User = this.sequelize.define('paranoiduser', {
username: Sequelize.STRING
}, { paranoid: true });
return User.sync({ force: true }).then(() => {
return User.bulkCreate([
{username: 'Bob'},
{username: 'Tobi', deletedAt: moment().add(30, 'minutes').format()},
{username: 'Max', deletedAt: moment().add(30, 'days').format()},
{username: 'Tony', deletedAt: moment().subtract(30, 'days').format()}
]);
}).then(() => {
return User.find({ where: {username: 'Tobi'} });
}).then(tobi => {
expect(tobi).not.to.be.null;
}).then(() => {
return User.findAll();
}).then(users => {
expect(users.length).to.be.eql(3);
});
});
}); });
}); });
...@@ -214,7 +214,7 @@ describe(Support.getTestDialectTeaser('Model'), () => { ...@@ -214,7 +214,7 @@ describe(Support.getTestDialectTeaser('Model'), () => {
if (dialect === 'sqlite') { if (dialect === 'sqlite') {
expect(created).to.be.undefined; expect(created).to.be.undefined;
} else { } else {
expect(created).to.be.okay; expect(created).to.be.ok;
} }
}); });
}); });
......
...@@ -184,9 +184,11 @@ describe(Support.getTestDialectTeaser('Utils'), () => { ...@@ -184,9 +184,11 @@ describe(Support.getTestDialectTeaser('Utils'), () => {
if (Support.getTestDialect() === 'postgres') { if (Support.getTestDialect() === 'postgres') {
describe('json', () => { describe('json', () => {
const queryGenerator = require('../../lib/dialects/postgres/query-generator.js'); beforeEach(function() {
this.queryGenerator = this.sequelize.getQueryInterface().QueryGenerator;
});
it('successfully parses a complex nested condition hash', () => { it('successfully parses a complex nested condition hash', function() {
const conditions = { const conditions = {
metadata: { metadata: {
language: 'icelandic', language: 'icelandic',
...@@ -195,23 +197,23 @@ describe(Support.getTestDialectTeaser('Utils'), () => { ...@@ -195,23 +197,23 @@ describe(Support.getTestDialectTeaser('Utils'), () => {
another_json_field: { x: 1 } another_json_field: { x: 1 }
}; };
const expected = '("metadata"#>>\'{language}\') = \'icelandic\' AND ("metadata"#>>\'{pg_rating,dk}\') = \'G\' AND ("another_json_field"#>>\'{x}\') = \'1\''; const expected = '("metadata"#>>\'{language}\') = \'icelandic\' AND ("metadata"#>>\'{pg_rating,dk}\') = \'G\' AND ("another_json_field"#>>\'{x}\') = \'1\'';
expect(queryGenerator.handleSequelizeMethod(new Utils.Json(conditions))).to.deep.equal(expected); expect(this.queryGenerator.handleSequelizeMethod(new Utils.Json(conditions))).to.deep.equal(expected);
}); });
it('successfully parses a string using dot notation', () => { it('successfully parses a string using dot notation', function() {
const path = 'metadata.pg_rating.dk'; const path = 'metadata.pg_rating.dk';
expect(queryGenerator.handleSequelizeMethod(new Utils.Json(path))).to.equal('("metadata"#>>\'{pg_rating,dk}\')'); expect(this.queryGenerator.handleSequelizeMethod(new Utils.Json(path))).to.equal('("metadata"#>>\'{pg_rating,dk}\')');
}); });
it('allows postgres json syntax', () => { it('allows postgres json syntax', function() {
const path = 'metadata->pg_rating->>dk'; const path = 'metadata->pg_rating->>dk';
expect(queryGenerator.handleSequelizeMethod(new Utils.Json(path))).to.equal(path); expect(this.queryGenerator.handleSequelizeMethod(new Utils.Json(path))).to.equal(path);
}); });
it('can take a value to compare against', () => { it('can take a value to compare against', function() {
const path = 'metadata.pg_rating.is'; const path = 'metadata.pg_rating.is';
const value = 'U'; const value = 'U';
expect(queryGenerator.handleSequelizeMethod(new Utils.Json(path, value))).to.equal('("metadata"#>>\'{pg_rating,is}\') = \'U\''); expect(this.queryGenerator.handleSequelizeMethod(new Utils.Json(path, value))).to.equal('("metadata"#>>\'{pg_rating,is}\') = \'U\'');
}); });
}); });
} }
......
...@@ -156,11 +156,18 @@ const Support = { ...@@ -156,11 +156,18 @@ const Support = {
}, },
getAbstractQueryGenerator(sequelize) { getAbstractQueryGenerator(sequelize) {
return Object.assign( class ModdedQueryGenerator extends AbstractQueryGenerator {
{}, quoteIdentifier(x) {
AbstractQueryGenerator, return x;
{options: sequelize.options, _dialect: sequelize.dialect, sequelize, quoteIdentifier(identifier) { return identifier; }} }
); }
const queryGenerator = new ModdedQueryGenerator({
sequelize,
_dialect: sequelize.dialect
});
return queryGenerator;
}, },
getTestDialect() { getTestDialect() {
......
...@@ -6,15 +6,6 @@ const chai = require('chai'), ...@@ -6,15 +6,6 @@ const chai = require('chai'),
getAbstractQueryGenerator = require(__dirname + '/../../support').getAbstractQueryGenerator; getAbstractQueryGenerator = require(__dirname + '/../../support').getAbstractQueryGenerator;
describe('QueryGenerator', () => { describe('QueryGenerator', () => {
describe('selectQuery', () => {
it('should generate correct query using array placeholder', function() {
const QG = getAbstractQueryGenerator(this.sequelize);
QG.selectQuery('foo', {where: {bar: {[Op.like]: {[Op.any]: ['a', 'b']}}}})
.should.be.equal('SELECT * FROM foo WHERE foo.bar LIKE ANY (\'a\', \'b\');');
});
});
describe('whereItemQuery', () => { describe('whereItemQuery', () => {
it('should generate correct query for Symbol operators', function() { it('should generate correct query for Symbol operators', function() {
const QG = getAbstractQueryGenerator(this.sequelize); const QG = getAbstractQueryGenerator(this.sequelize);
......
...@@ -608,20 +608,26 @@ if (dialect === 'mysql') { ...@@ -608,20 +608,26 @@ if (dialect === 'mysql') {
_.each(suites, (tests, suiteTitle) => { _.each(suites, (tests, suiteTitle) => {
describe(suiteTitle, () => { describe(suiteTitle, () => {
beforeEach(function() {
this.queryGenerator = new QueryGenerator({
sequelize: this.sequelize,
_dialect: this.sequelize.dialect
});
});
tests.forEach(test => { tests.forEach(test => {
const title = test.title || 'MySQL correctly returns ' + test.expectation + ' for ' + JSON.stringify(test.arguments); const title = test.title || 'MySQL correctly returns ' + test.expectation + ' for ' + JSON.stringify(test.arguments);
it(title, function() { it(title, function() {
// Options would normally be set by the query interface that instantiates the query-generator, but here we specify it explicitly
const context = test.context || {options: {}};
if (test.needsSequelize) { if (test.needsSequelize) {
if (_.isFunction(test.arguments[1])) test.arguments[1] = test.arguments[1](this.sequelize); if (_.isFunction(test.arguments[1])) test.arguments[1] = test.arguments[1](this.sequelize);
if (_.isFunction(test.arguments[2])) test.arguments[2] = test.arguments[2](this.sequelize); if (_.isFunction(test.arguments[2])) test.arguments[2] = test.arguments[2](this.sequelize);
} }
QueryGenerator.options = _.assign(context.options, { timezone: '+00:00' });
QueryGenerator._dialect = this.sequelize.dialect; // Options would normally be set by the query interface that instantiates the query-generator, but here we specify it explicitly
QueryGenerator.sequelize = this.sequelize; this.queryGenerator.options = Object.assign({}, this.queryGenerator.options, test.context && test.context.options || {});
QueryGenerator.setOperatorsAliases(Operators.LegacyAliases); this.queryGenerator.setOperatorsAliases(Operators.LegacyAliases);
const conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments);
const conditions = this.queryGenerator[suiteTitle].apply(this.queryGenerator, test.arguments);
expect(conditions).to.deep.equal(test.expectation); expect(conditions).to.deep.equal(test.expectation);
}); });
}); });
......
...@@ -984,27 +984,26 @@ if (dialect.match(/^postgres/)) { ...@@ -984,27 +984,26 @@ if (dialect.match(/^postgres/)) {
_.each(suites, (tests, suiteTitle) => { _.each(suites, (tests, suiteTitle) => {
describe(suiteTitle, () => { describe(suiteTitle, () => {
afterEach(function() { beforeEach(function() {
this.sequelize.options.quoteIdentifiers = true; this.queryGenerator = new QueryGenerator({
QueryGenerator.options.quoteIdentifiers = true; sequelize: this.sequelize,
_dialect: this.sequelize.dialect
});
}); });
tests.forEach(test => { tests.forEach(test => {
const title = test.title || 'Postgres correctly returns ' + test.expectation + ' for ' + JSON.stringify(test.arguments); const title = test.title || 'Postgres correctly returns ' + test.expectation + ' for ' + JSON.stringify(test.arguments);
it(title, function() { it(title, function() {
// Options would normally be set by the query interface that instantiates the query-generator, but here we specify it explicitly
const context = test.context || {options: {}};
if (test.needsSequelize) { if (test.needsSequelize) {
if (_.isFunction(test.arguments[1])) test.arguments[1] = test.arguments[1](this.sequelize); if (_.isFunction(test.arguments[1])) test.arguments[1] = test.arguments[1](this.sequelize);
if (_.isFunction(test.arguments[2])) test.arguments[2] = test.arguments[2](this.sequelize); if (_.isFunction(test.arguments[2])) test.arguments[2] = test.arguments[2](this.sequelize);
} }
QueryGenerator.options = _.assign(context.options, { timezone: '+00:00' }); // Options would normally be set by the query interface that instantiates the query-generator, but here we specify it explicitly
QueryGenerator._dialect = this.sequelize.dialect; this.queryGenerator.options = Object.assign({}, this.queryGenerator.options, test.context && test.context.options || {});
QueryGenerator.sequelize = this.sequelize; this.queryGenerator.setOperatorsAliases(Operators.LegacyAliases);
QueryGenerator.setOperatorsAliases(Operators.LegacyAliases);
const conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments); const conditions = this.queryGenerator[suiteTitle].apply(this.queryGenerator, test.arguments);
expect(conditions).to.deep.equal(test.expectation); expect(conditions).to.deep.equal(test.expectation);
}); });
}); });
......
...@@ -539,20 +539,26 @@ if (dialect === 'sqlite') { ...@@ -539,20 +539,26 @@ if (dialect === 'sqlite') {
_.each(suites, (tests, suiteTitle) => { _.each(suites, (tests, suiteTitle) => {
describe(suiteTitle, () => { describe(suiteTitle, () => {
beforeEach(function() {
this.queryGenerator = new QueryGenerator({
sequelize: this.sequelize,
_dialect: this.sequelize.dialect
});
});
tests.forEach(test => { tests.forEach(test => {
const title = test.title || 'SQLite correctly returns ' + test.expectation + ' for ' + JSON.stringify(test.arguments); const title = test.title || 'SQLite correctly returns ' + test.expectation + ' for ' + JSON.stringify(test.arguments);
it(title, function() { it(title, function() {
// Options would normally be set by the query interface that instantiates the query-generator, but here we specify it explicitly
const context = test.context || {options: {}};
if (test.needsSequelize) { if (test.needsSequelize) {
if (_.isFunction(test.arguments[1])) test.arguments[1] = test.arguments[1](this.sequelize); if (_.isFunction(test.arguments[1])) test.arguments[1] = test.arguments[1](this.sequelize);
if (_.isFunction(test.arguments[2])) test.arguments[2] = test.arguments[2](this.sequelize); if (_.isFunction(test.arguments[2])) test.arguments[2] = test.arguments[2](this.sequelize);
} }
QueryGenerator.options = _.assign(context.options, { timezone: '+00:00' });
QueryGenerator._dialect = this.sequelize.dialect; // Options would normally be set by the query interface that instantiates the query-generator, but here we specify it explicitly
QueryGenerator.sequelize = this.sequelize; this.queryGenerator.options = Object.assign({}, this.queryGenerator.options, test.context && test.context.options || {});
QueryGenerator.setOperatorsAliases(Operators.LegacyAliases); this.queryGenerator.setOperatorsAliases(Operators.LegacyAliases);
const conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments);
const conditions = this.queryGenerator[suiteTitle].apply(this.queryGenerator, test.arguments);
expect(conditions).to.deep.equal(test.expectation); expect(conditions).to.deep.equal(test.expectation);
}); });
}); });
......
...@@ -3,8 +3,6 @@ ...@@ -3,8 +3,6 @@
const Support = require(__dirname + '/../support'), const Support = require(__dirname + '/../support'),
DataTypes = require(__dirname + '/../../../lib/data-types'), DataTypes = require(__dirname + '/../../../lib/data-types'),
util = require('util'), util = require('util'),
chai = require('chai'),
expect = chai.expect,
expectsql = Support.expectsql, expectsql = Support.expectsql,
current = Support.sequelize, current = Support.sequelize,
sql = current.dialect.QueryGenerator; sql = current.dialect.QueryGenerator;
...@@ -406,16 +404,6 @@ suite(Support.getTestDialectTeaser('SQL'), () => { ...@@ -406,16 +404,6 @@ suite(Support.getTestDialectTeaser('SQL'), () => {
}); });
}); });
suite('$raw', () => {
test('should fail on $raw', () => {
expect(() => {
sql.whereItemQuery('rank', {
$raw: 'AGHJZ'
});
}).to.throw(Error, 'The `$raw` where property is no longer supported. Use `sequelize.literal` instead.');
});
});
suite('$like', () => { suite('$like', () => {
testsql('username', { testsql('username', {
$like: '%swagger' $like: '%swagger'
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!