where_exists 1.1.0 → 1.1.1
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/where_exists.rb +54 -12
- data/lib/where_exists/version.rb +1 -1
- data/test/db/test.db +0 -0
- data/test/has_and_belongs_to_many.rb +92 -0
- data/test/has_many_through_test.rb +5 -0
- 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: '09bda87b615e0962be005bda294cc0227e1d76ce'
|
4
|
+
data.tar.gz: 4cb809c77b97dfaad246f1a90be28e75cc2bb5a2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b4ca719701af78dfc661a35cb815adf49d1206072f0fa3db2af6a411677f7394ad19547706f0f14265462955231847922821732caa9c64ca4e22186cefeb1127
|
7
|
+
data.tar.gz: 6e147f5238c544d0691cfb982d38cc560b5baf6a97d82f5529b94cafed6683c9e1a0b7706b6d967e2cc0913b905906c0d3192d64e064407f60774cd6c309f94c
|
data/lib/where_exists.rb
CHANGED
@@ -23,8 +23,16 @@ module WhereExists
|
|
23
23
|
queries = where_exists_for_belongs_to_query(association, where_parameters)
|
24
24
|
when :has_many, :has_one
|
25
25
|
queries = where_exists_for_has_many_query(association, where_parameters)
|
26
|
+
when :has_and_belongs_to_many
|
27
|
+
queries = where_exists_for_habtm_query(association, where_parameters)
|
26
28
|
else
|
27
|
-
|
29
|
+
inspection = nil
|
30
|
+
begin
|
31
|
+
inspection = association.macros.inspect
|
32
|
+
rescue
|
33
|
+
inspection = association.macro
|
34
|
+
end
|
35
|
+
raise ArgumentError.new("where_exists: not supported association – #{inspection}")
|
28
36
|
end
|
29
37
|
|
30
38
|
if does_exist
|
@@ -33,7 +41,7 @@ module WhereExists
|
|
33
41
|
not_string = "NOT "
|
34
42
|
end
|
35
43
|
|
36
|
-
queries_sql = queries.map{|query| "EXISTS (" + query.to_sql + ")"}.join(" OR ")
|
44
|
+
queries_sql = queries.map { |query| "EXISTS (" + query.to_sql + ")" }.join(" OR ")
|
37
45
|
|
38
46
|
self.where("#{not_string}(#{queries_sql})")
|
39
47
|
end
|
@@ -62,7 +70,7 @@ module WhereExists
|
|
62
70
|
query = query.where(*where_parameters)
|
63
71
|
end
|
64
72
|
if association_scope
|
65
|
-
|
73
|
+
query = query.instance_exec(&association_scope)
|
66
74
|
end
|
67
75
|
if polymorphic
|
68
76
|
other_type = connection.quote(associated_model.name)
|
@@ -92,10 +100,6 @@ module WhereExists
|
|
92
100
|
|
93
101
|
result = associated_model.select("1").where("#{associated_ids} = #{self_ids}")
|
94
102
|
|
95
|
-
if association_scope
|
96
|
-
result = result.instance_exec(&association_scope)
|
97
|
-
end
|
98
|
-
|
99
103
|
if association.options[:as]
|
100
104
|
other_types = quote_table_and_column_name(associated_model.table_name, association.type)
|
101
105
|
self_class = connection.quote(self.name)
|
@@ -103,11 +107,49 @@ module WhereExists
|
|
103
107
|
end
|
104
108
|
|
105
109
|
if through
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
110
|
+
return [result.where_exists(next_association.name, *where_parameters)]
|
111
|
+
end
|
112
|
+
|
113
|
+
if where_parameters != []
|
114
|
+
result = result.where(*where_parameters)
|
115
|
+
end
|
116
|
+
if association_scope
|
117
|
+
result = result.instance_exec(&association_scope)
|
118
|
+
end
|
119
|
+
|
120
|
+
[result]
|
121
|
+
end
|
122
|
+
|
123
|
+
def where_exists_for_habtm_query(association, where_parameters)
|
124
|
+
association_scope = association.scope
|
125
|
+
|
126
|
+
associated_model = association.klass
|
127
|
+
|
128
|
+
primary_key = association.options[:primary_key] || self.primary_key
|
129
|
+
|
130
|
+
join_table = [self.table_name, associated_model.table_name].sort.join("_")
|
131
|
+
|
132
|
+
self_ids = quote_table_and_column_name(self.table_name, primary_key)
|
133
|
+
join_ids = quote_table_and_column_name(join_table, association.foreign_key)
|
134
|
+
associated_join_ids = quote_table_and_column_name(join_table, "#{associated_model.name.downcase}_id")
|
135
|
+
associated_ids = quote_table_and_column_name(associated_model.table_name, associated_model.primary_key)
|
136
|
+
|
137
|
+
result =
|
138
|
+
associated_model.
|
139
|
+
select("1").
|
140
|
+
joins(
|
141
|
+
<<-SQL
|
142
|
+
INNER JOIN #{connection.quote_table_name(join_table)}
|
143
|
+
ON #{associated_ids} = #{associated_join_ids}
|
144
|
+
SQL
|
145
|
+
).
|
146
|
+
where("#{join_ids} = #{self_ids}")
|
147
|
+
|
148
|
+
if where_parameters != []
|
149
|
+
result = result.where(*where_parameters)
|
150
|
+
end
|
151
|
+
if association_scope
|
152
|
+
result = result.instance_exec(&association_scope)
|
111
153
|
end
|
112
154
|
|
113
155
|
[result]
|
data/lib/where_exists/version.rb
CHANGED
data/test/db/test.db
CHANGED
Binary file
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
ActiveRecord::Migration.create_table :tasks, :force => true do |t|
|
4
|
+
t.string :name
|
5
|
+
end
|
6
|
+
|
7
|
+
ActiveRecord::Migration.create_table :invoices_tasks, :force => true do |t|
|
8
|
+
t.integer :invoice_id
|
9
|
+
t.integer :task_id
|
10
|
+
end
|
11
|
+
|
12
|
+
ActiveRecord::Migration.create_table :invoices, :force => true do |t|
|
13
|
+
t.string :name
|
14
|
+
end
|
15
|
+
|
16
|
+
class Task < ActiveRecord::Base
|
17
|
+
has_and_belongs_to_many :connected_invoices, class_name: 'Invoice'
|
18
|
+
end
|
19
|
+
|
20
|
+
class Invoice < ActiveRecord::Base
|
21
|
+
has_and_belongs_to_many :tasks
|
22
|
+
has_and_belongs_to_many :unnamed_tasks, -> { where(name: nil) }
|
23
|
+
end
|
24
|
+
|
25
|
+
# Invoices -> LineItems <- Tasks <- Project
|
26
|
+
|
27
|
+
class HasAndBelongsToManyTest < Minitest::Test
|
28
|
+
def setup
|
29
|
+
ActiveRecord::Base.descendants.each(&:delete_all)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_with_standard_naming
|
33
|
+
task = Task.create!(name: 'task')
|
34
|
+
irrelevant_task = Task.create!(name: 'task_2')
|
35
|
+
invoice = Invoice.create!(name: 'invoice')
|
36
|
+
invoice_no_join = Invoice.create!(name: 'invoice_2')
|
37
|
+
|
38
|
+
invoice.tasks << task
|
39
|
+
|
40
|
+
|
41
|
+
result = Invoice.where_exists(:tasks, name: 'task')
|
42
|
+
|
43
|
+
assert_equal 1, result.length
|
44
|
+
assert_equal invoice.id, result.first.id
|
45
|
+
|
46
|
+
result = Invoice.where_exists(:tasks, name: 'task_2')
|
47
|
+
|
48
|
+
assert_equal 0, result.length
|
49
|
+
|
50
|
+
result = Invoice.where_not_exists(:tasks)
|
51
|
+
assert_equal 1, result.length
|
52
|
+
assert_equal invoice_no_join.id, result.first.id
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_with_custom_naming
|
56
|
+
task = Task.create!(name: 'task')
|
57
|
+
task_no_join = Task.create!(name: 'invoice')
|
58
|
+
invoice = Invoice.create!(name: 'invoice')
|
59
|
+
irrelevant_invoice = Invoice.create!(name: 'invoice_2')
|
60
|
+
|
61
|
+
task.connected_invoices << invoice
|
62
|
+
|
63
|
+
result = Task.where_exists(:connected_invoices, name: 'invoice')
|
64
|
+
|
65
|
+
assert_equal 1, result.length
|
66
|
+
assert_equal task.id, result.first.id
|
67
|
+
|
68
|
+
result = Task.where_exists(:connected_invoices, name: 'invoice_2')
|
69
|
+
|
70
|
+
assert_equal 0, result.length
|
71
|
+
|
72
|
+
result = Task.where_not_exists(:connected_invoices)
|
73
|
+
assert_equal 1, result.length
|
74
|
+
assert_equal task_no_join.id, result.first.id
|
75
|
+
|
76
|
+
result = Task.where_not_exists(:connected_invoices, name: 'invoice_2')
|
77
|
+
assert_equal 2, result.length
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_with_condition
|
81
|
+
task_1 = Task.create! name: nil
|
82
|
+
task_2 = Task.create! name: 'task 2'
|
83
|
+
|
84
|
+
invoice_1 = Invoice.create!(tasks: [task_1])
|
85
|
+
invoice_2 = Invoice.create!(tasks: [task_1, task_2])
|
86
|
+
invoice_3 = Invoice.create!(tasks: [task_2)
|
87
|
+
|
88
|
+
result_ids = Invoice.where_exists(:unnamed_tasks).pluck(:id)
|
89
|
+
|
90
|
+
assert_equal [invoice_1.id, invoice_2.id].sort, result_ids.sort
|
91
|
+
end
|
92
|
+
end
|
@@ -91,5 +91,10 @@ class HasManyThroughTest < Minitest::Test
|
|
91
91
|
|
92
92
|
assert_equal 1, result.length
|
93
93
|
assert_equal irrelevant_project.id, result.first.id
|
94
|
+
|
95
|
+
result = Project.where_not_exists(:invoices, "name = ?", 'relevant')
|
96
|
+
|
97
|
+
assert_equal 1, result.length
|
98
|
+
assert_equal irrelevant_project.id, result.first.id
|
94
99
|
end
|
95
100
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
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.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eugene Zolotarev
|
@@ -73,6 +73,7 @@ files:
|
|
73
73
|
- test/belongs_to_test.rb
|
74
74
|
- test/db/test.db
|
75
75
|
- test/documentation_test.rb
|
76
|
+
- test/has_and_belongs_to_many.rb
|
76
77
|
- test/has_many_polymorphic_test.rb
|
77
78
|
- test/has_many_test.rb
|
78
79
|
- test/has_many_through_test.rb
|
@@ -107,6 +108,7 @@ test_files:
|
|
107
108
|
- test/documentation_test.rb
|
108
109
|
- test/test_helper.rb
|
109
110
|
- test/has_many_polymorphic_test.rb
|
111
|
+
- test/has_and_belongs_to_many.rb
|
110
112
|
- test/belongs_to_polymorphic_test.rb
|
111
113
|
- test/has_many_test.rb
|
112
114
|
- test/has_many_through_test.rb
|