promiscuous 0.92.0 → 0.100.0

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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/lib/promiscuous.rb +2 -5
  3. data/lib/promiscuous/amqp.rb +1 -2
  4. data/lib/promiscuous/cli.rb +3 -43
  5. data/lib/promiscuous/config.rb +5 -7
  6. data/lib/promiscuous/error/dependency.rb +1 -3
  7. data/lib/promiscuous/publisher/context.rb +1 -1
  8. data/lib/promiscuous/publisher/context/base.rb +3 -34
  9. data/lib/promiscuous/publisher/model/base.rb +5 -25
  10. data/lib/promiscuous/publisher/model/mock.rb +5 -7
  11. data/lib/promiscuous/publisher/operation/active_record.rb +4 -69
  12. data/lib/promiscuous/publisher/operation/atomic.rb +1 -3
  13. data/lib/promiscuous/publisher/operation/base.rb +33 -123
  14. data/lib/promiscuous/publisher/operation/mongoid.rb +0 -67
  15. data/lib/promiscuous/publisher/operation/non_persistent.rb +0 -1
  16. data/lib/promiscuous/publisher/operation/transaction.rb +1 -3
  17. data/lib/promiscuous/railtie.rb +0 -31
  18. data/lib/promiscuous/subscriber.rb +1 -1
  19. data/lib/promiscuous/subscriber/{worker/message.rb → message.rb} +12 -40
  20. data/lib/promiscuous/subscriber/model/active_record.rb +1 -1
  21. data/lib/promiscuous/subscriber/model/base.rb +4 -4
  22. data/lib/promiscuous/subscriber/model/mongoid.rb +3 -3
  23. data/lib/promiscuous/subscriber/operation.rb +74 -3
  24. data/lib/promiscuous/subscriber/unit_of_work.rb +110 -0
  25. data/lib/promiscuous/subscriber/worker.rb +3 -7
  26. data/lib/promiscuous/subscriber/worker/eventual_destroyer.rb +2 -6
  27. data/lib/promiscuous/subscriber/worker/pump.rb +2 -11
  28. data/lib/promiscuous/version.rb +1 -1
  29. metadata +18 -36
  30. data/lib/promiscuous/error/missing_context.rb +0 -29
  31. data/lib/promiscuous/publisher/bootstrap.rb +0 -27
  32. data/lib/promiscuous/publisher/bootstrap/connection.rb +0 -25
  33. data/lib/promiscuous/publisher/bootstrap/data.rb +0 -127
  34. data/lib/promiscuous/publisher/bootstrap/mode.rb +0 -19
  35. data/lib/promiscuous/publisher/bootstrap/status.rb +0 -40
  36. data/lib/promiscuous/publisher/bootstrap/version.rb +0 -46
  37. data/lib/promiscuous/publisher/context/middleware.rb +0 -94
  38. data/lib/promiscuous/resque.rb +0 -12
  39. data/lib/promiscuous/sidekiq.rb +0 -15
  40. data/lib/promiscuous/subscriber/message_processor.rb +0 -4
  41. data/lib/promiscuous/subscriber/message_processor/base.rb +0 -54
  42. data/lib/promiscuous/subscriber/message_processor/bootstrap.rb +0 -17
  43. data/lib/promiscuous/subscriber/message_processor/regular.rb +0 -238
  44. data/lib/promiscuous/subscriber/operation/base.rb +0 -66
  45. data/lib/promiscuous/subscriber/operation/bootstrap.rb +0 -60
  46. data/lib/promiscuous/subscriber/operation/regular.rb +0 -19
  47. data/lib/promiscuous/subscriber/worker/message_synchronizer.rb +0 -333
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d772f9b9786ef7ee6787030113bf9ec5934717d5
4
- data.tar.gz: 163c9cb61d4b359f1e6766effef9baccdfd8c229
3
+ metadata.gz: b49e20ef32de7aa2d0ff24941962adf673ab5332
4
+ data.tar.gz: 036b09d5ea13bc45751221693a7f8bb4edea4d1c
5
5
  SHA512:
