activerecord_where_assoc 1.1.5 → 1.2.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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ad309caebf6c729645f97a3c76959f0e61557b956fe86fe13dac641af06f87d4
|
4
|
+
data.tar.gz: 7f4967c6493d13550f31036753a50606f7e82f9fed1d5277b06db899517e89ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0efde09f38bd4c4913ac3b4cb36d114cb654c0c35bd05c07eb31559801d9febb87b479d9ae41b6bc07d9d77ddef775fd3b1e307ea20a3a10ccf2b829f03f27f1
|
7
|
+
data.tar.gz: ef3d2dbfef7f58f0221cdf5c32448410a1886fd1b8532bbe2d4a8643d5bde2dad5c2029eeddf5cb1b6620ab199b6ec2e3bd313ddd505d648a90d2d2f619b2747
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 1.2.1 - 2024-12-05
|
4
|
+
|
5
|
+
* Optimize `has_one` handling for `#where_assoc_exists` with a `has_one` as last association + without any conditions or offset.
|
6
|
+
* Optimize `has_one` handling when the foreign_key has a unique index and there is no offset
|
7
|
+
|
8
|
+
# 1.2.0 - 2024-08-31
|
9
|
+
|
10
|
+
* Add support for composite primary keys in Rails 7.2
|
11
|
+
|
3
12
|
# 1.1.5 - 2024-05-18
|
4
13
|
|
5
14
|
* Add compatibility for Rails 7.2
|
@@ -22,12 +31,12 @@
|
|
22
31
|
|
23
32
|
# 1.1.0 - 2020-02-24
|
24
33
|
|
25
|
-
* Added methods which return the SQL used by this gem: `assoc_exists_sql`, `assoc_not_exists_sql`, `compare_assoc_count_sql`, `only_assoc_count_sql`
|
34
|
+
* Added methods which return the SQL used by this gem: `assoc_exists_sql`, `assoc_not_exists_sql`, `compare_assoc_count_sql`, `only_assoc_count_sql`
|
26
35
|
[Documentation for them](https://maxlap.github.io/activerecord_where_assoc/ActiveRecordWhereAssoc/SqlReturningMethods.html)
|
27
36
|
|
28
37
|
# 1.0.1
|
29
38
|
|
30
|
-
* Fix broken urls in error messages
|
39
|
+
* Fix broken urls in error messages
|
31
40
|
|
32
41
|
# 1.0.0
|
33
42
|
|
@@ -35,16 +44,16 @@
|
|
35
44
|
|
36
45
|
# 0.1.3
|
37
46
|
|
38
|
-
* Use `SELECT 1` instead of `SELECT 0`...
|
47
|
+
* Use `SELECT 1` instead of `SELECT 0`...
|
39
48
|
... it just seems more natural that way.
|
40
49
|
* Bugfixes
|
41
50
|
|
42
51
|
# 0.1.2
|
43
52
|
|
44
|
-
* It is now possible to pass a `Range` as first argument to `#where_assoc_count`.
|
53
|
+
* It is now possible to pass a `Range` as first argument to `#where_assoc_count`.
|
45
54
|
Ex: Users that have between 10 and 20 posts
|
46
55
|
`User.where_assoc_count(10..20, :==, :posts)`
|
47
|
-
The operator in that case must be either :== or :!=.
|
48
|
-
This will use `BETWEEN` and `NOT BETWEEN`.
|
56
|
+
The operator in that case must be either :== or :!=.
|
57
|
+
This will use `BETWEEN` and `NOT BETWEEN`.
|
49
58
|
Ranges that exclude the last value, i.e. `5...10`, are also supported, resulting in `BETWEEN 5 and 9`.
|
50
59
|
Ranges with infinities are also supported.
|
@@ -101,5 +101,28 @@ module ActiveRecordWhereAssoc
|
|
101
101
|
reflection.is_a?(ActiveRecord::NullRelation)
|
102
102
|
end
|
103
103
|
end
|
104
|
+
|
105
|
+
if ActiveRecord.gem_version >= Gem::Version.new("6.0")
|
106
|
+
def self.indexes(model)
|
107
|
+
model.connection.schema_cache.indexes(model.table_name)
|
108
|
+
end
|
109
|
+
else
|
110
|
+
def self.indexes(model)
|
111
|
+
model.connection.indexes(model.table_name)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
@unique_indexes_cache = {}
|
116
|
+
def self.has_unique_index?(model, column_names)
|
117
|
+
column_names = Array(column_names).map(&:to_s)
|
118
|
+
@unique_indexes_cache.fetch([model, column_names]) do |k|
|
119
|
+
unique_indexes = indexes(model).select(&:unique)
|
120
|
+
columns_names_set = Set.new(column_names)
|
121
|
+
|
122
|
+
# We check for an index whose columns are a subset of the columns we specify
|
123
|
+
# This way, a composite column_names will find uniqueness if just a single of the column is unique
|
124
|
+
@unique_indexes_cache[k] = unique_indexes.any? { |ui| Set.new(ui.columns) <= columns_names_set }
|
125
|
+
end
|
126
|
+
end
|
104
127
|
end
|
105
128
|
end
|
@@ -155,9 +155,17 @@ module ActiveRecordWhereAssoc
|
|
155
155
|
|
156
156
|
init_scopes = initial_scopes_from_reflection(record_class, reflection_chain[i..-1], constraints_chain[i], options)
|
157
157
|
current_scopes = init_scopes.map do |alias_scope, current_scope, klass_scope|
|
158
|
-
current_scope = process_association_step_limits(current_scope, reflection, record_class, options)
|
159
|
-
|
160
158
|
if i.zero?
|
159
|
+
if given_conditions || klass_scope || last_assoc_block || current_scope.offset_value || nest_assocs_block == NestWithSumBlock
|
160
|
+
# In the deepest layer, the limit & offset complexities only matter when:
|
161
|
+
# * There is a condition to apply
|
162
|
+
# * There is an offset (which is a form of filtering)
|
163
|
+
# * We are counting the total matches
|
164
|
+
# Since last_assoc_block is always set except for the deepest association, and is only unset for the deepest layer if
|
165
|
+
# there is no condition given, using it as part of the condition does a lot of work here.
|
166
|
+
current_scope = process_association_step_limits(current_scope, reflection, record_class, options)
|
167
|
+
end
|
168
|
+
|
161
169
|
current_scope = current_scope.where(given_conditions) if given_conditions
|
162
170
|
if klass_scope
|
163
171
|
if klass_scope.respond_to?(:call)
|
@@ -167,6 +175,8 @@ module ActiveRecordWhereAssoc
|
|
167
175
|
end
|
168
176
|
end
|
169
177
|
current_scope = apply_proc_scope(current_scope, last_assoc_block) if last_assoc_block
|
178
|
+
else
|
179
|
+
current_scope = process_association_step_limits(current_scope, reflection, record_class, options)
|
170
180
|
end
|
171
181
|
|
172
182
|
# Those make no sense since at this point, we are only limiting the value that would match using conditions
|
@@ -338,10 +348,18 @@ module ActiveRecordWhereAssoc
|
|
338
348
|
|
339
349
|
current_scope = current_scope.limit(1) if reflection.macro == :has_one
|
340
350
|
|
341
|
-
|
342
|
-
|
351
|
+
if !current_scope.offset_value
|
352
|
+
if current_scope.limit_value
|
353
|
+
join_keys = ActiveRecordCompat.join_keys(reflection, nil)
|
354
|
+
# #join_keys is inverted... the foreign key is on the "source" table, and the key is on the "target" table...
|
355
|
+
# Everything is so complicated in ActiveRecord.
|
356
|
+
current_scope = current_scope.unscope(:limit) if ActiveRecordCompat.has_unique_index?(current_scope.model, join_keys.key)
|
357
|
+
end
|
358
|
+
|
359
|
+
# Order is useless without either limit or offset
|
360
|
+
return current_scope.unscope(:order) if !current_scope.limit_value
|
361
|
+
end
|
343
362
|
|
344
|
-
return current_scope unless current_scope.limit_value || current_scope.offset_value
|
345
363
|
if %w(mysql mysql2).include?(relation_klass.connection.adapter_name.downcase)
|
346
364
|
msg = String.new
|
347
365
|
msg << "Associations and default_scopes with a limit or offset are not supported for MySQL (this includes has_many). "
|
@@ -364,6 +382,9 @@ module ActiveRecordWhereAssoc
|
|
364
382
|
if reflection.klass.table_name.include?(".") || option_value(options, :never_alias_limit)
|
365
383
|
# We use unscoped to avoid duplicating the conditions in the query, which is noise. (unless it
|
366
384
|
# could helps the query planner of the DB, if someone can show it to be worth it, then this can be changed.)
|
385
|
+
if reflection.klass.primary_key.is_a?(Array)
|
386
|
+
raise NeverAliasLimitDoesntWorkWithCompositePrimaryKeysError, "Sorry, it just doesn't work..."
|
387
|
+
end
|
367
388
|
|
368
389
|
reflection.klass.unscoped.where(reflection.klass.primary_key.to_sym => current_scope)
|
369
390
|
else
|
@@ -395,8 +416,13 @@ module ActiveRecordWhereAssoc
|
|
395
416
|
|
396
417
|
alias_scope = foreign_klass.base_class.unscoped
|
397
418
|
alias_scope = alias_scope.from("#{table.name} #{ALIAS_TABLE.name}")
|
398
|
-
|
399
|
-
|
419
|
+
|
420
|
+
primary_key_constraints =
|
421
|
+
Array(primary_key).map do |a_primary_key|
|
422
|
+
table[a_primary_key].eq(ALIAS_TABLE[a_primary_key])
|
423
|
+
end
|
424
|
+
|
425
|
+
alias_scope.where(primary_key_constraints.inject(&:and))
|
400
426
|
end
|
401
427
|
|
402
428
|
def self.wrapper_and_join_constraints(record_class, reflection, options = {})
|
@@ -424,7 +450,18 @@ module ActiveRecordWhereAssoc
|
|
424
450
|
foreign_table = ALIAS_TABLE
|
425
451
|
end
|
426
452
|
|
427
|
-
|
453
|
+
constraint_keys = Array.wrap(key)
|
454
|
+
constraint_foreign_keys = Array.wrap(foreign_key)
|
455
|
+
constraint_key_map = constraint_keys.zip(constraint_foreign_keys)
|
456
|
+
|
457
|
+
primary_foreign_key_constraints =
|
458
|
+
constraint_key_map.map do |primary_and_foreign_keys|
|
459
|
+
a_primary_key, a_foreign_key = primary_and_foreign_keys
|
460
|
+
|
461
|
+
table[a_primary_key].eq(foreign_table[a_foreign_key])
|
462
|
+
end
|
463
|
+
|
464
|
+
constraints = primary_foreign_key_constraints.inject(&:and)
|
428
465
|
|
429
466
|
if reflection.type
|
430
467
|
# Handling of the polymorphic has_many/has_one's type column
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord_where_assoc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Maxime Handfield Lapointe
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-05
|
11
|
+
date: 2024-12-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -181,7 +181,7 @@ homepage: https://github.com/MaxLap/activerecord_where_assoc
|
|
181
181
|
licenses:
|
182
182
|
- MIT
|
183
183
|
metadata: {}
|
184
|
-
post_install_message:
|
184
|
+
post_install_message:
|
185
185
|
rdoc_options: []
|
186
186
|
require_paths:
|
187
187
|
- lib
|
@@ -196,8 +196,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
196
196
|
- !ruby/object:Gem::Version
|
197
197
|
version: '0'
|
198
198
|
requirements: []
|
199
|
-
rubygems_version: 3.
|
200
|
-
signing_key:
|
199
|
+
rubygems_version: 3.5.11
|
200
|
+
signing_key:
|
201
201
|
specification_version: 4
|
202
202
|
summary: Make ActiveRecord do conditions on your associations
|
203
203
|
test_files: []
|