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 +4 -4
- data/lib/querrel.rb +6 -2
- data/lib/querrel/connected_model_factory.rb +12 -0
- data/lib/querrel/connection_resolver.rb +2 -1
- data/lib/querrel/map_reduce.rb +50 -0
- data/lib/querrel/querreller.rb +7 -33
- data/lib/querrel/version.rb +1 -1
- data/test/instance_test.rb +19 -1
- data/test/non_instance_test.rb +19 -1
- data/test/resolver_test.rb +9 -7
- data/test/setup/database.yml +1 -1
- 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: 8a221606ea4c6afe6ec28d674c8a3991bb221d15
|
4
|
+
data.tar.gz: 3c1bb8daff36108b3addd087d3769cbe3b5cefab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 971c487ef162a42b1874616ea1f267a13836d0671766fe12f83dc359fef3df071d0b4b9c6cf8e39d9cd85cf896184b806f3bfb6881c4f9fb5d102942c7c9e744
|
7
|
+
data.tar.gz: d2aa19d3e6cb412bee5210107b616607847870baf61bc5d4c8948a13d756c771c278610aa578f5f5e4f1f0c6a225cb2af61a3b384a30a85751e00e52602681cd
|
data/lib/querrel.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/querrel/querreller.rb
CHANGED
@@ -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
|
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(
|
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
|
-
|
33
|
-
|
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)
|
data/lib/querrel/version.rb
CHANGED
data/test/instance_test.rb
CHANGED
@@ -39,6 +39,24 @@ class InstanceTest < Querrel::Test
|
|
39
39
|
scope.pluck(:name)
|
40
40
|
end
|
41
41
|
|
42
|
-
|
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
|
data/test/non_instance_test.rb
CHANGED
@@ -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
|
-
|
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
|
data/test/resolver_test.rb
CHANGED
@@ -2,11 +2,16 @@ require_relative 'setup/test_helper'
|
|
2
2
|
|
3
3
|
class InstanceTest < Querrel::Test
|
4
4
|
def test_env_resolver
|
5
|
-
|
6
|
-
|
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,
|
9
|
-
assert_equal
|
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
|
data/test/setup/database.yml
CHANGED
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.
|
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
|