ar_lazy_preload 2.1.0 → 2.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/README.md +4 -0
- data/lib/ar_lazy_preload/contexts/base_context.rb +53 -0
- data/lib/ar_lazy_preload/version.rb +1 -1
- metadata +38 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 927bf2110e3c5733916353191cbc1c1b9543dab216b6aef4b120cd6383822796
|
|
4
|
+
data.tar.gz: 24e78260d612a9d212c4b53937abff9cf6f68e32aa5728c60b4d686ea49efcf8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 88ca2ecb46671b3ec6f671d06c540a24bbcade260d68309993d2049e76730926b173074b3255cafc51e2d4e8636f5b7a3fbf4b17c1c838b5a4935c0545ffbf81
|
|
7
|
+
data.tar.gz: 5266eb7b7901631633a4c8ee554935c29757c60955f2749910ffd2e3688bc66a30edd330e9703c7775020868a0836f8d181cd6ed1f357719098f04a4791a437c
|
data/README.md
CHANGED
|
@@ -13,6 +13,8 @@ Used in production by:
|
|
|
13
13
|
- Toptal
|
|
14
14
|
- _Want to be here? Let me know_ 🙂
|
|
15
15
|
|
|
16
|
+
You can support my open–source work [here](https://boosty.to/dmitry_tsepelev).
|
|
17
|
+
|
|
16
18
|
## Why should I use it?
|
|
17
19
|
|
|
18
20
|
Lazy loading is super helpful when the list of associations to load is determined dynamically. For instance, in GraphQL this list comes from the API client, and you'll have to inspect the selection set to find out what associations are going to be used.
|
|
@@ -76,6 +78,8 @@ posts = User.preload_associations_lazily.flat_map(&:posts)
|
|
|
76
78
|
|
|
77
79
|
3. Lazy preloading for **ActiveStorage** variants is not working automatically because of the way how it is implemented ([here](https://github.com/DmitryTsepelev/ar_lazy_preload/pull/70) is the issue). You can preload them manually by calling `#with_all_variant_records`/`#with_attached_#{attachment_name}` on association. Example: `User.with_attached_avatar.first(10).map { |u| u.avatar.variant(:small).processed.url }`
|
|
78
80
|
|
|
81
|
+
4. Lazy preloading does not work for association object creation methods, so it is better if you separate the logic for writing and reading objects and use lazy preloading for read only, more information with example [here](https://github.com/DmitryTsepelev/ar_lazy_preload/issues/75)
|
|
82
|
+
|
|
79
83
|
## Installation
|
|
80
84
|
|
|
81
85
|
Add this line to your application's Gemfile, and you're all set:
|
|
@@ -52,12 +52,65 @@ module ArLazyPreload
|
|
|
52
52
|
preload_records(association_name, filtered_records)
|
|
53
53
|
loaded_association_names.add(association_name)
|
|
54
54
|
|
|
55
|
+
# Prepare context for intermediate through associations
|
|
56
|
+
prepare_through_association_contexts(association_name, filtered_records)
|
|
57
|
+
|
|
55
58
|
AssociatedContextBuilder.prepare(
|
|
56
59
|
parent_context: self,
|
|
57
60
|
association_name: association_name
|
|
58
61
|
)
|
|
59
62
|
end
|
|
60
63
|
|
|
64
|
+
# Prepare context for intermediate associations in through chains
|
|
65
|
+
def prepare_through_association_contexts(association_name, filtered_records)
|
|
66
|
+
filtered_records.group_by(&:class).each do |klass, klass_records|
|
|
67
|
+
chain = through_association_chain(association_name, klass)
|
|
68
|
+
next if chain.empty?
|
|
69
|
+
|
|
70
|
+
chain.each do |intermediate_name|
|
|
71
|
+
register_intermediate_context(klass, klass_records, intermediate_name)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def register_intermediate_context(klass, klass_records, intermediate_name)
|
|
77
|
+
return if association_loaded?(intermediate_name)
|
|
78
|
+
|
|
79
|
+
reflection = klass.reflect_on_association(intermediate_name)
|
|
80
|
+
return if reflection.nil?
|
|
81
|
+
|
|
82
|
+
loaded_association_names.add(intermediate_name)
|
|
83
|
+
|
|
84
|
+
intermediate_records = collect_intermediate_records(klass_records, reflection)
|
|
85
|
+
return if intermediate_records.empty?
|
|
86
|
+
|
|
87
|
+
ArLazyPreload::Context.register(records: intermediate_records, auto_preload: true)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def collect_intermediate_records(klass_records, reflection)
|
|
91
|
+
klass_records.flat_map do |record|
|
|
92
|
+
record_association = record.association(reflection.name)
|
|
93
|
+
reflection.collection? ? record_association.target : record_association.reader
|
|
94
|
+
end.compact
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Extract chain of intermediate association names for through associations
|
|
98
|
+
def through_association_chain(association_name, klass)
|
|
99
|
+
reflection = klass.reflect_on_association(association_name)
|
|
100
|
+
return [] unless reflection&.options&.key?(:through)
|
|
101
|
+
|
|
102
|
+
chain = []
|
|
103
|
+
current_reflection = reflection
|
|
104
|
+
|
|
105
|
+
while current_reflection&.options&.key?(:through)
|
|
106
|
+
through_name = current_reflection.options[:through]
|
|
107
|
+
chain.unshift(through_name)
|
|
108
|
+
current_reflection = klass.reflect_on_association(through_name)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
chain
|
|
112
|
+
end
|
|
113
|
+
|
|
61
114
|
# Method preloads associations for the specific sets of the records
|
|
62
115
|
# and provides automatically provides context for the records
|
|
63
116
|
# loaded using `includes` inside Relation#preload_associations with the
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ar_lazy_preload
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.1.
|
|
4
|
+
version: 2.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- DmitryTsepelev
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: rails
|
|
@@ -16,14 +15,14 @@ dependencies:
|
|
|
16
15
|
requirements:
|
|
17
16
|
- - ">="
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
18
|
+
version: '7.0'
|
|
20
19
|
type: :development
|
|
21
20
|
prerelease: false
|
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
22
|
requirements:
|
|
24
23
|
- - ">="
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
25
|
+
version: '7.0'
|
|
27
26
|
- !ruby/object:Gem::Dependency
|
|
28
27
|
name: rspec
|
|
29
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -109,19 +108,19 @@ dependencies:
|
|
|
109
108
|
- !ruby/object:Gem::Version
|
|
110
109
|
version: '0'
|
|
111
110
|
- !ruby/object:Gem::Dependency
|
|
112
|
-
name: database_cleaner
|
|
111
|
+
name: database_cleaner-active_record
|
|
113
112
|
requirement: !ruby/object:Gem::Requirement
|
|
114
113
|
requirements:
|
|
115
|
-
- -
|
|
114
|
+
- - '='
|
|
116
115
|
- !ruby/object:Gem::Version
|
|
117
|
-
version:
|
|
116
|
+
version: 2.2.1
|
|
118
117
|
type: :development
|
|
119
118
|
prerelease: false
|
|
120
119
|
version_requirements: !ruby/object:Gem::Requirement
|
|
121
120
|
requirements:
|
|
122
|
-
- -
|
|
121
|
+
- - '='
|
|
123
122
|
- !ruby/object:Gem::Version
|
|
124
|
-
version:
|
|
123
|
+
version: 2.2.1
|
|
125
124
|
- !ruby/object:Gem::Dependency
|
|
126
125
|
name: factory_bot
|
|
127
126
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -178,6 +177,34 @@ dependencies:
|
|
|
178
177
|
- - ">="
|
|
179
178
|
- !ruby/object:Gem::Version
|
|
180
179
|
version: '0'
|
|
180
|
+
- !ruby/object:Gem::Dependency
|
|
181
|
+
name: benchmark
|
|
182
|
+
requirement: !ruby/object:Gem::Requirement
|
|
183
|
+
requirements:
|
|
184
|
+
- - ">="
|
|
185
|
+
- !ruby/object:Gem::Version
|
|
186
|
+
version: '0'
|
|
187
|
+
type: :development
|
|
188
|
+
prerelease: false
|
|
189
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
190
|
+
requirements:
|
|
191
|
+
- - ">="
|
|
192
|
+
- !ruby/object:Gem::Version
|
|
193
|
+
version: '0'
|
|
194
|
+
- !ruby/object:Gem::Dependency
|
|
195
|
+
name: ostruct
|
|
196
|
+
requirement: !ruby/object:Gem::Requirement
|
|
197
|
+
requirements:
|
|
198
|
+
- - ">="
|
|
199
|
+
- !ruby/object:Gem::Version
|
|
200
|
+
version: '0'
|
|
201
|
+
type: :development
|
|
202
|
+
prerelease: false
|
|
203
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
204
|
+
requirements:
|
|
205
|
+
- - ">="
|
|
206
|
+
- !ruby/object:Gem::Version
|
|
207
|
+
version: '0'
|
|
181
208
|
description: lazy_preload implementation for ActiveRecord models
|
|
182
209
|
email:
|
|
183
210
|
- dmitry.a.tsepelev@gmail.com
|
|
@@ -212,7 +239,6 @@ homepage: https://github.com/DmitryTsepelev/ar_lazy_preload
|
|
|
212
239
|
licenses:
|
|
213
240
|
- MIT
|
|
214
241
|
metadata: {}
|
|
215
|
-
post_install_message:
|
|
216
242
|
rdoc_options: []
|
|
217
243
|
require_paths:
|
|
218
244
|
- lib
|
|
@@ -227,8 +253,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
227
253
|
- !ruby/object:Gem::Version
|
|
228
254
|
version: '0'
|
|
229
255
|
requirements: []
|
|
230
|
-
rubygems_version:
|
|
231
|
-
signing_key:
|
|
256
|
+
rubygems_version: 4.0.3
|
|
232
257
|
specification_version: 4
|
|
233
258
|
summary: lazy_preload implementation for ActiveRecord models
|
|
234
259
|
test_files: []
|