6
- metadata.gz: 6cacc43f226549868f963abbad29e7ba7249a1bbc1c4eb3e0b8014275935ca37e7455a73b48e36d7c0c56906308ab334c104bbf136a7cd2c7345ee976161eead
7
- data.tar.gz: 6f59e694ed2c89e2ebe9a6c73995c4b6e4987ee1f43d171f55f3783b9698c4974aff8ef684d22dd8e652956d943081b952f8bb313d492016629b9564a1447727
6
+ metadata.gz: ceaab91a632d2b7eaa71f0ae59f14d66a47e7c5f531582425f24b567b79530dc3f2602ca01b139001dd047001c1b5f54ed41f1beb798d9dc8976de93c26a29ae
7
+ data.tar.gz: 5d3313bc9aabb5f1da0a6e71216637dd326bc4d8c4a10cbfc3cbeb83b45733479c348f20a91b1b56160670d54e9653c70fd08e169c9a68dfaba8109aefddcad9
data/lib/promiscuous.rb CHANGED
@@ -20,9 +20,6 @@ module Promiscuous
20
20
  :CLI, :Error, :Loader, :AMQP, :Redis, :ZK, :Config, :DSL, :Key,
21
21
  :Convenience, :Dependency, :Timer
22
22
 
23
- # Shortcut for the middleware, TODO make load on demand
24
- Middleware = Publisher::Context::Middleware
25
-
26
23
  extend Promiscuous::DSL
27
24
 
28
25
  Object.__send__(:include, Promiscuous::Convenience)
@@ -82,8 +79,8 @@ module Promiscuous
82
79
  !!Thread.current[:promiscuous_disabled]
83
80
  end
84
81
 
85
- def context(*args, &block)
86
- Publisher::Context::Base.with_context(*args, &block)
82
+ def context
83
+ Publisher::Context::Base.current
87
84
  end
88
85
  end
89
86
 
@@ -2,8 +2,7 @@ module Promiscuous::AMQP
2
2
  extend Promiscuous::Autoload
3
3
  autoload :HotBunnies, :Bunny, :Null, :Fake, :File
4
4
 
5
- LIVE_EXCHANGE = 'promiscuous'
6
- BOOTSTRAP_EXCHANGE = 'promiscuous.bootstrap'
5
+ LIVE_EXCHANGE = 'promiscuous'
7
6
 
8
7
  class << self
9
8
  attr_accessor :backend
@@ -1,3 +1,5 @@
1
+ require 'ruby-progressbar'
2
+
1
3
  class Promiscuous::CLI
2
4
  attr_accessor :options
3
5
 
@@ -17,14 +19,6 @@ class Promiscuous::CLI
17
19
  print_status "Thread #{thread} #{thread['label']} -- no backtrace"
18
20
  end
19
21
  end
20
-
21
- if @worker && @worker.respond_to?(:message_synchronizer)
22
- if blocked_messages = @worker.message_synchronizer.try(:blocked_messages)
23
- print_status '----[ Pending Dependencies ]----' + '-' * (100-32)
24
- blocked_messages.reverse_each { |msg| print_status msg }
25
- end
26
- print_status '-' * 100
27
- end
28
22
  end
29
23
  end
30
24
  end
@@ -61,7 +55,7 @@ class Promiscuous::CLI
61
55
  bar = ProgressBar.create(:format => '%t |%b>%i| %c/%C %e', :title => title, :total => criteria.count)
62
56
  criteria.each do |doc|
63
57
  break if @stop
64
- Promiscuous.context("cli/sync") { doc.promiscuous.sync }
58
+ doc.promiscuous.sync
65
59
  bar.increment
66
60
  end
67
61
  end
@@ -100,16 +94,6 @@ class Promiscuous::CLI
100
94
  print_status "Replayed #{@num_msg} messages"
101
95
  end
102
96
 
103
- def bootstrap
104
- phase = options[:criterias][0].to_sym
105
- raise "Subscriber bootstrap must be one of [setup|run|finalize|status]" unless [:setup, :run, :finalize, :status].include?(phase)
106
- if phase == :setup && criteria = options[:bootstrap_criteria]
107
- Promiscuous::Publisher::Bootstrap.setup(:models => eval(criteria).to_a)
108
- else
109
- Promiscuous::Publisher::Bootstrap.__send__(phase)
110
- end
111
- end
112
-
113
97
  def subscribe
114
98
  @worker = Promiscuous::Subscriber::Worker.new
115
99
  @worker.start
@@ -143,7 +127,6 @@ class Promiscuous::CLI
143
127
  opts.separator " promiscuous publish \"Model1.where(:updated_at.gt => 1.day.ago)\" [Model2 Model3...]"
144
128
  opts.separator " promiscuous publisher_recovery"
