where_exists 1.1.1 → 1.1.2

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
- SHA1:
3
- metadata.gz: '09bda87b615e0962be005bda294cc0227e1d76ce'
4
- data.tar.gz: 4cb809c77b97dfaad246f1a90be28e75cc2bb5a2
2
+ SHA256:
3
+ metadata.gz: 6f1f20fb282b67f60382f0d48c47f506623c3941e6d003b07b217eaa42291b9d
4
+ data.tar.gz: a4d5235b9373ad42c223eb439a611da125cc35ab7107ff6cf0b4c045bbd4f29e
5
5
  SHA512:
6
- metadata.gz: b4ca719701af78dfc661a35cb815adf49d1206072f0fa3db2af6a411677f7394ad19547706f0f14265462955231847922821732caa9c64ca4e22186cefeb1127
7
- data.tar.gz: 6e147f5238c544d0691cfb982d38cc560b5baf6a97d82f5529b94cafed6683c9e1a0b7706b6d967e2cc0913b905906c0d3192d64e064407f60774cd6c309f94c
6
+ metadata.gz: dbffcaf8b56b8aaf0c4c6e18586e41fba2ece5a4373f5adb6f0d5e42aee574eaf8d2c1cfd60842fd07d8a633c14f597bc65a0ae78742fb8b03f75f5a8226a94b
7
+ data.tar.gz: 178fa0742ea16a40d0809d344cc42750a39157e24e2e4df40bb34148967d53b035248a093d4e82e890e219577fd618916fade84b56239d41da656623c63a3b3a
File without changes
data/Rakefile CHANGED
@@ -25,7 +25,7 @@ Rake::TestTask.new(:test) do |t|
25
25
  t.libs << 'lib'
26
26
  t.libs << 'test'
27
27
  t.pattern = 'test/**/*_test.rb'
28
- t.verbose = false
28
+ t.verbose = true
29
29
  end
30
30
 
31
31
 
@@ -12,10 +12,22 @@ module WhereExists
12
12
  protected
13
13
 
14
14
  def where_exists_or_not_exists(does_exist, association_name, where_parameters)
15
+ queries_sql = build_exists_string(association_name, *where_parameters)
16
+
17
+ if does_exist
18
+ not_string = ""
19
+ else
20
+ not_string = "NOT "
21
+ end
22
+
23
+ self.where("#{not_string}(#{queries_sql})")
24
+ end
25
+
26
+ def build_exists_string(association_name, *where_parameters)
15
27
  association = self.reflect_on_association(association_name)
16
28
 
17
29
  unless association
18
- raise ArgumentError.new("where_exists: association #{association_name.inspect} not found on #{self.name}")
30
+ raise ArgumentError.new("where_exists: association - #{association_name} - #{association_name.inspect} not found on #{self.name}")
19
31
  end
20
32
 
21
33
  case association.macro
@@ -34,16 +46,7 @@ module WhereExists
34
46
  end
35
47
  raise ArgumentError.new("where_exists: not supported association – #{inspection}")
36
48
  end
37
-
38
- if does_exist
39
- not_string = ""
40
- else
41
- not_string = "NOT "
42
- end
43
-
44
49
  queries_sql = queries.map { |query| "EXISTS (" + query.to_sql + ")" }.join(" OR ")
45
-
46
- self.where("#{not_string}(#{queries_sql})")
47
50
  end
48
51
 
49
52
  def where_exists_for_belongs_to_query(association, where_parameters)
@@ -82,16 +85,34 @@ module WhereExists
82
85
  queries
83
86
  end
84
87
 
85
- def where_exists_for_has_many_query(association, where_parameters)
86
- through = association.options[:through].present?
87
-
88
- association_scope = association.scope
89
-
90
- if through
91
- next_association = association.source_reflection
88
+ def where_exists_for_has_many_query(association, where_parameters, next_association = {})
89
+ if association.through_reflection
90
+ raise ArgumentError.new(association) unless association.source_reflection
91
+ next_association = {
92
+ association: association.source_reflection,
93
+ params: where_parameters,
94
+ next_association: next_association
95
+ }
92
96
  association = association.through_reflection
97
+
98
+ case association.macro
99
+ when :has_many, :has_one
100
+ return where_exists_for_has_many_query(association, {}, next_association)
101
+ when :has_and_belongs_to_many
102
+ return where_exists_for_habtm_query(association, {}, next_association)
103
+ else
104
+ inspection = nil
105
+ begin
106
+ inspection = association.macros.inspect
107
+ rescue
108
+ inspection = association.macro
109
+ end
110
+ raise ArgumentError.new("where_exists: not supported association – #{inspection}")
111
+ end
93
112
  end
