where_exists 3.0.0 → 3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 973c5c35ea3476b4178a7e2eb1f6ef93303d731922bf537e0d0d76e02a0f4372
4
- data.tar.gz: 6b30a099f143b8bfbcdcc4ff82b24f4a35c8c566d69c86a68b7b41e9342fd1bd
3
+ metadata.gz: d4749154c4976b45791c28a6e55d69016f57b09ccc47c0ada04d438d7851edf3
4
+ data.tar.gz: 67112fa90f4536950ebad7cad399dd2c5ad5cd6c9effc8758c21c22f637c3ccf
5
5
  SHA512:
6
- metadata.gz: a4386360276ae78d77f198690e06552a3c29ae08208749f580c4cfc78348b4c9dee005e8bb3f85fc182274926ef724b65daf605d9ba09159731aaf2ed2b8d353
7
- data.tar.gz: 9f47044c93ea46798c0bff7bad10ae3b1558eff50d23c1778c681169ad3979878ba52de97f138f0d1fa0dc639148d16acf9b1320bed128763e49472aa55afae9
6
+ metadata.gz: 8b57e52011f115272e0b13b0c24994ef0f3e7680082e57d3730712b73fd19e5ab36962e7a7b6d5b1a20b65bf316424d69da011cd0cf02b6576be6516fad09014
7
+ data.tar.gz: db7a5a208d5af8b72d6e49c84198ea1a8ceebeeea1a975aa295ec876b7d1c3d19ef547141c028d6f62b0673eb80dc1dff3f23a8961541d2a233a95719f093a98
@@ -1,3 +1,3 @@
1
1
  module WhereExists
2
- VERSION = "3.0.0"
2
+ VERSION = "3.2.0"
3
3
  end
data/lib/where_exists.rb CHANGED
@@ -105,12 +105,13 @@ module WhereExists
105
105
  next_association = {
106
106
  association: association.source_reflection,
107
107
  params: where_parameters,
108
- next_association: next_association
108
+ next_association: next_association,
109
+ scope: association.scope
109
110
  }
110
111
  association = association.through_reflection
111
112
 
112
113
  case association.macro
113
- when :has_many, :has_one
114
+ when :has_many, :has_one, :belongs_to
114
115
  return where_exists_for_has_many_query(association, {}, next_association, &block)
115
116
  when :has_and_belongs_to_many
116
117
  return where_exists_for_habtm_query(association, {}, next_association, &block)
@@ -125,13 +126,20 @@ module WhereExists
125
126
  end
126
127
  end
127
128
 
128
- association_scope = next_association[:scope] || association.scope
129
+ association_scope = association.scope
129
130
 
130
131
  associated_model = association.klass
131
- primary_key = association.options[:primary_key] || self.primary_key
132
+
133
+ if association.macro == :belongs_to
134
+ foreign_key = association.options[:primary_key] || self.primary_key
135
+ primary_key = association.foreign_key
136
+ else
137
+ primary_key = association.options[:primary_key] || self.primary_key
138
+ foreign_key = association.foreign_key
139
+ end
132
140
 
133
141
  self_ids = quote_table_and_column_name(self.table_name, primary_key)
134
- associated_ids = quote_table_and_column_name(associated_model.table_name, association.foreign_key)
142
+ associated_ids = quote_table_and_column_name(associated_model.table_name, foreign_key)
135
143
 
136
144
  result = associated_model.select("1").where("#{associated_ids} = #{self_ids}")
137
145
 
@@ -200,12 +208,18 @@ module WhereExists
200
208
  end
201
209
 
202
210
  def loop_nested_association(query, next_association = {}, nested = false, &block)
211
+ scope = next_association[:scope] || -> { self }
212
+ block ||= ->(it) { it }
213
+ block_with_scope =
214
+ lambda do |it|
215
+ block.call(it.instance_exec(&scope))
216
+ end
203
217
  str = query.klass.build_exists_string(
204
218
  next_association[:association].name,
205
219
  *[
206
220
  *next_association[:params]
207
- ],
208
- &block
221
+ ].compact,
222
+ &block_with_scope
209
223
  )
210
224
 
211
225
  if next_association[:next_association] && next_association[:next_association][:association]
@@ -215,7 +229,7 @@ module WhereExists
215
229
  next_association[:association],
216
230
  next_association[:next_association],
217
231
  true,
218
- &block
232
+ &block_with_scope
219
233
  )}))"
220
234
  end
221
235
  end
