Refactoring długiego ifa z zapytaniami do ActiveRecord

Mam takie monstrum jako service object:

  def initialize(rule)
     @rule = rule
  end

  def call
    users = Array.new

    if @rule[:match] === "=" # exact match
      users = User.where("#{@rule[:properties].keys.first.to_s} = ?", "#{@rule[:properties].values.first.to_s}")

    elsif @rule[:match] === "^" # begins with
      users = User.where("#{@rule[:properties].keys.first.to_s} LIKE ?", "#{@rule[:properties].values.first.to_s}%")

    elsif @rule[:match] === "~" # contains
      users = User.where("#{@rule[:properties].keys.first.to_s} LIKE ?", "%#{@rule[:properties].values.first.to_s}%")

    elsif @rule[:match] === "$" # ends with
      users = User.where("#{@rule[:properties].keys.first.to_s} LIKE ?", "%#{@rule[:properties].values.first.to_s}")

    elsif @rule[:match] === "!=" # does not match
      users = User.where.not("#{@rule[:properties].keys.first.to_s} = ?", "#{@rule[:properties].values.first.to_s}")

    elsif @rule[:match] === "!^" # does not begin with
      users = User.where.not("#{@rule[:properties].keys.first.to_s} LIKE ?", "#{@rule[:properties].values.first.to_s}%")

    elsif @rule[:match] === "!~" # does not contain
      users = User.where.not("#{@rule[:properties].keys.first.to_s} LIKE ?", "%#{@rule[:properties].values.first.to_s}%")

    elsif @rule[:match] === "!$" # does not end with
      users = User.where.not("#{@rule[:properties].keys.first.to_s} LIKE ?", "%#{@rule[:properties].values.first.to_s}")

    elsif @rule[:match] === "empty" # is empty
      users = User.where("#{@rule[:properties].keys.first.to_s} = ?", "")

    elsif @rule[:match] === "!empty" # is not empty
      users = User.where.not("#{@rule[:properties].keys.first.to_s} = ?", "")
    else
      users = []
    end

W jaki sposób można to poprawić? Każdy if wymaga nieco innego zapytania do Active Record (where/where.not, = / LIKE, wildcardy w różnych miejscach)

Może tak:
Hash wiążący wartość rule[:match] ze stringiem typu: “%#{@rule[:properties].values.first.to_s}”

Potem jeden if na “= ?” i elsif na “like ?” a wynik podstawisz a Hasha

1 Like

Zrób sobie mapowanie parametrów do warunków

super_crazy = {
  "=" => "%s",
  "^" => "%s%"
  "~" => "%%s%"
  ... itd
}

 rule_pattern = super_crazy[@rule[:match]]
 pattern =  rule_pattern % @rule[:properties].values.first.to_s
 users = User.where.not("#{@rule[:properties].keys.first.to_s} LIKE ?", pattern)

2 Likes