Skip to content

Commit

Permalink
fix(cursor): cursor count with collation fix
Browse files Browse the repository at this point in the history
When a collation set is applied to a cursor,
the count method reflects this and returns
the correct value.

Fixes NODE-1369
  • Loading branch information
rweinberger committed Jun 12, 2018
1 parent 38213dc commit 71879c3
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 13 deletions.
12 changes: 1 addition & 11 deletions lib/collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const toError = require('./utils').toError;
const normalizeHintField = require('./utils').normalizeHintField;
const handleCallback = require('./utils').handleCallback;
const decorateCommand = require('./utils').decorateCommand;
const decorateWithCollation = require('./utils').decorateWithCollation;
const formattedOrderClause = require('./utils').formattedOrderClause;
const ReadPreference = require('mongodb-core').ReadPreference;
const CommandCursor = require('./command_cursor');
Expand Down Expand Up @@ -2279,17 +2280,6 @@ var findAndRemove = function(self, query, sort, options, callback) {
self.findAndModify(query, sort, null, options, callback);
};

function decorateWithCollation(command, self, options) {
// Do we support collation 3.4 and higher
var capabilities = self.s.topology.capabilities();
// Do we support write concerns 3.4 and higher
if (capabilities && capabilities.commandsTakeCollation) {
if (options.collation && typeof options.collation === 'object') {
command.collation = options.collation;
}
}
}

function decorateWithReadConcern(command, self, options) {
let readConcern = Object.assign({}, command.readConcern || {});
if (self.s.readConcern) {
Expand Down
4 changes: 4 additions & 0 deletions lib/cursor.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const f = require('util').format;
const deprecate = require('util').deprecate;
const formattedOrderClause = require('./utils').formattedOrderClause;
const handleCallback = require('./utils').handleCallback;
const decorateWithCollation = require('./utils').decorateWithCollation;
const ReadPreference = require('mongodb-core').ReadPreference;
const MongoError = require('mongodb-core').MongoError;
const Readable = require('stream').Readable;
Expand Down Expand Up @@ -1013,6 +1014,9 @@ var count = function(self, applySkipLimit, opts, callback) {
command.hint = self.s.cmd.hint;
}

// Apply a collation if set
decorateWithCollation(command, self, self.s.cmd);

if (typeof opts.maxTimeMS === 'number') {
command.maxTimeMS = opts.maxTimeMS;
} else if (self.s.cmd && typeof self.s.cmd.maxTimeMS === 'number') {
Expand Down
27 changes: 26 additions & 1 deletion lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,30 @@ function isPromiseLike(maybePromise) {
return maybePromise && typeof maybePromise.then === 'function';
}

/**
* Applies collation to a given command.
*
* @param {object} [command] the command on which to apply collation
* @param {(Cursor|Collection)} [target] target of command
* @param {object} [options] options containing collation settings
*/
function decorateWithCollation(command, target, options) {
const topology = target.s && target.s.topology;

if (!topology) {
throw new TypeError('parameter "target" is missing a topology');
}

// Do we support collation 3.4 and higher
const capabilities = target.s.topology.capabilities();
// Do we support write concerns 3.4 and higher
if (capabilities && capabilities.commandsTakeCollation) {
if (options.collation && typeof options.collation === 'object') {
command.collation = options.collation;
}
}
}

module.exports = {
filterOptions,
mergeOptions,
Expand All @@ -554,5 +578,6 @@ module.exports = {
executeOperation,
applyWriteConcern,
convertReadPreference,
isPromiseLike
isPromiseLike,
decorateWithCollation
};
36 changes: 35 additions & 1 deletion test/functional/collations_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ var test = require('./shared').assert;
var setupDatabase = require('./shared').setupDatabase;
var co = require('co');
var mock = require('mongodb-mock-server');
const expect = require('chai').expect;

var defaultFields = {
ismaster: true,
Expand Down Expand Up @@ -1102,6 +1103,33 @@ describe('Collation', function() {
}
});

it('cursor count method should return the correct number when used with collation set', {
metadata: { requires: { mongodb: '>=3.4.0' } },
test: function(done) {
const configuration = this.configuration;
const client = configuration.newClient({ w: 1 }, { poolSize: 1, auto_reconnect: false });

client.connect(function(err, client) {
const db = client.db(configuration.db);
const docs = [{ _id: 0, name: 'foo' }, { _id: 1, name: 'Foo' }];
const collation = { locale: 'en_US', strength: 2 };
let collection, cursor;
const close = e => cursor.close(() => client.close(() => done(e)));

Promise.resolve()
.then(() => db.createCollection('cursor_collation_count'))
.then(() => (collection = db.collection('cursor_collation_count')))
.then(() => collection.insertMany(docs))
.then(() => collection.find({ name: 'foo' }).collation(collation))
.then(_cursor => (cursor = _cursor))
.then(() => cursor.count())
.then(val => expect(val).to.equal(2))
.then(() => close())
.catch(e => close(e));
});
}
});

/******************************************************************************
.___ __ __ .__
| | _____/ |_ ____ ________________ _/ |_|__| ____ ____
Expand All @@ -1125,7 +1153,13 @@ describe('Collation', function() {
var col = db.collection('collation_test');
// Create collation index
col.createIndexes(
[{ key: { a: 1 }, collation: { locale: 'nn' }, name: 'collation_test' }],
[
{
key: { a: 1 },
collation: { locale: 'nn' },
name: 'collation_test'
}
],
function(err) {
test.equal(null, err);

Expand Down

0 comments on commit 71879c3

Please sign in to comment.