tantot 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/lib/tantot/collector/base.rb +46 -0
- data/lib/tantot/collector/block.rb +16 -25
- data/lib/tantot/collector/watcher.rb +19 -39
- data/lib/tantot/collector.rb +5 -12
- data/lib/tantot/config.rb +3 -6
- data/lib/tantot/extensions/chewy.rb +4 -5
- data/lib/tantot/observe.rb +4 -1
- data/lib/tantot/performer/chewy.rb +31 -0
- data/lib/tantot/performer.rb +7 -0
- data/lib/tantot/railtie.rb +1 -1
- data/lib/tantot/version.rb +1 -1
- data/lib/tantot/watcher.rb +1 -1
- data/spec/extensions/chewy_spec.rb +97 -84
- data/spec/sidekiq_spec.rb +22 -4
- data/spec/tantot_spec.rb +6 -6
- metadata +3 -1
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 56725354395a9033cc635de74a735b73edac40b3
         | 
| 4 | 
            +
              data.tar.gz: f5a41a93122899cb7ee27946a18a50a6b7fec825
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 97e9aad665296f329b93269feb68ba1e6e3aecd099e3b91bc9fe60f3f91fc4f88dbaa4e32b9958e4ad7d4ac55950896b308d81cd6823144975b85033eeded7ce
         | 
| 7 | 
            +
              data.tar.gz: 195da978eb98c9accd59e17b2679012a8e74bbb6bf33092e21cff06f909c3fbac9fa6fd57345ae1b613ab4c6046a664d578437ed52f835fe0080107def78f3fa
         | 
    
        data/Gemfile
    CHANGED
    
    
| @@ -0,0 +1,46 @@ | |
| 1 | 
            +
            module Tantot
         | 
| 2 | 
            +
              module Collector
         | 
| 3 | 
            +
                class Base
         | 
| 4 | 
            +
                  class_attribute :context_key
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def self.manages?(context)
         | 
| 7 | 
            +
                    context.key?(self.context_key)
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def register_watch(context, block)
         | 
| 11 | 
            +
                    raise NotImplementedError
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def push(context, instance, mutations)
         | 
| 15 | 
            +
                    formatter = Tantot::Formatter.resolve(context[:options][:format] || Tantot.config.format).new
         | 
| 16 | 
            +
                    attribute_hash = get_stash(context, instance)
         | 
| 17 | 
            +
                    mutations.each do |attr, changes|
         | 
| 18 | 
            +
                      attribute_hash[attr] = formatter.push(attribute_hash[attr], context, changes)
         | 
| 19 | 
            +
                    end
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  def sweep(performer_name)
         | 
| 23 | 
            +
                    if @stash.any?
         | 
| 24 | 
            +
                      Tantot.logger.debug { "[Tantot] [Sweeping] [#{self.class.name.demodulize}] #{debug_state}" }
         | 
| 25 | 
            +
                      @stash.each do |id, changes|
         | 
| 26 | 
            +
                        context = Tantot.registry.watch_config[id][:context]
         | 
| 27 | 
            +
                        performer = Tantot::Performer.resolve(performer_name || context[:options][:performer] || Tantot.config.performer).new
         | 
| 28 | 
            +
                        Tantot.logger.debug { "[Tantot] [Performer] [#{self.class.name.demodulize}] [#{performer.class.name.demodulize}] #{debug_state(Hash[id, changes])}" }
         | 
| 29 | 
            +
                        performer.run(context, changes)
         | 
| 30 | 
            +
                      end
         | 
| 31 | 
            +
                      @stash.clear
         | 
| 32 | 
            +
                    end
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  def debug_changes_for_model(model, changes_by_id)
         | 
| 36 | 
            +
                    "#{model.name}#{changes_by_id.keys.inspect}"
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                protected
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  def get_stash(context, instance)
         | 
| 42 | 
            +
                    raise NotImplementedError
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
            end
         | 
| @@ -1,9 +1,7 @@ | |
| 1 1 | 
             
            module Tantot
         | 
| 2 2 | 
             
              module Collector
         | 
| 3 | 
            -
                class Block
         | 
| 4 | 
            -
                   | 
| 5 | 
            -
                    context.key?(:block_id)
         | 
| 6 | 
            -
                  end
         | 
| 3 | 
            +
                class Block < Base
         | 
| 4 | 
            +
                  self.context_key = :block_id
         | 
| 7 5 |  | 
| 8 6 | 
             
                  def initialize
         | 
| 9 7 | 
             
                    @stash = Hash.new do |block_id_hash, block_id|
         | 
| @@ -17,22 +15,6 @@ module Tantot | |
| 17 15 | 
             
                    Tantot.registry.watch_config[context[:block_id]] = {context: context, block: block}
         | 
| 18 16 | 
             
                  end
         | 
| 19 17 |  | 
| 20 | 
            -
                  def push(context, instance, mutations)
         | 
| 21 | 
            -
                    options = context.fetch(:options, {})
         | 
| 22 | 
            -
                    formatter = Tantot::Formatter.resolve(options[:format] || Tantot.config.default_watcher_options[:format]).new
         | 
| 23 | 
            -
                    attribute_hash = @stash[context[:block_id]][instance.id]
         | 
| 24 | 
            -
                    mutations.each do |attr, changes|
         | 
| 25 | 
            -
                      attribute_hash[attr] = formatter.push(attribute_hash[attr], context, changes)
         | 
