ar_lazy_preload 0.2.7 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0e0790a19fd33c7b141ba62725951c084f84cd0d1e8678e807081dac6d1b9c4c
4
- data.tar.gz: 714b3e6785f5ad4dd7278be3549638ec8ab2447cad82cc3f9a5cd53694d23006
3
+ metadata.gz: 122262e10bed3d8a2793e62f24ee39e7a01453933c68d8faffce8945b794a522
4
+ data.tar.gz: e50652dd855cbbbe39b292b20e07fca7f43ba660fd2f28f0c41de1fa0595c281
5
5
  SHA512:
6
- metadata.gz: e3f9bfdd8dec8fb021f96ad79b686248e15dc30e23585a3c7e386033c72ec8864d75de8c8a21c4c0ef00e57e63e61c7bd147a6554d5e634f6282959f11bade82
7
- data.tar.gz: d9537e25cc267fdc4278f2ae467945482abb78e2716d823c915ce2c5d82c7190ed9713ab8ad2cf5f219eceb4b72954c9eb25854b5b593e3c9726d0dcef50b8cb
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
@@ -8,7 +8,7 @@ module ArLazyPreload
8
8
  def merge
9
9
  result = super
10
10
 
11
- if other.lazy_preload_values
11
+ if other.lazy_preload_values.any?
12
12
  if other.klass == relation.klass
13
13
  merge_lazy_preloads
14
14
  else
@@ -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(*args)
12
- new(*args).perform
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(records: associated_records, association_tree: child_association_tree)
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 ArLazyPreload.config.auto_preload?
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(
@@ -4,6 +4,10 @@ module ArLazyPreload
4
4
  module Contexts
5
5
  # This class is responsible for automatic association preloading
6
6
  class AutoPreloadContext < BaseContext
7
+ def auto_preload?
8
+ true
9
+ end
10
+
7
11
  protected
8
12
 
9
13
  def association_needs_preload?(_association_name)
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ArLazyPreload
4
- VERSION = "0.2.7"
4
+ VERSION = "0.5.0"
5
5
  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.2.7
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-05-05 00:00:00.000000000 Z
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: '0'
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: '0'
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.0.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