mongo 1.2.rc1 → 1.2.rc2

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,7 +3,7 @@
3
3
  $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
4
 
5
5
  module Mongo
6
- VERSION = "1.2.rc1"
6
+ VERSION = "1.2.rc2"
7
7
  end
8
8
 
9
9
  module Mongo
@@ -556,17 +556,28 @@ module Mongo
556
556
 
557
557
  # Perform a group aggregation.
558
558
  #
559
- # @param [Array, String, BSON::Code, Nil] :key either 1) an array of fields to group by,
560
- # 2) a javascript function to generate the key object, or 3) nil.
561
- # @param [Hash] condition an optional document specifying a query to limit the documents over which group is run.
562
- # @param [Hash] initial initial value of the aggregation counter object
563
- # @param [String, BSON::Code] reduce aggregation function, in JavaScript
564
- # @param [String, BSON::Code] finalize :: optional. a JavaScript function that receives and modifies
565
- # each of the resultant grouped objects. Available only when group is run
566
- # with command set to true.
567
- #
568
- # @return [Array] the grouped items.
569
- def group(key, condition, initial, reduce, finalize=nil)
559
+ # @param [Hash] opts the options for this group operation. The minimum required are :initial
560
+ # and :reduce.
561
+ #
562
+ # @option opts [Array, String, Symbol] :key (nil) Either the name of a field or a list of fields to group by (optional).
563
+ # @option opts [String, BSON::Code] :keyf (nil) A JavaScript function to be used to generate the grouping keys (optional).
564
+ # @option opts [String, BSON::Code] :cond ({}) A document specifying a query for filtering the documents over
565
+ # which the aggregation is run (optional).
566
+ # @option opts [Hash] :initial the initial value of the aggregation counter object (required).
567
+ # @option opts [String, BSON::Code] :reduce (nil) a JavaScript aggregation function (required).
568
+ # @option opts [String, BSON::Code] :finalize (nil) a JavaScript function that receives and modifies
569
+ # each of the resultant grouped objects. Available only when group is run with command
570
+ # set to true.
571
+ #
572
+ # @return [Array] the command response consisting of grouped items.
573
+ def group(key, condition={}, initial={}, reduce=nil, finalize=nil)
574
+ if key.is_a?(Hash)
575
+ return new_group(key)
576
+ else
577
+ warn "Collection#group no longer take a list of paramters. This usage is deprecated." +
578
+ "Check out the new API at http://api.mongodb.org/ruby/current/Mongo/Collection.html#group-instance_method"
579
+ end
580
+
570
581
  reduce = BSON::Code.new(reduce) unless reduce.is_a?(BSON::Code)
571
582
 
572
583
  group_command = {
@@ -578,6 +589,11 @@ module Mongo
578
589
  }
579
590
  }
580
591
 
592
+ if key.is_a?(Symbol)
593
+ raise MongoArgumentError, "Group takes either an array of fields to group by or a JavaScript function" +
594
+ "in the form of a String or BSON::Code."
595
+ end
596
+
581
597
  unless key.nil?
582
598
  if key.is_a? Array
583
599
  key_type = "key"
@@ -605,6 +621,48 @@ module Mongo
605
621
  end
606
622
  end
607
623
 
624
+ private
625
+
626
+ def new_group(opts={})
627
+ reduce = opts[:reduce]
628
+ finalize = opts[:finalize]
629
+ cond = opts.fetch(:cond, {})
630
+ initial = opts[:initial]
631
+
632
+ if !(reduce && initial)
633
+ raise MongoArgumentError, "Group requires at minimum values for initial and reduce."
634
+ end
635
+
636
+ cmd = {
637
+ "group" => {
638
+ "ns" => @name,
639
+ "$reduce" => reduce.to_bson_code,
640
+ "cond" => cond,
641
+ "initial" => initial
642
+ }
643
+ }
644
+
645
+ if finalize
646
+ cmd['group']['finalize'] = finalize.to_bson_code
647
+ end
648
+
649
+ if key = opts[:key]
650
+ if key.is_a?(String) || key.is_a?(Symbol)
651
+ key = [key]
652
+ end
653
+ key_value = {}
654
+ key.each { |k| key_value[k] = 1 }
655
+ cmd["group"]["key"] = key_value
656
+ elsif keyf = opts[:keyf]
657
+ cmd["group"]["$keyf"] = keyf.to_bson_code
658
+ end
659
+
660
+ result = @db.command(cmd)
661
+ result["retval"]
662
+ end
663
+
664
+ public
665
+
608
666
  # Return a list of distinct values for +key+ across all
609
667
  # documents in the collection. The key may use dot notation
610
668
  # to reach into an embedded object.
@@ -48,3 +48,13 @@ class Hash
48
48
  end
