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

Commit caa03cd5 by cbauerme Committed by Mick Hansen

Fixed behavior where a mixed required status in an include would not honor given required's (#6170)

* Fixed behavior where a mixed required status in an include would not be respected
 Refactored include handling of abstract query-generator into seperate functions for through or non-thorugh joins
 Join generating functions now return join in parts so that it can be rearranged by the parent in even of a `required` mismatch
 Internal table names that are a combonation for multiple tables are now seperated by underscores instead of periods to avoid bad behavior inside parentheses
 Multiple fixes to tests to accommodate changing behavior

* Fixes to PR
 Fixed spelling of "separate"
 generateInclude now returns new attributes instead of adding them to arrays passed in
 consolidated topLevel options into one object

* Removed line ketp in merge. Whoops!

* Separate fix, shoulkd fix failing psql tests.

* Removed errant logging from tests, added more nested include testing.

* Replaced '_' sperator with '->' in 'internal' selections.

* fixed wrong name in abstract query-generator.

* translate literal keys and  in select where to new internal -> connectors.

* Replaced needlessly verbose ternary operator in abstract query-generator.

* Fixed foramtting and nameing, added fix to changelog.

* Fixed variable shadowing issue from rename.

* Fixed sql unit test from master.

* Fixed Postgres unit test.

* added .eslintrs.json back to git.

* Fixed postgres identifier quoting issues.

* Added line about bc breaks to changlog.

