Skip to content

Commit 592099d

Browse files
papbsushantdhiman
authored andcommitted
fix(count): fix null count with includes (#11295)
1 parent 80d3625 commit 592099d

File tree

2 files changed

+125
-118
lines changed

2 files changed

+125
-118
lines changed

lib/model.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2017,7 +2017,9 @@ class Model {
20172017
*/
20182018
static count(options) {
20192019
return Promise.try(() => {
2020-
options = _.defaults(Utils.cloneDeep(options), { hooks: true });
2020+
options = Utils.cloneDeep(options);
2021+
options = _.defaults(options, { hooks: true });
2022+
options.raw = true;
20212023
if (options.hooks) {
20222024
return this.runHooks('beforeCount', options);
20232025
}

test/integration/model/count.test.js

Lines changed: 122 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -6,119 +6,97 @@ const chai = require('chai'),
66
DataTypes = require('../../../lib/data-types');
77

88
describe(Support.getTestDialectTeaser('Model'), () => {
9-
beforeEach(function() {
10-
this.User = this.sequelize.define('User', {
11-
username: DataTypes.STRING,
12-
age: DataTypes.INTEGER
13-
});
14-
this.Project = this.sequelize.define('Project', {
15-
name: DataTypes.STRING
16-
});
17-
18-
this.User.hasMany(this.Project);
19-
this.Project.belongsTo(this.User);
20-
21-
return this.sequelize.sync({ force: true });
22-
});
23-
249
describe('count', () => {
2510
beforeEach(function() {
26-
return this.User.bulkCreate([
27-
{ username: 'boo' },
28-
{ username: 'boo2' }
29-
]).then(() => {
30-
return this.User.findOne();
31-
}).then(user => {
32-
return user.createProject({
33-
name: 'project1'
34-
});
11+
this.User = this.sequelize.define('User', {
12+
username: DataTypes.STRING,
13+
age: DataTypes.INTEGER
14+
});
15+
this.Project = this.sequelize.define('Project', {
16+
name: DataTypes.STRING
3517
});
18+
19+
this.User.hasMany(this.Project);
20+
this.Project.belongsTo(this.User);
21+
22+
return this.sequelize.sync({ force: true });
3623
});
3724

3825
it('should count rows', function() {
39-
return expect(this.User.count()).to.eventually.equal(2);
26+
return this.User.bulkCreate([
27+
{ username: 'foo' },
28+
{ username: 'bar' }
29+
]).then(() => {
30+
return expect(this.User.count()).to.eventually.equal(2);
31+
});
4032
});
4133

4234
it('should support include', function() {
43-
return expect(this.User.count({
44-
include: [{
45-
model: this.Project,
46-
where: {
47-
name: 'project1'
48-
}
49-
}]
50-
})).to.eventually.equal(1);
35+
return this.User.bulkCreate([
36+
{ username: 'foo' },
37+
{ username: 'bar' }
38+
]).then(() => this.User.findOne())
39+
.then(user => user.createProject({ name: 'project1' }))
40+
.then(() => {
41+
return expect(this.User.count({
42+
include: [{
43+
model: this.Project,
44+
where: { name: 'project1' }
45+
}]
46+
})).to.eventually.equal(1);
47+
});
5148
});
5249

53-
it('should return attributes', function() {
54-
return this.User.create({
55-
username: 'valak',
56-
createdAt: (new Date()).setFullYear(2015)
57-
})
58-
.then(() =>
59-
this.User.count({
60-
attributes: ['createdAt'],
61-
group: ['createdAt']
62-
})
63-
)
64-
.then(users => {
65-
expect(users.length).to.be.eql(2);
66-
67-
// have attributes
68-
expect(users[0].createdAt).to.exist;
69-
expect(users[1].createdAt).to.exist;
70-
});
50+
it('should count groups correctly and return attributes', function() {
51+
return this.User.bulkCreate([
52+
{ username: 'foo' },
53+
{ username: 'bar' },
54+
{
55+
username: 'valak',
56+
createdAt: (new Date()).setFullYear(2015)
57+
}
58+
]).then(() => this.User.count({
59+
attributes: ['createdAt'],
60+
group: ['createdAt']
61+
})).then(users => {
62+
expect(users.length).to.be.eql(2);
63+
expect(users[0].createdAt).to.exist;
64+
expect(users[1].createdAt).to.exist;
65+
});
7166
});
7267

7368
it('should not return NaN', function() {
74-
return this.sequelize.sync({ force: true })
75-
.then(() =>
76-
this.User.bulkCreate([
77-
{ username: 'valak', age: 10 },
78-
{ username: 'conjuring', age: 20 },
79-
{ username: 'scary', age: 10 }
80-
])
81-
)
82-
.then(() =>
83-
this.User.count({
84-
where: { age: 10 },
85-
group: ['age'],
86-
order: ['age']
87-
})
88-
)
89-
.then(result => {
90-
// TODO: `parseInt` should not be needed, see #10533
91-
expect(parseInt(result[0].count, 10)).to.be.eql(2);
92-
return this.User.count({
93-
where: { username: 'fire' }
94-
});
95-
})
96-
.then(count => {
97-
expect(count).to.be.eql(0);
98-
return this.User.count({
99-
where: { username: 'fire' },
100-
group: 'age'
101-
});
102-
})
103-
.then(count => {
104-
expect(count).to.be.eql([]);
69+
return this.User.bulkCreate([
70+
{ username: 'valak', age: 10 },
71+
{ username: 'conjuring', age: 20 },
72+
{ username: 'scary', age: 10 }
73+
]).then(() => this.User.count({
74+
where: { age: 10 },
75+
group: ['age'],
76+
order: ['age']
77+
})).then(result => {
78+
// TODO: `parseInt` should not be needed, see #10533
79+
expect(parseInt(result[0].count, 10)).to.be.eql(2);
80+
return this.User.count({
81+
where: { username: 'fire' }
10582
});
83+
}).then(count => {
84+
expect(count).to.be.eql(0);
85+
return this.User.count({
86+
where: { username: 'fire' },
87+
group: 'age'
88+
});
89+
}).then(count => {
90+
expect(count).to.be.eql([]);
91+
});
10692
});
10793

10894
it('should be able to specify column for COUNT()', function() {
109-
return this.sequelize.sync({ force: true })
110-
.then(() =>
111-
this.User.bulkCreate([
112-
{ username: 'ember', age: 10 },
113-
{ username: 'angular', age: 20 },
114-
{ username: 'mithril', age: 10 }
115-
])
116-
)
117-
.then(() =>
118-
this.User.count({
119-
col: 'username'
120-
})
121-
)
95+
return this.User.bulkCreate([
96+
{ username: 'ember', age: 10 },
97+
{ username: 'angular', age: 20 },
98+
{ username: 'mithril', age: 10 }
99+
]).then(() => this.User.count({ col: 'username' }))
122100
.then(count => {
123101
expect(count).to.be.eql(3);
124102
return this.User.count({
@@ -132,43 +110,70 @@ describe(Support.getTestDialectTeaser('Model'), () => {
132110
});
133111

134112
it('should be able to use where clause on included models', function() {
135-
const queryObject = {
113+
const countOptions = {
136114
col: 'username',
137115
include: [this.Project],
138116
where: {
139117
'$Projects.name$': 'project1'
140118
}
141119
};
142-
return this.User.count(queryObject).then(count => {
143-
expect(count).to.be.eql(1);
144-
queryObject.where['$Projects.name$'] = 'project2';
145-
return this.User.count(queryObject);
146-
}).then(count => {
147-
expect(count).to.be.eql(0);
148-
});
120+
return this.User.bulkCreate([
121+
{ username: 'foo' },
122+
{ username: 'bar' }
123+
]).then(() => this.User.findOne())
124+
.then(user => user.createProject({ name: 'project1' }))
125+
.then(() => {
126+
return this.User.count(countOptions).then(count => {
127+
expect(count).to.be.eql(1);
128+
countOptions.where['$Projects.name$'] = 'project2';
129+
return this.User.count(countOptions);
130+
});
131+
})
132+
.then(count => {
133+
expect(count).to.be.eql(0);
134+
});
149135
});
150136

151137
it('should be able to specify column for COUNT() with includes', function() {
152-
return this.sequelize.sync({ force: true }).then(() =>
153-
this.User.bulkCreate([
154-
{ username: 'ember', age: 10 },
155-
{ username: 'angular', age: 20 },
156-
{ username: 'mithril', age: 10 }
157-
])
158-
).then(() =>
159-
this.User.count({
160-
col: 'username',
161-
distinct: true,
162-
include: [this.Project]
163-
})
164-
).then(count => {
138+
return this.User.bulkCreate([
139+
{ username: 'ember', age: 10 },
140+
{ username: 'angular', age: 20 },
141+
{ username: 'mithril', age: 10 }
142+
]).then(() => this.User.count({
143+
col: 'username',
144+
distinct: true,
145+
include: [this.Project]
146+
})).then(count => {
165147
expect(count).to.be.eql(3);
166148
return this.User.count({
167149
col: 'age',
168150
distinct: true,
169151
include: [this.Project]
170152
});
171-
}).then(count => expect(count).to.be.eql(2));
153+
}).then(count => {
154+
expect(count).to.be.eql(2);
155+
});
156+
});
157+
158+
it('should work correctly with include and whichever raw option', function() {
159+
const Post = this.sequelize.define('Post', {});
160+
this.User.hasMany(Post);
161+
return Post.sync({ force: true })
162+
.then(() => Promise.all([this.User.create({}), Post.create({})]))
163+
.then(([user, post]) => user.addPost(post))
164+
.then(() => Promise.all([
165+
this.User.count(),
166+
this.User.count({ raw: undefined }),
167+
this.User.count({ raw: false }),
168+
this.User.count({ raw: true }),
169+
this.User.count({ include: Post }),
170+
this.User.count({ include: Post, raw: undefined }),
171+
this.User.count({ include: Post, raw: false }),
172+
this.User.count({ include: Post, raw: true })
173+
]))
174+
.then(counts => {
175+
expect(counts).to.deep.equal([1, 1, 1, 1, 1, 1, 1, 1]);
176+
});
172177
});
173178

174179
});

0 commit comments

Comments
 (0)