joiner 0.3.3 → 0.3.4

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: 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