94
113
 
114
+ association_scope = next_association[:scope] || association.scope
115
+
95
116
  associated_model = association.klass
96
117
  primary_key = association.options[:primary_key] || self.primary_key
97
118
 
@@ -106,13 +127,14 @@ module WhereExists
106
127
  result = result.where("#{other_types} = #{self_class}")
107
128
  end
108
129
 
109
- if through
110
- return [result.where_exists(next_association.name, *where_parameters)]
130
+ if next_association[:association]
131
+ return loop_nested_association(result, next_association)
111
132
  end
112
133
 
113
134
  if where_parameters != []
114
135
  result = result.where(*where_parameters)
115
136
  end
137
+
116
138
  if association_scope
117
139
  result = result.instance_exec(&association_scope)
118
140
  end
@@ -120,7 +142,7 @@ module WhereExists
120
142
  [result]
121
143
  end
122
144
 
123
- def where_exists_for_habtm_query(association, where_parameters)
145
+ def where_exists_for_habtm_query(association, where_parameters, next_association = {})
124
146
  association_scope = association.scope
125
147
 
126
148
  associated_model = association.klass
@@ -145,9 +167,14 @@ module WhereExists
145
167
  ).
146
168
  where("#{join_ids} = #{self_ids}")
147
169
 
170
+ if next_association[:association]
171
+ return loop_nested_association(result, next_association)
172
+ end
173
+
148
174
  if where_parameters != []
149
175
  result = result.where(*where_parameters)
150
176
  end
177
+
151
178
  if association_scope
152
179
  result = result.instance_exec(&association_scope)
153
180
  end
@@ -155,6 +182,28 @@ module WhereExists
155
182
  [result]
156
183
  end
157
184
 
185
+ def loop_nested_association(query, next_association = {}, nested = false)
186
+ str = query.klass.build_exists_string(
187
+ next_association[:association].name,
188
+ *[
189
+ *next_association[:params]
190
+ ],
191
+ )
192
+
193
+ if next_association[:next_association] && next_association[:next_association][:association]
194
+ subq = str.match(/\([^\(\)]+\)/mi)[0]
195
+ str.sub!(subq,
196
+ "(#{subq} AND (#{loop_nested_association(
197
+ next_association[:association],
198
+ next_association[:next_association],
199
+ true
200
+ )}))"
201
+ )
202
+ end
203
+
204
+ nested ? str : [query.where(str)]
205
+ end
206
+
158
207
  def quote_table_and_column_name(table_name, column_name)
159
208
  connection.quote_table_name(table_name) + '.' + connection.quote_column_name(column_name)
160
209
  end
@@ -1,3 +1,3 @@
1
1
  module WhereExists
2
- VERSION = "1.1.1"
2
+ VERSION = "1.1.2"
3
3
  end
File without changes
File without changes
Binary file
File without changes
File without changes
File without changes
File without changes
@@ -1,4 +1,4 @@
1
- require 'test_helper'
1
+ require_relative 'test_helper'
2
2
 
3
3
  ActiveRecord::Migration.create_table :projects, :force => true do |t|
4
4
  t.string :name
@@ -15,6 +15,11 @@ ActiveRecord::Migration.create_table :line_items, :force => true do |t|
15
15
  t.integer :task_id
16
16
  end
17
17
 
18
+ ActiveRecord::Migration.create_table :work_details, :force => true do |t|
19
+ t.string :name
20
+ t.integer :line_item_id
21
+ end
22
+
18
23
  ActiveRecord::Migration.create_table :invoices, :force => true do |t|
19
24
  t.string :name
20
25
  end
@@ -23,6 +28,7 @@ class Project < ActiveRecord::Base
23
28
  has_many :tasks
24
29
  has_many :invoices, :through => :tasks
25
30
  has_many :project_line_items, :through => :tasks, :source => :line_items
31
+ has_many :work_details, :through => :project_line_items
26
32
  end
27
33
 
28
34
  class Task < ActiveRecord::Base
@@ -35,6 +41,11 @@ end
35
41
  class LineItem < ActiveRecord::Base
36
42
  belongs_to :invoice
37
43
  belongs_to :task