| 26 | 
            -
                    end
         | 
| 27 | 
            -
                  end
         | 
| 28 | 
            -
             | 
| 29 | 
            -
                  def sweep(performer, context = {})
         | 
| 30 | 
            -
                    @stash.each do |block_id, changes|
         | 
| 31 | 
            -
                      performer.run({block_id: block_id}, changes)
         | 
| 32 | 
            -
                    end
         | 
| 33 | 
            -
                    @stash.clear
         | 
| 34 | 
            -
                  end
         | 
| 35 | 
            -
             | 
| 36 18 | 
             
                  def perform(context, changes_by_id)
         | 
| 37 19 | 
             
                    watch_config = Tantot.registry.watch_config[context[:block_id]]
         | 
| 38 20 | 
             
                    watch_config[:context][:model].instance_exec(Tantot::Changes::ById.new(changes_by_id), &watch_config[:block])
         | 
| @@ -60,17 +42,26 @@ module Tantot | |
| 60 42 | 
             
                    debug_block(block)
         | 
| 61 43 | 
             
                  end
         | 
| 62 44 |  | 
| 63 | 
            -
                  def  | 
| 64 | 
            -
                     | 
| 65 | 
            -
             | 
| 45 | 
            +
                  def debug_changes(watch_config, changes_by_id)
         | 
| 46 | 
            +
                    "#{debug_changes_for_model(watch_config[:context][:model], changes_by_id)} for #{debug_block(watch_config[:block])}"
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  def debug_state(stash = @stash)
         | 
| 50 | 
            +
                    stash.collect do |block_id, changes_by_id|
         | 
| 66 51 | 
             
                      watch_config = Tantot.registry.watch_config[block_id]
         | 
| 67 | 
            -
                       | 
| 52 | 
            +
                      debug_changes(watch_config, changes_by_id)
         | 
| 68 53 | 
             
                    end.join(" / ")
         | 
| 69 54 | 
             
                  end
         | 
| 70 55 |  | 
| 71 56 | 
             
                  def debug_perform(context, changes_by_id)
         | 
| 72 57 | 
             
                    watch_config = Tantot.registry.watch_config[context[:block_id]]
         | 
| 73 | 
            -
                     | 
| 58 | 
            +
                    debug_changes(watch_config, changes_by_id)
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                protected
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                  def get_stash(context, instance)
         | 
| 64 | 
            +
                    @stash[context[:block_id]][instance.id]
         | 
| 74 65 | 
             
                  end
         | 
| 75 66 |  | 
| 76 67 | 
             
                end
         | 
| @@ -1,9 +1,7 @@ | |
| 1 1 | 
             
            module Tantot
         | 
| 2 2 | 
             
              module Collector
         | 
| 3 | 
            -
                class Watcher
         | 
| 4 | 
            -
                   | 
| 5 | 
            -
                    context.key?(:watcher)
         | 
| 6 | 
            -
                  end
         | 
| 3 | 
            +
                class Watcher < Base
         | 
| 4 | 
            +
                  self.context_key = :watcher
         | 
| 7 5 |  | 
| 8 6 | 
             
                  def initialize
         | 
| 9 7 | 
             
                    @stash = Hash.new do |watcher_hash, watcher|
         | 
| @@ -16,30 +14,7 @@ module Tantot | |
| 16 14 | 
             
                  end
         | 
| 17 15 |  | 
| 18 16 | 
             
                  def register_watch(context, block)
         | 
| 19 | 
            -
                     | 
| 20 | 
            -
                  end
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                  def push(context, instance, mutations)
         | 
| 23 | 
            -
                    watcher = context[:watcher]
         | 
| 24 | 
            -
                    model = context[:model]
         | 
| 25 | 
            -
                    formatter = Tantot::Formatter.resolve(watcher.watcher_options[:format]).new
         | 
| 26 | 
            -
                    attribute_hash = @stash[watcher][model][instance.id]
         | 
| 27 | 
            -
                    mutations.each do |attr, changes|
         | 
| 28 | 
            -
                      attribute_hash[attr] = formatter.push(attribute_hash[attr], context, changes)
         | 
| 29 | 
            -
                    end
         | 
| 30 | 
            -
                  end
         | 
| 31 | 
            -
             | 
| 32 | 
            -
                  def sweep(performer, context = {})
         | 
| 33 | 
            -
                    watcher = context[:watcher]
         | 
| 34 | 
            -
                    filtered_stash = watcher ? @stash.select {|w, _c| w == watcher} : @stash
         | 
| 35 | 
            -
                    filtered_stash.each do |w, changes_by_model|
         | 
| 36 | 
            -
                      performer.run({watcher: w}, changes_by_model)
         | 
| 37 | 
            -
                    end
         | 
| 38 | 
            -
                    if watcher
         | 
| 39 | 
            -
                      @stash.delete(watcher)
         | 
| 40 | 
            -
                    else
         | 
| 41 | 
            -
                      @stash.clear
         | 
| 42 | 
            -
                    end
         | 
| 17 | 
            +
                    Tantot.registry.watch_config[context[:watcher]] = {context: context}
         | 
| 43 18 | 
             
                  end
         | 
| 44 19 |  | 
| 45 20 | 
             
                  def perform(context, changes_by_model)
         | 