145
129
  opts.separator " promiscuous subscribe"
146
- opts.separator " promiscuous bootstrap phase"
147
130
  opts.separator " promiscuous mocks"
148
131
  opts.separator " promiscuous record logfile"
149
132
  opts.separator " promiscuous replay logfile"
@@ -154,10 +137,6 @@ class Promiscuous::CLI
154
137
  Promiscuous::Config.no_deps = true
155
138
  end
156
139
 
157
- opts.on "-x", "--ignore-exceptions", "Ignore exceptions and continue to process messages" do
158
- Promiscuous::Config.ignore_exceptions = true
159
- end
160
-
161
140
  opts.on "-l", "--require FILE", "File to require to load your app. Don't worry about it with rails" do |file|
162
141
  options[:require] = file
163
142
  end
@@ -175,20 +154,6 @@ class Promiscuous::CLI
175
154
  Promiscuous::Config.stats_interval = duration.to_f
176
155
  end
177
156
 
178
- opts.on "-b", "--bootstrap [pass1|pass2]", "Run subscriber in bootstrap mode" do |mode|
179
- mode = mode.to_sym
180
- raise "Subscriber bootstrap must be run in pass1 or pass2 mode" unless [:pass1, :pass2].include?(mode)
181
- Promiscuous::Config.bootstrap = mode.to_sym
182
- end
183
-
184
- opts.on "-t", "--threads [NUM]", "Number of subscriber worker threads to run. Defaults to 10." do |threads|
185
- Promiscuous::Config.subscriber_threads = threads.to_i
186
- end
187
-
188
- opts.on "-c", "--criteria FILE", "Criteria to bootstrap a subset of data" do |criteria|
189
- options[:bootstrap_criteria] = criteria
190
- end
191
-
192
157
  opts.on "-D", "--daemonize", "Daemonize process" do
193
158
  options[:daemonize] = true
194
159
  end
@@ -210,15 +175,12 @@ class Promiscuous::CLI
210
175
  options[:action] = args.shift.try(:to_sym)
211
176
  options[:criterias] = args
212
177
  options[:log_file] = args.first
213
- options[:publisher_bootstrap] = args.first
214
178
 
215
179
  case options[:action]
216
180
  when :publish then raise "Please specify one or more criterias" unless options[:criterias].present?
217
181
  when :subscribe then raise "Why are you specifying a criteria?" if options[:criterias].present?
218
- when :bootstrap then raise "You must specify one of [setup|start|finalize]" unless options[:criterias].present?
219
182
  when :record then raise "Please specify a log file to record" unless options[:log_file].present?
220
183
  when :replay then raise "Please specify a log file to replay" unless options[:log_file].present?
221
- when :publisher_bootstrap then raise "Please specify 'on' or 'off'" unless options[:publisher_bootstrap].present?
222
184
  when :publisher_recovery
223
185
  when :mocks
224
186
  else puts parser; exit 1
@@ -270,12 +232,10 @@ class Promiscuous::CLI
270
232
  case options[:action]
271
233
  when :publish then publish
272
234
  when :subscribe then subscribe
273
- when :bootstrap then bootstrap
274
235
  when :record then record
275
236
  when :replay then replay
276
237
  when :mocks then generate_mocks
277
238
  when :publisher_recovery then publisher_recovery
278
- when :publisher_bootstrap then set_publisher_bootstrap
279
239
  end
280
240
  end
281
241
 
@@ -1,12 +1,12 @@
1
1
  module Promiscuous::Config
2
- mattr_accessor :app, :bootstrap, :bootstrap_chunk_size, :backend, :amqp_url,
2
+ mattr_accessor :app, :backend, :amqp_url,
3
3
  :publisher_amqp_url, :subscriber_amqp_url, :publisher_exchange,
4
4
  :subscriber_exchanges, :queue_name, :queue_options, :redis_url,
5
5
  :redis_urls, :redis_stats_url, :stats_interval,
6
6
  :socket_timeout, :heartbeat, :no_deps, :hash_size,
7
7
  :prefetch, :recovery_timeout, :logger, :subscriber_threads,
8
8
  :version_field, :error_notifier, :recovery_on_boot,
9
- :on_stats, :ignore_exceptions, :consistency, :max_retries, :generation
9
+ :on_stats, :max_retries, :generation, :destroy_timeout, :destroy_check_interval
10
10
 
11
11
  def self.backend=(value)
12
12
  @@backend = value
