where_exists 1.1.1 → 1.1.2
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 +5 -5
- data/MIT-LICENSE +0 -0
- data/Rakefile +1 -1
- data/lib/where_exists.rb +69 -20
- data/lib/where_exists/version.rb +1 -1
- data/test/belongs_to_polymorphic_test.rb +0 -0
- data/test/belongs_to_test.rb +0 -0
- data/test/db/test.db +0 -0
- data/test/documentation_test.rb +0 -0
- data/test/has_and_belongs_to_many.rb +0 -0
- data/test/has_many_polymorphic_test.rb +0 -0
- data/test/has_many_test.rb +0 -0
- data/test/has_many_through_test.rb +33 -5
- data/test/test_helper.rb +0 -0
- metadata +39 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6f1f20fb282b67f60382f0d48c47f506623c3941e6d003b07b217eaa42291b9d
|
4
|
+
data.tar.gz: a4d5235b9373ad42c223eb439a611da125cc35ab7107ff6cf0b4c045bbd4f29e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dbffcaf8b56b8aaf0c4c6e18586e41fba2ece5a4373f5adb6f0d5e42aee574eaf8d2c1cfd60842fd07d8a633c14f597bc65a0ae78742fb8b03f75f5a8226a94b
|
7
|
+
data.tar.gz: 178fa0742ea16a40d0809d344cc42750a39157e24e2e4df40bb34148967d53b035248a093d4e82e890e219577fd618916fade84b56239d41da656623c63a3b3a
|
data/MIT-LICENSE
CHANGED
File without changes
|
data/Rakefile
CHANGED
data/lib/where_exists.rb
CHANGED
@@ -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
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
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
|
110
|
-
return
|
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
|
data/lib/where_exists/version.rb
CHANGED
File without changes
|
data/test/belongs_to_test.rb
CHANGED
File without changes
|
data/test/db/test.db
CHANGED
Binary file
|
data/test/documentation_test.rb
CHANGED
File without changes
|
File without changes
|
File without changes
|
data/test/has_many_test.rb
CHANGED
File without changes
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
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
|
-
|
74
|
-
|
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
|
-
|
83
|
-
|
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
|
data/test/test_helper.rb
CHANGED
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.
|
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-
|
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: '
|
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.
|
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/
|
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/
|
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
|