where_exists 1.1.5 → 1.2.0
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/lib/where_exists.rb +18 -14
- data/lib/where_exists/version.rb +1 -1
- data/test/belongs_to_polymorphic_test.rb +17 -0
- data/test/db/test.db +0 -0
- data/test/has_many_polymorphic_test.rb +9 -2
- data/test/has_many_through_test.rb +72 -7
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8fe61ef5f7b676e2d9b3704b34f8101e7e84157060f2b11d56db8e99027765a9
|
4
|
+
data.tar.gz: e8de623c18fe2df6c50c809b6bf0b551eb66bf7ae2a36e0ca65cc18a44470b79
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9f4b7fe34573309d53e2e81255782a2d4f3dbfa190c9e975d5cc9eb6750f0b118d448401002786862932ed1fcda19cda6ee3387d5a7a036b7594d841872c907e
|
7
|
+
data.tar.gz: 389a33011c215ad3373388d20f5b49f186b80458dc18afee829c9ddf370d84b517e8ad16df300e041198b192f2884f9a4217cd6677179f7999591f5d74580f16
|
data/lib/where_exists.rb
CHANGED
@@ -61,7 +61,9 @@ module WhereExists
|
|
61
61
|
association_scope = association.scope
|
62
62
|
|
63
63
|
if polymorphic
|
64
|
-
associated_models = self.select("DISTINCT #{connection.quote_column_name(association.foreign_type)}").
|
64
|
+
associated_models = self.select("DISTINCT #{connection.quote_column_name(association.foreign_type)}").
|
65
|
+
where("#{connection.quote_column_name(association.foreign_type)} IS NOT NULL").pluck(association.foreign_type).
|
66
|
+
uniq.map(&:classify).map(&:constantize)
|
65
67
|
else
|
66
68
|
associated_models = [association.klass]
|
67
69
|
end
|
@@ -82,8 +84,10 @@ module WhereExists
|
|
82
84
|
query = query.instance_exec(&association_scope)
|
83
85
|
end
|
84
86
|
if polymorphic
|
85
|
-
|
86
|
-
|
87
|
+
other_types = [associated_model.name, associated_model.table_name]
|
88
|
+
other_types << associated_model.polymorphic_name if associated_model.respond_to?(:polymorphic_name)
|
89
|
+
|
90
|
+
query = query.where("#{self_type} IN (?)", other_types.uniq)
|
87
91
|
end
|
88
92
|
queries.push query
|
89
93
|
end
|
@@ -129,8 +133,14 @@ module WhereExists
|
|
129
133
|
|
130
134
|
if association.options[:as]
|
131
135
|
other_types = quote_table_and_column_name(associated_model.table_name, association.type)
|
132
|
-
|
133
|
-
|
136
|
+
class_values = [self.name, self.table_name]
|
137
|
+
class_values << self.polymorphic_name if associated_model.respond_to?(:polymorphic_name)
|
138
|
+
|
139
|
+
result = result.where("#{other_types} IN (?)", class_values.uniq)
|
140
|
+
end
|
141
|
+
|
142
|
+
if association_scope
|
143
|
+
result = result.instance_exec(&association_scope)
|
134
144
|
end
|
135
145
|
|
136
146
|
if next_association[:association]
|
@@ -141,10 +151,6 @@ module WhereExists
|
|
141
151
|
result = result.where(*where_parameters)
|
142
152
|
end
|
143
153
|
|
144
|
-
if association_scope
|
145
|
-
result = result.instance_exec(&association_scope)
|
146
|
-
end
|
147
|
-
|
148
154
|
[result]
|
149
155
|
end
|
150
156
|
|
@@ -155,11 +161,9 @@ module WhereExists
|
|
155
161
|
|
156
162
|
primary_key = association.options[:primary_key] || self.primary_key
|
157
163
|
|
158
|
-
join_table = [self.table_name, associated_model.table_name].sort.join("_")
|
159
|
-
|
160
164
|
self_ids = quote_table_and_column_name(self.table_name, primary_key)
|
161
|
-
join_ids = quote_table_and_column_name(join_table, association.foreign_key)
|
162
|
-
associated_join_ids = quote_table_and_column_name(join_table,
|
165
|
+
join_ids = quote_table_and_column_name(association.join_table, association.foreign_key)
|
166
|
+
associated_join_ids = quote_table_and_column_name(association.join_table, association.association_foreign_key)
|
163
167
|
associated_ids = quote_table_and_column_name(associated_model.table_name, associated_model.primary_key)
|
164
168
|
|
165
169
|
result =
|
@@ -167,7 +171,7 @@ module WhereExists
|
|
167
171
|
select("1").
|
168
172
|
joins(
|
169
173
|
<<-SQL
|
170
|
-
INNER JOIN #{connection.quote_table_name(join_table)}
|
174
|
+
INNER JOIN #{connection.quote_table_name(association.join_table)}
|
171
175
|
ON #{associated_ids} = #{associated_join_ids}
|
172
176
|
SQL
|
173
177
|
).
|
data/lib/where_exists/version.rb
CHANGED
@@ -60,4 +60,21 @@ class BelongsToPolymorphicTest < Minitest::Test
|
|
60
60
|
assert_equal 1, result.length
|
61
61
|
assert_equal orphaned_child.id, result.first.id
|
62
62
|
end
|
63
|
+
|
64
|
+
def test_table_name_based_lookup
|
65
|
+
first_entity = FirstPolymorphicEntity.create!
|
66
|
+
second_entity = SecondPolymorphicEntity.create! id: first_entity.id + 1
|
67
|
+
|
68
|
+
first_child = BelongsToPolymorphicChild.create!(polymorphic_entity_id: first_entity.id, polymorphic_entity_type: first_entity.class.table_name)
|
69
|
+
second_child = BelongsToPolymorphicChild.create!(polymorphic_entity_id: second_entity.id, polymorphic_entity_type: second_entity.class.table_name)
|
70
|
+
orphaned_child = BelongsToPolymorphicChild.create!(polymorphic_entity_id: second_entity.id, polymorphic_entity_type: first_entity.class.table_name)
|
71
|
+
|
72
|
+
result = BelongsToPolymorphicChild.where_exists(:polymorphic_entity)
|
73
|
+
assert_equal 2, result.length
|
74
|
+
assert_equal [first_child, second_child].map(&:id).sort, result.map(&:id).sort
|
75
|
+
|
76
|
+
result = BelongsToPolymorphicChild.where_not_exists(:polymorphic_entity)
|
77
|
+
assert_equal 1, result.length
|
78
|
+
assert_equal [orphaned_child].map(&:id).sort, result.map(&:id).sort
|
79
|
+
end
|
63
80
|
end
|
data/test/db/test.db
CHANGED
Binary file
|
@@ -35,10 +35,17 @@ class HasManyPolymorphicTest < Minitest::Test
|
|
35
35
|
child = HasManyPolymorphicChild.create!
|
36
36
|
|
37
37
|
irrelevant_entity = IrrelevantPolymorphicEntity.create!(children: [child])
|
38
|
-
|
38
|
+
relevant_entity = RelevantPolymorphicEntity.create!(id: irrelevant_entity.id)
|
39
|
+
|
40
|
+
assert_equal 0, RelevantPolymorphicEntity.where_exists(:children).length
|
41
|
+
assert_equal 1, IrrelevantPolymorphicEntity.where_exists(:children).length
|
42
|
+
|
43
|
+
child.update!(polymorphic_thing_type: RelevantPolymorphicEntity.table_name)
|
39
44
|
|
40
45
|
result = RelevantPolymorphicEntity.where_exists(:children)
|
41
46
|
|
42
|
-
assert_equal 0,
|
47
|
+
assert_equal 0, IrrelevantPolymorphicEntity.where_exists(:children).length
|
48
|
+
assert_equal 1, result.length
|
49
|
+
assert_equal relevant_entity.id, result.first&.id
|
43
50
|
end
|
44
51
|
end
|
@@ -1,34 +1,71 @@
|
|
1
1
|
require_relative 'test_helper'
|
2
2
|
|
3
|
-
ActiveRecord::Migration.create_table :projects, :
|
3
|
+
ActiveRecord::Migration.create_table :projects, force: true do |t|
|
4
4
|
t.string :name
|
5
5
|
end
|
6
6
|
|
7
|
-
ActiveRecord::Migration.create_table :tasks, :
|
7
|
+
ActiveRecord::Migration.create_table :tasks, force: true do |t|
|
8
8
|
t.string :name
|
9
9
|
t.integer :project_id
|
10
10
|
end
|
11
11
|
|
12
|
-
ActiveRecord::Migration.create_table :line_items, :
|
12
|
+
ActiveRecord::Migration.create_table :line_items, force: true do |t|
|
13
13
|
t.string :name
|
14
14
|
t.integer :invoice_id
|
15
15
|
t.integer :task_id
|
16
16
|
end
|
17
17
|
|
18
|
-
ActiveRecord::Migration.create_table :work_details, :
|
18
|
+
ActiveRecord::Migration.create_table :work_details, force: true do |t|
|
19
19
|
t.string :name
|
20
20
|
t.integer :line_item_id
|
21
21
|
end
|
22
22
|
|
23
|
-
ActiveRecord::Migration.create_table :invoices, :
|
23
|
+
ActiveRecord::Migration.create_table :invoices, force: true do |t|
|
24
24
|
t.string :name
|
25
25
|
end
|
26
26
|
|
27
|
+
ActiveRecord::Migration.create_table :blobs, force: true do |t|
|
28
|
+
end
|
29
|
+
|
30
|
+
ActiveRecord::Migration.create_table :attachments, force: true do |t|
|
31
|
+
t.string :name, null: false
|
32
|
+
t.references :record, null: false, polymorphic: true, index: false
|
33
|
+
t.references :blob, null: false
|
34
|
+
|
35
|
+
t.datetime :created_at, null: false
|
36
|
+
|
37
|
+
t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_attachments_uniqueness", unique: true
|
38
|
+
end
|
39
|
+
|
40
|
+
class Attachment < ActiveRecord::Base
|
41
|
+
belongs_to :record, polymorphic: true, touch: true
|
42
|
+
belongs_to :blob
|
43
|
+
end
|
44
|
+
|
45
|
+
class Blob < ActiveRecord::Base
|
46
|
+
has_many :attachments
|
47
|
+
|
48
|
+
scope :unattached, -> { left_joins(:attachments).where(Attachment.table_name => { blob_id: nil }) }
|
49
|
+
|
50
|
+
before_destroy(prepend: true) do
|
51
|
+
raise ActiveRecord::InvalidForeignKey if attachments.exists?
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
|
27
57
|
class Project < ActiveRecord::Base
|
28
58
|
has_many :tasks
|
29
59
|
has_many :invoices, :through => :tasks
|
30
60
|
has_many :project_line_items, :through => :tasks, :source => :line_items
|
31
61
|
has_many :work_details, :through => :project_line_items
|
62
|
+
|
63
|
+
has_many :attachments, as: :record
|
64
|
+
has_many :blobs, through: :attachments, source: :blob
|
65
|
+
has_many :relevant_attachments, -> { where(name: "relevant") }, as: :record, class_name: "Attachment", inverse_of: :record, dependent: false
|
66
|
+
has_many :relevant_blobs, through: :relevant_attachments, class_name: "Blob", source: :blob
|
67
|
+
has_many :irrelevant_attachments, -> { where(name: "irrelevant") }, as: :record, class_name: "Attachment", inverse_of: :record, dependent: false
|
68
|
+
has_many :irrelevant_blobs, through: :irrelevant_attachments, class_name: "Blob", source: :blob
|
32
69
|
end
|
33
70
|
|
34
71
|
class Task < ActiveRecord::Base
|
@@ -36,6 +73,7 @@ class Task < ActiveRecord::Base
|
|
36
73
|
|
37
74
|
has_many :invoices, :through => :line_items
|
38
75
|
has_many :line_items
|
76
|
+
has_many :scoped_line_items, -> { where(name: 'relevant') }, class_name: 'LineItem'
|
39
77
|
end
|
40
78
|
|
41
79
|
class LineItem < ActiveRecord::Base
|
@@ -94,12 +132,16 @@ class HasManyThroughTest < Minitest::Test
|
|
94
132
|
invoice = Invoice.create!(name: 'relevant')
|
95
133
|
irrelevant_invoice = Invoice.create!(name: 'irrelevant')
|
96
134
|
|
97
|
-
line_item = LineItem.create!(task: task, invoice: invoice)
|
98
|
-
irrelevant_line_item = LineItem.create!(task: irrelevant_task, invoice: irrelevant_invoice)
|
135
|
+
line_item = LineItem.create!(name: 'relevant', task: task, invoice: invoice)
|
136
|
+
irrelevant_line_item = LineItem.create!(name: 'relevant', task: irrelevant_task, invoice: irrelevant_invoice)
|
99
137
|
|
100
138
|
_work_detail = WorkDetail.create!(line_item: line_item, name: 'relevant')
|
101
139
|
_irrelevant_work_detail = WorkDetail.create!(line_item: irrelevant_line_item, name: 'irrelevant')
|
102
140
|
|
141
|
+
blob = Blob.create!()
|
142
|
+
_relevant_attachment = Attachment.create!(name: 'relevant', blob: blob, record: project)
|
143
|
+
_irrelevant_attachment = Attachment.create!(name: 'irrelevant', blob: blob, record: irrelevant_project)
|
144
|
+
|
103
145
|
result = Project.where_exists(:invoices, name: 'relevant')
|
104
146
|
|
105
147
|
assert_equal 1, result.length
|
@@ -124,5 +166,28 @@ class HasManyThroughTest < Minitest::Test
|
|
124
166
|
|
125
167
|
assert_equal 1, result.length
|
126
168
|
assert_equal irrelevant_project.id, result.first.id
|
169
|
+
|
170
|
+
result = Task.where_exists(:scoped_line_items)
|
171
|
+
|
172
|
+
assert_equal 2, result.length
|
173
|
+
|
174
|
+
result = Project.where_exists(:relevant_blobs)
|
175
|
+
|
176
|
+
assert_equal 1, result.length
|
177
|
+
assert_equal project.id, result.first.id
|
178
|
+
|
179
|
+
result = Project.where_not_exists(:relevant_blobs)
|
180
|
+
|
181
|
+
assert_equal 1, result.length
|
182
|
+
assert_equal irrelevant_project.id, result.first.id
|
183
|
+
|
184
|
+
result = Project.where_exists(:blobs)
|
185
|
+
|
186
|
+
assert_equal 2, result.length
|
187
|
+
|
188
|
+
result = Project.where_not_exists(:blobs)
|
189
|
+
|
190
|
+
assert_equal 0, result.length
|
191
|
+
|
127
192
|
end
|
128
193
|
end
|
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.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eugene Zolotarev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-07-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -125,8 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
125
125
|
- !ruby/object:Gem::Version
|
126
126
|
version: '0'
|
127
127
|
requirements: []
|
128
|
-
|
129
|
-
rubygems_version: 2.6.11
|
128
|
+
rubygems_version: 3.0.2
|
130
129
|
signing_key:
|
131
130
|
specification_version: 4
|
132
131
|
summary: "#where_exists extension of ActiveRecord"
|