| @@ -64,22 +39,27 @@ module Tantot | |
| 64 39 | 
             
                  end
         | 
| 65 40 |  | 
| 66 41 | 
             
                  def debug_context(context)
         | 
| 67 | 
            -
                    context[:watcher].name | 
| 42 | 
            +
                    context[:watcher].name
         | 
| 68 43 | 
             
                  end
         | 
| 69 44 |  | 
| 70 | 
            -
                  def  | 
| 71 | 
            -
                     | 
| 72 | 
            -
             | 
| 73 | 
            -
             | 
| 74 | 
            -
             | 
| 75 | 
            -
             | 
| 76 | 
            -
                    end.flatten.join(" / ")
         | 
| 45 | 
            +
                  def debug_changes(watcher, changes_by_model)
         | 
| 46 | 
            +
                    "#{watcher.name}(#{changes_by_model.collect {|model, changes_by_id| debug_changes_for_model(model, changes_by_id)}.join(" & ")})"
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  def debug_state(stash = @stash)
         | 
| 50 | 
            +
                    stash.collect {|watcher, changes_by_model| debug_changes(watcher, changes_by_model)}.flatten.join(" / ")
         | 
| 77 51 | 
             
                  end
         | 
| 78 52 |  | 
| 79 53 | 
             
                  def debug_perform(context, changes_by_model)
         | 
| 80 | 
            -
                     | 
| 81 | 
            -
             | 
| 82 | 
            -
             | 
| 54 | 
            +
                    debug_changes(context[:watcher], changes_by_model)
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                protected
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  def get_stash(context, instance)
         | 
| 60 | 
            +
                    watcher = context[:watcher]
         | 
| 61 | 
            +
                    model = context[:model]
         | 
| 62 | 
            +
                    @stash[watcher][model][instance.id]
         | 
| 83 63 | 
             
                  end
         | 
| 84 64 |  | 
| 85 65 | 
             
                end
         | 
    
        data/lib/tantot/collector.rb
    CHANGED
    
    | @@ -1,3 +1,4 @@ | |
| 1 | 
            +
            require 'tantot/collector/base'
         | 
| 1 2 | 
             
            require 'tantot/collector/watcher'
         | 
| 2 3 | 
             
            require 'tantot/collector/block'
         | 
| 3 4 |  | 
| @@ -27,24 +28,16 @@ module Tantot | |
| 27 28 | 
             
                      "[Tantot] [Collecting] [#{collector.class.name.demodulize}] #{mutate} on <#{instance.class.name}:#{instance.id}> for <#{collector.debug_context(context)}>"
         | 
| 28 29 | 
             
                    end
         | 
| 29 30 | 
             
                    collector.push(context, instance, mutations)
         | 
| 30 | 
            -
                    sweep | 
| 31 | 
            +
                    sweep if Tantot.config.sweep_on_push
         | 
| 31 32 | 
             
                  end
         | 
| 32 33 |  | 
| 33 | 
            -
                  def sweep( | 
| 34 | 
            -
                     | 
| 35 | 
            -
                    specific_collector = resolve(context)
         | 
| 36 | 
            -
                    collectors = specific_collector ? [specific_collector] : @collectors.values
         | 
| 37 | 
            -
                    collectors.each do |collector|
         | 
| 38 | 
            -
                      if Tantot.logger.debug? && (debug_state = collector.debug_state(context))
         | 
| 39 | 
            -
                        Tantot.logger.debug { "[Tantot] [Sweeping] [#{collector.class.name.demodulize}] [#{performer.class.name.demodulize}] #{debug_state}" }
         | 
| 40 | 
            -
                      end
         | 
| 41 | 
            -
                      collector.sweep(performer, context)
         | 
| 42 | 
            -
                    end
         | 
| 34 | 
            +
                  def sweep(performer_name = nil)
         | 
| 35 | 
            +
                    @collectors.values.each {|collector| collector.sweep(performer_name)}
         | 
| 43 36 | 
             
                  end
         | 
| 44 37 |  | 
| 45 38 | 
             
                  def perform(context, changes)
         | 
| 46 39 | 
             
                    collector = resolve!(context)
         | 
| 47 | 
            -
                    Tantot.logger.debug { "[Tantot] [ | 
| 40 | 
            +
                    Tantot.logger.debug { "[Tantot] [Run] [#{collector.class.name.demodulize}] #{collector.debug_perform(context, changes)}" }
         | 
| 48 41 | 
             
                    collector.perform(context, changes)
         | 
| 49 42 | 
             
                  end
         | 
| 50 43 |  | 
    
        data/lib/tantot/config.rb
    CHANGED
    
    | @@ -2,16 +2,13 @@ module Tantot | |
| 2 2 | 
             
              class Config
         | 
| 3 3 | 
             
                include Singleton
         | 
| 4 4 |  | 
| 5 | 
            -
                attr_accessor :performer, : | 
| 5 | 
            +
                attr_accessor :performer, :format, :use_after_commit_callbacks, :sweep_on_push
         | 
| 6 6 |  | 
| 7 7 | 
             
                def initialize
         | 
| 8 8 | 
             
                  @performer = :inline
         | 
| 9 | 
            +
                  @format = :compact
         | 
| 9 10 | 
             
                  @use_after_commit_callbacks = true
         | 
| 10 | 
            -
                  @ | 
| 11 | 
            -
                    format: :compact
         | 
| 12 | 
            -
                  }
         | 
| 13 | 
            -
                  @console_mode = false
         | 
| 14 | 
            -
                  @chewy_strategy = :atomic
         | 
| 11 | 
            +
                  @sweep_on_push = false
         | 
| 15 12 | 
             
                end
         | 
| 16 13 | 
             
              end
         | 
| 17 14 | 
             
            end
         | 
| @@ -26,6 +26,8 @@ module Tantot | |
| 26 26 | 
             
                  class ChewyWatcher
         | 
| 27 27 | 
             
                    include Tantot::Watcher
         | 
| 28 28 |  | 
| 29 | 
            +
                    watcher_options performer: :chewy
         | 
| 30 | 
            +
             | 
| 29 31 | 
             
                    def perform(changes_by_model)
         | 
| 30 32 | 
             
                      changes_by_model.each do |model, changes_by_id|
         | 
| 31 33 | 
             
                        model_watches = model._tantot_chewy_callbacks
         | 
| @@ -70,11 +72,8 @@ module Tantot | |
| 70 72 |  | 
| 71 73 | 
             
                              # Make sure there are any backreferences
         | 
| 72 74 | 
             
                              if backreference.any?
         | 
| 73 | 
            -
                                 | 
| 74 | 
            -
                                ::Chewy. | 
| 75 | 
            -
                                  Tantot.logger.debug { "[Tantot] [Chewy] [update_index] #{reference} (#{backreference.count} objects): #{backreference.inspect}" }
         | 
| 76 | 
            -
                                  ::Chewy.derive_type(reference).update_index(backreference, options)
         | 
| 77 | 
            -
                                end
         | 
| 75 | 
            +
                                Tantot.logger.debug { "[Tantot] [Chewy] [update_index] #{reference} (#{backreference.count} objects): #{backreference.inspect}" }
         | 
| 76 | 
            +
                                ::Chewy.derive_type(reference).update_index(backreference, options)
         | 
| 78 77 | 
             
                              end
         | 
| 79 78 | 
             
                            end
         | 
| 80 79 |  | 
    
        data/lib/tantot/observe.rb
    CHANGED
    
    | @@ -61,7 +61,10 @@ module Tantot | |
| 61 61 | 
             
                        options: options
         | 
| 62 62 | 
             
                      }
         | 