@@ -35,8 +35,6 @@ module Promiscuous::Config
35
35
  block.call(self) if block
36
36
 
37
37
  self.app ||= Rails.application.class.parent_name.underscore rescue nil if defined?(Rails)
38
- self.bootstrap ||= false
39
- self.bootstrap_chunk_size ||= 10000
40
38
  self.backend ||= best_amqp_backend
41
39
  self.amqp_url ||= 'amqp://guest:guest@localhost:5672'
42
40
  self.publisher_amqp_url ||= self.amqp_url
@@ -54,7 +52,7 @@ module Promiscuous::Config
54
52
  self.heartbeat ||= 60
55
53
  self.no_deps ||= false
56
54
  self.hash_size ||= 2**20 # one million keys ~ 200Mb.
57
- self.prefetch ||= self.bootstrap ? 10000000 : 1000
55
+ self.prefetch ||= 1000
58
56
  self.recovery_timeout ||= 10
59
57
  self.logger ||= defined?(Rails) ? Rails.logger : Logger.new(STDERR).tap { |l| l.level = Logger::WARN }
60
58
  self.subscriber_threads ||= 10
@@ -62,10 +60,10 @@ module Promiscuous::Config
62
60
  self.version_field ||= '_v'
63
61
  self.recovery_on_boot = true if self.recovery_on_boot.nil?
64
62
  self.on_stats ||= proc { |rate, latency| }
65
- self.ignore_exceptions ||= false
66
- self.consistency ||= :eventual
67
63
  self.max_retries ||= 10
68
64
  self.generation ||= 1
65
+ self.destroy_timeout ||= 1.hour
66
+ self.destroy_check_interval ||= 10.minutes
69
67
  end
70
68
 
71
69
  def self.configure(&block)
@@ -1,9 +1,8 @@
1
1
  class Promiscuous::Error::Dependency < Promiscuous::Error::Base
2
- attr_accessor :dependency_solutions, :operation, :context
2
+ attr_accessor :dependency_solutions, :operation
3
3
 
4
4
  def initialize(options={})
5
5
  self.operation = options[:operation]
6
- self.context = Promiscuous::Publisher::Context.current
7
6
  end
8
7
 
9
8
  # TODO Convert all that with Erb
@@ -69,7 +68,6 @@ class Promiscuous::Error::Dependency < Promiscuous::Error::Base
69
68
  when :update then msg += 'multi update'
70
69
  when :destroy then msg += 'multi destroy'
71
70
  end
72
- msg += " in the '#{context.name}' context:\n\n"
73
71
  msg += " #{self.class.explain_operation(self.operation)}"
74
72
  msg += "\n\nProTip: Try again with TRACE=2 in the shell or ENV['TRACE']='2' in the console.\n" unless ENV['TRACE']
75
73
  msg
@@ -1,6 +1,6 @@
1
1
  module Promiscuous::Publisher::Context
2
2
  extend Promiscuous::Autoload
3
- autoload :Base, :Transaction, :Middleware
3
+ autoload :Base, :Transaction
4
4
 
5
5
  def self.current
6
6
  Base.current
@@ -2,44 +2,13 @@ class Promiscuous::Publisher::Context::Base
2
2
  # XXX Context are not sharable among threads
3
3
 
4
4
  def self.current
5
- Thread.current[:promiscuous_context]
5
+ Thread.current[:promiscuous_context] ||= self.new
6
6
  end
7
7
 
8
- def self.current=(value)
9
- Thread.current[:promiscuous_context] = value
10
- end
11
-
12
- def self.with_context(*args, &block)
13
- raise "You cannot nest contexts" if self.current
14
-
15
- self.current = new(*args)
16
- begin
17
- self.current.trace "<<< open <<<", :level => 1
18
- yield
19
- ensure
20
- self.current.trace "<<< close <<<", :level => 1
21
- self.current = nil
22
-
23
- ActiveRecord::Base.clear_active_connections! if defined?(ActiveRecord::Base)
24
- end
25
- end
26
-
27
- attr_accessor :name, :read_operations, :extra_dependencies, :current_user
28
-
29
- def initialize(name=nil, options={})
30
- @name = name.try(:to_s) || 'anonymous'
31
- @current_user = options[:current_user]
32
- @read_operations = []
33
- @extra_dependencies = []
34
- @transaction_managers = {}
35
-
36
- Promiscuous::AMQP.ensure_connected
37
-
38
- Mongoid::IdentityMap.clear if defined?(Mongoid::IdentityMap)
39
- ActiveRecord::IdentityMap.clear if defined?(ActiveRecord::IdentityMap)
40
- end
8
+ attr_accessor :current_user
41
9
 
