plucky 0.6.3 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -3
  3. data/.rspec +1 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +7 -4
  6. data/Gemfile +6 -5
  7. data/Gemfile.lock +84 -0
  8. data/LICENSE +1 -1
  9. data/README.md +17 -75
  10. data/Rakefile +0 -3
  11. data/examples/query.rb +8 -7
  12. data/lib/plucky.rb +1 -0
  13. data/lib/plucky/criteria_hash.rb +78 -62
  14. data/lib/plucky/extensions/symbol.rb +8 -0
  15. data/lib/plucky/normalizers/criteria_hash_value.rb +3 -1
  16. data/lib/plucky/normalizers/fields_value.rb +3 -3
  17. data/lib/plucky/normalizers/hash_key.rb +19 -0
  18. data/lib/plucky/normalizers/options_hash_value.rb +5 -7
  19. data/lib/plucky/normalizers/sort_value.rb +8 -6
  20. data/lib/plucky/options_hash.rb +9 -3
  21. data/lib/plucky/pagination.rb +1 -1
  22. data/lib/plucky/pagination/{decorator.rb → collection.rb} +10 -1
  23. data/lib/plucky/query.rb +56 -21
  24. data/lib/plucky/transformer.rb +14 -0
  25. data/lib/plucky/version.rb +1 -1
  26. data/plucky.gemspec +4 -5
  27. data/script/bootstrap +21 -0
  28. data/script/release +42 -0
  29. data/script/test +20 -0
  30. data/spec/functional/options_hash_spec.rb +41 -0
  31. data/spec/helper.rb +12 -4
  32. data/spec/plucky/criteria_hash_spec.rb +68 -4
  33. data/spec/plucky/normalizers/criteria_hash_value_spec.rb +1 -1
  34. data/spec/plucky/normalizers/fields_value_spec.rb +5 -5
  35. data/spec/plucky/normalizers/hash_key_spec.rb +15 -0
  36. data/spec/plucky/normalizers/options_hash_value_spec.rb +2 -2
  37. data/spec/plucky/normalizers/sort_value_spec.rb +24 -20
  38. data/spec/plucky/options_hash_spec.rb +2 -2
  39. data/spec/plucky/pagination/{decorator_spec.rb → collection_spec.rb} +8 -5
  40. data/spec/plucky/query_spec.rb +92 -35
  41. data/spec/plucky_spec.rb +5 -5
  42. data/spec/symbol_operator_spec.rb +18 -1
  43. metadata +37 -36
  44. data/lib/plucky/normalizers/options_hash_key.rb +0 -23
  45. data/script/criteria_hash.rb +0 -21
  46. data/spec/plucky/normalizers/options_hash_key_spec.rb +0 -23
@@ -0,0 +1,20 @@
1
+ #!/bin/sh
2
+ #/ Usage: test
3
+ #/
4
+ #/ Bootstrap and run all tests.
5
+ #/
6
+ #/ Examples:
7
+ #/
8
+ #/ # run all tests
9
+ #/ test
10
+ #/
11
+
12
+ set -e
13
+ cd $(dirname "$0")/..
14
+
15
+ [ "$1" = "--help" -o "$1" = "-h" -o "$1" = "help" ] && {
16
+ grep '^#/' <"$0"| cut -c4-
17
+ exit 0
18
+ }
19
+
20
+ script/bootstrap && bundle exec rake
@@ -0,0 +1,41 @@
1
+ require 'helper'
2
+
3
+ describe Plucky::OptionsHash do
4
+ subject { described_class.new }
5
+
6
+ describe "#[]=" do
7
+ it "changes order to sort" do
8
+ subject[:order] = "foo asc"
9
+ subject[:sort].should == {"foo" => 1}
10
+ subject[:order].should be_nil
11
+ end
12
+
13
+ it "changes sort(id) to sort(_id)" do
14
+ subject[:sort] = "id asc"
15
+ subject[:sort].should == {"_id" => 1}
16
+ end
17
+
18
+ it "changes select to fields" do
19
+ subject[:select] = [:foo]
20
+ subject[:projection].should == {:foo => 1}
21
+ subject[:select].should be_nil
22
+ end
23
+
24
+ it "changes offset to skip" do
25
+ subject[:offset] = 10
26
+ subject[:skip].should == 10
27
+ subject[:offset].should be_nil
28
+ end
29
+
30
+ it "changes id to _id" do
31
+ subject[:id] = :foo
32
+ subject[:_id].should == :foo
33
+ subject[:id].should be_nil
34
+ end
35
+
36
+ it "does not change the sort field" do
37
+ subject[:order] = :order.asc
38
+ subject[:sort].should == {"order" => 1}
39
+ end
40
+ end
41
+ end
@@ -11,14 +11,19 @@ require 'fileutils'
11
11
  require 'logger'
