joiner 0.3.3 → 0.3.4

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: 01b97b89bc7c04f7a25d72b8436841e8f7fbfe24
4
- data.tar.gz: bab0b551d64f5c25b48f0202e2e0e5149e96d8fc
3
+ metadata.gz: 7249d05e24afee39fbb2547085068230f6b1d62b
4
+ data.tar.gz: 941f72f5d80c3a6c0b8b88684f7a35b77e7461ee
5
5
  SHA512:
6
- metadata.gz: 8a70f902aab2443b347718b8f3d71dff01bad841df1655cd4a4aaae048464468528bcf0f442a182cb00045caf0d2ef5dbea11b6c63d60ca96517ff4f304e22d3
7
- data.tar.gz: 5c9b0c43094294bd7e4b6bb788525742994828018c741b3ed663a0ae95384232c38d485f49429816ea1516f3e4baa8bf858fb137a8229b82792b7f788ad8115d
6
+ metadata.gz: 0fd9651d510164f7e5843589678ba62d3f214c67dca6309e4711f71cd8b4200b3e105cd780fdfab14d3a4240d4354fcd95b6568b101d710757da1d093e96600a
7
+ data.tar.gz: ff41eaace4916f013c03e7407a65709543251908daab4f3203f723282a9c38c50a35b9767a9b074bb6f7f336bb1042cf30542d8ee179cd08ca868a23228b66fe
data/README.md CHANGED
@@ -9,7 +9,7 @@ If this gem is used by anyone other than myself/Thinking Sphinx, I'll be surpris
9
9
  It's a gem - so you can either install it yourself, or add it to the appropriate Gemfile or gemspec.
10
10
 
11
11
  ```term
12
- gem install joiner --version 0.3.3
12
+ gem install joiner --version 0.3.4
13
13
  ```
14
14
 
15
15
  ## Usage
@@ -1,7 +1,7 @@
1
1
  # coding: utf-8
2
2
  Gem::Specification.new do |spec|
3
3
  spec.name = 'joiner'
4
- spec.version = '0.3.3'
4
+ spec.version = '0.3.4'
5
5
  spec.authors = ['Pat Allan']
6
6
  spec.email = ['pat@freelancing-gods.com']
7
7
  spec.summary = %q{Builds ActiveRecord joins from association paths}
@@ -1,3 +1,5 @@
1
+ require 'set'
2
+
1
3
  module Joiner
2
4
  class AssociationNotFound < StandardError
3
5
  end
@@ -1,103 +1,57 @@
1
+ require 'active_record'
2
+ require 'active_support/ordered_hash'
3
+
1
4
  class Joiner::Joins
2
- JoinDependency = ::ActiveRecord::Associations::JoinDependency
5
+ JoinDependency = ActiveRecord::Associations::JoinDependency
6
+ JoinAssociation = JoinDependency::JoinAssociation
3
7
 
4
- attr_reader :model
5
- attr_writer :join_association_class
8
+ attr_reader :model
9
+ attr_accessor :join_association_class
6
10
 
7
11
  def initialize(model)
8
12
  @model = model
9
- @base = JoinDependency.new model, [], []
10
- @joins_cache = ActiveSupport::OrderedHash.new
13
+ @joins_cache = Set.new
11
14
  end
12
15
 
13
16
  def add_join_to(path)
14
- @joins_cache[path] ||= build_join(path)
17
+ return if path.empty?
18
+
19
+ joins_cache.add path_as_hash(path)
15
20
  end
16
21
 
17
22
  def alias_for(path)
18
23
  return model.table_name if path.empty?
19
- add_join_to(path).aliased_table_name
20
- end
21
24
 
22
- def join_association_class
23
- @join_association_class || JoinDependency::JoinAssociation
25
+ add_join_to path
26
+ join_association_for(path).tables.first.name
24
27
  end
25
28
 
26
29
  def join_values
27
- @base
28
- end
29
-
30
- private
30
+ switch_join_dependency join_association_class
31
+ result = JoinDependency.new model, joins_cache.to_a, []
32
+ switch_join_dependency JoinAssociation
31
33
 
32
- def build_join(path)
33
- if join = find_join(path)
34
- return join
35
- end
36
-
37
- base_node, short_path = relative_path(path)
38
-
39
- join = build_join_association(short_path, base_node.base_klass)
40
- base_node.children << join
41
- construct_tables! base_node, join
42
-
43
- find_join(path)
34
+ result
44
35
  end
45
36
 
46
- def build_join_association(path, base_class)
47
- return nil if path.empty?
48
-
49
- step = path.first
50
- reflection = find_reflection(step, base_class)
51
- reflection.check_validity!
52
-
53
- join_association_class.new reflection,
54
- [build_join_association(path[1..-1], reflection.klass)].compact
55
- end
56
-
57
- def find_join(path, base = nil)
58
- base ||= @base.join_root
59
-
60
- return base if path.empty?
61
-
62
- if next_step = base.children.detect{ |c| c.reflection.name == path.first }
63
- find_join path[1..-1], next_step
64
- end
65
- end
37
+ private
66
38
 
67
- def relative_path(path)
68
- short_path = []
69
- test_path = path.dup
39
+ attr_reader :joins_cache
70
40
 
71
- while test_path.size > 1
72
- short_path << test_path.pop
73
- node = find_join(test_path)
74
- return [node, short_path] if node
41
+ def join_association_for(path)
42
+ path.inject(join_values.join_root) do |node, piece|
43
+ node.children.detect { |child| child.reflection.name == piece }
75
44
  end
76
-
77
- [@base.join_root, path]
78
45
  end