42
10
  def transaction_context_of(driver)
11
+ @transaction_managers ||= {}
43
12
  @transaction_managers[driver] ||= Promiscuous::Publisher::Context::Transaction.new(driver)
44
13
  end
45
14
 
@@ -2,12 +2,10 @@ module Promiscuous::Publisher::Model::Base
2
2
  extend ActiveSupport::Concern
3
3
 
4
4
  included do
5
- class_attribute :published_attrs, :tracked_attrs
5
+ class_attribute :published_attrs
6
6
  cattr_accessor :published_db_fields # There is one on each root class, none on the subclasses
7
7
  self.published_attrs = []
8
- self.tracked_attrs = []
9
8
  self.published_db_fields = []
10
- track_dependencies_of :id
11
9
  Promiscuous::Publisher::Model.publishers[self.promiscuous_collection_name] = self
12
10
  end
13
11
 
@@ -38,26 +36,13 @@ module Promiscuous::Publisher::Model::Base
38
36
  value
39
37
  end
40
38
 
41
- def get_dependency(attr, value)
42
- return nil unless value
39
+ def get_dependency
43
40
  @collection ||= @instance.class.promiscuous_collection_name
44
- Promiscuous::Dependency.new(@collection, attr, value)
41
+ Promiscuous::Dependency.new(@collection, :id, id)
45
42
  end
46
43
 
47
- def tracked_dependencies(options={})
48
- # FIXME This is not sufficient, we need to consider the previous and next
49
- # values in case of an update.
50
- # Note that the caller expect the id dependency to come first
51
- @instance.class.tracked_attrs.map do |attr|
52
- begin
53
- [attr, @instance.__send__(attr)]
54
- rescue Exception => e
55
- # Don't care about missing attributes for read dependencies.
56
- raise e unless options[:allow_missing_attributes] && e.is_a?(ActiveModel::MissingAttributeError)
57
- end
58
- end
59
- .map { |attr, value| get_dependency(attr, value) }
60
- .compact
44
+ def id
45
+ @instance.id
61
46
  end
62
47
  end
63
48
 
@@ -110,10 +95,6 @@ module Promiscuous::Publisher::Model::Base
110
95
  @in_publish_block.to_i > 0
111
96
  end
112
97
 
113
- def track_dependencies_of(*attributes)
114
- ([self] + descendants).each { |klass| klass.tracked_attrs |= attributes.map(&:to_sym) }
115
- end
116
-
117
98
  def promiscuous_collection_name
118
99
  self.name.pluralize.underscore
119
100
  end
@@ -129,7 +110,6 @@ module Promiscuous::Publisher::Model::Base
129
110
  def inherited(subclass)
130
111
  super
131
112
  subclass.published_attrs = self.published_attrs.dup
132
- subclass.tracked_attrs = self.tracked_attrs.dup
133
113
  # no copy for published_db_fields
134
114
  end
135
115
  end
@@ -25,14 +25,12 @@ module Promiscuous::Publisher::Model::Mock
25
25
  def save_operation(operation)
26
26
  payload = nil
27
27
 
28
- Promiscuous::Publisher::Context::Middleware.with_context("mocking #{self.class}") do
29
- op = Promiscuous::Publisher::Operation::Ephemeral.new(:instance => self, :operation => operation)
30
- # TODO FIX the mocks to populate app name, also we need to hook before the
31
- # json dump.
32
- payload = op.generate_payload
33
- end
28
+ op = Promiscuous::Publisher::Operation::Ephemeral.new(:instance => self, :operation => operation)
29
+ # TODO FIX the mocks to populate app name, also we need to hook before the
30
+ # json dump.
31
+ payload = op.generate_payload
34
32
 
35
- Promiscuous::Subscriber::Worker::Message.new(payload).process
33
+ Promiscuous::Subscriber::Message.new(payload).process
36
34
  end
37
35
 
38
36
  module ClassMethods
@@ -64,8 +64,7 @@ class ActiveRecord::Base
64
64
  alias_method :release_savepoint_without_promiscuous, :release_savepoint
65
65
 
66
66
  def with_promiscuous_transaction_context(&block)
