From fd270c3f292b6c4d0426776e7d6c45ee858a39aa Mon Sep 17 00:00:00 2001 From: "gabriele.lana" Date: Fri, 5 Dec 2014 17:14:15 +0100 Subject: [PATCH] distinctAndCount on some kind of object fields --- spec/distinct_and_count.js | 56 +++++++++++++++++++++++++++++++------- src/distinct_and_count.js | 42 +++++++++++++++++++++++++--- 2 files changed, 84 insertions(+), 14 deletions(-) diff --git a/spec/distinct_and_count.js b/spec/distinct_and_count.js index 19bdb0d..90fb52c 100644 --- a/spec/distinct_and_count.js +++ b/spec/distinct_and_count.js @@ -1,4 +1,6 @@ -assert.that('distinctAndCount on one field', function(c) { +/* global NumberLong:false */ + +assert.that('distinctAndCount works on one field', function(c) { c.save({field: 'value_1'}) c.save({field: 'value_2'}) c.save({field: 'value_1'}) @@ -9,7 +11,7 @@ assert.that('distinctAndCount on one field', function(c) { assert.eq(1, result['value_2']) }) -assert.that('distinctAndCount on one nested field', function(c) { +assert.that('distinctAndCount works on one nested field', function(c) { c.save({field: {nested: 'value_1'}}) c.save({field: {nested: 'value_2'}}) c.save({field: {nested: 'value_1'}}) @@ -20,7 +22,7 @@ assert.that('distinctAndCount on one nested field', function(c) { assert.eq(1, result['value_2']) }) -assert.that('distinctAndCount on deeply nested fields', function(c) { +assert.that('distinctAndCount works on deeply nested fields', function(c) { c.save({field: {nested: {nested: {nested: 'value_1'}}}}) c.save({field: {nested: {nested: {nested: 'value_2'}}}}) c.save({field: {nested: {nested: {nested: 'value_1'}}}}) @@ -31,7 +33,7 @@ assert.that('distinctAndCount on deeply nested fields', function(c) { assert.eq(1, result['value_2']) }) -assert.that('distinctAndCount on multiple fields', function(c) { +assert.that('distinctAndCount works on multiple fields', function(c) { c.save({'field_1': 'value_1', 'field_2': 'value_1'}) c.save({'field_1': 'value_2', 'field_2': 'value_2'}) c.save({'field_1': 'value_1', 'field_2': 'value_3'}) @@ -44,22 +46,56 @@ assert.that('distinctAndCount on multiple fields', function(c) { assert.eq(1, result['value_1,value_1']) }) -assert.that('distinctAndCount throws an exception with array fields', function(c) { +assert.that('distinctAndCount works on array fields', function(c) { + c.save({field: 'value_1'}) + c.save({field: ['value_2', 'value_3']}) + c.save({field: ['value_3', 'value_2']}) + c.save({field: ['value_1', 'value_2']}) + + var result = c.distinctAndCount('field') + + assert.eq(1, result['value_1']) + assert.eq(2, result['value_2,value_3']) + assert.eq(1, result['value_1,value_2']) +}) + +assert.that('distinctAndCount works on multiple array fields', function(c) { + c.save({'field_1': ['value_1','value_2'], 'field_2': 'value_1'}) + c.save({'field_1': ['value_1','value_2'], 'field_2': 'value_2'}) + c.save({'field_1': ['value_2','value_1'], 'field_2': 'value_2'}) + + var result = c.distinctAndCount(['field_1', 'field_2']) + + assert.eq(1, result['value_1,value_2,value_1']) + assert.eq(2, result['value_1,value_2,value_2']) +}) + +assert.that('distinctAndCount throws an exception on object fields', function(c) { c.save({field: 'value_1'}) - c.save({field: ['value_2']}) + c.save({field: {key: 'value_2'}}) assert.throws(function() { c.distinctAndCount('field') - }, []) + }) }) -assert.that('distinctAndCount throws an exception with object fields', function(c) { +assert.that('distinctAndCount throws an exception on array fields that contains objects', function(c) { c.save({field: 'value_1'}) - c.save({field: {key: 'value_2'}}) + c.save({field: [{key: 'value_2'}]}) assert.throws(function() { c.distinctAndCount('field') - }, []) + }) +}) + +assert.that('distinctAndCount works with Number fields', function(c) { + c.save({field: 'value_1'}) + c.save({field: NumberLong(200)}) + + var result = c.distinctAndCount('field') + + assert.eq(1, result['value_1']) + assert.eq(1, result[200]) }) assert.that('distinctAndCount takes a query as second parameter', function(c) { diff --git a/src/distinct_and_count.js b/src/distinct_and_count.js index e31e572..d382237 100644 --- a/src/distinct_and_count.js +++ b/src/distinct_and_count.js @@ -21,10 +21,44 @@ DBCollection.prototype.distinctAndCount = function(field, query) { var result = it.result || it.toArray() return _.reduce(result, function(all, r) { - if (!_.any(r.values, isObject)) { - all[_.values(r.values).join(',')] = r.count - return all + + var isValidValue = + _(r.values) + .chain() + .values() + .any(function(value) { + if (_(value).isArray()) { + return _(value).all(function(value) { + return !_(value).isObject() + }) + } + // we support values like Number or Date but not {} + return value.constructor.name !== '' + }) + .valueOf() + + if (!isValidValue) { + throw 'distinctAndCount could not work when one or more fields are objects: ' + tojson(r.values) } - throw 'distinctAndCount fields could not be objects: ' + tojson(r.values) + + var key = + _(r.values) + .chain() + .values() + .map(function(value) { + if (_(value.valueOf).isFunction()) { + value = value.valueOf() + } + if (_(value).isArray()) { + value = _(value).sort().valueOf() + } + return value + }) + .valueOf() + .join(',') + + all[key] = (all[key] || 0) + r.count + + return all }, {}) }