12
12
  require 'pp'
13
13
 
14
+ if RUBY_ENGINE == "ruby" && RUBY_VERSION >= '2.3'
15
+ require 'byebug'
16
+ end
17
+
14
18
  log_dir = File.expand_path('../../log', __FILE__)
15
19
  FileUtils.mkdir_p(log_dir)
16
20
  Log = Logger.new(File.join(log_dir, 'test.log'))
17
21
 
18
22
  LogBuddy.init :logger => Log
19
23
 
20
- connection = Mongo::MongoClient.new('127.0.0.1', 27017, :logger => Log)
21
- DB = connection.db('test')
24
+ port = ENV.fetch "BOXEN_MONGODB_PORT", 27017
25
+ connection = Mongo::Client.new(["127.0.0.1:#{port.to_i}"], :logger => Log)
26
+ DB = connection.use('test').database
22
27
 
23
28
  RSpec.configure do |config|
24
29
  config.filter_run :focused => true
@@ -26,16 +31,19 @@ RSpec.configure do |config|
26
31
  config.alias_example_to :xit, :pending => true
27
32
  config.run_all_when_everything_filtered = true
28
33
 
34
+ config.expect_with(:rspec) { |c| c.syntax = :should }
35
+ config.mock_with(:rspec) { |c| c.syntax = :should }
36
+
29
37
  config.before(:suite) do
30
38
  DB.collections.reject { |collection|
31
39
  collection.name =~ /system\./
32
- }.map(&:drop_indexes)
40
+ }.each { |collection| collection.indexes.drop_all}
33
41
  end
34
42
 
35
43
  config.before(:each) do
36
44
  DB.collections.reject { |collection|
37
45
  collection.name =~ /system\./
38
- }.map(&:remove)
46
+ }.map(&:drop)
39
47
  end
40
48
  end
41
49
 
@@ -37,9 +37,9 @@ describe Plucky::CriteriaHash do
37
37
  end
38
38
 
39
39
  it "raises argument error if not array" do
40
- expect { described_class.new.object_ids = {} }.to raise_error(ArgumentError)
41
- expect { described_class.new.object_ids = nil }.to raise_error(ArgumentError)
42
- expect { described_class.new.object_ids = 'foo' }.to raise_error(ArgumentError)
40
+ lambda { described_class.new.object_ids = {} }.should raise_error(ArgumentError)
41
+ lambda { described_class.new.object_ids = nil }.should raise_error(ArgumentError)
42
+ lambda { described_class.new.object_ids = 'foo' }.should raise_error(ArgumentError)
43
43
  end
44
44
  end
45
45
 
@@ -90,7 +90,7 @@ describe Plucky::CriteriaHash do
90
90
  it "uniques matching key values" do
91
91
  c1 = described_class.new(:foo => 'bar')
92
92
  c2 = described_class.new(:foo => 'bar')
93
- c1.merge(c2).source.should eq(:foo => {:$in => %w[bar]})
93
+ c1.merge(c2).source.should eq(:foo => 'bar')
94
94
  end
95
95
 
96
96
  it "correctly merges arrays and non-arrays" do
@@ -147,6 +147,70 @@ describe Plucky::CriteriaHash do
147
147
  c1.merge(c2).should_not equal(c1)
148
148
  c1[:foo].should == 'bar'
149
149
  end
