main
  1# frozen_string_literal: true
  2
  3module Scim
  4  class Visitor < Scim::Kit::V2::Filter::Visitor
  5    include Varkon
  6
  7    def initialize(clazz, mapper = {})
  8      @clazz = clazz
  9      @mapper = mapper
 10    end
 11
 12    protected
 13
 14    def visit_and(node)
 15      visit(node.left).merge(visit(node.right))
 16    end
 17
 18    def visit_or(node)
 19      visit(node.left).or(visit(node.right))
 20    end
 21
 22    def visit_equals(node)
 23      query_for(node, attr_for(node) => node.value)
 24    end
 25
 26    def visit_not_equals(node)
 27      if node.not?
 28        @clazz.where(attr_for(node) => node.value)
 29      else
 30        @clazz.where.not(attr_for(node) => node.value)
 31      end
 32    end
 33
 34    def visit_contains(node)
 35      query_for(
 36        node,
 37        "#{attr_for(node)} LIKE ?",
 38        "%#{escape_sql_wildcards(node.value)}%"
 39      )
 40    end
 41
 42    def visit_starts_with(node)
 43      query_for(
 44        node,
 45        "#{attr_for(node)} LIKE ?",
 46        "#{escape_sql_wildcards(node.value)}%"
 47      )
 48    end
 49
 50    def visit_ends_with(node)
 51      query_for(
 52        node,
 53        "#{attr_for(node)} LIKE ?",
 54        "%#{escape_sql_wildcards(node.value)}"
 55      )
 56    end
 57
 58    def visit_greater_than(node)
 59      query_for(node, "#{attr_for(node)} > ?", cast_value_from(node))
 60    end
 61
 62    def visit_greater_than_equals(node)
 63      query_for(node, "#{attr_for(node)} >= ?", cast_value_from(node))
 64    end
 65
 66    def visit_less_than(node)
 67      query_for(node, "#{attr_for(node)} < ?", cast_value_from(node))
 68    end
 69
 70    def visit_less_than_equals(node)
 71      query_for(node, "#{attr_for(node)} <= ?", cast_value_from(node))
 72    end
 73
 74    def visit_presence(node)
 75      if node.not?
 76        @clazz.where(attr_for(node) => nil)
 77      else
 78        @clazz.where.not(attr_for(node) => nil)
 79      end
 80    end
 81
 82    def visit_unknown(_node)
 83      @clazz.none
 84    end
 85
 86    def cast_value_from(node)
 87      case @clazz.columns_hash[attr_for(node).to_s].type
 88      when :datetime
 89        DateTime.parse(node.value).utc
 90      else
 91        node.value.to_s
 92      end
 93    end
 94
 95    def attr_for(node)
 96      @mapper.fetch(node.attribute, node.attribute)
 97    end
 98
 99    def query_for(node, *conditions)
100      node.not? ? @clazz.where.not(*conditions) : @clazz.where(*conditions)
101    end
102  end
103end