44
+ has_many :work_details
45
+ end
46
+
47
+ class WorkDetail < ActiveRecord::Base
48
+ belongs_to :line_item
38
49
  end
39
50
 
40
51
  class Invoice < ActiveRecord::Base
@@ -50,6 +61,8 @@ class HasManyThroughTest < Minitest::Test
50
61
  end
51
62
 
52
63
  def test_one_level_through
64
+ ActiveRecord::Base.descendants.each(&:delete_all)
65
+
53
66
  project = Project.create!
54
67
  irrelevant_project = Project.create!
55
68
 
@@ -70,8 +83,10 @@ class HasManyThroughTest < Minitest::Test
70
83
  end
71
84
 
72
85
  def test_deep_through
73
- project = Project.create!
74
- irrelevant_project = Project.create!
86
+ ActiveRecord::Base.descendants.each(&:delete_all)
87
+
88
+ project = Project.create! name: 'relevant'
89
+ irrelevant_project = Project.create! name: 'irrelevant'
75
90
 
76
91
  task = Task.create!(project: project)
77
92
  irrelevant_task = Task.create!(project: irrelevant_project)
@@ -79,8 +94,11 @@ class HasManyThroughTest < Minitest::Test
79
94
  invoice = Invoice.create!(name: 'relevant')
80
95
  irrelevant_invoice = Invoice.create!(name: 'irrelevant')
81
96
 
82
- _line_item = LineItem.create!(task: task, invoice: invoice)
83
- _irrelevant_line_item = LineItem.create!(task: irrelevant_task, invoice: irrelevant_invoice)
97
+ line_item = LineItem.create!(task: task, invoice: invoice)
98
+ irrelevant_line_item = LineItem.create!(task: irrelevant_task, invoice: irrelevant_invoice)
99
+
100
+ _work_detail = WorkDetail.create!(line_item: line_item, name: 'relevant')
101
+ _irrelevant_work_detail = WorkDetail.create!(line_item: irrelevant_line_item, name: 'irrelevant')
84
102
 
85
103
  result = Project.where_exists(:invoices, name: 'relevant')
86
104
 
@@ -96,5 +114,15 @@ class HasManyThroughTest < Minitest::Test
96
114
 
97
115
  assert_equal 1, result.length
98
116
  assert_equal irrelevant_project.id, result.first.id
117
+
118
+ result = Project.where_exists(:work_details, name: 'relevant')
119
+
120
+ assert_equal 1, result.length
121
+ assert_equal project.id, result.first.id
122
+
123
+ result = Project.where_not_exists(:work_details, name: 'relevant')
124
+
125
+ assert_equal 1, result.length
126
+ assert_equal irrelevant_project.id, result.first.id
99
127
  end
100
128
  end
File without changes
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: where_exists
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eugene Zolotarev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-06 00:00:00.000000000 Z
11
+ date: 2018-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -48,16 +48,44 @@ dependencies:
48
48
  name: minitest
49
49
  requirement: !ruby/object:Gem::Requirement
50
50
  requirements:
51
- - - ">="
51
+ - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '0'
53
+ version: '5.10'
54
54
  type: :development
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  requirements:
58
- - - ">="
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '5.10'
61
+ - !ruby/object:Gem::Dependency
62
+ name: rake
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '12.3'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '12.3'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rdoc
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '6.0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
59
87
  - !ruby/object:Gem::Version
60
- version: '0'
88
+ version: '6.0'
61
89
  description: Rails way to harness the power of SQL "EXISTS" statement
62
90
  email:
63
91
  - eugzol@gmail.com
@@ -98,17 +126,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
126
  version: '0'
99
127
  requirements: []
100
128
  rubyforge_project:
101
- rubygems_version: 2.6.11
129
+ rubygems_version: 2.7.7
102
130
  signing_key:
103
131
  specification_version: 4
104
132
  summary: "#where_exists extension of ActiveRecord"
105
133
  test_files:
106
- - test/db/test.db
134
+ - test/belongs_to_polymorphic_test.rb
107
135
  - test/belongs_to_test.rb
136
+ - test/db/test.db
108
137
  - test/documentation_test.rb
109
- - test/test_helper.rb
110
- - test/has_many_polymorphic_test.rb
111
138
  - test/has_and_belongs_to_many.rb
112
- - test/belongs_to_polymorphic_test.rb
139
+ - test/has_many_polymorphic_test.rb
113
140
  - test/has_many_test.rb
114
141
  - test/has_many_through_test.rb
142
+ - test/test_helper.rb