querrel 1.1.0 → 1.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 10e25c9b7852624e963fb30af3d5fe9197f82205
4
- data.tar.gz: 2cd4c6c58b3bbc6939df6d3e7033775bce6dbcb0
3
+ metadata.gz: 8a221606ea4c6afe6ec28d674c8a3991bb221d15
4
+ data.tar.gz: 3c1bb8daff36108b3addd087d3769cbe3b5cefab
5
5
  SHA512:
6
- metadata.gz: ba13c28586b08e6253b7f3fb5a535e1658772f03301babebdb8886669e9606e8d560198a90f54d77c890320f0a37936210aa5c4720c7d9b38b5499dd6b4e1388
7
- data.tar.gz: cf49fe63a453d70c3ca8271463f6a77d4463291f3dc2319c477859671b22c6d924a0abd73a248908c2291a7aa27d783117dcbec0baaf31108e8ab92cfe35ede4
6
+ metadata.gz: 971c487ef162a42b1874616ea1f267a13836d0671766fe12f83dc359fef3df071d0b4b9c6cf8e39d9cd85cf896184b806f3bfb6881c4f9fb5d102942c7c9e744
7
+ data.tar.gz: d2aa19d3e6cb412bee5210107b616607847870baf61bc5d4c8948a13d756c771c278610aa578f5f5e4f1f0c6a225cb2af61a3b384a30a85751e00e52602681cd
@@ -8,11 +8,15 @@ module Querrel
8
8
  end
9
9
 
10
10
  def query(scope, opts, &blk)
11
- Querreller.new(opts.delete(:on), opts).query(scope)
11
+ Querreller.new(opts.delete(:on), opts).query(scope, &blk)
12
12
  end
13
13
 
14
14
  def map(scope, opts, &blk)
15
- Querreller.new(opts.delete(:on), opts).map(scope)
15
+ Querreller.new(opts.delete(:on), opts).map(scope, &blk)
16
+ end
17
+
18
+ def run(opts, &blk)
19
+ Querreller.new(opts.delete(:on), opts).run(&blk)
16
20
  end
17
21
  end
18
22
  end
@@ -0,0 +1,12 @@
1
+ module Querrel
2
+ class ConnectedModelFactory
3
+ def self.[](model, con_spec = nil)
4
+ con_spec ||= Thread.current[:querrel_con_spec]
5
+ dynamic_class_name = "#{model.name}#{Thread.current.object_id}"
6
+ Class.new(model).tap do |m|
7
+ m.send(:define_singleton_method, :name) { dynamic_class_name }
8
+ m.establish_connection(con_spec.config)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -15,7 +15,8 @@ module Querrel
15
15
  when Hash
16
16
  specs = conns
17
17
  when Array
18
- specs = ActiveRecord::Base.configurations.select{ |n, _| conns.include?(n.to_sym) }
18
+ conns.map!(&:to_s)
19
+ specs = ActiveRecord::Base.configurations.select{ |n, _| conns.include?(n.to_s) }
19
20
  end
20
21
  end
21
22
 
