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.
- checksums.yaml +7 -0
- data/.gitignore +1 -3
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -4
- data/Gemfile +6 -5
- data/Gemfile.lock +84 -0
- data/LICENSE +1 -1
- data/README.md +17 -75
- data/Rakefile +0 -3
- data/examples/query.rb +8 -7
- data/lib/plucky.rb +1 -0
- data/lib/plucky/criteria_hash.rb +78 -62
- data/lib/plucky/extensions/symbol.rb +8 -0
- data/lib/plucky/normalizers/criteria_hash_value.rb +3 -1
- data/lib/plucky/normalizers/fields_value.rb +3 -3
- data/lib/plucky/normalizers/hash_key.rb +19 -0
- data/lib/plucky/normalizers/options_hash_value.rb +5 -7
- data/lib/plucky/normalizers/sort_value.rb +8 -6
- data/lib/plucky/options_hash.rb +9 -3
- data/lib/plucky/pagination.rb +1 -1
- data/lib/plucky/pagination/{decorator.rb → collection.rb} +10 -1
- data/lib/plucky/query.rb +56 -21
- data/lib/plucky/transformer.rb +14 -0
- data/lib/plucky/version.rb +1 -1
- data/plucky.gemspec +4 -5
- data/script/bootstrap +21 -0
- data/script/release +42 -0
- data/script/test +20 -0
- data/spec/functional/options_hash_spec.rb +41 -0
- data/spec/helper.rb +12 -4
- data/spec/plucky/criteria_hash_spec.rb +68 -4
- data/spec/plucky/normalizers/criteria_hash_value_spec.rb +1 -1
- data/spec/plucky/normalizers/fields_value_spec.rb +5 -5
- data/spec/plucky/normalizers/hash_key_spec.rb +15 -0
- data/spec/plucky/normalizers/options_hash_value_spec.rb +2 -2
- data/spec/plucky/normalizers/sort_value_spec.rb +24 -20
- data/spec/plucky/options_hash_spec.rb +2 -2
- data/spec/plucky/pagination/{decorator_spec.rb → collection_spec.rb} +8 -5
- data/spec/plucky/query_spec.rb +92 -35
- data/spec/plucky_spec.rb +5 -5
- data/spec/symbol_operator_spec.rb +18 -1
- metadata +37 -36
- data/lib/plucky/normalizers/options_hash_key.rb +0 -23
- data/script/criteria_hash.rb +0 -21
- data/spec/plucky/normalizers/options_hash_key_spec.rb +0 -23
    
        data/script/test
    ADDED
    
    | @@ -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
         | 
    
        data/spec/helper.rb
    CHANGED
    
    | @@ -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 | 
            -
             | 
| 21 | 
            -
             | 
| 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 | 
            -
                }. | 
| 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(&: | 
| 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 | 
            -
                   | 
| 41 | 
            -
                   | 
| 42 | 
            -
                   | 
| 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 =>  | 
| 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( | 
| 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( | 
| 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( | 
| 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( | 
| 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( | 
| 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 | 
            -
                 | 
| 29 | 
            +
                lambda {
         | 
| 30 30 | 
             
                  described_class.new
         | 
| 31 | 
            -
                }. | 
| 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 | 
            -
                 | 
| 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 | 
            -
                 | 
| 16 | 
            +
                lambda {
         | 
| 17 17 | 
             
                  described_class.new
         | 
| 18 | 
            -
                }. | 
| 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( | 
| 35 | 
            -
                subject.call('foo ASC').should eq( | 
| 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( | 
| 40 | 
            -
                subject.call('foo DESC').should eq( | 
| 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( | 
| 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( | 
| 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( | 
| 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( | 
| 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( | 
| 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( | 
| 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( | 
| 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( | 
| 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( | 
| 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( | 
| 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( | 
| 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( | 
| 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( | 
| 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(: | 
| 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[: | 
| 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:: | 
| 4 | 
            -
              context "Object decorated with  | 
| 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
         | 
    
        data/spec/plucky/query_spec.rb
    CHANGED
    
    | @@ -2,13 +2,13 @@ require 'helper' | |
| 2 2 |  | 
| 3 3 | 
             
            describe Plucky::Query do
         | 
| 4 4 | 
             
              before do
         | 
| 5 | 
            -
                @chris      =  | 
| 6 | 
            -
                @steve      =  | 
| 7 | 
            -
                @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. | 
| 10 | 
            -
                @collection. | 
| 11 | 
            -
                @collection. | 
| 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( | 
| 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( | 
| 82 | 
            -
                  cursor.next.should  | 
| 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. | 
| 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 =  | 
| 294 | 
            -
                  @collection. | 
| 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 ==  | 
| 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 ==  | 
| 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 ==  | 
| 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 ==  | 
| 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 ==  | 
| 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       ==  | 
| 519 | 
            -
                  subject.order(:foo, :bar).options[:sort].should ==  | 
| 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 | 
            -
                   | 
| 557 | 
            +
                  lambda {
         | 
| 533 558 | 
             
                    subject.reverse
         | 
| 534 | 
            -
                  }. | 
| 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 ==  | 
| 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 ==  | 
| 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 ==  | 
| 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. | 
| 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:: | 
| 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 | 
            -
                  : | 
| 741 | 
            -
                  :sort       =>  | 
| 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[: | 
| 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 ==  | 
| 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   =>  | 
| 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   =>  | 
| 788 | 
            -
                    : | 
| 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 | 
            -
             | 
| 819 | 
            -
                  explain[' | 
| 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
         |