150
+
151
+ it "merges two hashes with the same key, but nil values as nil" do
152
+ c1 = described_class.new(:foo => nil)
153
+ c2 = described_class.new(:foo => nil)
154
+ c1.merge(c2).source.should == { :foo => nil }
155
+ end
156
+
157
+ it "merges two hashes with the same key, but false values as false" do
158
+ c1 = described_class.new(:foo => false)
159
+ c2 = described_class.new(:foo => false)
160
+ c1.merge(c2).source.should == { :foo => false }
161
+ end
162
+
163
+ it "merges two hashes with the same key, but different values with $in" do
164
+ c1 = described_class.new(:foo => false)
165
+ c2 = described_class.new(:foo => true)
166
+ c1.merge(c2).source.should == { :foo => { :'$in' => [false, true] } }
167
+ end
168
+
169
+ it "merges two hashes with different keys and different values properly" do
170
+ c1 = described_class.new(:foo => 1)
171
+ c2 = described_class.new(:bar => 2)
172
+ c1.merge(c2).source.should == { :foo => 1, :bar => 2 }
173
+ end
174
+
175
+ it "merges two sets" do
176
+ c1 = described_class.new(:foo => Set.new([1, 2]))
177
+ c2 = described_class.new(:foo => Set.new([2, 3]))
178
+ c1.merge(c2).source.should == { :foo => { :'$in' => [1,2,3] } }
179
+ end
180
+
181
+ context "given multiple $or clauses" do
182
+ before do
183
+ @c1 = described_class.new(:$or => [{:a => 1}, {:b => 2}])
184
+ @c2 = described_class.new(:$or => [{:a => 3}, {:b => 4}])
185
+ @c3 = described_class.new(:$or => [{:a => 4}, {:b => 4}])
186
+ end
187
+
188
+ it "merges two $ors into a compound $and" do
189
+ merged = @c1.merge(@c2)
190
+ merged[:$and].should == [
191
+ {:$or => [{:a => 1}, {:b => 2}]},
192
+ {:$or => [{:a => 3}, {:b => 4}]}
193
+ ]
194
+ end
195
+
196
+ it "merges an $and and a $or into a compound $and" do
197
+ merged = @c1.merge(@c2).merge(@c3)
198
+ merged[:$and].should == [
199
+ {:$or => [{:a => 1}, {:b => 2}]},
200
+ {:$or => [{:a => 3}, {:b => 4}]},
201
+ {:$or => [{:a => 4}, {:b => 4}]}
202
+ ]
203
+ end
204
+
205
+ it "merges an $or and an $and into a compound $and" do
206
+ merged = @c3.merge @c1.merge(@c2)
207
+ merged[:$and].should == [
208
+ {:$or => [{:a => 1}, {:b => 2}]},
209
+ {:$or => [{:a => 3}, {:b => 4}]},
210
+ {:$or => [{:a => 4}, {:b => 4}]}
211
+ ]
212
+ end
213
+ end
150
214
  end
151
215
 
152
216
  context "#merge!" do
@@ -155,7 +155,7 @@ describe Plucky::Normalizers::CriteriaHashValue do
155
155
 
156
156
  context "nested clauses" do
157
157
  it "knows constant array of operators that take nested queries" do
158
- described_class::NestingOperators.should == [:$or, :$and, :$nor]
158
+ described_class::NestingOperators.should == Set[:$or, :$and, :$nor]
159
159
  end
160
160
 
161
161
  described_class::NestingOperators.each do |operator|
@@ -15,7 +15,7 @@ describe Plucky::Normalizers::FieldsValue do
15
15
  end
16
16
 
17
17
  it "works with array" do
18
- subject.call(['one', 'two']).should eq(['one', 'two'])
18
+ subject.call(['one', 'two']).should eq({'one' => 1, 'two' => 1})
19
19
  end
20
20
 
21
21
  # Ruby 1.9.x was sending array [{:age => 20}], instead of hash.
@@ -24,15 +24,15 @@ describe Plucky::Normalizers::FieldsValue do
24
24
  end
25
25
 
26
26
  it "flattens multi-dimensional array" do
27
- subject.call([[:one, :two]]).should eq([:one, :two])
27
+ subject.call([[:one, :two]]).should eq({:one => 1, :two => 1})
28
28
  end
29
29
 
30
30
  it "works with symbol" do
31
- subject.call(:one).should eq([:one])
31
+ subject.call(:one).should eq({:one => 1})
32
32
  end
33
33
 
34
34
  it "works with array of symbols" do
35
- subject.call([:one, :two]).should eq([:one, :two])
35
+ subject.call([:one, :two]).should eq({:one => 1, :two => 1})
36
36
  end