| 63 63 |  | 
| 64 | 
            -
                       | 
| 64 | 
            +
                      if watcher
         | 
| 65 | 
            +
                        context[:watcher] = watcher
         | 
| 66 | 
            +
                        options.reverse_merge!(watcher.watcher_options)
         | 
| 67 | 
            +
                      end
         | 
| 65 68 | 
             
                      context[:block_id] = CityHash.hash64(block.source_location.collect(&:to_s).join) if block_given?
         | 
| 66 69 |  | 
| 67 70 | 
             
                      Tantot.collector.register_watch(context, block)
         | 
| @@ -0,0 +1,31 @@ | |
| 1 | 
            +
            module Tantot
         | 
| 2 | 
            +
              module Performer
         | 
| 3 | 
            +
                class Chewy
         | 
| 4 | 
            +
                  class Worker
         | 
| 5 | 
            +
                    include ::Sidekiq::Worker
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                    def perform(context, changes)
         | 
| 8 | 
            +
                      context, changes = Tantot.collector.unmarshal(context, changes)
         | 
| 9 | 
            +
                      ::Chewy.strategy(Tantot.config.chewy_strategy) do
         | 
| 10 | 
            +
                        Tantot.collector.perform(context, changes)
         | 
| 11 | 
            +
                      end
         | 
| 12 | 
            +
                    end
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def run(context, changes)
         | 
| 16 | 
            +
                    case ::Chewy.strategy.current.name
         | 
| 17 | 
            +
                    when :atomic, :urgent
         | 
| 18 | 
            +
                      Tantot::Performer::Inline.new.run(context, changes)
         | 
| 19 | 
            +
                    when /sidekiq/
         | 
| 20 | 
            +
                      context, changes = Tantot.collector.marshal(context, changes)
         | 
| 21 | 
            +
                      Tantot::Performer::Chewy::Worker.perform_async(context, changes)
         | 
| 22 | 
            +
                    when :bypass
         | 
| 23 | 
            +
                      return
         | 
| 24 | 
            +
                    else
         | 
| 25 | 
            +
                      # No strategy defined, do an Inline run and let Chewy fail
         | 
| 26 | 
            +
                      Tantot::Performer::Inline.new.run(context, changes)
         | 
| 27 | 
            +
                    end
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
            end
         | 
    
        data/lib/tantot/performer.rb
    CHANGED
    
    
    
        data/lib/tantot/railtie.rb
    CHANGED
    
    
    
        data/lib/tantot/version.rb
    CHANGED
    
    
    
        data/lib/tantot/watcher.rb
    CHANGED
    
    | @@ -8,7 +8,7 @@ module Tantot | |
| 8 8 |  | 
| 9 9 | 
             
                class_methods do
         | 
| 10 10 | 
             
                  def watcher_options(opts = {})
         | 
| 11 | 
            -
                    self.watcher_options_hash ||=  | 
| 11 | 
            +
                    self.watcher_options_hash ||= {}
         | 
| 12 12 | 
             
                    self.watcher_options_hash = self.watcher_options_hash.merge(opts)
         | 
