lib/graphql/pagination/relation_connection.rb in graphql-1.10.0 vs lib/graphql/pagination/relation_connection.rb in graphql-1.10.1

- old
+ new

@@ -9,16 +9,36 @@ load_nodes @nodes end def has_previous_page - load_nodes + if @has_previous_page.nil? + @has_previous_page = if @after_offset && @after_offset > 0 + true + elsif last + # See whether there are any nodes _before_ the current offset. + # If there _is no_ current offset, then there can't be any nodes before it. + # Assume that if the offset is positive, there are nodes before the offset. + limited_nodes + !(@paged_nodes_offset.nil? || @paged_nodes_offset == 0) + else + false + end + end @has_previous_page end def has_next_page - load_nodes + if @has_next_page.nil? + @has_next_page = if @before_offset && @before_offset > 0 + true + elsif first + relation_count(set_limit(sliced_nodes, first + 1)) == first + 1 + else + false + end + end @has_next_page end def cursor_for(item) load_nodes @@ -78,41 +98,49 @@ else relation end end - # Populate all the pagination info _once_, - # It doesn't do anything on subsequent calls. - def load_nodes - @nodes ||= begin + # Apply `before` and `after` to the underlying `items`, + # returning a new relation. + def sliced_nodes + @sliced_nodes ||= begin paginated_nodes = items - after_offset = after && offset_from_cursor(after) - before_offset = before && offset_from_cursor(before) + @after_offset = after && offset_from_cursor(after) + @before_offset = before && offset_from_cursor(before) - if after_offset + if @after_offset previous_offset = relation_offset(items) || 0 - paginated_nodes = set_offset(paginated_nodes, previous_offset + after_offset) + paginated_nodes = set_offset(paginated_nodes, previous_offset + @after_offset) end - if before_offset && after_offset - if after_offset < before_offset + if @before_offset && @after_offset + if @after_offset < @before_offset # Get the number of items between the two cursors - space_between = before_offset - after_offset - 1 + space_between = @before_offset - @after_offset - 1 paginated_nodes = set_limit(paginated_nodes, space_between) else # TODO I think this is untested # The cursors overextend one another to an empty set paginated_nodes = null_relation(paginated_nodes) end - elsif before_offset + elsif @before_offset # Use limit to cut off the tail of the relation - paginated_nodes = set_limit(paginated_nodes, before_offset - 1) + paginated_nodes = set_limit(paginated_nodes, @before_offset - 1) end - sliced_nodes_count = relation_count(paginated_nodes) + paginated_nodes + end + end - if first && (relation_limit(paginated_nodes).nil? || relation_limit(paginated_nodes) > first) + # Apply `first` and `last` to `sliced_nodes`, + # returning a new relation + def limited_nodes + @limited_nodes ||= begin + paginated_nodes = sliced_nodes + + if first && (relation_limit(paginated_nodes).nil? || relation_limit(paginated_nodes) > first) && last.nil? # `first` would create a stricter limit that the one already applied, so add it paginated_nodes = set_limit(paginated_nodes, first) end if last @@ -123,29 +151,26 @@ paginated_nodes = set_offset(paginated_nodes, offset) paginated_nodes = set_limit(paginated_nodes, last) end else # No limit, so get the last items + sliced_nodes_count = relation_count(@sliced_nodes) offset = (relation_offset(paginated_nodes) || 0) + sliced_nodes_count - [last, sliced_nodes_count].min paginated_nodes = set_offset(paginated_nodes, offset) paginated_nodes = set_limit(paginated_nodes, last) end end - @has_next_page = !!( - (before_offset && before_offset > 0) || - (first && sliced_nodes_count > first) - ) - - @has_previous_page = !!( - (after_offset && after_offset > 0) || - (last && sliced_nodes_count > last) - ) - @paged_nodes_offset = relation_offset(paginated_nodes) - # Return an array so we can consistently use `.index(node)` on it - paginated_nodes.to_a + paginated_nodes end + end + + # Load nodes after applying first/last/before/after, + # returns an array of nodes + def load_nodes + # Return an array so we can consistently use `.index(node)` on it + @nodes ||= limited_nodes.to_a end end end end