49
49
 
50
50
  end
51
+
52
+ #:nodoc:
53
+ class String
54
+
55
+ #:nodoc:
56
+ def to_bson_code
57
+ BSON::Code.new(self)
58
+ end
59
+
60
+ end
@@ -150,6 +150,12 @@ class BSONTest < Test::Unit::TestCase
150
150
  assert_doc_pass(doc)
151
151
  end
152
152
 
153
+ def test_code_with_symbol
154
+ assert_raise_error ArgumentError, "BSON::Code must be in the form of a String" do
155
+ Code.new(:fubar)
156
+ end
157
+ end
158
+
153
159
  def test_code_with_scope
154
160
  doc = {'$where' => Code.new('this.a.b < this.b', {'foo' => 1})}
155
161
  assert_doc_pass(doc)
@@ -626,15 +626,25 @@ class TestCollection < Test::Unit::TestCase
626
626
  @reduce_function = "function (obj, prev) { prev.count += inc_value; }"
627
627
  end
628
628
 
629
+ should "fail if missing required options" do
630
+ assert_raise MongoArgumentError do
631
+ @@test.group(:initial => {})
632
+ end
633
+
634
+ assert_raise MongoArgumentError do
635
+ @@test.group(:reduce => "foo")
636
+ end
637
+ end
638
+
629
639
  should "group results using eval form" do
630
- assert_equal 1, @@test.group([], {}, @initial, Code.new(@reduce_function, {"inc_value" => 0.5}))[0]["count"]
631
- assert_equal 2, @@test.group([], {}, @initial, Code.new(@reduce_function, {"inc_value" => 1}))[0]["count"]
632
- assert_equal 4, @@test.group([], {}, @initial, Code.new(@reduce_function, {"inc_value" => 2}))[0]["count"]
640
+ assert_equal 1, @@test.group(:initial => @initial, :reduce => Code.new(@reduce_function, {"inc_value" => 0.5}))[0]["count"]
641
+ assert_equal 2, @@test.group(:initial => @initial, :reduce => Code.new(@reduce_function, {"inc_value" => 1}))[0]["count"]
642
+ assert_equal 4, @@test.group(:initial => @initial, :reduce => Code.new(@reduce_function, {"inc_value" => 2}))[0]["count"]
633
643
  end
634
644
 
635
645
  should "finalize grouped results" do
636
646
  @finalize = "function(doc) {doc.f = doc.count + 200; }"
637
- assert_equal 202, @@test.group([], {}, @initial, Code.new(@reduce_function, {"inc_value" => 1}), @finalize)[0]["f"]
647
+ assert_equal 202, @@test.group(:initial => @initial, :reduce => Code.new(@reduce_function, {"inc_value" => 1}), :finalize => @finalize)[0]["f"]
638
648
  end
639
649
  end
640
650
 
@@ -650,7 +660,7 @@ class TestCollection < Test::Unit::TestCase
650
660
  end
651
661
 
652
662
  should "group" do
653
- result = @@test.group([:a], {}, @initial, @reduce_function, nil)
663
+ result = @@test.group(:key => :a, :initial => @initial, :reduce => @reduce_function)
654
664
  assert result.all? { |r| r['count'] == 200 }
655
665
  end
656
666
  end
@@ -669,10 +679,17 @@ class TestCollection < Test::Unit::TestCase
669
679
  end
670
680
 
671
681
  should "group results" do
672
- results = @@test.group(@keyf, {}, @initial, @reduce).sort {|a, b| a['count'] <=> b['count']}
682
+ results = @@test.group(:keyf => @keyf, :initial => @initial, :reduce => @reduce).sort {|a, b| a['count'] <=> b['count']}
673
683
  assert results[0]['even'] && results[0]['count'] == 2.0
674
684
  assert results[1]['odd'] && results[1]['count'] == 3.0
675
685
  end
686
+
687
+ should "group filtered results" do
688
+ results = @@test.group(:keyf => @keyf, :cond => {:a => {'$ne' => 2}},
689
+ :initial => @initial, :reduce => @reduce).sort {|a, b| a['count'] <=> b['count']}
690
+ assert results[0]['even'] && results[0]['count'] == 1.0
691
+ assert results[1]['odd'] && results[1]['count'] == 3.0
692
+ end
676
693
  end
677
694
 
678
695
  context "A collection with two records" do
@@ -509,33 +509,37 @@ class DBAPITest < Test::Unit::TestCase
509
509
  @@db.drop_collection("test")
510
510
  test = @@db.collection("test")
511
511
 