| 13 13 | 
             
                  end
         | 
| 14 14 | 
             
                end
         | 
| @@ -1,127 +1,140 @@ | |
| 1 1 | 
             
            require "spec_helper"
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 3 | 
            +
            if defined?(::Chewy)
         | 
| 4 4 |  | 
| 5 | 
            -
               | 
| 6 | 
            -
              before do
         | 
| 7 | 
            -
                stub_const("Chewy", {})
         | 
| 8 | 
            -
              end
         | 
| 5 | 
            +
              describe Tantot::Extensions::Chewy do
         | 
| 9 6 |  | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 7 | 
            +
                [nil, :self, :class_method, :block].product([:some, :all]).each do |backreference_opt, attribute_opt|
         | 
| 8 | 
            +
                  it "should update indexes using backreference: #{backreference_opt.inspect}, attributes: #{attribute_opt}" do
         | 
| 9 | 
            +
                    chewy_type = double
         | 
| 13 10 |  | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 11 | 
            +
                    watch_index_params = ['foo']
         | 
| 12 | 
            +
                    watch_index_params << :id if attribute_opt == :some
         | 
| 16 13 |  | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 14 | 
            +
                    block_callback = proc do |changes|
         | 
| 15 | 
            +
                      self.yielded_changes = changes
         | 
| 16 | 
            +
                      [1, 2, 3]
         | 
| 17 | 
            +
                    end
         | 
| 21 18 |  | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 19 | 
            +
                    case backreference_opt
         | 
| 20 | 
            +
                    when nil, :block
         | 
| 21 | 
            +
                    when :self
         | 
| 22 | 
            +
                      watch_index_params << {method: :self}
         | 
| 23 | 
            +
                    when :class_method
         | 
| 24 | 
            +
                      watch_index_params << {method: :class_get_ids}
         | 
| 25 | 
            +
                    end
         | 
| 29 26 |  | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 27 | 
            +
                    stub_model(:city) do
         | 
| 28 | 
            +
                      class_attribute :yielded_changes
         | 
| 32 29 |  | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 30 | 
            +
                      if backreference_opt == :block
         | 
| 31 | 
            +
                        watch_index(*watch_index_params, &block_callback)
         | 
| 32 | 
            +
                      else
         | 
| 33 | 
            +
                        watch_index(*watch_index_params)
         | 
| 34 | 
            +
                      end
         | 
| 38 35 |  | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 36 | 
            +
                      def self.class_get_ids(changes)
         | 
| 37 | 
            +
                        self.yielded_changes = changes
         | 
| 38 | 
            +
                        [1, 2, 3]
         | 
| 39 | 
            +
                      end
         | 
| 42 40 | 
             
                    end
         | 
| 43 | 
            -
                  end
         | 
| 44 41 |  | 
| 45 | 
            -
             | 
| 42 | 
            +
                    city1 = city2 = nil
         | 
| 46 43 |  | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 44 | 
            +
                    Tantot.collector.run do
         | 
| 45 | 
            +
                      city1 = City.create!
         | 
| 46 | 
            +
                      city2 = City.create!
         | 
| 50 47 |  | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
                    expect(Chewy).to receive(:derive_type).with('foo').and_return(chewy_type)
         | 
| 48 | 
            +
                      # Stub the integration point between us and Chewy
         | 
| 49 | 
            +
                      expect(Chewy).to receive(:derive_type).with('foo').and_return(chewy_type)
         | 
| 54 50 |  | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 51 | 
            +
                      # Depending on backreference
         | 
| 52 | 
            +
                      case backreference_opt
         | 
| 53 | 
            +
                      when nil, :self
         | 
| 54 | 
            +
                        # Implicit and self reference will update with the created model id
         | 
| 55 | 
            +
                        expect(chewy_type).to receive(:update_index).with([city1.id, city2.id], {})
         | 
| 56 | 
            +
                      when :class_method, :block
         | 
| 57 | 
            +
                        # Validate that the returned ids are updated
         | 
| 58 | 
            +
                        expect(chewy_type).to receive(:update_index).with([1, 2, 3], {})
         | 
| 59 | 
            +
                      end
         | 
| 63 60 | 
             
                    end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                    # Make sure the callbacks received the changes
         | 
| 63 | 
            +
                    if [:class_method, :block].include?(backreference_opt)
         | 
| 64 | 
            +
                      expect(City.yielded_changes).to eq(Tantot::Changes::ById.new({city1.id => {"id" => [nil, city1.id]}, city2.id => {"id" => [nil, city2.id]}}))
         | 
| 65 | 
            +
                    end
         | 
| 66 | 
            +
             | 
| 64 67 | 
             
                  end
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                it "should allow registering an index watch on self (all attributes, destroy)" do
         | 
| 71 | 
            +
                  chewy_type = double
         | 
| 65 72 |  | 
| 66 | 
            -
                   | 
| 67 | 
            -
             | 
| 68 | 
            -
                    expect(City.yielded_changes).to eq(Tantot::Changes::ById.new({city1.id => {"id" => [nil, city1.id]}, city2.id => {"id" => [nil, city2.id]}}))
         | 
| 73 | 
            +
                  stub_model(:city) do
         | 
| 74 | 
            +
                    watch_index 'foo'
         | 
| 69 75 | 
             
                  end
         | 
| 70 76 |  | 
| 71 | 
            -
             | 