@@ -0,0 +1,50 @@
1
+ module Querrel
2
+ module MapReduce
3
+ def query(scope, options = {}, &blk)
4
+ buckets = map(scope, options, &blk)
5
+ reduce(buckets)
6
+ end
7
+
8
+ def map(scope, options = {}, &blk)
9
+ if options.key?(:on)
10
+ resolver = ConnectionResolver.new(options[:on], !!options[:db_names])
11
+ dbs = resolver.configurations.keys
12
+ else
13
+ resolver = @connection_resolver
14
+ dbs = @connection_resolver.configurations.keys
15
+ end
16
+
17
+ query_model = scope.model
18
+ results = {}
19
+
20
+ threads = []
21
+ dbs.each do |db|
22
+ threads << Thread.new do
23
+ con_spec = retrieve_connection_spec(db, resolver)
24
+ Thread.current[:querrel_con_spec] = con_spec
25
+ dynamic_class = ConnectedModelFactory[query_model, con_spec]
26
+
27
+ begin
28
+ local_scope = dynamic_class.all.merge(scope)
29
+ results[db] = if block_given?
30
+ res = yield(local_scope)
31
+ res.to_a.each(&:readonly!) if res.is_a?(ActiveRecord::Relation)
32
+ res
33
+ else
34
+ local_scope.to_a.each(&:readonly!)
35
+ end
36
+ ensure
37
+ dynamic_class.connection_pool.release_connection
38
+ end
39
+ end
40
+ end
41
+ threads.each(&:join)
42
+
43
+ results
44
+ end
45
+
46
+ def reduce(buckets)
47
+ buckets.flat_map{ |db, results| results }
48
+ end
49
+ end
50
+ end
@@ -1,60 +1,34 @@
1
+ require 'querrel/connected_model_factory'
1
2
  require 'querrel/connection_resolver'
3
+ require 'querrel/map_reduce'
2
4
 
3
5
  module Querrel
4
6
  class Querreller
7
+ include MapReduce
5
8
  attr_accessor :connection_resolver
6
9
 
7
10
  def initialize(dbs, options = {})
8
11
  @connection_resolver = ConnectionResolver.new(dbs, options[:db_names])
9
12
  end
10
13
 
11
- def query(scope, options = {}, &blk)
12
- buckets = map(scope, options, &blk)
13
- reduce(buckets)
14
- end
15
-
16
- def map(scope, options = {}, &blk)
14
+ def run(options = {}, &blk)
17
15
  if options.key?(:on)
18
- resolver = ConnectionResolver.new(dbs, !!options[:db_names])
16
+ resolver = ConnectionResolver.new(options[:on], !!options[:db_names])
19
17
  dbs = resolver.configurations.keys
20
18
  else
21
19
  resolver = @connection_resolver
22
20
  dbs = @connection_resolver.configurations.keys
23
21
  end
24
22
 
25
- query_model = scope.model
26
- results = {}
27
-
28
23
  threads = []
29
24
  dbs.each do |db|
30
25
  threads << Thread.new do
31
26
  con_spec = retrieve_connection_spec(db, resolver)
32
- dynamic_class_name = "TempModel#{Thread.current.object_id}"
33
- dynamic_class = Class.new(query_model)
34
- dynamic_class.send(:define_singleton_method, :name) { dynamic_class_name }
35
-
36
- begin
37
- dynamic_class.establish_connection(con_spec.config)
38
- local_scope = dynamic_class.all.merge(scope)
39
- results[db] = if block_given?
40
- res = yield(local_scope)
41
- res.to_a.each(&:readonly!) if res.is_a?(ActiveRecord::Relation)
42
- res
43
- else
44
- local_scope.to_a.each(&:readonly!)
45
- end
46
- ensure
47
- dynamic_class.connection_pool.release_connection
48
- end
27
+ Thread.current[:querrel_con_spec] = con_spec
28
+ yield(ConnectedModelFactory)
49
29
  end
50
30
  end
51
31
  threads.each(&:join)
52
-
53
- results
54
- end
55
-
56
- def reduce(buckets)
57
- buckets.flat_map{ |db, results| results }
58
32
  end
59
33
 
60
34
  def retrieve_connection_spec(db, resolver)
@@ -1,3 +1,3 @@
1
1
  module Querrel
2
- VERSION = "1.1.0"
2
+ VERSION = "1.2.0"
3
3
  end
@@ -39,6 +39,24 @@ class InstanceTest < Querrel::Test
39
39
  scope.pluck(:name)
40
40
  end
41
41
 