data/test/db/test.db ADDED
Binary file
@@ -0,0 +1,62 @@
1
+ require_relative 'test_helper'
2
+
3
+ ActiveRecord::Migration.create_table :houses, force: true do |t|
4
+ t.string :name
5
+ end
6
+
7
+ ActiveRecord::Migration.create_table :windows, force: true do |t|
8
+ t.string :name
9
+ t.integer :house_id
10
+ end
11
+
12
+ ActiveRecord::Migration.create_table :doors, force: true do |t|
13
+ t.string :name
14
+ t.integer :house_id
15
+ end
16
+
17
+ class House < ActiveRecord::Base
18
+ has_many :windows
19
+ has_many :doors
20
+ end
21
+
22
+ class Window < ActiveRecord::Base
23
+ belongs_to :house
24
+ has_many :doors, through: :house
25
+ end
26
+
27
+ class Door < ActiveRecord::Base
28
+ belongs_to :house
29
+ end
30
+
31
+ class HasManyThroughBelongsToTest < Minitest::Test
32
+ def setup
33
+ ActiveRecord::Base.descendants.each(&:delete_all)
34
+ end
35
+
36
+ def test_through_belongs_to
37
+ house = House.create! name: 'relevant'
38
+ irrelevant_house = House.create! name: 'irrelevant'
39
+
40
+ window = Window.create!(house: house)
41
+ irrelevant_window = Window.create!(house: irrelevant_house)
42
+
43
+ door = Door.create!(name: 'relevant', house: house)
44
+ irrelevant_door = Door.create!(name: 'irrelevant', house: irrelevant_house)
45
+
46
+ result = House.where_exists(:doors, name: 'relevant')
47
+ assert_equal 1, result.length
48
+ assert_equal house.id, result.first.id
49
+
50
+ result = House.where_not_exists(:doors, name: 'relevant')
51
+ assert_equal 1, result.length
52
+ assert_equal irrelevant_house.id, result.first.id
53
+
54
+ result = House.where_not_exists(:doors, "name = ?", 'relevant')
55
+ assert_equal 1, result.length
56
+ assert_equal irrelevant_house.id, result.first.id
57
+
58
+ result = Window.where_exists(:doors, name: 'relevant')
59
+ assert_equal 1, result.length
60
+ assert_equal window.id, result.first.id
61
+ end
62
+ end
@@ -0,0 +1,41 @@
1
+ require 'test_helper'
2
+
3
+ ActiveRecord::Migration.create_table :posts, :force => true do |t|
4
+ t.boolean :archived, default: false, null: false
5
+ end
6
+
7
+ ActiveRecord::Migration.create_table :comments, :force => true do |t|
8
+ t.integer :post_id
9
+ t.integer :commentator_id
10
+ end
11
+
12
+ ActiveRecord::Migration.create_table :commentators, :force => true do |t|
13
+ end
14
+
15
+ class Post < ActiveRecord::Base
16
+ has_many :comments
17
+ end
18
+
19
+ class Comment < ActiveRecord::Base
20
+ belongs_to :post
21
+ belongs_to :commentator
22
+ end
23
+
24
+ class Commentator < ActiveRecord::Base
25
+ has_many :comments
26
+ has_many :posts, -> { where(archived: false) }, through: :comments
27
+ end
28
+
29
+ class HasManyThroughConditionsTest < Minitest::Test
30
+ def test_where_exists
31
+ post = Post.create!
32
+ archived_post = Post.create! archived: true
33
+
34
+ commentator = Commentator.create! posts: [post]
35
+ commentator2 = Commentator.create! posts: [archived_post]
36
+ commentator3 = Commentator.create!
37
+
38
+ assert_equal [commentator], Commentator.where_exists(:posts).to_a # fail: also includes commentator2
39
+ assert_equal [commentator2, commentator3], Commentator.where_not_exists(:posts).to_a # fail: does not include commentator2
40
+ end
41
+ end
data/test/test_helper.rb CHANGED
@@ -13,8 +13,5 @@ else
13
13
  end
14
14
 
15
15
  ActiveRecord::Base.time_zone_aware_attributes = true
16
-
17
- ActiveRecord::Base.establish_connection(
18
- :adapter => 'sqlite3',
19
- :database => File.dirname(__FILE__) + '/db/test.db'
20
- )
16
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
17
+ ActiveRecord::Base.logger = Logger.new(STDOUT)
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: 3.0.0
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eugene Zolotarev
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-11-11 00:00:00.000000000 Z
11
+ date: 2025-09-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -114,17 +114,20 @@ files:
114
114
  - lib/where_exists/version.rb
115
115
  - test/belongs_to_polymorphic_test.rb
116
116
  - test/belongs_to_test.rb
117
+ - test/db/test.db
117
118
  - test/documentation_test.rb
118
119
  - test/has_and_belongs_to_many.rb
119
120
  - test/has_many_polymorphic_test.rb
120
121
  - test/has_many_test.rb
122
+ - test/has_many_through_belongs_to_test.rb
123
+ - test/has_many_through_conditions_test.rb
121
124
  - test/has_many_through_test.rb
122
125
  - test/test_helper.rb
123
126
  homepage: http://github.com/eugzol/where_exists
124
127
  licenses:
125
128
  - MIT
126
129
  metadata: {}
127
- post_install_message:
130
+ post_install_message:
128
131
  rdoc_options: []
129
132
  require_paths:
130
133
  - lib
@@ -139,16 +142,19 @@ required_rubygems_version: !ruby/object:Gem::Requirement
139
142
  - !ruby/object:Gem::Version
140
143
  version: '0'
141
144
  requirements: []
142
- rubygems_version: 3.5.20
143
- signing_key:
145
+ rubygems_version: 3.1.6
146
+ signing_key:
144
147
  specification_version: 4
145
148
  summary: "#where_exists extension of ActiveRecord"
146
149
  test_files:
150
+ - test/documentation_test.rb
151
+ - test/has_many_through_conditions_test.rb
147
152
  - test/belongs_to_polymorphic_test.rb
148
153
  - test/belongs_to_test.rb
149
- - test/documentation_test.rb
150
- - test/has_and_belongs_to_many.rb
151
154
  - test/has_many_polymorphic_test.rb
152
- - test/has_many_test.rb
155
+ - test/db/test.db
153
156
  - test/has_many_through_test.rb
154
157
  - test/test_helper.rb
158
+ - test/has_many_through_belongs_to_test.rb
159
+ - test/has_and_belongs_to_many.rb
160
+ - test/has_many_test.rb