Class: ParamsReady::Pagination::KeysetPagination
Constant Summary
ParamsReady::Parameter::AbstractStructParameter::EMPTY_HASH
Instance Attribute Summary
#definition
Instance Method Summary
collapse
-
#after_page_value(keyset) ⇒ Object
-
#before_page_value(keyset) ⇒ Object
-
#cursor ⇒ Object
-
#cursor_columns ⇒ Object
-
#cursor_columns_arel(ordering, arel_table, context, columns: cursor_columns) ⇒ Object
-
#cursor_predicates(direction, keyset, ordering, arel_table, context) ⇒ Object
-
#direction ⇒ Object
-
#exists_predicate(subselect, ordering, arel_table) ⇒ Object
-
#first_page_value ⇒ Object
-
#keyset ⇒ Object
-
#keyset_query(query, limit, direction, keyset, ordering, arel_table, context) ⇒ Object
-
#keysets_for_relation(relation, limit, direction, keyset, ordering, context) ⇒ Object
-
#last_page_value ⇒ Object
-
#limit ⇒ Object
-
#limit_key ⇒ Object
-
#ordering_arel(direction, ordering, arel_table, context) ⇒ Object
-
#paginate_query(query, ordering, arel_table, context) ⇒ Object
-
#paginate_relation(relation, ordering, context) ⇒ Object
-
#primary_keys_arel(ordering, arel_table, context) ⇒ Object
-
#related_clause(arel_table, aliased, primary_keys) ⇒ Object
-
#select_keysets(query, limit, direction, keyset, ordering, arel_table, context) ⇒ Object
-
#table_alias(arel_table) ⇒ Object
-
#with_cte(relation, select, cursor) ⇒ Object
-
#with_cte_grouped(relation, select, cursor) ⇒ Object
#first_page, #last_page, #num_pages
#marshal
#[], #[]=, #find_in_hash, #for_frontend, #for_model, #for_output, #wrap_output
#update_child
#allows_undefined?, #definite_default?, #eligible_for_output?, #find_in_hash, #format, #format_self_permitted, #freeze, #hash, #hash_key, #initialize, #inspect_content, #is_default?, #is_definite?, #is_nil?, #is_undefined?, #memo, #memo!, #nil_default?, #populate_other, #set_from_input, #set_value, #to_hash_if_eligible, #unwrap, #unwrap_or, #wrap_output
#==, #dup, #initialize, #inspect, intent_for_children, #match?, #populate, #to_hash, #update_if_applicable, #update_in
#freeze_variable, #freeze_variables, #variables_to_freeze
#set_from_hash
#freeze
Instance Method Details
#after_page_value(keyset) ⇒ Object
130
131
132
133
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 130
def after_page_value(keyset)
keyset ||= {}
{ limit: limit, direction: :aft, keyset: keyset }
end
|
#before_page_value(keyset) ⇒ Object
125
126
127
128
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 125
def before_page_value(keyset)
keyset ||= {}
{ limit: limit, direction: :bfr, keyset: keyset }
end
|
#cursor ⇒ Object
170
171
172
173
174
175
176
177
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 170
def cursor
return nil unless is_definite?
keyset = self[:keyset]
keyset.names.keys.map do |column_name|
keyset[column_name].unwrap
end
end
|
#cursor_columns ⇒ Object
151
152
153
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 151
def cursor_columns
self[:keyset].names.keys
end
|
#cursor_columns_arel(ordering, arel_table, context, columns: cursor_columns) ⇒ Object
155
156
157
158
159
160
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 155
def cursor_columns_arel(ordering, arel_table, context, columns: cursor_columns)
columns.map do |name|
column = ordering.definition.columns[name]
column.attribute(name, arel_table, context)
end
end
|
#cursor_predicates(direction, keyset, ordering, arel_table, context) ⇒ Object
112
113
114
115
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 112
def cursor_predicates(direction, keyset, ordering, arel_table, context)
direction = Direction.instance(direction)
direction.cursor_predicates(keyset, ordering, arel_table, context)
end
|
#direction ⇒ Object
143
144
145
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 143
def direction
self[:direction].unwrap
end
|
#exists_predicate(subselect, ordering, arel_table) ⇒ Object
70
71
72
73
74
75
76
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 70
def exists_predicate(subselect, ordering, arel_table)
table_alias = self.table_alias(arel_table)
aliased = arel_table.alias(table_alias)
select_manager = Arel::SelectManager.new.from(subselect.as(table_alias))
related = related_clause(arel_table, aliased, ordering.definition.primary_keys)
select_manager.where(related).project('1').exists
end
|
#first_page_value ⇒ Object
117
118
119
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 117
def first_page_value
{ limit: limit, direction: :aft, keyset: {} }
end
|
#keyset ⇒ Object
147
148
149
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 147
def keyset
self[:keyset].unwrap
end
|
#keyset_query(query, limit, direction, keyset, ordering, arel_table, context) ⇒ Object
17
18
19
20
21
22
23
24
25
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 17
def keyset_query(query, limit, direction, keyset, ordering, arel_table, context)
cursor, grouping = cursor_predicates(direction, keyset, ordering, arel_table, context)
cte = cursor.cte_for_query(query, arel_table) unless cursor.nil?
query = query.where(grouping) unless grouping.nil?
query = query.with(cte) unless cte.nil?
ordered = query.order(ordering_arel(direction, ordering, arel_table, context))
ordered.take(limit)
end
|
#keysets_for_relation(relation, limit, direction, keyset, ordering, context) ⇒ Object
27
28
29
30
31
32
33
34
35
36
37
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 27
def keysets_for_relation(relation, limit, direction, keyset, ordering, context)
arel_table = relation.arel_table
cursor, predicates = cursor_predicates(direction, keyset, ordering, arel_table, context)
full_query = relation.where(predicates)
.reorder(ordering_arel(direction, ordering, arel_table, context))
.limit(limit)
.select(*cursor_columns_arel(ordering, arel_table, context))
full_query = Arel::Nodes::SqlLiteral.new(full_query.to_sql)
with_cte(relation, full_query, cursor)
end
|
#last_page_value ⇒ Object
121
122
123
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 121
def last_page_value
{ limit: limit, direction: :bfr, keyset: {} }
end
|
#limit ⇒ Object
135
136
137
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 135
def limit
self[:limit].unwrap
end
|
#limit_key ⇒ Object
139
140
141
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 139
def limit_key
:limit
end
|
#ordering_arel(direction, ordering, arel_table, context) ⇒ Object
107
108
109
110
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 107
def ordering_arel(direction, ordering, arel_table, context)
inverted = Direction.instance(direction).invert_ordering?
ordering.to_arel(arel_table, context: context, inverted: inverted)
end
|
#paginate_query(query, ordering, arel_table, context) ⇒ Object
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 55
def paginate_query(query, ordering, arel_table, context)
cursor, predicates = cursor_predicates(direction, keyset, ordering, arel_table, context)
cte = cursor.cte_for_query(query, arel_table) unless cursor.nil?
subquery = query.deep_dup
subquery = subquery.where(predicates) unless predicates.nil?
subquery = subquery.with(cte) unless cte.nil?
subselect = subquery.order(ordering_arel(direction, ordering, arel_table, context))
.take(limit)
.project(primary_keys_arel(ordering, arel_table, context))
exists = exists_predicate(subselect, ordering, arel_table)
query.where(exists)
end
|
#paginate_relation(relation, ordering, context) ⇒ Object
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 39
def paginate_relation(relation, ordering, context)
arel_table = relation.arel_table
cursor, predicates = cursor_predicates(direction, keyset, ordering, arel_table, context)
subselect = relation.where(predicates)
.reorder(ordering_arel(direction, ordering, arel_table, context))
.limit(limit)
.select(primary_keys_arel(ordering, arel_table, context))
subselect_sql = Arel::Nodes::SqlLiteral.new(subselect.to_sql)
subselect_sql = with_cte_grouped(relation, subselect_sql, cursor)
exists = exists_predicate(subselect_sql, ordering, arel_table)
relation.where(exists)
end
|
#primary_keys_arel(ordering, arel_table, context) ⇒ Object
162
163
164
165
166
167
168
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 162
def primary_keys_arel(ordering, arel_table, context)
columns = cursor_columns.lazy.select do |name|
ordering.definition.primary_keys.member? name
end
cursor_columns_arel(ordering, arel_table, context, columns: columns).force
end
|
78
79
80
81
82
83
84
85
86
87
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 78
def related_clause(arel_table, aliased, primary_keys)
cursor_columns.reduce(nil) do |clause, name|
next clause unless primary_keys.member?(name)
predicate = arel_table[name].eq(aliased[name])
next predicate if clause.nil?
next clause.and(predicate)
end
end
|
#select_keysets(query, limit, direction, keyset, ordering, arel_table, context) ⇒ Object
12
13
14
15
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 12
def select_keysets(query, limit, direction, keyset, ordering, arel_table, context)
query = keyset_query(query, limit, direction, keyset, ordering, arel_table, context)
query.project(*cursor_columns_arel(ordering, arel_table, context))
end
|
#table_alias(arel_table) ⇒ Object
103
104
105
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 103
def table_alias(arel_table)
Helpers::ArelBuilder.safe_name "#{arel_table.name}_#{cursor_columns.join('_')}"
end
|
#with_cte(relation, select, cursor) ⇒ Object
94
95
96
97
98
99
100
101
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 94
def with_cte(relation, select, cursor)
return select if cursor.nil?
cte = cursor.cte_for_relation(relation)
return select if cte.nil?
Arel::Nodes::SqlLiteral.new([cte.to_sql, select].join(' '))
end
|
#with_cte_grouped(relation, select, cursor) ⇒ Object
89
90
91
92
|
# File 'lib/params_ready/pagination/keyset_pagination.rb', line 89
def with_cte_grouped(relation, select, cursor)
with_cte = with_cte(relation, select, cursor)
Arel::Nodes::Grouping.new(with_cte)
end
|