Skip to content

Commit 8d6befb

Browse files
committed
added collation support and tests
1 parent d30f150 commit 8d6befb

File tree

7 files changed

+1311
-7
lines changed

7 files changed

+1311
-7
lines changed

lib/collection.js

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ var Collection = function(db, topology, dbName, name, pkFactory, options) {
122122
, promiseLibrary: promiseLibrary
123123
// Read Concern
124124
, readConcern: options.readConcern
125+
// Collation
126+
, collation: options.collation
125127
}
126128
}
127129

@@ -351,6 +353,9 @@ Collection.prototype.find = function() {
351353
findCommand.readConcern = this.s.readConcern;
352354
}
353355

356+
// Decorate find command with collation options
357+
decorateWithCollation(findCommand, this, options);
358+
354359
// Create the cursor
355360
if(typeof callback == 'function') return handleCallback(callback, null, this.s.topology.cursor(this.s.namespace, findCommand, newOptions));
356361
return this.s.topology.cursor(this.s.namespace, findCommand, newOptions);
@@ -623,11 +628,6 @@ var bulkWrite = function(self, operations, options, callback) {
623628
return callback(toError(r.getWriteErrorAt(0)), r);
624629
}
625630

626-
// console.log("!!!!!! BULK EXECUTE FINISHED")
627-
// console.dir(err)
628-
// console.dir(r)
629-
630-
// if(err) return callback(err);
631631
r.insertedCount = r.nInserted;
632632
r.matchedCount = r.nMatched;
633633
r.modifiedCount = r.nModified || 0;
@@ -1006,6 +1006,9 @@ var updateDocuments = function(self, selector, document, options, callback) {
10061006
op.upsert = typeof options.upsert == 'boolean' ? options.upsert : false;
10071007
op.multi = typeof options.multi == 'boolean' ? options.multi : false;
10081008

1009+
// Have we specified collation
1010+
decorateWithCollation(finalOptions, self, options);
1011+
10091012
// Update options
10101013
self.s.topology.update(self.s.namespace, [op], finalOptions, function(err, result) {
10111014
if(callback == null) return;
@@ -1161,6 +1164,7 @@ Collection.prototype.deleteMany = function(filter, options, callback) {
11611164

11621165
var deleteMany = function(self, filter, options, callback) {
11631166
options.single = false;
1167+
11641168
removeDocuments(self, filter, options, function(err, r) {
11651169
if(callback == null) return;
11661170
if(err && callback) return callback(err);
@@ -1192,6 +1196,9 @@ var removeDocuments = function(self, selector, options, callback) {
11921196
var op = {q: selector, limit: 0};
11931197
if(options.single) op.limit = 1;
11941198

1199+
// Have we specified collation
1200+
decorateWithCollation(finalOptions, self, options);
1201+
11951202
// Execute the remove
11961203
self.s.topology.remove(self.s.namespace, [op], finalOptions, function(err, result) {
11971204
if(callback == null) return;
@@ -1989,6 +1996,9 @@ var count = function(self, query, options, callback) {
19891996
cmd.readConcern = self.s.readConcern;
19901997
}
19911998

1999+
// Have we specified collation
2000+
decorateWithCollation(cmd, self, options);
2001+
19922002
// Execute command
19932003
self.s.db.command(cmd, options, function(err, result) {
19942004
if(err) return handleCallback(callback, err);
@@ -2050,6 +2060,9 @@ var distinct = function(self, key, query, options, callback) {
20502060
cmd.readConcern = self.s.readConcern;
20512061
}
20522062

2063+
// Have we specified collation
2064+
decorateWithCollation(cmd, self, options);
2065+
20532066
// Execute the command
20542067
self.s.db.command(cmd, options, function(err, result) {
20552068
if(err) return handleCallback(callback, err);
@@ -2408,6 +2421,9 @@ var findAndModify = function(self, query, sort, doc, options, callback) {
24082421
queryObject.bypassDocumentValidation = finalOptions.bypassDocumentValidation;
24092422
}
24102423

2424+
// Have we specified collation
2425+
decorateWithCollation(queryObject, self, options);
2426+
24112427
// Execute the command
24122428
self.s.db.command(queryObject
24132429
, options, function(err, result) {
@@ -2472,6 +2488,19 @@ function decorateWithWriteConcern(command, self, options) {
24722488
}
24732489
}
24742490

2491+
function decorateWithCollation(command, self, options) {
2492+
// Do we support collation 3.4 and higher
2493+
if(self.s.topology.capabilities().commandsTakeCollation) {
2494+
if(options.collation && typeof options.collation == 'object') {
2495+
command.collation = options.collation;
2496+
} else if(self.s.collation && typeof self.s.collation == 'object') {
2497+
command.collation = self.s.collation;
2498+
} else if(self.s.db.s.collation && typeof self.s.db.s.collation == 'object') {
2499+
command.collation = self.s.db.s.collation;
2500+
}
2501+
}
2502+
}
2503+
24752504
/**
24762505
* Execute an aggregation framework pipeline against the collection, needs MongoDB >= 2.2
24772506
* @method
@@ -2533,6 +2562,8 @@ Collection.prototype.aggregate = function(pipeline, options, callback) {
25332562

25342563
// Decorate command with writeConcern if supported
25352564
decorateWithWriteConcern(command, self, options);
2565+
// Have we specified collation
2566+
decorateWithCollation(command, self, options);
25362567

25372568
// If we have bypassDocumentValidation set
25382569
if(typeof options.bypassDocumentValidation == 'boolean') {
@@ -2767,6 +2798,9 @@ var geoNear = function(self, x, y, point, options, callback) {
27672798
commandObject.readConcern = self.s.readConcern;
27682799
}
27692800

2801+
// Have we specified collation
2802+
decorateWithCollation(commandObject, self, options);
2803+
27702804
// Execute the command
27712805
self.s.db.command(commandObject, options, function (err, res) {
27722806
if(err) return handleCallback(callback, err);
@@ -2976,6 +3010,9 @@ var group = function(self, keys, condition, initial, reduce, finalize, command,
29763010
selector.readConcern = self.s.readConcern;
29773011
}
29783012

3013+
// Have we specified collation
3014+
decorateWithCollation(selector, self, options);
3015+
29793016
// Execute command
29803017
self.s.db.command(selector, options, function(err, result) {
29813018
if(err) return handleCallback(callback, err, null);
@@ -3122,6 +3159,9 @@ var mapReduce = function(self, map, reduce, options, callback) {
31223159
mapCommandHash.bypassDocumentValidation = options.bypassDocumentValidation;
31233160
}
31243161

3162+
// Have we specified collation
3163+
decorateWithCollation(mapCommandHash, self, options);
3164+
31253165
// Execute command
31263166
self.s.db.command(mapCommandHash, {readPreference:options.readPreference}, function (err, result) {
31273167
if(err) return handleCallback(callback, err);
@@ -3254,6 +3294,7 @@ var testForFields = {
32543294
limit: 1, sort: 1, fields:1, skip: 1, hint: 1, explain: 1, snapshot: 1, timeout: 1, tailable: 1, tailableRetryInterval: 1
32553295
, numberOfRetries: 1, awaitdata: 1, awaitData: 1, exhaust: 1, batchSize: 1, returnKey: 1, maxScan: 1, min: 1, max: 1, showDiskLoc: 1
32563296
, comment: 1, raw: 1, readPreference: 1, partial: 1, read: 1, dbName: 1, oplogReplay: 1, connection: 1, maxTimeMS: 1, transforms: 1
3297+
, collation: 1
32573298
}
32583299

32593300
module.exports = Collection;

lib/cursor.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,20 @@ Cursor.prototype.batchSize = function(value) {
578578

579579
define.classMethod('batchSize', {callback: false, promise:false, returns: [Cursor]});
580580

581+
/**
582+
* Set the collation options for the cursor.
583+
* @method
584+
* @param {object} value The cursor collation options
585+
* @throws {MongoError}
586+
* @return {Cursor}
587+
*/
588+
Cursor.prototype.collation = function(value) {
589+
this.s.cmd.collation = value;
590+
return this;
591+
}
592+
593+
define.classMethod('collation', {callback: false, promise:false, returns: [Cursor]});
594+
581595
/**
582596
* Set the limit for the cursor.
583597
* @method

lib/db.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ var debugFields = ['authSource', 'w', 'wtimeout', 'j', 'native_parser', 'forceSe
4747
var legalOptionNames = ['w', 'wtimeout', 'fsync', 'j', 'readPreference', 'readPreferenceTags', 'native_parser'
4848
, 'forceServerObjectId', 'pkFactory', 'serializeFunctions', 'raw', 'bufferMaxEntries', 'authSource'
4949
, 'ignoreUndefined', 'promoteLongs', 'promiseLibrary', 'readConcern', 'retryMiliSeconds', 'numberOfRetries'
50-
, 'parentDb', 'noListener', 'loggerLevel', 'logger'];
50+
, 'parentDb', 'noListener', 'loggerLevel', 'logger', 'collation'];
5151

5252
/**
5353
* Creates a new Db instance
@@ -143,6 +143,8 @@ var Db = function(databaseName, topology, options) {
143143
, noListener: typeof options.noListener == 'boolean' ? options.noListener : false
144144
// ReadConcern
145145
, readConcern: options.readConcern
146+
// Collation
147+
, collation: options.collation
146148
}
147149

148150
// Ensure we have a valid db name
@@ -437,6 +439,11 @@ Db.prototype.collection = function(name, options, callback) {
437439
// If we have not set a collection level readConcern set the db level one
438440
options.readConcern = options.readConcern || this.s.readConcern;
439441

442+
// Do we have a db level collation but not one for the collection
443+
if(!options.collation && this.s.collation && typeof this.s.collation == 'object') {
444+
options.collation = this.s.collation;
445+
}
446+
440447
// Do we have ignoreUndefined set
441448
if(this.s.options.ignoreUndefined) {
442449
options.ignoreUndefined = this.s.options.ignoreUndefined;

lib/mongo_client.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,12 @@ var mergeOptions = function(target, source, flatten) {
131131
var createUnifiedOptions = function(finalOptions, options) {
132132
var childOptions = ['mongos', 'server', 'db'
133133
, 'replset', 'db_options', 'server_options', 'rs_options', 'mongos_options'];
134+
var noMerge = ['collation'];
134135

135136
for(var name in options) {
136-
if(childOptions.indexOf(name.toLowerCase()) != -1) {
137+
if(noMerge.indexOf(name.toLowerCase()) != -1) {
138+
finalOptions[name] = options[name];
139+
} else if(childOptions.indexOf(name.toLowerCase()) != -1) {
137140
finalOptions = mergeOptions(finalOptions, options[name], false);
138141
} else {
139142
if(options[name] && typeof options[name] == 'object' && !Buffer.isBuffer(options[name]) && !Array.isArray(options[name])) {

lib/topology_base.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ var ServerCapabilities = function(ismaster) {
114114
var listIndexes = false;
115115
var maxNumberOfDocsInBatch = ismaster.maxWriteBatchSize || 1000;
116116
var commandsTakeWriteConcern = false;
117+
var commandsTakeCollation = false;
117118

118119
if(ismaster.minWireVersion >= 0) {
119120
textSearch = true;
@@ -135,6 +136,7 @@ var ServerCapabilities = function(ismaster) {
135136

136137
if(ismaster.maxWireVersion >= 5) {
137138
commandsTakeWriteConcern = true;
139+
commandsTakeCollation = true;
138140
}
139141

140142
// If no min or max wire version set to 0
@@ -157,6 +159,7 @@ var ServerCapabilities = function(ismaster) {
157159
setup_get_property(this, "maxWireVersion", ismaster.maxWireVersion);
158160
setup_get_property(this, "maxNumberOfDocsInBatch", maxNumberOfDocsInBatch);
159161
setup_get_property(this, "commandsTakeWriteConcern", commandsTakeWriteConcern);
162+
setup_get_property(this, "commandsTakeCollation", commandsTakeCollation);
160163
}
161164

162165
exports.Store = Store;

0 commit comments

Comments
 (0)