37
37
 
38
38
  it "works with hash" do
@@ -40,6 +40,6 @@ describe Plucky::Normalizers::FieldsValue do
40
40
  end
41
41
 
42
42
  it "converts comma separated list to array" do
43
- subject.call('one, two').should eq(['one', 'two'])
43
+ subject.call('one, two').should eq({'one' => 1, 'two' => 1})
44
44
  end
45
45
  end
@@ -0,0 +1,15 @@
1
+ require 'helper'
2
+
3
+ describe Plucky::Normalizers::HashKey do
4
+ subject {
5
+ described_class.new(:bacon => :sizzle)
6
+ }
7
+
8
+ it "changes defined fields" do
9
+ subject.call(:bacon).should eq(:sizzle)
10
+ end
11
+
12
+ it "does not change undefined fields" do
13
+ subject.call(:sausage).should eq(:sausage)
14
+ end
15
+ end
@@ -26,9 +26,9 @@ describe Plucky::Normalizers::OptionsHashValue do
26
26
  }
27
27
 
28
28
  it "raises exception if missing key normalizer" do
29
- expect {
29
+ lambda {
30
30
  described_class.new
31
- }.to raise_error(ArgumentError, "Missing required key :key_normalizer")
31
+ }.should raise_error(ArgumentError, "Missing required key :key_normalizer")
32
32
  end
33
33
 
34
34
  it "allows injecting a new value normalizer" do
@@ -3,7 +3,7 @@ require 'plucky/normalizers/sort_value'
3
3
 
4
4
  describe Plucky::Normalizers::SortValue do
5
5
  let(:key_normalizer) {
6
- lambda { |key| key == :id ? :_id : key.to_sym }
6
+ Plucky::Normalizers::HashKey.new({:id => :_id})
7
7
  }
8
8
 
9
9
  subject {
@@ -13,9 +13,9 @@ describe Plucky::Normalizers::SortValue do
13
13
  }
14
14
 
15
15
  it "raises exception if missing key normalizer" do
16
- expect {
16
+ lambda {
17
17
  described_class.new
18
- }.to raise_error(ArgumentError, "Missing required key :key_normalizer")
18
+ }.should raise_error(ArgumentError, "Missing required key :key_normalizer")
19
19
  end
20
20
 
21
21
  it "defaults to nil" do
@@ -31,64 +31,68 @@ describe Plucky::Normalizers::SortValue do
31
31
  end
32
32
 
33
33
  it "converts single ascending field (string)" do
34
- subject.call('foo asc').should eq([['foo', 1]])
35
- subject.call('foo ASC').should eq([['foo', 1]])
34
+ subject.call('foo asc').should eq({'foo' => 1})
35
+ subject.call('foo ASC').should eq({'foo' => 1})
36
36
  end
37
37
 
38
38
  it "converts single descending field (string)" do
39
- subject.call('foo desc').should eq([['foo', -1]])
40
- subject.call('foo DESC').should eq([['foo', -1]])
39
+ subject.call('foo desc').should eq({'foo' => -1})
40
+ subject.call('foo DESC').should eq({'foo' => -1})
41
41
  end
42
42
 
43
43
  it "converts multiple fields (string)" do
44
- subject.call('foo desc, bar asc').should eq([['foo', -1], ['bar', 1]])
44
+ subject.call('foo desc, bar asc').should eq({'foo' => -1, 'bar' => 1})
45
45
  end
46
46
 
47
47
  it "converts multiple fields and default no direction to ascending (string)" do
48
- subject.call('foo desc, bar, baz').should eq([['foo', -1], ['bar', 1], ['baz', 1]])
48
+ subject.call('foo desc, bar, baz').should eq({'foo' => -1, 'bar' => 1, 'baz' => 1})
49
49
  end
50
50
 
51
51
  it "converts symbol" do
52
- subject.call(:name).should eq([['name', 1]])
52
+ subject.call(:name).should eq({'name' => 1})
53
53
  end
54
54
 
55
55
  it "converts operator" do
56
- subject.call(:foo.desc).should eq([['foo', -1]])
56
+ subject.call(:foo.desc).should eq({'foo' => -1})
57
57
  end
58
58
 
59
59
  it "converts array of operators" do
