ar_lazy_preload 0.3.1 → 0.5.2
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 +16 -0
- data/lib/ar_lazy_preload/active_record/association_relation.rb +1 -0
- data/lib/ar_lazy_preload/active_record/base.rb +7 -0
- data/lib/ar_lazy_preload/active_record/relation.rb +20 -1
- data/lib/ar_lazy_preload/associated_context_builder.rb +13 -5
- data/lib/ar_lazy_preload/context.rb +2 -2
- data/lib/ar_lazy_preload/contexts/auto_preload_context.rb +4 -0
- data/lib/ar_lazy_preload/contexts/base_context.rb +18 -1
- data/lib/ar_lazy_preload/version.rb +1 -1
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f8b1ef234e5a995bfce176e47fe5526fba9330b61cc27374e6667a5f5dfca3af
|
4
|
+
data.tar.gz: 3516b8bf449802b2ba3ff7022faec299ff274fe4716db884e46da63fe47d5ac9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 80a0a1e05b961a6d66b20c0b5e1a32ee2824d868e7e96d25e85b4e2b3c48baa1ee9129cf934b71e73a2887245faa9f54b3ecc23cc7815d60c30efc8bca9fbb7b
|
7
|
+
data.tar.gz: bbb5f854ed701c562d31f00cf3f832eb668c42aca809e4376aed4b78c114bd3c25db15edea712d65419a23c3fbbe1dfac5d698055dad5c5ae61ea837ea6fa273
|
data/README.md
CHANGED
@@ -44,6 +44,22 @@ ArLazyPreload.config.auto_preload = true
|
|
44
44
|
|
45
45
|
After that there is no need to call `#lazy_preload` on the association, everything would be loaded lazily.
|
46
46
|
|
47
|
+
If you want to turn automatic preload off for a specific record, you can call `.skip_preload` before any associations method:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
users.first.skip_preload.posts # => SELECT * FROM posts WHERE user_id = ?
|
51
|
+
```
|
52
|
+
|
53
|
+
### Relation auto preloading
|
54
|
+
|
55
|
+
Another alternative for auto preloading is using relation `#preload_associations_lazily` method
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
posts = User.preload_associations_lazily.flat_map(&:posts)
|
59
|
+
# => SELECT * FROM users LIMIT 10
|
60
|
+
# => SELECT * FROM posts WHERE user_id in (...)
|
61
|
+
```
|
62
|
+
|
47
63
|
## Installation
|
48
64
|
|
49
65
|
Add this line to your application's Gemfile, and you're all set:
|
@@ -16,6 +16,7 @@ module ArLazyPreload
|
|
16
16
|
|
17
17
|
def setup_preloading_context
|
18
18
|
return if lazy_preload_context.nil?
|
19
|
+
return if lazy_preload_context.association_tree.nil?
|
19
20
|
|
20
21
|
association_tree_builder = AssociationTreeBuilder.new(lazy_preload_context.association_tree)
|
21
22
|
subtree = association_tree_builder.subtree_for(reflection.name)
|
@@ -5,10 +5,17 @@ module ArLazyPreload
|
|
5
5
|
module Base
|
6
6
|
def self.included(base)
|
7
7
|
base.class.delegate :lazy_preload, to: :all
|
8
|
+
base.class.delegate :preload_associations_lazily, to: :all
|
8
9
|
end
|
9
10
|
|
10
11
|
attr_accessor :lazy_preload_context
|
11
12
|
|
12
13
|
delegate :try_preload_lazily, to: :lazy_preload_context, allow_nil: true
|
14
|
+
|
15
|
+
def skip_preload
|
16
|
+
lazy_preload_context&.records&.delete(self)
|
17
|
+
self.lazy_preload_context = nil
|
18
|
+
self
|
19
|
+
end
|
13
20
|
end
|
14
21
|
end
|
@@ -5,6 +5,8 @@ require "ar_lazy_preload/context"
|
|
5
5
|
module ArLazyPreload
|
6
6
|
# ActiveRecord::Relation patch with lazy preloading support
|
7
7
|
module Relation
|
8
|
+
attr_writer :preloads_associations_lazily
|
9
|
+
|
8
10
|
# Enhanced #load method will check if association has not been loaded yet and add a context
|
9
11
|
# for lazy preloading to loaded each record
|
10
12
|
def load
|
@@ -13,12 +15,25 @@ module ArLazyPreload
|
|
13
15
|
if need_context
|
14
16
|
Context.register(
|
15
17
|
records: ar_lazy_preload_records,
|
16
|
-
association_tree: lazy_preload_values
|
18
|
+
association_tree: lazy_preload_values,
|
19
|
+
auto_preload: preloads_associations_lazily?
|
17
20
|
)
|
18
21
|
end
|
19
22
|
result
|
20
23
|
end
|
21
24
|
|
25
|
+
# Lazily autoloads all associations. For example:
|
26
|
+
#
|
27
|
+
# users = User.preload_associations_lazily
|
28
|
+
# users.each do |user|
|
29
|
+
# user.posts.flat_map {|post| post.comments.map(&:id)}
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# Same effect can be achieved by User.lazy_preload(posts: :comments)
|
33
|
+
def preload_associations_lazily
|
34
|
+
spawn.tap { |relation| relation.preloads_associations_lazily = true }
|
35
|
+
end
|
36
|
+
|
22
37
|
# Specify relationships to be loaded lazily when association is loaded for the first time. For
|
23
38
|
# example:
|
24
39
|
#
|
@@ -56,6 +71,10 @@ module ArLazyPreload
|
|
56
71
|
@records
|
57
72
|
end
|
58
73
|
|
74
|
+
def preloads_associations_lazily?
|
75
|
+
@preloads_associations_lazily ||= false
|
76
|
+
end
|
77
|
+
|
59
78
|
attr_writer :lazy_preload_values
|
60
79
|
end
|
61
80
|
end
|
@@ -8,8 +8,8 @@ module ArLazyPreload
|
|
8
8
|
# the associated records based on the parent association tree.
|
9
9
|
class AssociatedContextBuilder
|
10
10
|
# Initiates lazy preload context the records loaded lazily
|
11
|
-
def self.prepare(
|
12
|
-
new(
|
11
|
+
def self.prepare(**args)
|
12
|
+
new(**args).perform
|
13
13
|
end
|
14
14
|
|
15
15
|
attr_reader :parent_context, :association_name
|
@@ -23,23 +23,31 @@ module ArLazyPreload
|
|
23
23
|
|
24
24
|
# Takes all the associated records for the records, attached to the :parent_context and creates
|
25
25
|
# a preloading context for them
|
26
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
26
27
|
def perform
|
27
28
|
associated_records = parent_context.records.flat_map do |record|
|
28
29
|
next if record.nil?
|
29
30
|
|
30
|
-
record_association = record.association(association_name)
|
31
31
|
reflection = reflection_cache[record.class]
|
32
|
+
next if reflection.nil?
|
33
|
+
|
34
|
+
record_association = record.association(association_name)
|
32
35
|
reflection.collection? ? record_association.target : record_association.reader
|
33
36
|
end
|
34
37
|
|
35
|
-
Context.register(
|
38
|
+
Context.register(
|
39
|
+
records: associated_records,
|
40
|
+
association_tree: child_association_tree,
|
41
|
+
auto_preload: parent_context.auto_preload?
|
42
|
+
)
|
36
43
|
end
|
44
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
37
45
|
|
38
46
|
private
|
39
47
|
|
40
48
|
def child_association_tree
|
41
49
|
# `association_tree` is unnecessary when auto preload is enabled
|
42
|
-
return nil if
|
50
|
+
return nil if parent_context.auto_preload?
|
43
51
|
|
44
52
|
AssociationTreeBuilder.new(parent_context.association_tree).subtree_for(association_name)
|
45
53
|
end
|
@@ -7,10 +7,10 @@ require "ar_lazy_preload/contexts/lazy_preload_context"
|
|
7
7
|
module ArLazyPreload
|
8
8
|
class Context
|
9
9
|
# Initiates lazy preload context for given records
|
10
|
-
def self.register(records:, association_tree:)
|
10
|
+
def self.register(records:, association_tree:, auto_preload: false)
|
11
11
|
return if records.empty?
|
12
12
|
|
13
|
-
if ArLazyPreload.config.auto_preload?
|
13
|
+
if ArLazyPreload.config.auto_preload? || auto_preload
|
14
14
|
Contexts::AutoPreloadContext.new(records: records)
|
15
15
|
elsif association_tree.any?
|
16
16
|
Contexts::LazyPreloadContext.new(
|
@@ -19,6 +19,9 @@ module ArLazyPreload
|
|
19
19
|
@records.each { |record| record.lazy_preload_context = self }
|
20
20
|
end
|
21
21
|
|
22
|
+
# @api
|
23
|
+
def association_tree; nil; end
|
24
|
+
|
22
25
|
# This method checks if the association should be loaded and preloads it for all
|
23
26
|
# objects in the context it if needed.
|
24
27
|
def try_preload_lazily(association_name)
|
@@ -28,6 +31,10 @@ module ArLazyPreload
|
|
28
31
|
perform_preloading(association_name)
|
29
32
|
end
|
30
33
|
|
34
|
+
def auto_preload?
|
35
|
+
false
|
36
|
+
end
|
37
|
+
|
31
38
|
protected
|
32
39
|
|
33
40
|
def association_needs_preload?(_association_name)
|
@@ -37,7 +44,11 @@ module ArLazyPreload
|
|
37
44
|
private
|
38
45
|
|
39
46
|
def perform_preloading(association_name)
|
40
|
-
|
47
|
+
filtered_records = records.select do |record|
|
48
|
+
reflection_names_cache[record.class].include?(association_name)
|
49
|
+
end
|
50
|
+
preloader.preload(filtered_records, association_name)
|
51
|
+
|
41
52
|
loaded_association_names.add(association_name)
|
42
53
|
|
43
54
|
AssociatedContextBuilder.prepare(
|
@@ -57,6 +68,12 @@ module ArLazyPreload
|
|
57
68
|
def preloader
|
58
69
|
@preloader ||= ActiveRecord::Associations::Preloader.new
|
59
70
|
end
|
71
|
+
|
72
|
+
def reflection_names_cache
|
73
|
+
@reflection_names_cache ||= Hash.new do |hash, klass|
|
74
|
+
hash[klass] = klass.reflect_on_all_associations.map(&:name)
|
75
|
+
end
|
76
|
+
end
|
60
77
|
end
|
61
78
|
end
|
62
79
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ar_lazy_preload
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- DmitryTsepelev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-09-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -56,16 +56,16 @@ dependencies:
|
|
56
56
|
name: rubocop
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - '='
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: 0.81.0
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - '='
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
68
|
+
version: 0.81.0
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: db-query-matchers
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -196,7 +196,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
196
196
|
- !ruby/object:Gem::Version
|
197
197
|
version: '0'
|
198
198
|
requirements: []
|
199
|
-
rubygems_version: 3.
|
199
|
+
rubygems_version: 3.1.2
|
200
200
|
signing_key:
|
201
201
|
specification_version: 4
|
202
202
|
summary: lazy_preload implementation for ActiveRecord models
|