graphql-page_cursors 0.0.1 → 0.0.2
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/.rubocop.yml +4 -0
- data/lib/graphql/page_cursors.rb +11 -102
- data/lib/page_cursor.rb +40 -0
- data/lib/page_cursor_resolver.rb +111 -0
- data/lib/page_cursors/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 86e6f9c53e954f6da661bd84e583650bf1238c9c20708e7d8b271670d9132917
|
4
|
+
data.tar.gz: b145ce2ebc6d45729da5adfe14901cd992f6dec597ca3c84537015b361cc0389
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd4075765ff52c8d216824e21b62f265522498f196fcd07eb297c344382823ffd797e2856b07dfa9454847193fa108f67815acfe4afe41ef18dae41d06afc6a9
|
7
|
+
data.tar.gz: 957064f909047bb83a7761e8d75f21f31ee4bba38d47812ec6c3380f6a7b4a5ed6ed06e3f0a0becb2c02b42e76a1a128674f6a5ebf176b4bd3ae2beaaf99e821
|
data/.rubocop.yml
CHANGED
data/lib/graphql/page_cursors.rb
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
require 'graphql'
|
4
4
|
|
5
|
+
require 'page_cursor_resolver'
|
6
|
+
|
5
7
|
module GraphQL
|
6
8
|
class PageCursor < GraphQL::Schema::Object
|
7
9
|
field :cursor, String, 'first cursor on the page', null: false
|
@@ -21,116 +23,23 @@ module GraphQL
|
|
21
23
|
field :total_pages, Int, null: true
|
22
24
|
field :total_count, Int, null: true
|
23
25
|
|
24
|
-
|
26
|
+
attr_reader :resolver
|
25
27
|
|
26
|
-
def
|
27
|
-
|
28
|
+
def initialize(object, context)
|
29
|
+
super(object, context)
|
30
|
+
@resolver = PageCursorResolver.new(object, context)
|
31
|
+
end
|
28
32
|
|
29
|
-
|
30
|
-
|
31
|
-
first: first_cursor,
|
32
|
-
last: last_cursor,
|
33
|
-
previous: previous_cursor
|
34
|
-
}.compact
|
33
|
+
def page_cursors
|
34
|
+
resolver.page_cursors
|
35
35
|
end
|
36
36
|
|
37
37
|
def total_pages
|
38
|
-
|
39
|
-
return 1 if nodes_per_page.nil?
|
40
|
-
|
41
|
-
(object.items.size.to_f / nodes_per_page).ceil
|
38
|
+
resolver.total_pages
|
42
39
|
end
|
43
40
|
|
44
41
|
def total_count
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
|
50
|
-
def around_cursors
|
51
|
-
around_page_numbers.map { |page_num| page_cursor(page_num) }
|
52
|
-
end
|
53
|
-
|
54
|
-
def first_cursor
|
55
|
-
exceeds_max_cursor_count = total_pages > MAX_CURSOR_COUNT
|
56
|
-
include_first_cursor =
|
57
|
-
exceeds_max_cursor_count && around_page_numbers.exclude?(1)
|
58
|
-
return unless include_first_cursor
|
59
|
-
|
60
|
-
page_cursor(1)
|
61
|
-
end
|
62
|
-
|
63
|
-
def last_cursor
|
64
|
-
exceeds_max_cursor_count = total_pages > MAX_CURSOR_COUNT
|
65
|
-
include_last_cursor =
|
66
|
-
exceeds_max_cursor_count && around_page_numbers.exclude?(total_pages)
|
67
|
-
return unless include_last_cursor
|
68
|
-
|
69
|
-
page_cursor(total_pages)
|
70
|
-
end
|
71
|
-
|
72
|
-
def previous_cursor
|
73
|
-
include_previous_cursor = current_page > 1
|
74
|
-
return unless include_previous_cursor
|
75
|
-
|
76
|
-
page_cursor(current_page - 1)
|
77
|
-
end
|
78
|
-
|
79
|
-
def page_cursor(page_num)
|
80
|
-
{
|
81
|
-
cursor: cursor_for_page(page_num),
|
82
|
-
is_current: current_page == page_num,
|
83
|
-
page: page_num
|
84
|
-
}
|
85
|
-
end
|
86
|
-
|
87
|
-
def cursor_for_page(page_num)
|
88
|
-
return '' if page_num == 1
|
89
|
-
|
90
|
-
after_cursor = (page_num - 1) * nodes_per_page
|
91
|
-
encode(after_cursor.to_s)
|
92
|
-
end
|
93
|
-
|
94
|
-
def current_page
|
95
|
-
nodes_before / nodes_per_page + 1
|
96
|
-
end
|
97
|
-
|
98
|
-
def around_page_numbers # rubocop:disable Metrics/AbcSize
|
99
|
-
if total_pages <= MAX_CURSOR_COUNT
|
100
|
-
(1..total_pages).to_a
|
101
|
-
elsif current_page <= 3
|
102
|
-
(1..4).to_a
|
103
|
-
elsif current_page >= total_pages - 2
|
104
|
-
((total_pages - 3)..total_pages).to_a
|
105
|
-
else
|
106
|
-
[current_page - 1, current_page, current_page + 1]
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
def nodes_before
|
111
|
-
node_offset(object.edge_nodes.first) - 1
|
112
|
-
end
|
113
|
-
|
114
|
-
def nodes_after
|
115
|
-
node_offset(object.edge_nodes.last)
|
116
|
-
end
|
117
|
-
|
118
|
-
def node_offset(node)
|
119
|
-
# this was previously accomplished by calling a private method:
|
120
|
-
# object.send(:offset_from_cursor, object.cursor_from_node(object.edge_nodes.first))
|
121
|
-
object.items.index(node) + 1
|
122
|
-
end
|
123
|
-
|
124
|
-
def nodes_per_page
|
125
|
-
object.first || object.last
|
126
|
-
end
|
127
|
-
|
128
|
-
# borrowed from https://graphql-ruby.org/api-doc/1.10.6/Base64Bp.html
|
129
|
-
def encode(value)
|
130
|
-
str = Base64.strict_encode64(value)
|
131
|
-
str.tr!('+/', '-_')
|
132
|
-
str.delete!('=')
|
133
|
-
str
|
42
|
+
resolver.total_count
|
134
43
|
end
|
135
44
|
end
|
136
45
|
end
|
data/lib/page_cursor.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'base64'
|
4
|
+
|
5
|
+
class PageCursor
|
6
|
+
def self.as_hash(current_page, page_number, per_page)
|
7
|
+
new(current_page, page_number, per_page).to_hash
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :current_page, :page_number, :per_page
|
11
|
+
|
12
|
+
def initialize(current_page, page_number, per_page)
|
13
|
+
@current_page = current_page
|
14
|
+
@page_number = page_number
|
15
|
+
@per_page = per_page
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_hash
|
19
|
+
{
|
20
|
+
cursor: encoded_cursor,
|
21
|
+
is_current: current?,
|
22
|
+
page: page_number
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def current?
|
29
|
+
current_page == page_number
|
30
|
+
end
|
31
|
+
|
32
|
+
def encoded_cursor
|
33
|
+
previous_page = page_number - 1
|
34
|
+
return '' if previous_page.zero?
|
35
|
+
|
36
|
+
after_cursor = previous_page * per_page
|
37
|
+
encoded = Base64.strict_encode64(after_cursor.to_s)
|
38
|
+
encoded.tr('+/', '-_').delete('=')
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'page_cursor'
|
4
|
+
|
5
|
+
class PageCursorResolver
|
6
|
+
MAX_CURSOR_COUNT = 5
|
7
|
+
|
8
|
+
attr_reader :object, :context
|
9
|
+
|
10
|
+
def initialize(object, context)
|
11
|
+
@object = object
|
12
|
+
@context = context
|
13
|
+
end
|
14
|
+
|
15
|
+
def page_cursors
|
16
|
+
return if total_pages <= 1
|
17
|
+
|
18
|
+
{
|
19
|
+
around: around_cursors,
|
20
|
+
first: first_cursor,
|
21
|
+
last: last_cursor,
|
22
|
+
previous: previous_cursor
|
23
|
+
}.compact
|
24
|
+
end
|
25
|
+
|
26
|
+
def total_pages
|
27
|
+
return 0 if object_items.size.zero?
|
28
|
+
return 1 if nodes_per_page.nil?
|
29
|
+
|
30
|
+
(object_items.size.to_f / nodes_per_page).ceil
|
31
|
+
end
|
32
|
+
|
33
|
+
def total_count
|
34
|
+
object_items.size
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def object_items
|
40
|
+
return object.nodes unless object.respond_to?(:items)
|
41
|
+
|
42
|
+
object.items
|
43
|
+
end
|
44
|
+
|
45
|
+
def around_cursors
|
46
|
+
around_page_numbers.map { |page_num| page_cursor(page_num) }
|
47
|
+
end
|
48
|
+
|
49
|
+
def first_cursor
|
50
|
+
exceeds_max_cursor_count = total_pages > MAX_CURSOR_COUNT
|
51
|
+
include_first_cursor =
|
52
|
+
exceeds_max_cursor_count && !around_page_numbers.include?(1)
|
53
|
+
return unless include_first_cursor
|
54
|
+
|
55
|
+
page_cursor(1)
|
56
|
+
end
|
57
|
+
|
58
|
+
def last_cursor
|
59
|
+
exceeds_max_cursor_count = total_pages > MAX_CURSOR_COUNT
|
60
|
+
include_last_cursor =
|
61
|
+
exceeds_max_cursor_count && !around_page_numbers.include?(total_pages)
|
62
|
+
return unless include_last_cursor
|
63
|
+
|
64
|
+
page_cursor(total_pages)
|
65
|
+
end
|
66
|
+
|
67
|
+
def previous_cursor
|
68
|
+
include_previous_cursor = current_page > 1
|
69
|
+
return unless include_previous_cursor
|
70
|
+
|
71
|
+
page_cursor(current_page - 1)
|
72
|
+
end
|
73
|
+
|
74
|
+
def page_cursor(page_number)
|
75
|
+
PageCursor.as_hash(current_page, page_number, nodes_per_page)
|
76
|
+
end
|
77
|
+
|
78
|
+
def current_page
|
79
|
+
nodes_before / nodes_per_page + 1
|
80
|
+
end
|
81
|
+
|
82
|
+
def around_page_numbers # rubocop:disable Metrics/AbcSize
|
83
|
+
if total_pages <= MAX_CURSOR_COUNT
|
84
|
+
(1..total_pages).to_a
|
85
|
+
elsif current_page <= 3
|
86
|
+
(1..4).to_a
|
87
|
+
elsif current_page >= total_pages - 2
|
88
|
+
((total_pages - 3)..total_pages).to_a
|
89
|
+
else
|
90
|
+
[current_page - 1, current_page, current_page + 1]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def nodes_before
|
95
|
+
node_offset(object.edge_nodes.first) - 1
|
96
|
+
end
|
97
|
+
|
98
|
+
def nodes_after
|
99
|
+
node_offset(object.edge_nodes.last)
|
100
|
+
end
|
101
|
+
|
102
|
+
def node_offset(node)
|
103
|
+
# this was previously accomplished by calling a private method:
|
104
|
+
# object.send(:offset_from_cursor, object.cursor_from_node(object.edge_nodes.first))
|
105
|
+
object_items.index(node) + 1
|
106
|
+
end
|
107
|
+
|
108
|
+
def nodes_per_page
|
109
|
+
object.first || object.last
|
110
|
+
end
|
111
|
+
end
|
data/lib/page_cursors/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql-page_cursors
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Allured
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-11-
|
11
|
+
date: 2020-11-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: graphql
|
@@ -104,6 +104,8 @@ files:
|
|
104
104
|
- bin/setup
|
105
105
|
- graphql-page_cursors.gemspec
|
106
106
|
- lib/graphql/page_cursors.rb
|
107
|
+
- lib/page_cursor.rb
|
108
|
+
- lib/page_cursor_resolver.rb
|
107
109
|
- lib/page_cursors/version.rb
|
108
110
|
homepage: https://github.com/artsy/graphql-page_cursors
|
109
111
|
licenses:
|