60
- subject.call([:foo.desc, :bar.asc]).should eq([['foo', -1], ['bar', 1]])
60
+ subject.call([:foo.desc, :bar.asc]).should eq({'foo' => -1, 'bar' => 1})
61
61
  end
62
62
 
63
63
  it "converts array of symbols" do
64
- subject.call([:first_name, :last_name]).should eq([['first_name', 1], ['last_name', 1]])
64
+ subject.call([:first_name, :last_name]).should eq({'first_name' => 1, 'last_name' => 1})
65
65
  end
66
66
 
67
67
  it "works with array and one string element" do
68
- subject.call(['foo, bar desc']).should eq([['foo', 1], ['bar', -1]])
68
+ subject.call(['foo, bar desc']).should eq({'foo' => 1, 'bar' => -1})
69
69
  end
70
70
 
71
71
  it "works with array of single array" do
72
- subject.call([['foo', -1]]).should eq([['foo', -1]])
72
+ subject.call([['foo', -1]]).should eq({'foo' => -1})
73
73
  end
74
74
 
75
75
  it "works with array of multiple arrays" do
76
- subject.call([['foo', -1], ['bar', 1]]).should eq([['foo', -1], ['bar', 1]])
76
+ subject.call([['foo', -1], ['bar', 1]]).should eq({'foo' => -1, 'bar' => 1})
77
77
  end
78
78
 
79
79
  it "compacts nil values in array" do
80
- subject.call([nil, :foo.desc]).should eq([['foo', -1]])
80
+ subject.call([nil, :foo.desc]).should eq({'foo' => -1})
81
81
  end
82
82
 
83
83
  it "converts array with mix of values" do
84
- subject.call([:foo.desc, 'bar']).should eq([['foo', -1], ['bar', 1]])
84
+ subject.call([:foo.desc, 'bar']).should eq({'foo' => -1, 'bar' => 1})
85
85
  end
86
86
 
87
87
  it "converts keys based on key normalizer" do
88
- subject.call([:id.asc]).should eq([['_id', 1]])
88
+ subject.call([:id.asc]).should eq({'_id' => 1})
89
+ end
90
+
91
+ it "doesn't convert keys like :sort to :order via key normalizer" do
92
+ subject.call(:order.asc).should eq({'order' => 1})
89
93
  end
90
94
 
91
95
  it "converts string with $natural correctly" do
92
- subject.call('$natural desc').should eq([['$natural', -1]])
96
+ subject.call('$natural desc').should eq({'$natural' => -1})
93
97
  end
94
98
  end
@@ -3,7 +3,7 @@ require 'helper'
3
3
  describe Plucky::OptionsHash do
4
4
  describe "#initialize_copy" do
5
5
  before do
6
- @original = described_class.new(:fields => {:name => true}, :sort => :name, :limit => 10)
6
+ @original = described_class.new(:projection => {:name => true}, :sort => :name, :limit => 10)
7
7
  @cloned = @original.clone
8
8
  end
9
9
 
@@ -12,7 +12,7 @@ describe Plucky::OptionsHash do
12
12
  end
13
13
 
14
14
  it "clones duplicable? values" do
15
- @cloned[:fields].should_not equal(@original[:fields])
15
+ @cloned[:projection].should_not equal(@original[:projection])
16
16
  @cloned[:sort].should_not equal(@original[:sort])
17
17
  end
18
18
  end
@@ -1,15 +1,13 @@
1
1
  require 'helper'
2
2
 
3
- describe Plucky::Pagination::Decorator do
4
- context "Object decorated with Decorator with paginator set" do
3
+ describe Plucky::Pagination::Collection do
4
+ context "Object decorated with Collection with paginator set" do
5
5
  before do
6
6
  @object = [1, 2, 3, 4]
7
7
  @object_id = @object.object_id
8
8
  @paginator = Plucky::Pagination::Paginator.new(20, 2, 10)
9
- @object.extend(described_class)
10
- @object.paginator(@paginator)
11
9
  end
12
- subject { @object }
10
+ subject { Plucky::Pagination::Collection.new(@object, @paginator) }
13
11
 
14
12
  it "knows paginator" do
15
13
  subject.paginator.should == @paginator
@@ -28,5 +26,10 @@ describe Plucky::Pagination::Decorator do
28
26
  @object.size.should == 4