| 72 | 
            -
             | 
| 77 | 
            +
                  city = City.create!
         | 
| 78 | 
            +
                  Tantot.collector.sweep(:bypass)
         | 
| 73 79 |  | 
| 74 | 
            -
             | 
| 75 | 
            -
             | 
| 80 | 
            +
                  Tantot.collector.run do
         | 
| 81 | 
            +
                    city.destroy
         | 
| 76 82 |  | 
| 77 | 
            -
             | 
| 78 | 
            -
             | 
| 83 | 
            +
                    expect(Chewy).to receive(:derive_type).with('foo').and_return(chewy_type)
         | 
| 84 | 
            +
                    expect(chewy_type).to receive(:update_index).with([city.id], {})
         | 
| 85 | 
            +
                  end
         | 
| 79 86 | 
             
                end
         | 
| 80 87 |  | 
| 81 | 
            -
                 | 
| 82 | 
            -
             | 
| 88 | 
            +
                it "should allow registering an index watch on self (all attributes, destroy, block)" do
         | 
| 89 | 
            +
                  chewy_type = double
         | 
| 83 90 |  | 
| 84 | 
            -
             | 
| 85 | 
            -
             | 
| 91 | 
            +
                  stub_model(:city) do
         | 
| 92 | 
            +
                    watch_index 'foo' do |changes|
         | 
| 93 | 
            +
                      changes.ids
         | 
| 94 | 
            +
                    end
         | 
| 95 | 
            +
                  end
         | 
| 86 96 |  | 
| 87 | 
            -
                   | 
| 88 | 
            -
                   | 
| 89 | 
            -
                  expect(chewy_type).to receive(:update_index).with([city.id], {})
         | 
| 90 | 
            -
                end
         | 
| 91 | 
            -
              end
         | 
| 97 | 
            +
                  city = City.create!
         | 
| 98 | 
            +
                  Tantot.collector.sweep(:bypass)
         | 
| 92 99 |  | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 100 | 
            +
                  Tantot.collector.run do
         | 
| 101 | 
            +
                    city.destroy
         | 
| 95 102 |  | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 98 | 
            -
                    changes.ids
         | 
| 103 | 
            +
                    expect(Chewy).to receive(:derive_type).with('foo').and_return(chewy_type)
         | 
| 104 | 
            +
                    expect(chewy_type).to receive(:update_index).with([city.id], {})
         | 
| 99 105 | 
             
                  end
         | 
| 100 106 | 
             
                end
         | 
| 101 107 |  | 
| 102 | 
            -
                 | 
| 103 | 
            -
             | 
| 108 | 
            +
                it "should allow returning nothing in a callback" do
         | 
| 109 | 
            +
                  stub_model(:city) do
         | 
| 110 | 
            +
                    watch_index('foo') { 1 if false }
         | 
| 111 | 
            +
                    watch_index('bar') { [] }
         | 
| 112 | 
            +
                    watch_index('baz') { nil }
         | 
| 113 | 
            +
                  end
         | 
| 104 114 |  | 
| 105 | 
            -
             | 
| 106 | 
            -
             | 
| 115 | 
            +
                  Tantot.collector.run do
         | 
| 116 | 
            +
                    City.create!
         | 
| 107 117 |  | 
| 108 | 
            -
             | 
| 109 | 
            -
                   | 
| 110 | 
            -
                  expect(chewy_type).to receive(:update_index).with([city.id], {})
         | 
| 118 | 
            +
                    expect(Chewy).not_to receive(:derive_type)
         | 
| 119 | 
            +
                  end
         | 
| 111 120 | 
             
                end
         | 
| 112 121 | 
             
              end
         | 
| 113 122 |  | 
| 114 | 
            -
               | 
| 115 | 
            -
                 | 
| 116 | 
            -
                   | 
| 117 | 
            -
                  watch_index('bar') { [] }
         | 
| 118 | 
            -
                  watch_index('baz') { nil }
         | 
| 123 | 
            +
              describe "Chewy.strategy" do
         | 
| 124 | 
            +
                before do
         | 
| 125 | 
            +
                  allow(Tantot.config).to receive(:sweep_on_push).and_return(true)
         | 
| 119 126 | 
             
                end
         | 
| 120 127 |  | 
| 121 | 
            -
                 | 
| 122 | 
            -
                   | 
| 128 | 
            +
                it "should bypass if Chewy.strategy is :bypass" do
         | 
| 129 | 
            +
                  stub_model(:city) do
         | 
| 130 | 
            +
                    watch_index('foo')
         | 
| 131 | 
            +
                  end
         | 
| 123 132 |  | 
| 124 133 | 
             
                  expect(Chewy).not_to receive(:derive_type)
         | 
| 134 | 
            +
                  Chewy.strategy :bypass do
         | 
| 135 | 
            +
                    City.create!
         | 
| 136 | 
            +
                  end
         | 
| 125 137 | 
             
                end
         | 
| 126 138 | 
             
              end
         | 
| 139 | 
            +
             | 
| 127 140 | 
             
            end
         | 
    
        data/spec/sidekiq_spec.rb
    CHANGED
    
    | @@ -31,7 +31,13 @@ if defined?(::Sidekiq) | |
| 31 31 | 
             
                      City.create name: 'foo'
         | 
| 32 32 | 
             
                    end
         | 