79
46
 
80
- def find_reflection(name, klass)
81
- klass._reflect_on_association(name)
47
+ def path_as_hash(path)
48
+ path[0..-2].reverse.inject(path.last) { |key, item| {item => key} }
82
49
  end
83
50
 
84
- def table_aliases_for(parent, node)
85
- node.reflection.chain.map { |reflection|
86
- @base.alias_tracker.aliased_table_for(
87
- reflection.table_name,
88
- table_alias_for(reflection, parent, reflection != node.reflection)
89
- )
90
- }
91
- end
92
-
93
- def construct_tables!(parent, node)
94
- node.tables = table_aliases_for(parent, node)
95
- node.children.each { |child| construct_tables! node, child }
96
- end
51
+ def switch_join_dependency(klass)
52
+ return unless join_association_class
97
53
 
98
- def table_alias_for(reflection, parent, join)
99
- name = "#{reflection.plural_name}_#{parent.table_name}"
100
- name << "_join" if join
101
- name
54
+ JoinDependency.send :remove_const, :JoinAssociation
55
+ JoinDependency.const_set :JoinAssociation, klass
102
56
  end
103
57
  end
@@ -63,4 +63,15 @@ describe 'Joiner' do
63
63
  expect(joiner.alias_for([:comments])).to eq('comments')
64
64
  expect(joiner.alias_for([:user, :comments])).to eq('comments_users')
65
65
  end
66
+
67
+ it 'handles simple and deep chains' do
68
+ joiner = Joiner::Joins.new Article
69
+ joiner.add_join_to [:comments]
70
+ joiner.add_join_to [:comments, :user, :articles]
71
+
72
+ expect(joiner.alias_for([:comments])).to eq('comments')
73
+ expect(joiner.alias_for([:comments, :user, :articles])).to eq(
74
+ 'articles_users'
75
+ )
76
+ end
66
77
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: joiner
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pat Allan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-28 00:00:00.000000000 Z
11
+ date: 2014-11-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -105,7 +105,6 @@ files:
105
105
  - spec/internal/config/database.yml
106
106
  - spec/internal/db/schema.rb
107
107
  - spec/internal/log/.gitignore
108
- - spec/joiner/joins_spec.rb
109
108
  - spec/spec_helper.rb
110
109
  homepage: https://github.com/pat/joiner
111
110
  licenses:
@@ -140,5 +139,4 @@ test_files:
140
139
  - spec/internal/config/database.yml
141
140
  - spec/internal/db/schema.rb
142
141
  - spec/internal/log/.gitignore
143
- - spec/joiner/joins_spec.rb
144
142
  - spec/spec_helper.rb
@@ -1,83 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Joiner::Joins do
4
- JoinDependency = ::ActiveRecord::Associations::JoinDependency
5
-
6
- subject { Joiner::Joins.new Article }
7
-
8
- describe '#add_join_to' do
9
- it "adds just one join for a stack with a single association" do
10
- JoinDependency::JoinAssociation.should_receive(:new).
11
- with(Article.reflections[:user], []).once.and_call_original
12
-
13
- subject.add_join_to([:user])
14
- end
15
-
16
- it "does not duplicate joins when given the same stack twice" do
17
- JoinDependency::JoinAssociation.should_receive(:new).once.and_call_original
18
-
19
- subject.add_join_to([:user])
20
- subject.add_join_to([:user])
21
- end
22
-
23
- context 'when joins are nested' do
24
- it "adds two joins for a stack with two associations" do
25
- JoinDependency::JoinAssociation.should_receive(:new).
26
- with(Article.reflections[:user], kind_of(Array)).once.and_call_original
27
- JoinDependency::JoinAssociation.should_receive(:new).
28
- with(User.reflections[:comments], kind_of(Array)).once.and_call_original
29
-
30
- subject.add_join_to([:user, :comments])
31
- end
32
-
33
- it "extends upon existing joins when given stacks where parts are already mapped" do
34
- JoinDependency::JoinAssociation.should_receive(:new).twice.and_call_original
35
-
36
- join1 = subject.add_join_to([:user])
37
- join2 = subject.add_join_to([:user, :comments])
38
-
39
- join1.children.should include(join2)
40
- end
41
- end
42
- end
43
-
44
- describe '#alias_for' do
45
- it "returns the model's table name when no stack is given" do
46
- subject.alias_for([]).should == 'articles'
47
- end
48
-
49
- it "gets join association using #add_join_to" do
50
- subject.should_receive(:add_join_to).with([:user]).and_call_original
51
- subject.alias_for([:user])
52
- end
53
-
54
- it "returns the aliased table name for the join" do
55
- subject.alias_for([:user]).should == 'users'
56
- end
57
-
58
- it "does not duplicate joins when given the same stack twice" do
59
- JoinDependency::JoinAssociation.should_receive(:new).once.and_call_original
60
-
61
- subject.alias_for([:user])
62
- subject.alias_for([:user])
63
- end
64
-
65
- context 'when joins are nested' do
66
- it "returns the sub join's aliased table name" do
67
- subject.alias_for([:user, :comments]).should == 'comments'
68
- end
69
- end
70
- end
71
-
72
- describe '#join_values' do
73
- it "returns JoinDependency with all joins that have been created" do
74
- join1 = subject.add_join_to([:user])
75
- join2 = subject.add_join_to([:comments])
76
- join3 = subject.add_join_to([:comments, :user])
77
-
78
- join_values = subject.join_values
79
- join_values.should be_a JoinDependency
80
- join_values.join_root.children.should == [join1, join2]
81
- end
82
- end
83
- end