29
27
  @object.select { |o| o > 2 }.should == [3, 4]
30
28
  end
29
+
30
+ it "delegates missing methods to the paginator" do
31
+ @paginator.should_receive(:blather_matter).with('hello', :xyz, 4)
32
+ subject.blather_matter('hello', :xyz, 4)
33
+ end
31
34
  end
32
35
  end
@@ -2,13 +2,13 @@ require 'helper'
2
2
 
3
3
  describe Plucky::Query do
4
4
  before do
5
- @chris = BSON::OrderedHash['_id', 'chris', 'age', 26, 'name', 'Chris']
6
- @steve = BSON::OrderedHash['_id', 'steve', 'age', 29, 'name', 'Steve']
7
- @john = BSON::OrderedHash['_id', 'john', 'age', 28, 'name', 'John']
5
+ @chris = Hash['_id', 'chris', 'age', 26, 'name', 'Chris']
6
+ @steve = Hash['_id', 'steve', 'age', 29, 'name', 'Steve']
7
+ @john = Hash['_id', 'john', 'age', 28, 'name', 'John']
8
8
  @collection = DB['users']
9
- @collection.insert(@chris)
10
- @collection.insert(@steve)
11
- @collection.insert(@john)
9
+ @collection.insert_one(@chris)
10
+ @collection.insert_one(@steve)
11
+ @collection.insert_one(@john)
12
12
  end
13
13
 
14
14
  context "#initialize" do
@@ -57,7 +57,7 @@ describe Plucky::Query do
57
57
  context "#find_each" do
58
58
  it "returns a cursor" do
59
59
  cursor = described_class.new(@collection).find_each
60
- cursor.should be_instance_of(Mongo::Cursor)
60
+ cursor.should be_instance_of(Enumerator)
61
61
  end
62
62
 
63
63
  it "works with and normalize criteria" do
@@ -78,8 +78,8 @@ describe Plucky::Query do
78
78
 
79
79
  it "is Ruby-like and returns a reset cursor if a block is given" do
80
80
  cursor = described_class.new(@collection).find_each {}
81
- cursor.should be_instance_of(Mongo::Cursor)
82
- cursor.next.should be_instance_of(BSON::OrderedHash)
81
+ cursor.should be_instance_of(Enumerator)
82
+ cursor.next.should be_kind_of(Hash)
83
83
  end
84
84
  end
85
85
 
@@ -128,7 +128,7 @@ describe Plucky::Query do
128
128
  end
129
129
 
130
130
  it "normalizes if using object id" do
131
- id = @collection.insert(:name => 'Frank')
131
+ id = @collection.insert_one(:name => 'Frank').inserted_id
132
132
  @query.object_ids([:_id])
133
133
  doc = @query.find(id.to_s)
134
134
  doc['name'].should == 'Frank'
@@ -203,6 +203,27 @@ describe Plucky::Query do
203
203
  end
204
204
  end
205
205
 
206
+ context "#view" do
207
+ it 'returns a mongo::collection::view' do
208
+ described_class.new(@collection).view.should be_a(Mongo::Collection::View)
209
+ end
210
+
211
+ it 'converts criteria into the view' do
212
+ view = described_class.new(@collection).where(:name => "bob").view
213
+ view.filter.should == {"name" => "bob"}
214
+ end
215
+
216
+ it "converts read option symbol to a server selector" do
217
+ view = described_class.new(@collection, :read => :secondary_preferred).view
218
+ view.read.should be_a(Mongo::ServerSelector::SecondaryPreferred)
219
+ end
220
+
221
+ it "converts read option hash to a server selector" do
222
+ view = described_class.new(@collection, :read => {:mode =>:secondary_preferred}).view
223
+ view.read.should be_a(Mongo::ServerSelector::SecondaryPreferred)
224
+ end
225
+ end
226
+
206
227
  context "#all" do
207
228
  it "works with no arguments" do
208
229
  docs = described_class.new(@collection).all
@@ -279,6 +300,10 @@ describe Plucky::Query do
279
300
  query.count(:name => 'Steve')
280
301
  query[:name].should be_nil
281
302
  end
303
+
304
+ it 'counts the result set and not the enumerator' do
305
+ described_class.new(@collection).limit(1).count.should == 3
306
+ end
282
307
  end
