pageturner 3.1.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +16 -1
- data/lib/pageturner.rb +15 -35
- data/pageturner.gemspec +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9ec92e81b1919467490096e12c1bb8413a028262
|
4
|
+
data.tar.gz: 2215eda44407930869479a61c51f40c631d971b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c8ada0c35616416882e52147758e98dfb86222ac440f17c194f27eebc057da2013ae4331742b04356223d59b95881e936284a13e621168b5ce9b7ae68e96df4
|
7
|
+
data.tar.gz: 6de96592c15e9cd52ef14b08c09d1f378107877c93df23b2bdec14817f5fb9a8115c924da77e785f6633c966e1080cb19e37064dc9f539551f617f693d88c63c
|
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# Pageturner
|
2
2
|
|
3
|
-
Cursor based pagination for activerecord queries.
|
3
|
+
Cursor based pagination for activerecord queries as described in [Pagination Done the Right Way](http://use-the-index-luke.com/blog/2013-07/pagination-done-the-postgresql-way).
|
4
|
+
|
5
|
+
Pageturner allows you to paginate over a collection's attribute (`anchor_column`) starting from a given record as noted by its id and value (`anchor_id`, `anchor_value`). The `anchor_value` is the main value that divides your collection's pages. When the `anchor_value` is `nil`, we can't perform comparisons so we augment it with `anchor_id` to decide ambiguities about ordering.
|
4
6
|
|
5
7
|
## Usage
|
6
8
|
|
@@ -39,6 +41,19 @@ json.pagination do
|
|
39
41
|
end
|
40
42
|
```
|
41
43
|
|
44
|
+
If the column that you want to paginate on is referenced differently in your database schema than in your application, then you can pass the translations into Pageturner. This may happen when you want to paginate over an associated model's column and the association is aliased in your model (e.g. `has_one :subordinate, class_name: "Employee"`).
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
@pagination = Pageturner.new(
|
48
|
+
anchor_column: "subordinate",
|
49
|
+
anchor_column_active_record_identifier: "subordinate.id",
|
50
|
+
anchor_column_sql_identifier: "employees.id",
|
51
|
+
...
|
52
|
+
)
|
53
|
+
```
|
54
|
+
|
55
|
+
Pageturner will send the `anchor_column_active_record_identifier` as a method chain to an instance of the model you're paginating when calculating the next cursor from the current page and it will interpolate the `anchor_column_sql_identifier` string when building the where and order by clauses of the query that paginates your model.
|
56
|
+
|
42
57
|
## API
|
43
58
|
|
44
59
|
### `#next_cursor`
|
data/lib/pageturner.rb
CHANGED
@@ -6,16 +6,17 @@ class Pageturner
|
|
6
6
|
LESS_THAN_OPERATOR = "<"
|
7
7
|
|
8
8
|
# @param [String] anchor_column - Field to paginate on.
|
9
|
-
# @param [
|
9
|
+
# @param [Anything, nil] anchor_value - Value of the anchor_column for the record to paginate from.
|
10
10
|
# @param [ActiveRecord::Relation] ar_relation - Resource collection to paginate.
|
11
11
|
# @param [String] sort_direction - Order of the pagination. Valid values: Pageturner::ASC, Pageturner::DESC.
|
12
12
|
# @param [Number] anchor_id - ID of the record to paginate from.
|
13
|
-
|
14
|
-
|
13
|
+
# @param [String, nil] anchor_column_active_record_identifier - Method chain that references the anchor column in the model you are paginating.
|
14
|
+
# @param [String, nil] anchor_column_sql_identifier - SQL identifier that references the anchor column in your database schema.
|
15
|
+
def initialize(anchor_column:, anchor_value:, ar_relation:, sort_direction:, page_size:, anchor_id:, anchor_column_active_record_identifier: nil, anchor_column_sql_identifier: nil)
|
15
16
|
@anchor_column = anchor_column
|
16
17
|
|
17
|
-
|
18
|
-
@
|
18
|
+
@anchor_column_active_record_identifier = anchor_column_active_record_identifier || @anchor_column
|
19
|
+
@anchor_column_sql_identifier = anchor_column_sql_identifier || @anchor_column
|
19
20
|
|
20
21
|
@anchor_value = anchor_value
|
21
22
|
|
@@ -43,17 +44,10 @@ class Pageturner
|
|
43
44
|
end
|
44
45
|
|
45
46
|
def next_cursor
|
46
|
-
anchor_value =
|
47
|
-
if external_anchor_column?
|
48
|
-
public_send_chain_from_sql(self.resources.last, @anchor_column)
|
49
|
-
else
|
50
|
-
self.resources.last&.public_send(@anchor_column)
|
51
|
-
end
|
52
|
-
|
53
47
|
{
|
54
48
|
anchor_column: @anchor_column,
|
55
49
|
anchor_id: self.resources.last&.id,
|
56
|
-
anchor_value:
|
50
|
+
anchor_value: try_chain(self.resources.last, @anchor_column_active_record_identifier),
|
57
51
|
page_size: @page_size,
|
58
52
|
sort_direction: @sort_direction
|
59
53
|
}
|
@@ -91,12 +85,13 @@ class Pageturner
|
|
91
85
|
end
|
92
86
|
|
93
87
|
def calculate_next_page
|
94
|
-
if
|
95
|
-
|
88
|
+
# Heuristic to check if the `anchor_column_sql_identifier` is a joined column.
|
89
|
+
if @anchor_column_sql_identifier.include?(".")
|
90
|
+
table, column = @anchor_column_sql_identifier.split(".")
|
96
91
|
|
97
92
|
qualified_anchor_column = "`#{table}`.`#{column}`"
|
98
93
|
else
|
99
|
-
qualified_anchor_column = "#{@ar_relation.quoted_table_name}.#{@
|
94
|
+
qualified_anchor_column = "#{@ar_relation.quoted_table_name}.#{ActiveRecord::Base.connection.quote_column_name(@anchor_column)}"
|
100
95
|
end
|
101
96
|
|
102
97
|
qualified_anchor_pk_column = "#{@ar_relation.quoted_table_name}.#{@ar_relation.quoted_primary_key}"
|
@@ -117,7 +112,7 @@ class Pageturner
|
|
117
112
|
|
118
113
|
def apply_sort_direction(ar_relation)
|
119
114
|
ar_relation
|
120
|
-
.order("#{@
|
115
|
+
.order("#{@anchor_column_sql_identifier} #{@sort_direction}", @ar_relation.primary_key => @sort_direction)
|
121
116
|
.limit(@page_size)
|
122
117
|
end
|
123
118
|
|
@@ -137,24 +132,9 @@ class Pageturner
|
|
137
132
|
ar_relation.select_values.empty? || ar_relation.select_values.include?(@ar_relation.primary_key.to_sym)
|
138
133
|
end
|
139
134
|
|
140
|
-
#
|
141
|
-
|
142
|
-
|
143
|
-
# `object` must be an ActiveRecord instance.
|
144
|
-
def public_send_chain_from_sql(object, qualified_column_sql_identifier)
|
145
|
-
# We limit `split` to 2 because we are assuming that the SQL identifier is in table.column format.
|
146
|
-
association, attribute = qualified_column_sql_identifier.split(".", 2).each_with_index.map do |string, index|
|
147
|
-
# The first element should be the joined table's sql identifier.
|
148
|
-
# These are always pluralized, so we must singularize it in order to use it as a method call.
|
149
|
-
index == 0 ? string.singularize : string
|
150
|
-
end
|
151
|
-
|
152
|
-
object.try!(association).try!(attribute)
|
153
|
-
end
|
154
|
-
|
155
|
-
# Heuristic to check if the `anchor_column` is a joined column.
|
156
|
-
def external_anchor_column?
|
157
|
-
@anchor_column.include?(".")
|
135
|
+
# Given attribute_chain = "association.attribute", it will call `.association.attribute` on `object`.
|
136
|
+
def try_chain(object, attribute_chain)
|
137
|
+
attribute_chain.split(".").reduce(object) { |o, command| o.try!(command) }
|
158
138
|
end
|
159
139
|
|
160
140
|
class Exception
|
data/pageturner.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pageturner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- crzrcn
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-02-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|