* Removed lines from development, tightened spacing to match style.
1 parent b94a271b
...@@ -78,6 +78,7 @@ ...@@ -78,6 +78,7 @@
- [FIXED] All associations now prefer aliases to construct foreign key [#5267](https://github.com/sequelize/sequelize/issues/5267) - [FIXED] All associations now prefer aliases to construct foreign key [#5267](https://github.com/sequelize/sequelize/issues/5267)
- [REMOVED] Default transaction auto commit [#5094](https://github.com/sequelize/sequelize/issues/5094) - [REMOVED] Default transaction auto commit [#5094](https://github.com/sequelize/sequelize/issues/5094)
- [REMOVED] Callback support for hooks [#5228](https://github.com/sequelize/sequelize/issues/5228) - [REMOVED] Callback support for hooks [#5228](https://github.com/sequelize/sequelize/issues/5228)
- [FIXED] Setting required in a nested include will not force the parent include to be required as well [#5999](https://github.com/sequelize/sequelize/issues/5999)
## BC breaks: ## BC breaks:
- `hookValidate` removed in favor of `validate` with `hooks: true | false`. `validate` returns a promise which is rejected if validation fails - `hookValidate` removed in favor of `validate` with `hooks: true | false`. `validate` returns a promise which is rejected if validation fails
...@@ -95,6 +96,7 @@ ...@@ -95,6 +96,7 @@
- All associations type will prefer `as` when constructing the `foreignKey` name. You can override this by `foreignKey` option. - All associations type will prefer `as` when constructing the `foreignKey` name. You can override this by `foreignKey` option.
- Removed default `AUTO COMMIT` for transaction. Its only sent if explicitly set by user or required by dialects (like `mysql`) - Removed default `AUTO COMMIT` for transaction. Its only sent if explicitly set by user or required by dialects (like `mysql`)
- Hooks no longer provide a callback - you can return a `then`-able instead if you are doing async stuff - Hooks no longer provide a callback - you can return a `then`-able instead if you are doing async stuff
- Table names of a select query have change internally from 'originModel.associatedModel.field' to 'originModel->associatedModel.field'
# 3.23.2 # 3.23.2
- [FIXED] Type validation now works with non-strings due to updated validator@5.0.0 [#5861](https://github.com/sequelize/sequelize/pull/5861) - [FIXED] Type validation now works with non-strings due to updated validator@5.0.0 [#5861](https://github.com/sequelize/sequelize/pull/5861)
......
...@@ -750,7 +750,7 @@ const QueryGenerator = { ...@@ -750,7 +750,7 @@ const QueryGenerator = {
quoteIdentifier(identifier, force) { quoteIdentifier(identifier, force) {
if (identifier === '*') return identifier; if (identifier === '*') return identifier;
if (!force && this.options && this.options.quoteIdentifiers === false && identifier.indexOf('.') === -1) { // default is `true` if (!force && this.options && this.options.quoteIdentifiers === false && identifier.indexOf('.') === -1 && identifier.indexOf('->') === -1) { // default is `true`
// In Postgres, if tables or attributes are created double-quoted, // In Postgres, if tables or attributes are created double-quoted,
// they are also case sensitive. If they contain any uppercase // they are also case sensitive. If they contain any uppercase
// characters, they must always be double-quoted. This makes it // characters, they must always be double-quoted. This makes it
......
...@@ -45,11 +45,16 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), function() { ...@@ -45,11 +45,16 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), function() {
}]).then(function() { }]).then(function() {
return Task.findAll({ return Task.findAll({
include: [ include: [
{model: Project, include: [ {
model: Project,
include: [
{model: User, where: {username: 'leia'}} {model: User, where: {username: 'leia'}}
]} ],
required: true,
}
] ]
}).then(function(tasks) { }).then(function(tasks) {
expect(tasks.length).to.be.equal(2); expect(tasks.length).to.be.equal(2);
expect(tasks[0].title).to.be.equal('fight empire'); expect(tasks[0].title).to.be.equal('fight empire');
expect(tasks[1].title).to.be.equal('stablish republic'); expect(tasks[1].title).to.be.equal('stablish republic');
...@@ -99,12 +104,16 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), function() { ...@@ -99,12 +104,16 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), function() {
}]).then(function() { }]).then(function() {
return Task.findAll({ return Task.findAll({
include: [ include: [
{model: Project, include: [ {
model: Project,
include: [
{model: User, where: { {model: User, where: {
username: 'leia', username: 'leia',
id: 1 id: 1
}} }}
]} ],
required: true,
}
] ]
}).then(function(tasks) { }).then(function(tasks) {
expect(tasks.length).to.be.equal(2); expect(tasks.length).to.be.equal(2);
...@@ -156,9 +165,13 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), function() { ...@@ -156,9 +165,13 @@ describe(Support.getTestDialectTeaser('Multiple Level Filters'), function() {
}]).then(function() { }]).then(function() {
return User.findAll({ return User.findAll({
include: [ include: [
{model: Project, include: [ {
model: Project,
include: [
{model: Task, where: {title: 'fight empire'}} {model: Task, where: {title: 'fight empire'}}
]} ],
required: true,
}
] ]
}).then(function(users) { }).then(function(users) {
expect(users.length).to.be.equal(1); expect(users.length).to.be.equal(1);
......
...@@ -858,4 +858,97 @@ describe(Support.getTestDialectTeaser('Include'), function() { ...@@ -858,4 +858,97 @@ describe(Support.getTestDialectTeaser('Include'), function() {
}); });
}); });
}); });
describe('nested includes', function () {
beforeEach(function () {
var Employee = this.sequelize.define('Employee', { 'name': DataTypes.STRING });
var Team = this.sequelize.define('Team', { 'name': DataTypes.STRING });
var Clearence = this.sequelize.define('Clearence', { 'level': DataTypes.INTEGER });
Team.Members = Team.hasMany(Employee, { as: 'members' });
Employee.Clearence = Employee.hasOne(Clearence, { as: 'clearence' });
Clearence.Employee = Clearence.belongsTo(Employee, { as: 'employee' });
this.Employee = Employee;
this.Team = Team;
this.Clearence = Clearence;
return this.sequelize.sync({ force: true }).then(function () {
return Promise.all([
Team.create({ name: 'TeamA' }),
Team.create({ name: 'TeamB' }),
Employee.create({ name: 'John' }),
Employee.create({ name: 'Jane' }),
Employee.create({ name: 'Josh' }),
Employee.create({ name: 'Jill' }),
Clearence.create({ level: 3 }),
Clearence.create({ level: 5 })
]).then(function (instances) {
return Promise.all([
instances[0].addMembers([instances[2], instances[3]]),
instances[1].addMembers([instances[4], instances[5]]),
instances[2].setClearence(instances[6]),
instances[3].setClearence(instances[7])
]);
});
});
});
it('should not ripple grandchild required to top level find when required of child is set to false', function () {
return this.Team.findAll({
include: [
{
association: this.Team.Members,
required: false,
include: [
{
association: this.Employee.Clearence,
required: true,
}
]
}
],
}).then(function (teams) {
expect(teams).to.have.length(2);
});
});
it('should not ripple grandchild required to top level find when required of child is not given (implicitly false)', function () {
return this.Team.findAll({
include: [
{
association: this.Team.Members,
include: [
{
association: this.Employee.Clearence,
required: true,
}
]
}
],
}).then(function (teams) {
expect(teams).to.have.length(2);
});
});
it('should ripple grandchild required to top level find when required of child is set to true as well', function () {
return this.Team.findAll({
include: [
{
association: this.Team.Members,
required: true,
include: [
{
association: this.Employee.Clearence,
required: true,
}
]
}
],
}).then(function (teams) {
expect(teams).to.have.length(1);
});
});
});
}); });
'use strict';
/* jshint -W110 */
var Support = require(__dirname + '/../support')
, DataTypes = require(__dirname + '/../../../lib/data-types')
, Sequelize = require(__dirname + '/../../../lib/sequelize')
, util = require('util')
, _ = require('lodash')
, expectsql = Support.expectsql
, current = Support.sequelize
, sql = current.dialect.QueryGenerator;
// Notice: [] will be replaced by dialect specific tick/quote character when there is not dialect specific expectation but only a default expectation
suite(Support.getTestDialectTeaser('SQL'), function() {
suite('generateJoin', function () {
var testsql = function (path, options, expectation) {
let name = `${path}, ${util.inspect(options, { depth: 10 })}`;
Sequelize.Model._conformOptions(options);
options = Sequelize.Model._validateIncludedElements(options);
let include = _.at(options, path)[0];
test(name, function () {
let join = sql.generateJoin(include,
{
options,
subQuery: options.subQuery === undefined ? options.limit && options.hasMultiAssociation : options.subQuery
}
);
return expectsql(`${join.join} ${join.body} ON ${join.condition}`, expectation);
});
};
var User = current.define('User', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
field: 'id_user'
},
companyId: {
type: DataTypes.INTEGER,
field: 'company_id'
}
}, {
tableName: 'user'
});
var Task = current.define('Task', {
title: Sequelize.STRING,
userId: {
type: DataTypes.INTEGER,
field: 'user_id'
}
}, {
tableName: 'task'
});
var Company = current.define('Company', {
name: Sequelize.STRING,
ownerId: {
type: Sequelize.INTEGER,
field: 'owner_id'
},
public: {
type: Sequelize.BOOLEAN
}
}, {
tableName: 'company'
});
var Profession = current.define('Profession', {
name: Sequelize.STRING
}, {
tableName: 'profession'
});
User.Tasks = User.hasMany(Task, {as: 'Tasks', foreignKey: 'userId'});
User.Company = User.belongsTo(Company, {foreignKey: 'companyId'});
User.Profession = User.belongsTo(Profession, {foreignKey: 'professionId'});
Profession.Professionals = Profession.hasMany(User, {as: 'Professionals', foreignKey: 'professionId'});
Company.Employees = Company.hasMany(User, {as: 'Employees', foreignKey: 'companyId'});
Company.Owner = Company.belongsTo(User, {as: 'Owner', foreignKey: 'ownerId'});
/*
* BelongsTo
*/
testsql(
"include[0]",
{
model: User,
include: [
User.Company
]
},
{
default: "LEFT OUTER JOIN [company] AS [Company] ON [User].[company_id] = [Company].[id]"
}
);
testsql(
"include[0]",
{
model: User,
include: [
{
association: User.Company,
where: { public: true },
or: true
}
]
},
{
default: "INNER JOIN [company] AS [Company] ON [User].[company_id] = [Company].[id] OR [Company].[public] = true",
sqlite: "INNER JOIN `company` AS `Company` ON `User`.`company_id` = `Company`.`id` OR `Company`.`public` = 1",
mssql: "INNER JOIN [company] AS [Company] ON [User].[company_id] = [Company].[id] OR [Company].[public] = 1",
}
);
testsql(
"include[0].include[0]",
{
model: Profession,
include: [
{
association: Profession.Professionals,
limit: 3,
include: [
User.Company
]
}
]
},
{
default: "LEFT OUTER JOIN [company] AS [Professionals->Company] ON [Professionals].[company_id] = [Professionals->Company].[id]"
}
);
testsql(
"include[0]",
{
model: User,
subQuery: true,
include: [
User.Company
]
},
{
default: "LEFT OUTER JOIN [company] AS [Company] ON [User].[companyId] = [Company].[id]"
}
);
testsql(
"include[0]",
{
model: User,
subQuery: true,
include: [
{
association: User.Company, required: false, where: { name: 'ABC' }
}
]
},
{
default: "LEFT OUTER JOIN [company] AS [Company] ON [User].[companyId] = [Company].[id] AND [Company].[name] = 'ABC'",
mssql: "LEFT OUTER JOIN [company] AS [Company] ON [User].[companyId] = [Company].[id] AND [Company].[name] = N'ABC'"
}
);
testsql(
"include[0].include[0]",
{
subQuery: true,
model: User,
include: [
{
association: User.Company, include: [
Company.Owner
]
}
]
},
{
default: "LEFT OUTER JOIN [user] AS [Company->Owner] ON [Company].[owner_id] = [Company->Owner].[id_user]"
}
);
testsql(
"include[0].include[0].include[0]",
{
model: User,
subQuery: true,
include: [
{
association: User.Company,
include: [{
association: Company.Owner,
include: [
User.Profession
]
}]
}
]
},
{ default: "LEFT OUTER JOIN [profession] AS [Company->Owner->Profession] ON [Company->Owner].[professionId] = [Company->Owner->Profession].[id]" }
);
testsql(
"include[0].include[0]",
{
model: User,
subQuery: true,
include: [
{
association: User.Company,
required: true,
include: [
Company.Owner
]
}
]
},
{ default: "LEFT OUTER JOIN [user] AS [Company->Owner] ON [Company].[owner_id] = [Company->Owner].[id_user]" }
);
testsql(
"include[0]",
{
model: User,
subQuery: true,
include: [
{ association: User.Company, required: true }
]
},
{
default: "INNER JOIN [company] AS [Company] ON [User].[companyId] = [Company].[id]"
}
);
// /*
// * HasMany
// */
testsql(
"include[0]",
{
model: User,
include: [
User.Tasks
]
},
{ default: "LEFT OUTER JOIN [task] AS [Tasks] ON [User].[id_user] = [Tasks].[user_id]" }
);
testsql(
"include[0]",
{
model: User,
subQuery: true,
include: [
User.Tasks
]
},
{
// The primary key of the main model will be aliased because it's coming from a subquery that the :M join is not a part of
default: "LEFT OUTER JOIN [task] AS [Tasks] ON [User].[id] = [Tasks].[user_id]"
}
);
testsql(
"include[0]",
{
model: User,
include: [
{
association: User.Tasks, on: {
$or: [
{ '$User.id_user$': { $col: 'Tasks.user_id' } },
{ '$Tasks.user_id$': 2 }
]
}
}
]
}, { default: "LEFT OUTER JOIN [task] AS [Tasks] ON ([User].[id_user] = [Tasks].[user_id] OR [Tasks].[user_id] = 2)" }
);
testsql(
"include[0]",
{
model: User,
include: [
{
association: User.Tasks,
on: { 'user_id': { $col: 'User.alternative_id' } }
}
]
}, { default: "LEFT OUTER JOIN [task] AS [Tasks] ON [Tasks].[user_id] = [User].[alternative_id]" }
);
testsql(
"include[0].include[0]",
{
subQuery: true,
model: User,
include: [
{
association: User.Company,
include: [
{
association: Company.Owner,
on: {
$or: [
{ '$Company.owner_id$': { $col: 'Company.Owner.id_user'} },
{ '$Company.Owner.id_user$': 2 }
]
}
}
]
}
]
},
{
default: "LEFT OUTER JOIN [user] AS [Company->Owner] ON ([Company].[owner_id] = [Company->Owner].[id_user] OR [Company->Owner].[id_user] = 2)"
}
);
});
});
'use strict';
/* jshint -W110 */
var Support = require(__dirname + '/../support')
, DataTypes = require(__dirname + '/../../../lib/data-types')
, util = require('util')
, Sequelize = require(__dirname + '/../../../lib/sequelize')
, expectsql = Support.expectsql
, current = Support.sequelize
, sql = current.dialect.QueryGenerator;
// Notice: [] will be replaced by dialect specific tick/quote character when there is not dialect specific expectation but only a default expectation
suite(Support.getTestDialectTeaser('SQL'), function() {
suite('joinIncludeQuery', function () {
var testsql = function (params, options, expectation) {
if (expectation === undefined) {
expectation = options;
options = undefined;
}
test(util.inspect(params, {depth: 10})+(options && ', '+util.inspect(options) || ''), function () {
return expectsql(sql.joinIncludeQuery(params, options), expectation);
});
};
var User = current.define('User', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
field: 'id_user'
},
companyId: {
type: DataTypes.INTEGER,
field: 'company_id'
}
}, {
tableName: 'user'
});
var Task = current.define('Task', {
title: Sequelize.STRING,
userId: {
type: DataTypes.INTEGER,
field: 'user_id'
}
}, {
tableName: 'task'
});
var Company = current.define('Company', {
name: Sequelize.STRING,
ownerId: {
type: Sequelize.INTEGER,
field: 'owner_id'
},
public: {
type: Sequelize.BOOLEAN
}
}, {
tableName: 'company'
});
var Profession = current.define('Profession', {
name: Sequelize.STRING
}, {
tableName: 'profession'
});
User.Tasks = User.hasMany(Task, {as: 'Tasks', foreignKey: 'userId'});
User.Company = User.belongsTo(Company, {foreignKey: 'companyId'});
User.Profession = User.belongsTo(Profession, {foreignKey: 'professionId'});
Company.Employees = Company.hasMany(User, {as: 'Employees', foreignKey: 'companyId'});
Company.Owner = Company.belongsTo(User, {as: 'Owner', foreignKey: 'ownerId'});
/*
* BelongsTo
*/
testsql({
model: User,
subQuery: false,
include: Sequelize.Model._validateIncludedElements({
model: User,
include: [
User.Company
]
}).include[0]
}, {
default: "LEFT OUTER JOIN [company] AS [Company] ON [User].[company_id] = [Company].[id]"
});
testsql({
model: User,
subQuery: false,
include: Sequelize.Model._validateIncludedElements({
model: User,
include: [
{association: User.Company, where: {public: true}, or: true}
]
}).include[0]
}, {
default: "INNER JOIN [company] AS [Company] ON [User].[company_id] = [Company].[id] OR [Company].[public] = true",
sqlite: "INNER JOIN `company` AS `Company` ON `User`.`company_id` = `Company`.`id` OR `Company`.`public` = 1",
mssql: "INNER JOIN [company] AS [Company] ON [User].[company_id] = [Company].[id] OR [Company].[public] = 1",
});
testsql({
model: User,
subQuery: true,
include: Sequelize.Model._validateIncludedElements({
limit: 3,
model: User,
include: [
User.Company
]
}).include[0]
}, {
default: "LEFT OUTER JOIN [company] AS [Company] ON [User].[company_id] = [Company].[id]"
});
testsql({
model: User,
subQuery: true,
groupedLimit: {},
include: Sequelize.Model._validateIncludedElements({
limit: 3,
model: User,
include: [
User.Company
]
}).include[0]
}, {
default: "LEFT OUTER JOIN [company] AS [Company] ON [User].[companyId] = [Company].[id]"
});
testsql({
model: User,
subQuery: true,
include: Sequelize.Model._validateIncludedElements({
limit: 3,
model: User,
include: [
{association: User.Company, required: false, where: {
name: 'ABC'
}},
User.Tasks
]
}).include[0]
}, {
default: "LEFT OUTER JOIN [company] AS [Company] ON [User].[companyId] = [Company].[id] AND [Company].[name] = 'ABC'",
mssql: "LEFT OUTER JOIN [company] AS [Company] ON [User].[companyId] = [Company].[id] AND [Company].[name] = N'ABC'"
});
testsql({
model: User,
subQuery: true,
include: Sequelize.Model._validateIncludedElements({
limit: 3,
model: User,
include: [
{association: User.Company, include: [
Company.Owner
]}
]
}).include[0].include[0]
}, {
default: "LEFT OUTER JOIN [user] AS [Company.Owner] ON [Company].[owner_id] = [Company.Owner].[id_user]"
});
testsql({
model: User,
subQuery: true,
include: Sequelize.Model._validateIncludedElements({
limit: 3,
model: User,
include: [
{association: User.Company, include: [
{association: Company.Owner, include: [
User.Profession
]}
]}
]
}).include[0].include[0].include[0]
}, {
default: "LEFT OUTER JOIN [profession] AS [Company.Owner.Profession] ON [Company.Owner].[professionId] = [Company.Owner.Profession].[id]"
});
testsql({
model: User,
subQuery: true,
include: Sequelize.Model._validateIncludedElements({
limit: 3,
model: User,
include: [
{association: User.Company, required: true, include: [
Company.Owner
]},
User.Tasks
]
}).include[0].include[0]
}, {
default: "LEFT OUTER JOIN [user] AS [Company.Owner] ON [Company.ownerId] = [Company.Owner].[id_user]"
});
testsql({
model: User,
subQuery: true,
include: Sequelize.Model._validateIncludedElements({
limit: 3,
model: User,
include: [
{association: User.Company, required: true}
]
}).include[0]
}, {
default: "INNER JOIN [company] AS [Company] ON [User].[company_id] = [Company].[id]"
});
/*
* HasMany
*/
testsql({
model: User,
subQuery: false,
include: Sequelize.Model._validateIncludedElements({
model: User,
include: [
User.Tasks
]
}).include[0]
}, {
default: "LEFT OUTER JOIN [task] AS [Tasks] ON [User].[id_user] = [Tasks].[user_id]"
});
testsql({
model: User,
subQuery: true,
include: Sequelize.Model._validateIncludedElements({
limit: 3,
model: User,
include: [
User.Tasks
]
}).include[0]
}, {
// The primary key of the main model will be aliased because it's coming from a subquery that the :M join is not a part of
default: "LEFT OUTER JOIN [task] AS [Tasks] ON [User].[id] = [Tasks].[user_id]"
});
testsql({
model: User,
subQuery: true,
include: Sequelize.Model._validateIncludedElements({
limit: 3,
model: User,
include: [
User.Tasks
]
}).include[0]
}, {
// The primary key of the main model will be aliased because it's coming from a subquery that the :M join is not a part of
default: "LEFT OUTER JOIN [task] AS [Tasks] ON [User].[id] = [Tasks].[user_id]"
});
testsql({
model: User,
subQuery: false,
include: Sequelize.Model._validateIncludedElements({
model: User,
include: [
{association: User.Tasks, on: {
$or: [
{'$User.id_user$': {$col: 'Tasks.user_id'}},
{'$Tasks.user_id$': 2}
]
}}
]
}).include[0]
}, {
default: "LEFT OUTER JOIN [task] AS [Tasks] ON ([User].[id_user] = [Tasks].[user_id] OR [Tasks].[user_id] = 2)"
});
testsql({
model: User,
subQuery: false,
include: Sequelize.Model._validateIncludedElements({
model: User,
include: [
{association: User.Tasks, on: {'user_id': {$col: 'User.alternative_id'}}}
]
}).include[0]
}, {
default: "LEFT OUTER JOIN [task] AS [Tasks] ON [Tasks].[user_id] = [User].[alternative_id]"
});
});
});
...@@ -290,12 +290,12 @@ suite(Support.getTestDialectTeaser('SQL'), function() { ...@@ -290,12 +290,12 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
] ]
} }
}, { }, {
default: 'SELECT [user].*, [POSTS].[id] AS [POSTS.id], [POSTS].[title] AS [POSTS.title], [POSTS.COMMENTS].[id] AS [POSTS.COMMENTS.id], [POSTS.COMMENTS].[title] AS [POSTS.COMMENTS.title] FROM ('+ default: 'SELECT [user].*, [POSTS].[id] AS [POSTS.id], [POSTS].[title] AS [POSTS.title], [POSTS->COMMENTS].[id] AS [POSTS.COMMENTS.id], [POSTS->COMMENTS].[title] AS [POSTS.COMMENTS.title] FROM ('+
[ [
'(SELECT [id_user] AS [id], [email], [first_name] AS [firstName], [last_name] AS [lastName] FROM [users] AS [user] WHERE [user].[companyId] = 1 ORDER BY [user].[last_name] ASC'+sql.addLimitAndOffset({ limit: 3, order: ['last_name', 'ASC'] })+')', '(SELECT [id_user] AS [id], [email], [first_name] AS [firstName], [last_name] AS [lastName] FROM [users] AS [user] WHERE [user].[companyId] = 1 ORDER BY [user].[last_name] ASC'+sql.addLimitAndOffset({ limit: 3, order: ['last_name', 'ASC'] })+')',
'(SELECT [id_user] AS [id], [email], [first_name] AS [firstName], [last_name] AS [lastName] FROM [users] AS [user] WHERE [user].[companyId] = 5 ORDER BY [user].[last_name] ASC'+sql.addLimitAndOffset({ limit: 3, order: ['last_name', 'ASC'] })+')' '(SELECT [id_user] AS [id], [email], [first_name] AS [firstName], [last_name] AS [lastName] FROM [users] AS [user] WHERE [user].[companyId] = 5 ORDER BY [user].[last_name] ASC'+sql.addLimitAndOffset({ limit: 3, order: ['last_name', 'ASC'] })+')'
].join(current.dialect.supports['UNION ALL'] ?' UNION ALL ' : ' UNION ') ].join(current.dialect.supports['UNION ALL'] ?' UNION ALL ' : ' UNION ')
+') AS [user] LEFT OUTER JOIN [post] AS [POSTS] ON [user].[id] = [POSTS].[user_id] LEFT OUTER JOIN [comment] AS [POSTS.COMMENTS] ON [POSTS].[id] = [POSTS.COMMENTS].[post_id];' +') AS [user] LEFT OUTER JOIN [post] AS [POSTS] ON [user].[id] = [POSTS].[user_id] LEFT OUTER JOIN [comment] AS [POSTS->COMMENTS] ON [POSTS].[id] = [POSTS->COMMENTS].[post_id];'
}); });
})(); })();
...@@ -430,8 +430,8 @@ suite(Support.getTestDialectTeaser('SQL'), function() { ...@@ -430,8 +430,8 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
}).include, }).include,
model: User model: User
}, User), { }, User), {
default: 'SELECT [User].[name], [User].[age], [Posts].[id] AS [Posts.id], [Posts].[title] AS [Posts.title], [Posts.Comments].[id] AS [Posts.Comments.id], [Posts.Comments].[title] AS [Posts.Comments.title], [Posts.Comments].[createdAt] AS [Posts.Comments.createdAt], [Posts.Comments].[updatedAt] AS [Posts.Comments.updatedAt], [Posts.Comments].[post_id] AS [Posts.Comments.post_id] FROM [User] AS [User] LEFT OUTER JOIN [Post] AS [Posts] ON [User].[id] = [Posts].[user_id] LEFT OUTER JOIN [Comment] AS [Posts.Comments] ON [Posts].[id] = [Posts.Comments].[post_id];', default: 'SELECT [User].[name], [User].[age], [Posts].[id] AS [Posts.id], [Posts].[title] AS [Posts.title], [Posts->Comments].[id] AS [Posts.Comments.id], [Posts->Comments].[title] AS [Posts.Comments.title], [Posts->Comments].[createdAt] AS [Posts.Comments.createdAt], [Posts->Comments].[updatedAt] AS [Posts.Comments.updatedAt], [Posts->Comments].[post_id] AS [Posts.Comments.post_id] FROM [User] AS [User] LEFT OUTER JOIN [Post] AS [Posts] ON [User].[id] = [Posts].[user_id] LEFT OUTER JOIN [Comment] AS [Posts->Comments] ON [Posts].[id] = [Posts->Comments].[post_id];',
postgres: 'SELECT User.name, User.age, Posts.id AS "Posts.id", Posts.title AS "Posts.title", "Posts.Comments".id AS "Posts.Comments.id", "Posts.Comments".title AS "Posts.Comments.title", "Posts.Comments".createdAt AS "Posts.Comments.createdAt", "Posts.Comments".updatedAt AS "Posts.Comments.updatedAt", "Posts.Comments".post_id AS "Posts.Comments.post_id" FROM User AS User LEFT OUTER JOIN Post AS Posts ON User.id = Posts.user_id LEFT OUTER JOIN Comment AS "Posts.Comments" ON Posts.id = "Posts.Comments".post_id;' postgres: 'SELECT User.name, User.age, Posts.id AS "Posts.id", Posts.title AS "Posts.title", "Posts->Comments".id AS "Posts.Comments.id", "Posts->Comments".title AS "Posts.Comments.title", "Posts->Comments".createdAt AS "Posts.Comments.createdAt", "Posts->Comments".updatedAt AS "Posts.Comments.updatedAt", "Posts->Comments".post_id AS "Posts.Comments.post_id" FROM User AS User LEFT OUTER JOIN Post AS Posts ON User.id = Posts.user_id LEFT OUTER JOIN Comment AS "Posts->Comments" ON Posts.id = "Posts->Comments".post_id;'
}); });
}); });
......
...@@ -377,7 +377,7 @@ suite(Support.getTestDialectTeaser('SQL'), function() { ...@@ -377,7 +377,7 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
testsql('$offer.organization.id$', { testsql('$offer.organization.id$', {
$col: 'offer.user.organizationId' $col: 'offer.user.organizationId'
}, { }, {
default: '[offer.organization].[id] = [offer.user].[organizationId]' default: '[offer->organization].[id] = [offer->user].[organizationId]'
}); });
}); });
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!