# frozen_string_literal: true module Gitlab module Graphql module Connections module Keyset class OrderInfo def initialize(order_value) @order_value = order_value end def attribute_name order_value.expr.name end def operator_for(before_or_after) case before_or_after when :before sort_direction == :asc ? '<' : '>' when :after sort_direction == :asc ? '>' : '<' end end # Only allow specific node types. For example ignore String nodes def self.build_order_list(relation) order_list = relation.order_values.select do |value| value.is_a?(Arel::Nodes::Ascending) || value.is_a?(Arel::Nodes::Descending) end order_list.map { |info| OrderInfo.new(info) } end def self.validate_ordering(relation, order_list) if order_list.empty? raise ArgumentError.new('A minimum of 1 ordering field is required') end if order_list.count > 2 raise ArgumentError.new('A maximum of 2 ordering fields are allowed') end # make sure the last ordering field is non-nullable attribute_name = order_list.last&.attribute_name if relation.columns_hash[attribute_name].null raise ArgumentError.new("Column `#{attribute_name}` must not allow NULL") end if order_list.last.attribute_name != relation.primary_key raise ArgumentError.new("Last ordering field must be the primary key, `#{relation.primary_key}`") end end private attr_reader :order_value def sort_direction order_value.direction end end end end end end