sequel-seek-pagination 0.2.1 → 0.3.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 +4 -4
- data/README.md +6 -6
- data/lib/sequel/extensions/seek_pagination.rb +51 -46
- data/lib/sequel/extensions/seek_pagination/version.rb +1 -1
- data/spec/seek_pagination_spec.rb +38 -51
- data/tasks/benchmark.rb +8 -8
- metadata +3 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 6618c26ae7817aca156c266b2981123bb313b7c4
         | 
| 4 | 
            +
              data.tar.gz: 00b368ee9b8ff804aa9f658c3793d24c98262c4f
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 85ad99ff1ed0031e3bd60c79492de37f5248f5702f32ce7b07bfa957338153f17d84e82acf46dc31f5e9a2bafb6c794e00614620c5059512e0d976a8cde4fd41
         | 
| 7 | 
            +
              data.tar.gz: 947e63b6731d904e9ea22cc3b91f1ad0dc4ea68480c9d7dc8019352b601c2a88727abba1d164da8a8ff8818e6ba2435a47fc8bbcaabd2cc2af5cb514338d217f
         | 
    
        data/README.md
    CHANGED
    
    | @@ -13,16 +13,16 @@ DB.extension :seek_pagination | |
| 13 13 | 
             
            ds = DB[:seek]
         | 
| 14 14 | 
             
            ds.extension(:seek_pagination)
         | 
| 15 15 |  | 
| 16 | 
            -
            #  | 
| 17 | 
            -
            DB[:seek].order(:id). | 
| 16 | 
            +
            # Get the first page of data:
         | 
| 17 | 
            +
            DB[:seek].order(:id).limit(50) # SELECT * FROM "seek" ORDER BY "id" LIMIT 50
         | 
| 18 18 |  | 
| 19 | 
            -
            #  | 
| 19 | 
            +
            # Pass the last data to the you saw to get the second page.
         | 
| 20 20 | 
             
            # (suppose the id of the last row you got was 1456)
         | 
| 21 | 
            -
            DB[:seek].order(:id). | 
| 21 | 
            +
            DB[:seek].order(:id).limit(50).seek(value: 1456) # SELECT * FROM "seek" WHERE ("id" > 1456) ORDER BY "id" LIMIT 50
         | 
| 22 22 |  | 
| 23 23 | 
             
            # Also works when sorting by multiple columns.
         | 
| 24 | 
            -
            DB[:seek].order(:col1, :col2). | 
| 25 | 
            -
            DB[:seek].order(:col1, :col2). | 
| 24 | 
            +
            DB[:seek].order(:col1, :col2).limit(50) # SELECT * FROM "seek" ORDER BY "col1", "col2" LIMIT 50
         | 
| 25 | 
            +
            DB[:seek].order(:col1, :col2).limit(50).seek(value: [12, 56]) # SELECT * FROM "seek" WHERE (("col1", "col2") > (12, 56)) ORDER BY "col1", "col2" LIMIT 50
         | 
