ar_lazy_preload 0.2.7 → 0.5.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 +4 -4
- data/README.md +16 -0
- data/lib/ar_lazy_preload/active_record/base.rb +7 -0
- data/lib/ar_lazy_preload/active_record/collection_association.rb +21 -0
- data/lib/ar_lazy_preload/active_record/merger.rb +1 -1
- data/lib/ar_lazy_preload/active_record/relation.rb +20 -1
- data/lib/ar_lazy_preload/associated_context_builder.rb +10 -4
- 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 +5 -0
- data/lib/ar_lazy_preload/railtie.rb +2 -0
- data/lib/ar_lazy_preload/version.rb +1 -1
- metadata +8 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 122262e10bed3d8a2793e62f24ee39e7a01453933c68d8faffce8945b794a522
|
|
4
|
+
data.tar.gz: e50652dd855cbbbe39b292b20e07fca7f43ba660fd2f28f0c41de1fa0595c281
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 97a5044a80f021ea4f4c0bd0b27b0881858371bb60051014f885c791570346bafae8c2e4110f5f492817cbe38d44c551a4045d886a67e1ede30a5af5079afdac
|
|
7
|
+
data.tar.gz: '0458891f44c12464f6ce33295c6ef4e20bf55df63dc81a46ad840401cb47f1a782c466ee87f4c44c965b5090bc1c02ed2bead8a90f9b5031f9665803ade8e0a6'
|
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:
|
|
@@ -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
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ArLazyPreload
|
|
4
|
+
# ActiveRecord::CollectionAssociation patch with a hook for lazy preloading
|
|
5
|
+
module CollectionAssociation
|
|
6
|
+
# rubocop:disable Metrics/AbcSize
|
|
7
|
+
def ids_reader
|
|
8
|
+
return super if owner.lazy_preload_context.blank?
|
|
9
|
+
|
|
10
|
+
primary_key = reflection.association_primary_key.to_sym
|
|
11
|
+
if loaded?
|
|
12
|
+
target.map(&primary_key)
|
|
13
|
+
elsif !target.empty?
|
|
14
|
+
load_target.map(&primary_key)
|
|
15
|
+
else
|
|
16
|
+
@association_ids ||= reader.map(&primary_key)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
# rubocop:enable Metrics/AbcSize
|
|
20
|
+
end
|
|
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,6 +23,7 @@ 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?
|
|
@@ -32,14 +33,19 @@ module ArLazyPreload
|
|
|
32
33
|
reflection.collection? ? record_association.target : record_association.reader
|
|
33
34
|
end
|
|
34
35
|
|
|
35
|
-
Context.register(
|
|
36
|
+
Context.register(
|
|
37
|
+
records: associated_records,
|
|
38
|
+
association_tree: child_association_tree,
|
|
39
|
+
auto_preload: parent_context.auto_preload?
|
|
40
|
+
)
|
|
36
41
|
end
|
|
42
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
|
37
43
|
|
|
38
44
|
private
|
|
39
45
|
|
|
40
46
|
def child_association_tree
|
|
41
47
|
# `association_tree` is unnecessary when auto preload is enabled
|
|
42
|
-
return nil if
|
|
48
|
+
return nil if parent_context.auto_preload?
|
|
43
49
|
|
|
44
50
|
AssociationTreeBuilder.new(parent_context.association_tree).subtree_for(association_name)
|
|
45
51
|
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(
|
|
@@ -15,6 +15,7 @@ module ArLazyPreload
|
|
|
15
15
|
def initialize(records:)
|
|
16
16
|
@records = records.dup
|
|
17
17
|
@records.compact!
|
|
18
|
+
@records.uniq!
|
|
18
19
|
@records.each { |record| record.lazy_preload_context = self }
|
|
19
20
|
end
|
|
20
21
|
|
|
@@ -27,6 +28,10 @@ module ArLazyPreload
|
|
|
27
28
|
perform_preloading(association_name)
|
|
28
29
|
end
|
|
29
30
|
|
|
31
|
+
def auto_preload?
|
|
32
|
+
false
|
|
33
|
+
end
|
|
34
|
+
|
|
30
35
|
protected
|
|
31
36
|
|
|
32
37
|
def association_needs_preload?(_association_name)
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "ar_lazy_preload/active_record/base"
|
|
4
4
|
require "ar_lazy_preload/active_record/relation"
|
|
5
5
|
require "ar_lazy_preload/active_record/association"
|
|
6
|
+
require "ar_lazy_preload/active_record/collection_association"
|
|
6
7
|
require "ar_lazy_preload/active_record/merger"
|
|
7
8
|
require "ar_lazy_preload/active_record/association_relation"
|
|
8
9
|
require "ar_lazy_preload/active_record/collection_proxy"
|
|
@@ -22,6 +23,7 @@ module ArLazyPreload
|
|
|
22
23
|
ActiveRecord::Associations::Association
|
|
23
24
|
].each { |klass| klass.prepend(Association) }
|
|
24
25
|
|
|
26
|
+
ActiveRecord::Associations::CollectionAssociation.prepend(CollectionAssociation)
|
|
25
27
|
ActiveRecord::Associations::CollectionProxy.prepend(CollectionProxy)
|
|
26
28
|
end
|
|
27
29
|
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.0
|
|
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-08-27 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
|
|
@@ -164,6 +164,7 @@ files:
|
|
|
164
164
|
- lib/ar_lazy_preload/active_record/association.rb
|
|
165
165
|
- lib/ar_lazy_preload/active_record/association_relation.rb
|
|
166
166
|
- lib/ar_lazy_preload/active_record/base.rb
|
|
167
|
+
- lib/ar_lazy_preload/active_record/collection_association.rb
|
|
167
168
|
- lib/ar_lazy_preload/active_record/collection_proxy.rb
|
|
168
169
|
- lib/ar_lazy_preload/active_record/merger.rb
|
|
169
170
|
- lib/ar_lazy_preload/active_record/relation.rb
|
|
@@ -195,7 +196,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
195
196
|
- !ruby/object:Gem::Version
|
|
196
197
|
version: '0'
|
|
197
198
|
requirements: []
|
|
198
|
-
rubygems_version: 3.
|
|
199
|
+
rubygems_version: 3.1.2
|
|
199
200
|
signing_key:
|
|
200
201
|
specification_version: 4
|
|
201
202
|
summary: lazy_preload implementation for ActiveRecord models
|