1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-07-31 19:19:38 +02:00
Maybe/app/models/rule/condition.rb

63 lines
2 KiB
Ruby
Raw Normal View History

class Rule::Condition < ApplicationRecord
UnsupportedOperatorError = Class.new(StandardError)
UnsupportedConditionTypeError = Class.new(StandardError)
OPERATORS = [ "and", "or", "like", ">", ">=", "<", "<=", "=" ]
belongs_to :rule, optional: -> { where.not(parent_id: nil) }
belongs_to :parent, class_name: "Rule::Condition", optional: true
has_many :sub_conditions, class_name: "Rule::Condition", foreign_key: :parent_id, dependent: :destroy
validates :operator, inclusion: { in: OPERATORS }, allow_nil: true
validates :condition_type, presence: true
def apply(resource_scope)
filtered_scope = resource_scope
case condition_type
when "compound"
2025-04-02 12:47:07 -04:00
filtered_scope = build_compound_scope(filtered_scope)
when "transaction_name"
2025-04-02 12:47:07 -04:00
filtered_scope = filtered_scope.where("account_entries.name #{Arel.sql(sanitize_operator(operator))} ?", value)
when "transaction_amount"
2025-04-02 12:47:07 -04:00
filtered_scope = filtered_scope.where("account_entries.amount #{Arel.sql(sanitize_operator(operator))} ?", value.to_d)
when "transaction_merchant"
filtered_scope = filtered_scope.left_joins(:merchant).where(merchant: { name: value })
else
raise UnsupportedConditionTypeError, "Unsupported condition type: #{condition_type}"
end
filtered_scope
end
private
def sanitize_operator(operator)
raise UnsupportedOperatorError, "Unsupported operator: #{operator}" unless OPERATORS.include?(operator)
operator
end
2025-04-02 12:47:07 -04:00
def build_compound_scope(filtered_scope)
if operator == "or"
combined_scope = nil
sub_conditions.each do |sub_condition|
sub_scope = sub_condition.apply(filtered_scope)
if combined_scope.nil?
combined_scope = sub_scope
else
combined_scope = combined_scope.or(sub_scope)
end
end
filtered_scope = combined_scope || filtered_scope
else
sub_conditions.each do |sub_condition|
filtered_scope = sub_condition.apply(filtered_scope)
end
end
filtered_scope
end
end