| 26 26 | 
             
            ```
         | 
| 27 27 |  | 
| 28 28 | 
             
            ### Why Seek Pagination?
         | 
| @@ -5,27 +5,19 @@ module Sequel | |
| 5 5 | 
             
              module SeekPagination
         | 
| 6 6 | 
             
                class Error < StandardError; end
         | 
| 7 7 |  | 
| 8 | 
            -
                def  | 
| 8 | 
            +
                def seek(value: nil, pk: nil, include_exact_match: false, not_null: nil)
         | 
| 9 9 | 
             
                  order = opts[:order]
         | 
| 10 10 | 
             
                  model = @model
         | 
| 11 11 |  | 
| 12 | 
            -
                  if  | 
| 13 | 
            -
                    raise Error, " | 
| 14 | 
            -
                  elsif  | 
| 15 | 
            -
                    raise Error, "cannot  | 
| 16 | 
            -
                  elsif model.nil? &&  | 
| 17 | 
            -
                    raise Error, " | 
| 12 | 
            +
                  if !(value.nil? ^ pk.nil?)
         | 
| 13 | 
            +
                    raise Error, "must pass exactly one of :value and :pk to #seek"
         | 
| 14 | 
            +
                  elsif order.nil? || order.length.zero?
         | 
| 15 | 
            +
                    raise Error, "cannot call #seek on a dataset with no order"
         | 
| 16 | 
            +
                  elsif model.nil? && pk
         | 
| 17 | 
            +
                    raise Error, "attempted a primary key lookup on a dataset that doesn't have an associated model"
         | 
| 18 18 | 
             
                  end
         | 
| 19 19 |  | 
| 20 | 
            -
                   | 
| 21 | 
            -
             | 
| 22 | 
            -
                  if values = from || after
         | 
| 23 | 
            -
                    values = Array(values)
         | 
| 24 | 
            -
             | 
| 25 | 
            -
                    if values.length != order.length
         | 
| 26 | 
            -
                      raise Error, "passed the wrong number of values in the :#{from ? 'from' : 'after'} option to seek_paginate"
         | 
| 27 | 
            -
                    end
         | 
| 28 | 
            -
                  elsif pk = from_pk || after_pk
         | 
| 20 | 
            +
                  if pk
         | 
| 29 21 | 
             
                    target_ds = where(model.qualified_primary_key_hash(pk))
         | 
| 30 22 |  | 
| 31 23 | 
             
                    # Need to load the values to order from for that pk from the DB, so we
         | 
| @@ -33,7 +25,7 @@ module Sequel | |
| 33 25 | 
             
                    # Dataset#get won't like it if we pass it expressions that aren't
         | 
| 34 26 | 
             
                    # simple columns, so we need to give it aliases for everything.
         | 
| 35 27 | 
             
                    al = :a
         | 
| 36 | 
            -
                    gettable = order.map do |o | 
| 28 | 
            +
                    gettable = order.map do |o|
         | 
| 37 29 | 
             
                      expression = Sequel::SQL::OrderedExpression === o ? o.expression : o
         | 
| 38 30 | 
             
                      Sequel.as(expression, (al = al.next))
         | 
| 39 31 | 
             
                    end
         | 
| @@ -41,27 +33,31 @@ module Sequel | |
| 41 33 | 
             
                    unless values = target_ds.get(gettable)
         | 
| 42 34 | 
             
                      raise NoMatchingRow.new(target_ds)
         | 
| 43 35 | 
             
                    end
         | 
| 36 | 
            +
                  else
         | 
| 37 | 
            +
                    values = Array(value)
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                    if values.length != order.length
         | 
| 40 | 
            +
                      raise Error, "passed the wrong number of values to #seek"
         | 
| 41 | 
            +
                    end
         | 
| 44 42 | 
             
                  end
         | 
| 45 43 |  | 
| 46 | 
            -
                  if  | 
| 47 | 
            -
                     | 
| 48 | 
            -
                      not_null = []
         | 
| 44 | 
            +
                  if not_null.nil?
         | 
| 45 | 
            +
                    not_null = []
         | 
| 49 46 |  | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 55 | 
            -
                        end
         | 
| 47 | 
            +
                    # If the dataset was chained off a model, use its stored schema
         | 
| 48 | 
            +
                    # information to figure out what columns are not null.
         | 
| 49 | 
            +
                    if model
         | 
| 50 | 
            +
                      model.db_schema.each do |column, schema|
         | 
| 51 | 
            +
                        not_null << column if schema[:allow_null] == false
         | 
| 56 52 | 
             
                      end
         | 
| 57 53 | 
             
                    end
         | 
| 58 | 
            -
             | 
| 59 | 
            -
                    # If we're paginating with a :from value, we want to include the row
         | 
| 60 | 
            -
                    # that has those exact values.
         | 
| 61 | 
            -
                    OrderedColumnSet.new(order.zip(values), include_exact_match: !!(from || from_pk), not_null: not_null).apply(ds)
         | 
| 62 | 
            -
                  else
         | 
| 63 | 
            -
                    ds
         | 
| 64 54 | 
             
                  end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                  OrderedColumnSet.new(
         | 
| 57 | 
            +
                    order.zip(values),
         | 
| 58 | 
            +
                    include_exact_match: include_exact_match,
         | 
| 59 | 
            +
                    not_null: not_null
         | 
| 60 | 
            +
                  ).apply(self)
         | 
| 65 61 | 
             
                end
         | 
| 66 62 |  | 
| 67 63 | 
             
                private
         | 
| @@ -92,21 +88,21 @@ module Sequel | |
| 92 88 | 
             
                      else
         | 
| 93 89 | 
             
                        Sequel.&(
         | 
| 94 90 | 
             
                          *length.times.map { |i|
         | 
| 95 | 
            -
                            allow_equal = include_exact_match || i != length - 1
         | 
| 91 | 
            +
                            allow_equal = include_exact_match || i != (length - 1)
         | 
| 96 92 | 
             
                            conditions = orders[0..i]
         | 
| 97 93 |  | 
| 98 94 | 
             
                            if i.zero?
         | 
| 99 | 
            -
                              conditions[0]. | 
| 95 | 
            +
                              conditions[0].inequality_condition(allow_equal: allow_equal)
         | 
| 100 96 | 
             
                            else
         | 
| 101 97 | 
             
                              c = conditions[-2]
         | 
| 102 98 |  | 
| 103 | 
            -
                              list = if filter = conditions[-1]. | 
| 99 | 
            +
                              list = if filter = conditions[-1].inequality_condition(allow_equal: allow_equal)
         | 
| 104 100 | 
             
                                       [Sequel.&(c.eq_filter, filter)]
         | 
| 105 101 | 
             
                                     else
         | 
| 106 102 | 
             
                                       [c.eq_filter]
         | 
| 107 103 | 
             
                                     end
         | 
| 108 104 |  | 
| 109 | 
            -
                              list += conditions[0..-2].map { |c| c. | 
| 105 | 
            +
                              list += conditions[0..-2].map { |c| c.inequality_condition(allow_equal: false) }
         | 
| 110 106 |  | 
| 111 107 | 
             
                              Sequel.|(*list.compact)
         | 
| 112 108 | 
             
                            end
         | 
| @@ -160,25 +156,34 @@ module Sequel | |
| 160 156 | 
             
                    {name => nil}
         | 
| 161 157 | 
             
                  end
         | 
| 162 158 |  | 
| 163 | 
            -
                  def  | 
| 159 | 
            +
                  def inequality_condition(allow_equal:)
         | 
| 164 160 | 
             
                    nulls_upcoming = !not_null && nulls == :last
         | 
| 165 161 |  | 
| 166 | 
            -
                    if  | 
| 167 | 
            -
                       | 
| 168 | 
            -
                      nulls_upcoming ? Sequel.|(filter, null_filter) : filter
         | 
| 169 | 
            -
                    else
         | 
| 170 | 
            -
                      if nulls_upcoming && eq
         | 
| 162 | 
            +
                    if value.nil?
         | 
| 163 | 
            +
                      if nulls_upcoming && allow_equal
         | 
| 171 164 | 
             
                        null_filter
         | 
| 172 | 
            -
                      elsif !nulls_upcoming && ! | 
| 165 | 
            +
                      elsif !nulls_upcoming && !allow_equal
         | 
| 173 166 | 
             
                        Sequel.~(null_filter)
         | 
| 167 | 
            +
                      else
         | 
| 168 | 
            +
                        # No condition necessary.
         | 
| 169 | 
            +
                        nil
         | 
| 170 | 
            +
                      end
         | 
| 171 | 
            +
                    else
         | 
| 172 | 
            +
                      # Value is not null.
         | 
| 173 | 
            +
                      filter = Sequel.virtual_row { |o| o.__send__(inequality_method(allow_equal), name, value) }
         | 
| 174 | 
            +
             | 
| 175 | 
            +
                      if nulls_upcoming
         | 
| 176 | 
            +
                        Sequel.|(filter, null_filter)
         | 
| 177 | 
            +
                      else
         | 
| 178 | 
            +
                        filter
         | 
| 174 179 | 
             
                      end
         | 
| 175 180 | 
             
                    end
         | 
| 176 181 | 
             
                  end
         | 
| 177 182 |  | 
| 178 | 
            -
                  def inequality_method( | 
| 183 | 
            +
                  def inequality_method(allow_equal)
         | 
| 179 184 | 
             
                    case direction
         | 
| 180 | 
            -
                    when :asc  then  | 
| 181 | 
            -
                    when :desc then  | 
| 185 | 
            +
                    when :asc  then allow_equal ? :>= : :>
         | 
| 186 | 
            +
                    when :desc then allow_equal ? :<= : :<
         | 
| 182 187 | 
             
                    else raise "Bad direction: #{direction.inspect}"
         | 
| 183 188 | 
             
                    end
         | 
| 184 189 | 
             
                  end
         | 
| @@ -13,7 +13,7 @@ class SeekPaginationSpec < Minitest::Spec | |
| 13 13 | 
             
              end
         | 
| 14 14 |  | 
| 15 15 | 
             
              class << self
         | 
| 16 | 
            -
                def  | 
| 16 | 
            +
                def it_should_seek_properly(ordering)
         | 
| 17 17 | 
             
                  columns = ordering.map do |order|
         | 
| 18 18 | 
             
                              case order
         | 
| 19 19 | 
             
                              when Sequel::SQL::OrderedExpression then order.expression
         | 
| @@ -24,33 +24,28 @@ class SeekPaginationSpec < Minitest::Spec | |
| 24 24 | 
             
                  [:plain, :model].each do |dataset_type|
         | 
| 25 25 | 
             
                    describe "for a #{dataset_type} dataset" do
         | 
| 26 26 | 
             
                      dataset = dataset_type == :plain ? DB[:seek] : SeekModel
         | 
| 27 | 
            -
                      dataset = dataset.order(*ordering)
         | 
| 27 | 
            +
                      dataset = dataset.order(*ordering).limit(100)
         | 
| 28 28 |  | 
| 29 29 | 
             
                      # Can't pass any random expression to #get, so give them all aliases.
         | 
| 30 30 | 
             
                      gettable = columns.zip(:a..:z).map{|c,a| Sequel.as(c, a)}
         | 
| 31 31 |  | 
| 32 | 
            -
                      it "should limit the dataset appropriately when a starting point is not given" do
         | 
| 33 | 
            -
                        assert_equal_results dataset.limit(10),
         | 
| 34 | 
            -
                                             dataset.seek_paginate(10)
         | 
| 35 | 
            -
                      end
         | 
| 36 | 
            -
             | 
| 37 32 | 
             
                      it "should page properly when given a point to start from/after" do
         | 
| 38 33 | 
             
                        offset = rand(SEEK_COUNT)
         | 
| 39 34 | 
             
                        values = dataset.offset(offset).get(gettable)
         | 
| 40 35 |  | 
| 41 | 
            -
                        assert_equal_results dataset.offset(offset) | 
| 42 | 
            -
                                             dataset. | 
| 36 | 
            +
                        assert_equal_results dataset.offset(offset),
         | 
| 37 | 
            +
                                             dataset.seek(value: values, include_exact_match: true)
         | 
| 43 38 |  | 
| 44 | 
            -
                        assert_equal_results dataset.offset(offset + 1) | 
| 45 | 
            -
                                             dataset. | 
| 39 | 
            +
                        assert_equal_results dataset.offset(offset + 1),
         | 
| 40 | 
            +
                                             dataset.seek(value: values)
         | 
| 46 41 |  | 
| 47 42 | 
             
                        if columns.length == 1
         | 
| 48 43 | 
             
                          # Should wrap values in an array if necessary
         | 
| 49 | 
            -
                          assert_equal_results dataset.offset(offset) | 
| 50 | 
            -
                                               dataset. | 
| 44 | 
            +
                          assert_equal_results dataset.offset(offset),
         | 
| 45 | 
            +
                                               dataset.seek(value: values.first, include_exact_match: true)
         | 
| 51 46 |  | 
| 52 | 
            -
                          assert_equal_results dataset.offset(offset + 1) | 
| 53 | 
            -
                                               dataset. | 
| 47 | 
            +
                          assert_equal_results dataset.offset(offset + 1),
         | 
| 48 | 
            +
                                               dataset.seek(value: values.first)
         | 
| 54 49 | 
             
                        end
         | 
| 55 50 | 
             
                      end
         | 
| 56 51 |  | 
| @@ -58,11 +53,11 @@ class SeekPaginationSpec < Minitest::Spec | |
| 58 53 | 
             
                        offset = rand(SEEK_COUNT)
         | 
| 59 54 | 
             
                        values = dataset.offset(offset).get(gettable)
         | 
| 60 55 |  | 
| 61 | 
            -
                        assert_equal_results dataset.offset(offset) | 
| 62 | 
            -
                                             dataset. | 
| 56 | 
            +
                        assert_equal_results dataset.offset(offset),
         | 
| 57 | 
            +
                                             dataset.seek(value: values, include_exact_match: true, not_null: [:id, :non_nullable_1, :non_nullable_2])
         | 
| 63 58 |  | 
| 64 | 
            -
                        assert_equal_results dataset.offset(offset + 1) | 
| 65 | 
            -
                                             dataset. | 
| 59 | 
            +
                        assert_equal_results dataset.offset(offset + 1),
         | 
| 60 | 
            +
                                             dataset.seek(value: values, not_null: [:id, :non_nullable_1, :non_nullable_2])
         | 
| 66 61 | 
             
                      end
         | 
| 67 62 |  | 
| 68 63 | 
             
                      if dataset_type == :model
         | 
| @@ -70,11 +65,11 @@ class SeekPaginationSpec < Minitest::Spec | |
| 70 65 | 
             
                          offset = rand(SEEK_COUNT)
         | 
| 71 66 | 
             
                          id     = dataset.offset(offset).get(:id)
         | 
| 72 67 |  | 
| 73 | 
            -
                          assert_equal_results dataset.offset(offset) | 
| 74 | 
            -
                                               dataset. | 
| 68 | 
            +
                          assert_equal_results dataset.offset(offset),
         | 
| 69 | 
            +
                                               dataset.seek(pk: id, include_exact_match: true)
         | 
| 75 70 |  | 
| 76 | 
            -
                          assert_equal_results dataset.offset(offset + 1) | 
| 77 | 
            -
                                               dataset. | 
| 71 | 
            +
                          assert_equal_results dataset.offset(offset + 1),
         | 
| 72 | 
            +
                                               dataset.seek(pk: id)
         | 
| 78 73 | 
             
                        end
         | 
| 79 74 | 
             
                      end
         | 
| 80 75 | 
             
                    end
         | 
| @@ -84,14 +79,14 @@ class SeekPaginationSpec < Minitest::Spec | |
| 84 79 |  | 
| 85 80 | 
             
              describe "for ordering by a single not-null column in either order" do
         | 
| 86 81 | 
             
                [Sequel.asc(:id), Sequel.desc(:id)].each do |o1|
         | 
| 87 | 
            -
                   | 
| 82 | 
            +
                  it_should_seek_properly [o1]
         | 
| 88 83 | 
             
                end
         | 
| 89 84 | 
             
              end
         | 
| 90 85 |  | 
| 91 86 | 
             
              describe "for ordering by two not-null columns in any order" do
         | 
| 92 87 | 
             
                [Sequel.asc(:not_nullable_1), Sequel.desc(:not_nullable_1)].each do |o1|
         | 
| 93 88 | 
             
                  [Sequel.asc(:id), Sequel.desc(:id)].each do |o2|
         | 
| 94 | 
            -
                     | 
| 89 | 
            +
                    it_should_seek_properly [o1, o2]
         | 
| 95 90 | 
             
                  end
         | 
| 96 91 | 
             
                end
         | 
| 97 92 | 
             
              end
         | 
| @@ -100,7 +95,7 @@ class SeekPaginationSpec < Minitest::Spec | |
| 100 95 | 
             
                [Sequel.asc(:not_nullable_1), Sequel.desc(:not_nullable_1)].each do |o1|
         | 
| 101 96 | 
             
                  [Sequel.asc(:not_nullable_2), Sequel.desc(:not_nullable_2)].each do |o2|
         | 
| 102 97 | 
             
                    [Sequel.asc(:id), Sequel.desc(:id)].each do |o3|
         | 
| 103 | 
            -
                       | 
| 98 | 
            +
                      it_should_seek_properly [o1, o2, o3]
         | 
| 104 99 | 
             
                    end
         | 
| 105 100 | 
             
                  end
         | 
| 106 101 | 
             
                end
         | 
| @@ -110,7 +105,7 @@ class SeekPaginationSpec < Minitest::Spec | |
| 110 105 | 
             
                # We still tack on :id because the ordering needs to be unique.
         | 
| 111 106 | 
             
                [Sequel.asc(:nullable_1), Sequel.desc(:nullable_1), Sequel.asc(:nullable_1, nulls: :first), Sequel.desc(:nullable_1, nulls: :last)].each do |o1|
         | 
| 112 107 | 
             
                  [Sequel.asc(:id), Sequel.desc(:id)].each do |o2|
         | 
| 113 | 
            -
                     | 
| 108 | 
            +
                    it_should_seek_properly [o1, o2]
         | 
| 114 109 | 
             
                  end
         | 
| 115 110 | 
             
                end
         | 
| 116 111 | 
             
              end
         | 
| @@ -120,7 +115,7 @@ class SeekPaginationSpec < Minitest::Spec | |
| 120 115 | 
             
                [Sequel.asc(:nullable_1), Sequel.desc(:nullable_1), Sequel.asc(:nullable_1, nulls: :first), Sequel.desc(:nullable_1, nulls: :last)].each do |o1|
         | 
| 121 116 | 
             
                  [Sequel.asc(:nullable_2), Sequel.desc(:nullable_2), Sequel.asc(:nullable_2, nulls: :first), Sequel.desc(:nullable_2, nulls: :last)].each do |o2|
         | 
| 122 117 | 
             
                    [Sequel.asc(:id), Sequel.desc(:id)].each do |o3|
         | 
| 123 | 
            -
                       | 
| 118 | 
            +
                      it_should_seek_properly [o1, o2, o3]
         | 
| 124 119 | 
             
                    end
         | 
| 125 120 | 
             
                  end
         | 
| 126 121 | 
             
                end
         | 
| @@ -138,7 +133,7 @@ class SeekPaginationSpec < Minitest::Spec | |
| 138 133 | 
             
                  testing_columns = columns.sample(rand(columns.count) + 1).map(&:sample)
         | 
| 139 134 | 
             
                  testing_columns << [:id, Sequel.asc(:id), Sequel.desc(:id)].sample
         | 
| 140 135 |  | 
| 141 | 
            -
                   | 
| 136 | 
            +
                  it_should_seek_properly(testing_columns)
         | 
| 142 137 | 
             
                end
         | 
| 143 138 | 
             
              end
         | 
| 144 139 |  | 
| @@ -154,7 +149,7 @@ class SeekPaginationSpec < Minitest::Spec | |
| 154 149 | 
             
                  testing_columns = columns.sample(rand(columns.count) + 1).map(&:sample)
         | 
| 155 150 | 
             
                  testing_columns << [:id, Sequel.asc(:id), Sequel.desc(:id)].sample
         | 
| 156 151 |  | 
| 157 | 
            -
                   | 
| 152 | 
            +
                  it_should_seek_properly(testing_columns)
         | 
| 158 153 | 
             
                end
         | 
| 159 154 | 
             
              end
         | 
| 160 155 |  | 
| @@ -172,49 +167,41 @@ class SeekPaginationSpec < Minitest::Spec | |
| 172 167 | 
             
                id = DB[:seek].order(:id).offset(56).get(:id)
         | 
| 173 168 |  | 
| 174 169 | 
             
                datasets.each do |dataset|
         | 
| 175 | 
            -
                  assert_equal_results DB[:seek].order(:id).limit(5),
         | 
| 176 | 
            -
                                       dataset.seek_paginate(5)
         | 
| 177 | 
            -
             | 
| 178 170 | 
             
                  assert_equal_results DB[:seek].order(:id).offset(56).limit(5),
         | 
| 179 | 
            -
                                       dataset. | 
| 171 | 
            +
                                       dataset.limit(5).seek(value: id, include_exact_match: true)
         | 
| 180 172 |  | 
| 181 173 | 
             
                  assert_equal_results DB[:seek].order(:id).offset(57).limit(5),
         | 
| 182 | 
            -
                                       dataset. | 
| 174 | 
            +
                                       dataset.limit(5).seek(value: id)
         | 
| 183 175 | 
             
                end
         | 
| 184 176 | 
             
              end
         | 
| 185 177 |  | 
| 186 178 | 
             
              it "should raise an error if the dataset is not ordered" do
         | 
| 187 | 
            -
                assert_error_message("cannot  | 
| 179 | 
            +
                assert_error_message("cannot call #seek on a dataset with no order") { DB[:seek].seek(value: 3) }
         | 
| 188 180 | 
             
              end
         | 
| 189 181 |  | 
| 190 | 
            -
              it "should raise an error  | 
| 191 | 
            -
                assert_error_message(" | 
| 192 | 
            -
                assert_error_message(" | 
| 193 | 
            -
                assert_error_message("cannot pass more than one of the :from, :after, :from_pk and :after_pk arguments to seek_paginate") { DB[:seek].order(:id).seek_paginate(30, from: 3, after_pk: 4) }
         | 
| 194 | 
            -
                assert_error_message("cannot pass more than one of the :from, :after, :from_pk and :after_pk arguments to seek_paginate") { DB[:seek].order(:id).seek_paginate(30, from_pk: 3, after: 4) }
         | 
| 182 | 
            +
              it "should raise an error unless exactly one of :value and :pk is passed" do
         | 
| 183 | 
            +
                assert_error_message("must pass exactly one of :value and :pk to #seek") { DB[:seek].seek }
         | 
| 184 | 
            +
                assert_error_message("must pass exactly one of :value and :pk to #seek") { DB[:seek].seek(value: 3, pk: 3) }
         | 
| 195 185 | 
             
              end
         | 
| 196 186 |  | 
| 197 | 
            -
              it "should raise an error if given the wrong number of values | 
| 198 | 
            -
                assert_error_message("passed the wrong number of values  | 
| 199 | 
            -
                assert_error_message("passed the wrong number of values  | 
| 200 | 
            -
                assert_error_message("passed the wrong number of values  | 
| 201 | 
            -
                assert_error_message("passed the wrong number of values in the :after option to seek_paginate") { DB[:seek].order(:id, :nullable_1).seek_paginate(30, after: [3, 4, 5]) }
         | 
| 187 | 
            +
              it "should raise an error if given the wrong number of values" do
         | 
| 188 | 
            +
                assert_error_message("passed the wrong number of values to #seek") { DB[:seek].order(:id, :nullable_1).seek(value: 3) }
         | 
| 189 | 
            +
                assert_error_message("passed the wrong number of values to #seek") { DB[:seek].order(:id, :nullable_1).seek(value: [3]) }
         | 
| 190 | 
            +
                assert_error_message("passed the wrong number of values to #seek") { DB[:seek].order(:id, :nullable_1).seek(value: [3, 4, 5]) }
         | 
| 202 191 | 
             
              end
         | 
| 203 192 |  | 
| 204 193 | 
             
              it "should raise an error if from_pk or after_pk are passed to a dataset without an associated model" do
         | 
| 205 | 
            -
                assert_error_message(" | 
| 206 | 
            -
                assert_error_message("passed the :after_pk option to seek_paginate on a dataset that doesn't have an associated model") { DB[:seek].order(:id, :nullable_1).seek_paginate(30, after_pk: 3) }
         | 
| 194 | 
            +
                assert_error_message("attempted a primary key lookup on a dataset that doesn't have an associated model") { DB[:seek].order(:id, :nullable_1).seek(pk: 3) }
         | 
| 207 195 | 
             
              end
         | 
| 208 196 |  | 
| 209 197 | 
             
              describe "when chained from a model" do
         | 
| 210 198 | 
             
                it "should be able to determine from the schema what columns are not null" do
         | 
| 211 199 | 
             
                  assert_equal %(SELECT * FROM "seek" WHERE (("not_nullable_1", "not_nullable_2", "id") > (1, 2, 3)) ORDER BY "not_nullable_1", "not_nullable_2", "id" LIMIT 5),
         | 
| 212 | 
            -
                    SeekModel.order(:not_nullable_1, :not_nullable_2, :id). | 
| 200 | 
            +
                    SeekModel.order(:not_nullable_1, :not_nullable_2, :id).seek(value: [1, 2, 3]).limit(5).sql
         | 
| 213 201 | 
             
                end
         | 
| 214 202 |  | 
| 215 203 | 
             
                it "should raise an error when passed a pk for a record that doesn't exist in the dataset" do
         | 
| 216 | 
            -
                  assert_raises(Sequel::NoMatchingRow) { SeekModel.order(:id). | 
| 217 | 
            -
                  assert_raises(Sequel::NoMatchingRow) { SeekModel.order(:id).seek_paginate(5, from_pk:  -45) }
         | 
| 204 | 
            +
                  assert_raises(Sequel::NoMatchingRow) { SeekModel.order(:id).seek(pk: -45) }
         | 
| 218 205 | 
             
                end
         | 
| 219 206 | 
             
              end
         | 
| 220 207 | 
             
            end
         | 
    
        data/tasks/benchmark.rb
    CHANGED
    
    | @@ -37,17 +37,17 @@ task :benchmark do | |
| 37 37 | 
             
              DB.add_index :seek, [:non_nullable_1]
         | 
| 38 38 |  | 
| 39 39 | 
             
              {
         | 
| 40 | 
            -
                "1 column, not-null, ascending, no not-null information"  => DB[:seek].order(:id.asc ). | 
| 41 | 
            -
                "1 column, not-null, descending, no not-null information" => DB[:seek].order(:id.desc). | 
| 40 | 
            +
                "1 column, not-null, ascending, no not-null information"  => DB[:seek].limit(30).order(:id.asc ).seek(value: rand(RECORD_COUNT) + 1),
         | 
| 41 | 
            +
                "1 column, not-null, descending, no not-null information" => DB[:seek].limit(30).order(:id.desc).seek(value: rand(RECORD_COUNT) + 1),
         | 
| 42 42 |  | 
| 43 | 
            -
                "1 column, not-null, ascending, with not-null information"  => DB[:seek].order(:id.asc ). | 
| 44 | 
            -
                "1 column, not-null, descending, with not-null information" => DB[:seek].order(:id.desc). | 
| 43 | 
            +
                "1 column, not-null, ascending, with not-null information"  => DB[:seek].limit(30).order(:id.asc ).seek(value: rand(RECORD_COUNT) + 1, not_null: [:id, :not_nullable_1, :not_nullable_2]),
         | 
| 44 | 
            +
                "1 column, not-null, descending, with not-null information" => DB[:seek].limit(30).order(:id.desc).seek(value: rand(RECORD_COUNT) + 1, not_null: [:id, :not_nullable_1, :not_nullable_2]),
         | 
| 45 45 |  | 
| 46 | 
            -
                "2 columns, not-null, ascending, no not-null information"  => DB[:seek].order(:non_nullable_1.asc,  :id.asc ). | 
| 47 | 
            -
                "2 columns, not-null, descending, no not-null information" => DB[:seek].order(:non_nullable_1.desc, :id.desc). | 
| 46 | 
            +
                "2 columns, not-null, ascending, no not-null information"  => DB[:seek].limit(30).order(:non_nullable_1.asc,  :id.asc ).seek(value: [5, rand(RECORD_COUNT) + 1]),
         | 
| 47 | 
            +
                "2 columns, not-null, descending, no not-null information" => DB[:seek].limit(30).order(:non_nullable_1.desc, :id.desc).seek(value: [5, rand(RECORD_COUNT) + 1]),
         | 
| 48 48 |  | 
| 49 | 
            -
                "2 columns, not-null, ascending, with not-null information"  => DB[:seek].order(:non_nullable_1.asc,  :id.asc ). | 
| 50 | 
            -
                "2 columns, not-null, descending, with not-null information" => DB[:seek].order(:non_nullable_1.desc, :id.desc). | 
| 49 | 
            +
                "2 columns, not-null, ascending, with not-null information"  => DB[:seek].limit(30).order(:non_nullable_1.asc,  :id.asc ).seek(value: [5, rand(RECORD_COUNT) + 1], not_null: [:id, :non_nullable_1, :non_nullable_2]),
         | 
| 50 | 
            +
                "2 columns, not-null, descending, with not-null information" => DB[:seek].limit(30).order(:non_nullable_1.desc, :id.desc).seek(value: [5, rand(RECORD_COUNT) + 1], not_null: [:id, :non_nullable_1, :non_nullable_2]),
         | 
| 51 51 | 
             
              }.each do |description, ds|
         | 
| 52 52 | 
             
                puts
         | 
| 53 53 | 
             
                puts description + ':'
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: sequel-seek-pagination
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.3.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Chris Hanks
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 11 | 
            +
            date: 2016-07-25 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: bundler
         | 
| @@ -107,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 107 107 | 
             
                  version: '0'
         | 
| 108 108 | 
             
            requirements: []
         | 
| 109 109 | 
             
            rubyforge_project: 
         | 
| 110 | 
            -
            rubygems_version: 2. | 
| 110 | 
            +
            rubygems_version: 2.5.1
         | 
| 111 111 | 
             
            signing_key: 
         | 
| 112 112 | 
             
            specification_version: 4
         | 
| 113 113 | 
             
            summary: Seek pagination for Sequel + PostgreSQL
         |