promiscuous 0.92.0 → 0.100.0

Sign up to get free protection for your applications and to get access to all the features.
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