Skip to content

Commit

Permalink
simplify for multiple rules with a single set of acceptable values on…
Browse files Browse the repository at this point in the history
… the same column
  • Loading branch information
splitice committed Oct 31, 2024
1 parent 3be6be6 commit b62de80
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 8 deletions.
2 changes: 1 addition & 1 deletion lib/cancan/controller_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def self.before_callback_name(options)

def initialize(controller, *args)
@controller = controller
@params = controller.params.to_unsafe_h
@params = controller.params.to_unsafe_h
@options = args.extract_options!
@name = args.first
end
Expand Down
48 changes: 41 additions & 7 deletions lib/cancan/rules_compressor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,49 @@ def compress(array)
.tap { |a| a.unshift(value) unless value.cannot_catch_all? }
end

# If we have A OR (!A AND anything ), then we can simplify to A OR anything
# If we have A OR (A OR anything ), then we can simplify to A OR anything
# If we have !A AND (A OR something), then we can simplify it to !A AND something
# If we have !A AND (!A AND something), then we can simplify it to !A AND something
#
# So as soon as we see a condition that is the same as the previous one,
# we can skip it, no matter of the base_behavior
def simplify(rules)
seen = Set.new

# If we have a bunch of of rules with conditions on the same key, we can simplify them
# to a single rule with an array of values
# e.g contact_id = 1, contact_id = [2, 3] => contact_id = [1, 2, 3]
potentially_simplify_singular = rules.size > 1 && rules.all? do |rule|
if rule.conditions.is_a?(Hash)
rule.conditions.size == 1
else
false
end
end

if potentially_simplify_singular
potentially_simplify_singular = rules.map do |rule|
rule.conditions.keys.first
end.uniq
if potentially_simplify_singular.size == 1
new_valid_values = rules.map do |rule|
r = rule.conditions.values

if r.is_a?(Array)
r
else
[r]
end
end.flatten.uniq

h = {}
h[potentially_simplify_singular.first] = new_valid_values
rules.last.conditions = h
return [rules.last]
end
end

# If we have A OR (!A AND anything ), then we can simplify to A OR anything
# If we have A OR (A OR anything ), then we can simplify to A OR anything
# If we have !A AND (A OR something), then we can simplify it to !A AND something
# If we have !A AND (!A AND something), then we can simplify it to !A AND something
#
# So as soon as we see a condition that is the same as the previous one,
# we can skip it, no matter of the base_behavior
rules.reverse_each.filter_map do |rule|
next if seen.include?(rule.conditions)

Expand Down

0 comments on commit b62de80

Please sign in to comment.