42
- assert names * @dbs.length, res
42
+ assert_equal names * @dbs.length, res
43
+ end
44
+
45
+ def test_runner
46
+ s = Mutex.new
47
+ configs_actual = []
48
+
49
+ @q.run do |q|
50
+ s.synchronize do
51
+ configs_actual << q[Product].connection_config
52
+ end
53
+ end
54
+
55
+ configs = Querrel::ConnectionResolver.new(@dbs, false).configurations.values
56
+
57
+ configs = configs.map{ |c| Hash[c.map{ |k, v| [k.to_s, v] }] }.sort_by{ |c| c["database"] }
58
+ configs_actual = configs_actual.map{ |c| Hash[c.map{ |k, v| [k.to_s, v] }] }.sort_by{ |c| c["database"] }
59
+
60
+ assert_equal configs, configs_actual
43
61
  end
44
62
  end
@@ -1,3 +1,4 @@
1
+ require 'thread'
1
2
  require_relative 'setup/test_helper'
2
3
 
3
4
  class NonInstanceTest < Querrel::Test
@@ -38,6 +39,23 @@ class NonInstanceTest < Querrel::Test
38
39
  scope.pluck(:name)
39
40
  end
40
41
 
41
- assert names * @dbs.length, res
42
+ assert_equal names * @dbs.length, res
43
+ end
44
+
45
+ def test_runner
46
+ s = Mutex.new
47
+ configs_actual = []
48
+ Querrel.run(on: @dbs) do |q|
49
+ s.synchronize do
50
+ configs_actual << q[Product].connection_config
51
+ end
52
+ end
53
+
54
+ configs = Querrel::ConnectionResolver.new(@dbs, false).configurations.values
55
+
56
+ configs = configs.map{ |c| Hash[c.map{ |k, v| [k.to_s, v] }] }.sort_by{ |c| c["database"] }
57
+ configs_actual = configs_actual.map{ |c| Hash[c.map{ |k, v| [k.to_s, v] }] }.sort_by{ |c| c["database"] }
58
+
59
+ assert_equal configs, configs_actual
42
60
  end
43
61
  end
@@ -2,11 +2,16 @@ require_relative 'setup/test_helper'
2
2
 
3
3
  class InstanceTest < Querrel::Test
4
4
  def test_env_resolver
5
- conns = [:sqlite_db_0, :sqlite_db_1]
6
- resolver = Querrel::ConnectionResolver.new(conns, false)
5
+ sym_conns = [:sqlite_db_0, :sqlite_db_1]
6
+ resolver_sym = Querrel::ConnectionResolver.new(sym_conns, false)
7
+ string_conns = ['sqlite_db_0', 'sqlite_db_1']
8
+ resolver_string = Querrel::ConnectionResolver.new(string_conns, false)
9
+
10
+ assert_equal 2, resolver_sym.configurations.length
11
+ assert_equal string_conns, resolver_sym.configurations.keys
7
12
 
8
- assert_equal 2, resolver.configurations.length
9
- assert_equal conns.map(&:to_s), resolver.configurations.keys
13
+ assert_equal 2, resolver_string.configurations.length
14
+ assert_equal string_conns, resolver_string.configurations.keys
10
15
  end
11
16
 
12
17
  def test_db_name_resolver
@@ -34,7 +39,4 @@ class InstanceTest < Querrel::Test
34
39
 
35
40
  assert_equal conns, resolver.configurations
36
41
  end
37
-
38
- def test_default_resolver
39
- end
40
42
  end
@@ -1,4 +1,4 @@
1
- <% 100.times do |i| %>
1
+ <% 20.times do |i| %>
2
2
  sqlite_db_<%= i %>:
3
3
  adapter: sqlite3
4
4
  database: test/dbs/test_db_<%= i %>.sqlite3
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: querrel
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Campbell
@@ -93,7 +93,9 @@ files:
93
93
  - README.md
94
94
  - Rakefile
95
95
  - lib/querrel.rb
96
+ - lib/querrel/connected_model_factory.rb
96
97
  - lib/querrel/connection_resolver.rb
98
+ - lib/querrel/map_reduce.rb
97
99
  - lib/querrel/querreller.rb
98
100
  - lib/querrel/version.rb
99
101
  - querrel.gemspec