283
308
 
284
309
  context "#size" do
@@ -290,8 +315,8 @@ describe Plucky::Query do
290
315
  context "#distinct" do
291
316
  before do
292
317
  # same age as John
293
- @mark = BSON::OrderedHash['_id', 'mark', 'age', 28, 'name', 'Mark']
294
- @collection.insert(@mark)
318
+ @mark = Hash['_id', 'mark', 'age', 28, 'name', 'Mark']
319
+ @collection.insert_one(@mark)
295
320
  end
296
321
 
297
322
  it "works with just a key" do
@@ -489,23 +514,23 @@ describe Plucky::Query do
489
514
  end
490
515
 
491
516
  it "works with symbol operators" do
492
- subject.sort(:foo.asc, :bar.desc).options[:sort].should == [['foo', 1], ['bar', -1]]
517
+ subject.sort(:foo.asc, :bar.desc).options[:sort].should == {"foo" => 1, "bar" => -1}
493
518
  end
494
519
 
495
520
  it "works with string" do
496
- subject.sort('foo, bar desc').options[:sort].should == [['foo', 1], ['bar', -1]]
521
+ subject.sort('foo, bar desc').options[:sort].should == {"foo" => 1, "bar" => -1}
497
522
  end
498
523
 
499
524
  it "works with just a symbol" do
500
- subject.sort(:foo).options[:sort].should == [['foo', 1]]
525
+ subject.sort(:foo).options[:sort].should == {"foo" => 1}
501
526
  end
502
527
 
503
528
  it "works with symbol descending" do
504
- subject.sort(:foo.desc).options[:sort].should == [['foo', -1]]
529
+ subject.sort(:foo.desc).options[:sort].should == {"foo" => -1}
505
530
  end
506
531
 
507
532
  it "works with multiple symbols" do
508
- subject.sort(:foo, :bar).options[:sort].should == [['foo', 1], ['bar', 1]]
533
+ subject.sort(:foo, :bar).options[:sort].should == {"foo" => 1, "bar" => 1}
509
534
  end
510
535
 
511
536
  it "returns new instance of query" do
@@ -515,8 +540,8 @@ describe Plucky::Query do
515
540
  end
516
541
 
517
542
  it "is aliased to order" do
518
- subject.order(:foo).options[:sort].should == [['foo', 1]]
519
- subject.order(:foo, :bar).options[:sort].should == [['foo', 1], ['bar', 1]]
543
+ subject.order(:foo).options[:sort].should == {"foo" => 1}
544
+ subject.order(:foo, :bar).options[:sort].should == {"foo" => 1, "bar" => 1}
520
545
  end
521
546
  end
522
547
 
@@ -529,27 +554,27 @@ describe Plucky::Query do
529
554
  end
530
555
 
531
556
  it "does not error if no sort provided" do
532
- expect {
557
+ lambda {
533
558
  subject.reverse
534
- }.to_not raise_error
559
+ }.should_not raise_error
535
560
  end
536
561
 
537
562
  it "reverses the sort order" do
538
563
  subject.sort('foo asc, bar desc').
539
- reverse.options[:sort].should == [['foo', -1], ['bar', 1]]
564
+ reverse.options[:sort].should == {"foo" => -1, "bar" => 1}
540
565
  end
541
566
 
542
567
  it "returns new instance of query" do
543
568
  sorted_query = subject.sort(:name)
544
569
  new_query = sorted_query.reverse
545
570
  new_query.should_not equal(sorted_query)
546
- sorted_query[:sort].should == [['name', 1]]
571
+ sorted_query[:sort].should == {'name' => 1}
547
572
  end
548
573
  end
549
574
 
550
575
  context "#amend" do
551
576
  it "normalizes and update options" do
552
- described_class.new(@collection).amend(:order => :age.desc).options[:sort].should == [['age', -1]]
577
+ described_class.new(@collection).amend(:order => :age.desc).options[:sort].should == {'age' => -1}
553
578
  end
554
579
 
555
580
  it "works with simple stuff" do
@@ -611,7 +636,7 @@ describe Plucky::Query do
611
636
 
612
637
  context "#empty?" do
613
638
  it "returns true if empty" do
614
- @collection.remove
639
+ @collection.drop
615
640
  described_class.new(@collection).should be_empty
