Skip to content

Instantly share code, notes, and snippets.

@dteoh
Last active October 28, 2019 16:51
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dteoh/bf063050ee3298910c70f2af1c61c879 to your computer and use it in GitHub Desktop.
Save dteoh/bf063050ee3298910c70f2af1c61c879 to your computer and use it in GitHub Desktop.
GrapQL Ruby: Custom Relay connection class for ActiveRecord::Relation objects
# This custom relay connection class exists because the built-in connection
# class is broken when max_page_size is used.
#
# See: https://github.com/rmosolgo/graphql-ruby/issues/1109
class CustomArRelationRelayConnection < GraphQL::Relay::BaseConnection
def cursor_from_node(item)
cursor_col = item.class.implicit_order_column
encode(item.send(cursor_col).to_s)
end
def has_next_page
paged_nodes && @will_have_next_page
end
def has_previous_page
paged_nodes && @will_have_prev_page
end
private
def paged_nodes
return @computed_paged_nodes if defined? @computed_paged_nodes
@will_have_next_page = false
@will_have_prev_page = false
page =
ActiveRecord::Base.transaction do
rel = sliced_nodes
if first
if rel.count > first
@will_have_next_page = true
end
rel = rel.limit(first)
end
if last
skip = rel.count - last
if skip > 0
rel = rel.offset(skip)
@will_have_prev_page = true
end
end
if max_page_size
if rel.count > max_page_size
rel = rel.limit(max_page_size)
@will_have_next_page = true
end
end
rel.to_a
end
@computed_paged_nodes = page
@computed_paged_nodes
end
def sliced_nodes
ActiveRecord::Base.transaction do
cursor_col = nodes.klass.implicit_order_column
rel = nodes
if after
after_val = decode(after)
rel = rel.where(rel.arel_table[cursor_col].gt(after_val))
if nodes.where(nodes.arel_table[cursor_col].lteq(after_val)).exists?
@will_have_prev_page = true
end
end
if before
before_val = decode(before)
rel = rel.where(rel.arel_table[cursor_col].lt(before_val))
if nodes.where(nodes.arel_table[cursor_col].gteq(before_val)).exists?
@will_have_next_page = true
end
end
rel
end
end
end
@dteoh
Copy link
Author

dteoh commented Oct 9, 2019

This implementation assumes:

  • you are using Postgres
  • the relation you are paging is ordered ascending by the ID column (override by changing implicit_order_column value on the model
    class)
  • you are trying to solve this issue: rmosolgo/graphql-ruby#1109

To use this:

class ApplicationSchema < GraphQL::Schema
  # ... other code here

  GraphQL::Relay::BaseConnection.register_connection_implementation(ActiveRecord::Relation, CustomArRelationRelayConnection)

  # ... other code here
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment