Skip to content

Commit

Permalink
Add ability to decrement on destroy
Browse files Browse the repository at this point in the history
  • Loading branch information
Michaelvilleneuve committed Dec 8, 2023
1 parent 841efff commit 7d6d86f
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 14 deletions.
5 changes: 4 additions & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ Metrics/AbcSize:
Metrics/BlockLength:
Enabled: false

Style/MultilineIfModifier:
Enabled: false

Metrics/CyclomaticComplexity:
Enabled: false

Expand All @@ -36,4 +39,4 @@ Layout/LineLength:
Max: 120

Metrics/MethodLength:
Max: 20
Max: 30
19 changes: 18 additions & 1 deletion lib/statisfy/counter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ module ClassMethods
def count(args = {})
raise ArgumentError, "You must provide at least one event" if args[:every].blank?

catch_events(*args[:every], if: args[:if] || -> { true })
catch_events(*args[:every])
apply_default_counter_options(args)
const_set(:COUNTER_TYPE, args[:type] || :increment)
class_eval(&Statisfy.configuration.append_to_counters) if Statisfy.configuration.append_to_counters.present?
Expand All @@ -45,6 +45,8 @@ def apply_default_counter_options(args)
define_method(:decrement?, args[:decrement_if] || -> { false })
define_method(:value, args[:value] || -> {})
define_method(:should_run?, args[:if] || -> { true })
define_method(:on_destroy, args[:on_destroy]) if args[:on_destroy].present?
define_method(:decrement_on_destroy?, args[:decrement_on_destroy].is_a?(Proc) ? args[:decrement_on_destroy] : -> { args[:decrement_on_destroy] || false })
end

#
Expand Down Expand Up @@ -168,6 +170,7 @@ def month_to_set
end

def process_event
return if destroy_event_handled?
return unless if_async

if value.present?
Expand All @@ -177,6 +180,20 @@ def process_event
end
end

def destroy_event_handled?
return false unless params[:statisfy_trigger] == :destroy

if decrement_on_destroy?
decrement
return true
elsif respond_to?(:on_destroy)
on_destroy
return true
end

false
end

#
# This allows to iterate over all the counters that need to be updated
# (in general the Department(s) and Organisation(s) for both the current month and the global counter)
Expand Down
38 changes: 26 additions & 12 deletions lib/statisfy/subscriber.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
require "pry"
module Statisfy
module Subscriber
def self.included(klass)
klass.extend(ClassMethods)
end

module ClassMethods
def catch_events(*event_names, **options)
define_method(:should_run?, &options[:if] || -> { true })
def catch_events(*event_names)
[*event_names].flatten.map do |event_name|
model_and_event_from_event_name(event_name).tap do |model, event|
append_callback_to_model(model, event)
Expand All @@ -17,18 +17,33 @@ def catch_events(*event_names, **options)

def append_callback_to_model(model, event)
listener = self

statisfy_counter = lambda {
counter = listener.new
counter.subject = self
counter
}

trigger_event = lambda { |statisfy_trigger|
if listener.respond_to?(Statisfy.configuration.default_async_method)
listener.send(Statisfy.configuration.default_async_method, attributes.merge(statisfy_trigger:))
else
instance_exec(&statisfy_counter).perform(attributes.merge(statisfy_trigger:))
end
}

model.class_eval do
after_commit on: event do
counter = listener.new
counter.subject = self
after_commit on: [:destroy] do
counter = instance_exec(&statisfy_counter)
next unless counter.decrement_on_destroy? || counter.respond_to?(:on_destroy)

instance_exec(:destroy, &trigger_event)
end

next unless counter.should_run?
after_commit on: [event] do
next unless instance_exec(&statisfy_counter).should_run?

if listener.respond_to?(Statisfy.configuration.default_async_method)
listener.send(Statisfy.configuration.default_async_method, attributes)
else
counter.perform(attributes)
end
instance_exec(event, &trigger_event)
end
end
end
Expand Down Expand Up @@ -64,7 +79,6 @@ def define_subject_method(model)
# This is the method that will be called when an event is triggered
# It will be executed in the background by Sidekiq
#
# @resource_or_hash [Hash] The attributes of the model that triggered the event + the previous_changes
#
def perform(resource_or_hash)
@params = resource_or_hash
Expand Down
13 changes: 13 additions & 0 deletions test/statisfy_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -216,4 +216,17 @@ class SalaryPerUser
assert_equal 3000, SalaryPerUser.average
assert_equal 9000, SalaryPerUser.sum
end

test "decrement_on_destroy option allows to decrement a counter when a resource is destroyed" do
class UserCounter
include Statisfy::Counter

count every: :user_created, decrement_on_destroy: true
end

User.create!
assert_equal UserCounter.value, 1
User.last.destroy
assert_equal UserCounter.value, 0
end
end

0 comments on commit 7d6d86f

Please sign in to comment.