67
- ctx = Promiscuous::Publisher::Context.current
68
- block.call(ctx.transaction_context_of(:active_record)) if ctx
67
+ block.call(Promiscuous::Publisher::Context.current.transaction_context_of(:active_record))
69
68
  end
70
69
 
71
70
  def begin_db_transaction
@@ -106,24 +105,10 @@ class ActiveRecord::Base
106
105
  with_promiscuous_transaction_context { |tx| tx.commit }
107
106
  end
108
107
 
109
- alias_method :select_all_without_promiscuous, :select_all
110
- alias_method :select_values_without_promiscuous, :select_values
111
108
  alias_method :insert_without_promiscuous, :insert
112
109
  alias_method :update_without_promiscuous, :update
113
110
  alias_method :delete_without_promiscuous, :delete
114
111
 
115
- def select_all(arel, name = nil, binds = [])
116
- PromiscuousSelectOperation.new(arel, name, binds, :connection => self).execute do
117
- select_all_without_promiscuous(arel, name, binds)
118
- end
119
- end
120
-
121
- def select_values(arel, name = nil)
122
- PromiscuousSelectOperation.new(arel, name, [], :connection => self).execute do
123
- select_values_without_promiscuous(arel, name)
124
- end
125
- end
126
-
127
112
  def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
128
113
  PromiscuousInsertOperation.new(arel, name, pk, id_value, sequence_name, binds, :connection => self).execute do
129
114
  insert_without_promiscuous(arel, name, pk, id_value, sequence_name, binds)
@@ -157,11 +142,11 @@ class ActiveRecord::Base
157
142
  end
158
143
 
159
144
  def transaction_context
160
- current_context.transaction_context_of(:active_record)
145
+ Promiscuous::Publisher::Context.current.transaction_context_of(:active_record)
161
146
  end
162
147
 
163
148
  def ensure_transaction!
164
- if current_context && write? && !transaction_context.in_transaction?
149
+ if !transaction_context.in_transaction?
165
150
  raise "You need to write to the database within an ActiveRecord transaction"
166
151
  end
167
152
  end
@@ -180,7 +165,7 @@ class ActiveRecord::Base
180
165
  query.non_instrumented { db_operation.call }
181
166
  query.instrumented do
182
167
  db_operation_and_select.tap do
183
- transaction_context.add_write_operation(self) if write? && !@instances.empty?
168
+ transaction_context.add_write_operation(self) if !@instances.empty?
184
169
  end
185
170
  end
186
171
  end
@@ -277,56 +262,6 @@ class ActiveRecord::Base
277
262
  end
278
263
  end
279
264
 
280
- class PromiscuousSelectOperation < PromiscousOperation
281
- def initialize(arel, name, binds, options={})
282
- super
283
- @operation = :read
284
- @result = []
285
- end
286
-
287
- def model
288
- @model ||= begin
289
- case @arel
290
- when Arel::SelectManager
291
- raise "SQL statement too complicated (joins?)" if @arel.ast.cores.size != 1
292
- model = @arel.ast.cores.first.source.left.engine
293
- when ActiveRecord::Relation
294
- return nil # TODO
295
- else
296
- raise "What is this query?" unless @arel.is_a?(Arel::SelectManager)
297
- end
298
-
299
- model = nil unless model < Promiscuous::Publisher::Model::ActiveRecord
300
- model
301
- end
302
- rescue
303
- # TODO Track dependencies of complex queries properly...
304
- nil
305
- end
306
-
307
- def get_selector_instance
308
- attrs = @arel.ast.cores.first.wheres.map { |w| [w.children.first.left.name, w.children.first.right] }
309
- model.instantiate(Hash[attrs])
310
- end
311
-
312
- def query_dependencies
313
- deps = dependencies_for(get_selector_instance)
314
- deps.empty? ? super : deps
315
- end
316
-
317
- def execute(&db_operation)
318
- # We dup because ActiveRecord modifies our return value
319
- super.tap { @result = @result.dup }
320
- end
321
-
322
- def db_operation_and_select
323
- # XXX This is only supported by Postgres.
324
- @connection.exec_query("#{@connection.to_sql(@arel, @binds)}", @operation_name, @binds).to_a.tap do |result|
325
- @instances = result.map { |row| model.instantiate(row) }
326
- end
327
- end
328
- end
329
-
330
265
  class PromiscuousTransaction < Promiscuous::Publisher::Operation::Transaction
331
266
  attr_accessor :connection
332
267