querrel 1.1.0 → 1.2.0

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