512
- assert_equal [], test.group([], {}, {"count" => 0}, "function (obj, prev) { prev.count++; }")
513
- assert_equal [], test.group([], {}, {"count" => 0}, "function (obj, prev) { prev.count++; }")
512
+ assert_equal [], test.group(:initial => {"count" => 0}, :reduce => "function (obj, prev) { prev.count++; }")
513
+ assert_equal [], test.group(:initial => {"count" => 0}, :reduce => "function (obj, prev) { prev.count++; }")
514
514
 
515
515
  test.insert("a" => 2)
516
516
  test.insert("b" => 5)
517
517
  test.insert("a" => 1)
518
518
 
519
- assert_equal 3, test.group([], {}, {"count" => 0}, "function (obj, prev) { prev.count++; }")[0]["count"]
520
- assert_equal 3, test.group([], {}, {"count" => 0}, "function (obj, prev) { prev.count++; }")[0]["count"]
521
- assert_equal 1, test.group([], {"a" => {"$gt" => 1}}, {"count" => 0}, "function (obj, prev) { prev.count++; }")[0]["count"]
522
- assert_equal 1, test.group([], {"a" => {"$gt" => 1}}, {"count" => 0}, "function (obj, prev) { prev.count++; }")[0]["count"]
519
+ assert_equal 3, test.group(:initial => {"count" => 0},
520
+ :reduce => "function (obj, prev) { prev.count++; }")[0]["count"]
521
+ assert_equal 3, test.group(:initial => {"count" => 0},
522
+ :reduce => "function (obj, prev) { prev.count++; }")[0]["count"]
523
+ assert_equal 1, test.group(:cond => {"a" => {"$gt" => 1}},
524
+ :initial => {"count" => 0}, :reduce => "function (obj, prev) { prev.count++; }")[0]["count"]
525
+ assert_equal 1, test.group(:cond => {"a" => {"$gt" => 1}},
526
+ :initial => {"count" => 0}, :reduce => "function (obj, prev) { prev.count++; }")[0]["count"]
523
527
 
524
528
  finalize = "function (obj) { obj.f = obj.count - 1; }"
525
- assert_equal 2, test.group([], {}, {"count" => 0}, "function (obj, prev) { prev.count++; }", finalize)[0]["f"]
529
+ assert_equal 2, test.group(:initial => {"count" => 0},
530
+ :reduce => "function (obj, prev) { prev.count++; }", :finalize => finalize)[0]["f"]
526
531
 
527
532
  test.insert("a" => 2, "b" => 3)
528
533
  expected = [{"a" => 2, "count" => 2},
529
534
  {"a" => nil, "count" => 1},
530
535
  {"a" => 1, "count" => 1}]
531
- assert_equal expected, test.group(["a"], {}, {"count" => 0}, "function (obj, prev) { prev.count++; }")
532
- assert_equal expected, test.group(["a"], {}, {"count" => 0}, "function (obj, prev) { prev.count++; }", true)
536
+ assert_equal expected, test.group(:key => ["a"], :initial => {"count" => 0},
537
+ :reduce => "function (obj, prev) { prev.count++; }")
538
+ assert_equal expected, test.group(:key => :a, :initial => {"count" => 0},
539
+ :reduce => "function (obj, prev) { prev.count++; }")
533
540
 
534
541
  assert_raise OperationFailure do
535
- test.group([], {}, {}, "5 ++ 5")
536
- end
537
- assert_raise OperationFailure do
538
- test.group([], {}, {}, "5 ++ 5", true)
542
+ test.group(:initial => {}, :reduce => "5 ++ 5")
539
543
  end
540
544
  end
541
545
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongo
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15424231
4
+ hash: 15424225
5
5
  prerelease: 4
6
6
  segments:
7
7
  - 1
8
8
  - 2
9
9
  - rc
10
- - 1
11
- version: 1.2.rc1
10
+ - 2
11
+ version: 1.2.rc2
12
12
  platform: ruby
13
13
  authors:
14
14
  - Jim Menard
@@ -18,7 +18,7 @@ autorequire:
18
18
  bindir: bin
19
19
  cert_chain: []
20
20
 
21
- date: 2011-01-05 00:00:00 -05:00
21
+ date: 2011-01-06 00:00:00 -05:00
22
22
  default_executable:
23
23
  dependencies:
24
24
  - !ruby/object:Gem::Dependency
@@ -29,13 +29,13 @@ dependencies:
29
29
  requirements:
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
- hash: 15424231
32
+ hash: 15424225
33
33
  segments:
34
34
  - 1
35
35
  - 2
36
36
  - rc
37
- - 1
38
- version: 1.2.rc1
37
+ - 2
38
+ version: 1.2.rc2
39
39
  type: :runtime
40
40
  version_requirements: *id001
41
41
  description: A Ruby driver for MongoDB. For more information about Mongo, see http://www.mongodb.org.