| 33 33 | 
             
                    expect(Tantot::Performer::Sidekiq::Worker.jobs.size).to eq(1)
         | 
| 34 | 
            -
                    expect(Tantot::Performer::Sidekiq::Worker.jobs.first["args"]).to eq([{ | 
| 34 | 
            +
                    expect(Tantot::Performer::Sidekiq::Worker.jobs.first["args"]).to eq([{
         | 
| 35 | 
            +
                      "model" => "City",
         | 
| 36 | 
            +
                      "attributes" => ["name"],
         | 
| 37 | 
            +
                      "options" => {},
         | 
| 38 | 
            +
                      "watcher" => "SidekiqWatcher",
         | 
| 39 | 
            +
                      "collector_class" => "Tantot::Collector::Watcher"},
         | 
| 40 | 
            +
                      {"City" => {"1" => {"name" => [nil, 'foo']}}}])
         | 
| 35 41 | 
             
                  end
         | 
| 36 42 |  | 
| 37 43 | 
             
                  it "should call the watcher" do
         | 
| @@ -49,7 +55,7 @@ if defined?(::Sidekiq) | |
| 49 55 | 
             
                        # Create a model, then sweep. It should have called perform wihtout triggering a sidekiq worker
         | 
| 50 56 | 
             
                        city = City.create name: 'foo'
         | 
| 51 57 | 
             
                        expect_any_instance_of(SidekiqWatcher).to receive(:perform).with(Tantot::Changes::ByModel.new({City => {city.id => {"name" => [nil, 'foo']}}}))
         | 
| 52 | 
            -
                        Tantot.collector.sweep( | 
| 58 | 
            +
                        Tantot.collector.sweep(:inline)
         | 
| 53 59 | 
             
                        expect(Tantot::Performer::Sidekiq::Worker.jobs.size).to eq(0)
         | 
| 54 60 |  | 
| 55 61 | 
             
                        # Further modifications should trigger through sidekiq when exiting the strategy block
         | 
| @@ -57,7 +63,13 @@ if defined?(::Sidekiq) | |
| 57 63 | 
             
                        city.save
         | 
| 58 64 | 
             
                      end
         | 
| 59 65 | 
             
                      expect(Tantot::Performer::Sidekiq::Worker.jobs.size).to eq(1)
         | 
| 60 | 
            -
                      expect(Tantot::Performer::Sidekiq::Worker.jobs.first["args"]).to eq([{ | 
| 66 | 
            +
                      expect(Tantot::Performer::Sidekiq::Worker.jobs.first["args"]).to eq([{
         | 
| 67 | 
            +
                        "model" => "City",
         | 
| 68 | 
            +
                        "attributes" => ["name"],
         | 
| 69 | 
            +
                        "options" => {},
         | 
| 70 | 
            +
                        "watcher" => "SidekiqWatcher",
         | 
| 71 | 
            +
                        "collector_class" => "Tantot::Collector::Watcher"},
         | 
| 72 | 
            +
                        {"City" => {"1" => {"name" => ['foo', 'bar']}}}])
         | 
| 61 73 | 
             
                    end
         | 
| 62 74 | 
             
                  end
         | 
| 63 75 | 
             
                end
         | 
| @@ -81,7 +93,13 @@ if defined?(::Sidekiq) | |
| 81 93 | 
             
                    end
         | 
| 82 94 | 
             
                    expect(Tantot::Performer::Sidekiq::Worker.jobs.size).to eq(1)
         | 
| 83 95 | 
             
                    block_id = Tantot.registry.watch_config.keys.last
         | 
| 84 | 
            -
                    expect(Tantot::Performer::Sidekiq::Worker.jobs.first["args"]).to eq([{ | 
| 96 | 
            +
                    expect(Tantot::Performer::Sidekiq::Worker.jobs.first["args"]).to eq([{
         | 
| 97 | 
            +
                      "model" => "City",
         | 
| 98 | 
            +
                      "attributes" => ["name"],
         | 
| 99 | 
            +
                      "options" => {},
         | 
| 100 | 
            +
                      "block_id" => block_id,
         | 
| 101 | 
            +
                      "collector_class" => "Tantot::Collector::Block"},
         | 
| 102 | 
            +
                      {"1" => {"name" => [nil, 'foo']}}])
         | 
| 85 103 | 
             
                  end
         | 
| 86 104 |  | 
| 87 105 | 
             
                  it "should call the watcher" do
         | 
    
        data/spec/tantot_spec.rb
    CHANGED
    
    | @@ -64,7 +64,7 @@ describe Tantot do | |
| 64 64 | 
             
                      it "calls back on model update" do
         | 
| 65 65 | 
             
                        city = City.create!
         | 
| 66 66 | 
             
                        city.reload
         | 
| 67 | 
            -
                        Tantot.collector.sweep( | 
| 67 | 
            +
                        Tantot.collector.sweep(:bypass)
         | 
| 68 68 |  | 
| 69 69 | 
             
                        expect(watcher_instance).to receive(:perform).with(Tantot::Changes::ByModel.new({City => {city.id => {"name" => [nil, 'foo']}}}))
         | 
| 70 70 | 
             
                        Tantot.collector.run do
         | 
| @@ -76,7 +76,7 @@ describe Tantot do | |
| 76 76 | 
             
                      it "calls back on model destroy" do
         | 
| 77 77 | 
             
                        city = City.create!(name: 'foo')
         | 
| 78 78 | 
             
                        city.reload
         | 
| 79 | 
            -
                        Tantot.collector.sweep( | 
| 79 | 
            +
                        Tantot.collector.sweep(:bypass)
         | 
| 80 80 |  | 
| 81 81 | 
             
                        expect(watcher_instance).to receive(:perform).with(Tantot::Changes::ByModel.new({City => {city.id => {"name" => ['foo']}}}))
         | 
| 82 82 | 
             
                        Tantot.collector.run do
         | 
| @@ -99,7 +99,7 @@ describe Tantot do | |
| 99 99 | 
             
                        Tantot.collector.run do
         | 
| 100 100 | 
             
                          city = City.create name: 'foo'
         | 
| 101 101 | 
             
                          expect(watcher_instance).to receive(:perform).with(Tantot::Changes::ByModel.new({City => {city.id => {"name" => [nil, 'foo']}}}))
         | 
| 102 | 
            -
                          Tantot.collector.sweep( | 
| 102 | 
            +
                          Tantot.collector.sweep(:inline)
         | 
| 103 103 | 
             
                          city.name = 'bar'
         | 
| 104 104 | 
             
                          city.save
         | 
| 105 105 | 
             
                          expect(watcher_instance).to receive(:perform).with(Tantot::Changes::ByModel.new({City => {city.id => {"name" => ['foo', 'bar']}}}))
         | 
| @@ -148,7 +148,7 @@ describe Tantot do | |
| 148 148 | 
             
                    city = City.create!(name: "Quebec", country_id: country.id)
         | 
| 149 149 | 
             
                    country.reload
         | 
| 150 150 | 
             
                    city.reload
         | 
| 151 | 
            -
                    Tantot.collector.sweep( | 
| 151 | 
            +
                    Tantot.collector.sweep(:bypass)
         | 
| 152 152 |  | 
| 153 153 | 
             
                    expect(watcher_instance).to receive(:perform).once.with(Tantot::Changes::ByModel.new({City => {city.id => {"name" => ['Quebec', 'foo', 'bar'], "country_id" => [country.id, nil]}}, Country => {country.id => {"country_code" => ['CDN', 'US']}}}))
         | 
| 154 154 | 
             
                    Tantot.collector.run do
         | 
| @@ -191,7 +191,7 @@ describe Tantot do | |
| 191 191 | 
             
                    expect(watchA_instance).to receive(:perform).once.with(Tantot::Changes::ByModel.new({City => {city.id => {"name" => ['Quebec', 'foo', 'bar'], "country_id" => [country.id, nil]}}, Country => {country.id => {"country_code" => ['CDN', 'US']}}}))
         | 
| 192 192 | 
             
                    # WatchB receives the last value of rating since it has been destroyed
         | 
| 193 193 | 
             
                    expect(watchB_instance).to receive(:perform).once.with(Tantot::Changes::ByModel.new({City => {city.id => {"rating" => [12]}}}))
         | 
| 194 | 
            -
                    Tantot.collector.sweep( | 
| 194 | 
            +
                    Tantot.collector.sweep(:bypass)
         | 
| 195 195 |  | 
| 196 196 | 
             
                    Tantot.collector.run do
         | 
| 197 197 | 
             
                      city.name = "foo"
         | 
| @@ -224,7 +224,7 @@ describe Tantot do | |
| 224 224 | 
             
                  it "should also watch on destroy, but when watching all attributes, change hash is empty" do
         | 
| 225 225 | 
             
                    city = City.create!(name: 'foo')
         | 
| 226 226 | 
             
                    city.reload
         | 
| 227 | 
            -
                    Tantot.collector.sweep( | 
| 227 | 
            +
                    Tantot.collector.sweep(:bypass)
         | 
| 228 228 |  | 
| 229 229 | 
             
                    expect(watcher_instance).to receive(:perform).with(Tantot::Changes::ByModel.new({City => {city.id => {}}}))
         | 
| 230 230 | 
             
                    Tantot.collector.run do
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: tantot
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.1. | 
| 4 | 
            +
              version: 0.1.2
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - François-Pierre Bouchard
         | 
| @@ -159,6 +159,7 @@ files: | |
| 159 159 | 
             
            - lib/tantot.rb
         | 
| 160 160 | 
             
            - lib/tantot/changes.rb
         | 
| 161 161 | 
             
            - lib/tantot/collector.rb
         | 
| 162 | 
            +
            - lib/tantot/collector/base.rb
         | 
| 162 163 | 
             
            - lib/tantot/collector/block.rb
         | 
| 163 164 | 
             
            - lib/tantot/collector/watcher.rb
         | 
| 164 165 | 
             
            - lib/tantot/config.rb
         | 
| @@ -171,6 +172,7 @@ files: | |
| 171 172 | 
             
            - lib/tantot/observe.rb
         | 
| 172 173 | 
             
            - lib/tantot/performer.rb
         | 
| 173 174 | 
             
            - lib/tantot/performer/bypass.rb
         | 
| 175 | 
            +
            - lib/tantot/performer/chewy.rb
         | 
| 174 176 | 
             
            - lib/tantot/performer/inline.rb
         | 
| 175 177 | 
             
            - lib/tantot/performer/sidekiq.rb
         | 
| 176 178 | 
             
            - lib/tantot/railtie.rb
         |