# frozen-string-literal: true
#
# The set_literalizer extension allows for using Set instances in many of the
# same places that you would use Array instances:
#
#   DB[:table].where(column: Set.new([1, 2, 3]))
#   # SELECT FROM table WHERE (column IN (1, 2, 3))
#
# To load the extension into all datasets created from a given Database:
#
#   DB.extension :set_literalizer
#
# Related module: Sequel::Dataset::SetLiteralizer

require 'set'

module Sequel
  class Dataset
    module SetLiteralizer
      # Try to generate the same SQL for Set instances used in datasets
      # that would be used for equivalent Array instances.
      def complex_expression_sql_append(sql, op, args)
        # Array instances are treated specially by
        # Sequel::SQL::BooleanExpression.from_value_pairs. That cannot
        # be modified by a dataset extension, so this tries to convert
        # the complex expression values generated by default to what would
        # be the complex expression values used for the equivalent array.
        case op
        when :'=', :'!='
          if (set = args[1]).is_a?(Set)
            op = op == :'=' ? :IN : :'NOT IN'
            col = args[0]
            array = set.to_a
            if Sequel.condition_specifier?(array) && col.is_a?(Array)
              array = Sequel.value_list(array)
            end
            args = [col, array]
          end
        end

        super
      end

      private

      # Literalize Set instances by converting the set to array.
      def literal_other_append(sql, v)
        if Set === v
          literal_append(sql, v.to_a) 
        else
          super
        end
      end
    end

    register_extension(:set_literalizer, SetLiteralizer)
  end
end