616
641
  end
617
642
 
@@ -672,7 +697,7 @@ describe Plucky::Query do
672
697
  it "returns a working enumerator" do
673
698
  query = described_class.new(@collection)
674
699
  query.each.methods.map(&:to_sym).include?(:group_by).should be(true)
675
- query.each.next.should be_instance_of(BSON::OrderedHash)
700
+ query.each.next.should be_instance_of(BSON::Document)
676
701
  end
677
702
  end
678
703
 
@@ -737,8 +762,8 @@ describe Plucky::Query do
737
762
  end
738
763
 
739
764
  {
740
- :fields => ['foo'],
741
- :sort => [['foo', 1]],
765
+ :projection => {'foo' => 1},
766
+ :sort => {'foo' => 1},
742
767
  :hint => '',
743
768
  :skip => 0,
744
769
  :limit => 0,
@@ -754,14 +779,14 @@ describe Plucky::Query do
754
779
 
755
780
  it "knows select is an option and remove it from options" do
756
781
  query = described_class.new(@collection, :select => 'foo')
757
- query.options[:fields].should == ['foo']
782
+ query.options[:projection].should == {'foo' => 1}
758
783
  query.criteria.keys.should_not include(:select)
759
784
  query.options.keys.should_not include(:select)
760
785
  end
761
786
 
762
787
  it "knows order is an option and remove it from options" do
763
788
  query = described_class.new(@collection, :order => 'foo')
764
- query.options[:sort].should == [['foo', 1]]
789
+ query.options[:sort].should == {'foo' => 1}
765
790
  query.criteria.keys.should_not include(:order)
766
791
  query.options.keys.should_not include(:order)
767
792
  end
@@ -777,15 +802,15 @@ describe Plucky::Query do
777
802
  query = described_class.new(@collection, {
778
803
  :foo => 'bar',
779
804
  :baz => true,
780
- :sort => [['foo', 1]],
805
+ :sort => {"foo" => 1},
781
806
  :fields => ['foo', 'baz'],
782
807
  :limit => 10,
783
808
  :skip => 10,
784
809
  })
785
810
  query.criteria.source.should eq(:foo => 'bar', :baz => true)
786
811
  query.options.source.should eq({
787
- :sort => [['foo', 1]],
788
- :fields => ['foo', 'baz'],
812
+ :sort => {"foo" => 1},
813
+ :projection => {'foo' => 1, 'baz' => 1},
789
814
  :limit => 10,
790
815
  :skip => 10,
791
816
  })
@@ -815,8 +840,14 @@ describe Plucky::Query do
815
840
 
816
841
  it "works" do
817
842
  explain = subject.where(:age.lt => 28).explain
818
- explain['cursor'].should == 'BasicCursor'
819
- explain['nscanned'].should == 3
843
+
844
+ if explain['cursor']
845
+ explain['cursor'].should == 'BasicCursor'
846
+ explain['nscanned'].should == 3
847
+ elsif explain['executionStats']
848
+ explain['executionStats']['executionSuccess'].should == true
849
+ explain['executionStats']['totalDocsExamined'].should == 3
850
+ end
820
851
  end
821
852
  end
822
853
 
@@ -838,5 +869,31 @@ describe Plucky::Query do
838
869
  result.should be_instance_of(@user_class)
839
870
  end
840
871
  end
872
+
873
+ it "works with block form of find_each" do
874
+ results = []
875
+ @query.find_each do |doc|
876
+ results << doc
877
+ end
878
+ results.each do |result|
879
+ result.should be_instance_of(@user_class)
880
+ end
881
+ end
882
+ end
883
+
884
+ describe "insert" do
885
+ before { @query = described_class.new(@collection) }
886
+ subject { @query }
887
+
888
+ it "should be able to insert one doc" do
889
+ subject.insert({ foo: 'bar' })
890
+ subject.count({ foo: 'bar' }).should == 1
891
+ end
892
+
893
+ it "should be able to insert multiple" do
894
+ subject.insert([{ foo: 'bar' }, { baz: 'quxx' }])
895
+ subject.count({ foo: 'bar' }).should == 1
896
+ subject.count({ baz: 'quxx' }).should == 1
897
+ end
841
898
  end
842
899
  end