ar_lazy_preload 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +50 -0
- data/Rakefile +8 -0
- data/lib/ar_lazy_preload.rb +20 -0
- data/lib/ar_lazy_preload/associated_context_builder.rb +58 -0
- data/lib/ar_lazy_preload/association_tree_builder.rb +26 -0
- data/lib/ar_lazy_preload/context.rb +54 -0
- data/lib/ar_lazy_preload/ext/association.rb +17 -0
- data/lib/ar_lazy_preload/ext/association_relation.rb +21 -0
- data/lib/ar_lazy_preload/ext/base.rb +17 -0
- data/lib/ar_lazy_preload/ext/merger.rb +37 -0
- data/lib/ar_lazy_preload/ext/relation.rb +63 -0
- data/lib/ar_lazy_preload/version.rb +5 -0
- metadata +155 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 18eb45f9e1c299f719a7bdde76d9da3c9de0175919ad71556c4dfee750405d35
|
4
|
+
data.tar.gz: cec719881cff10f3687c8a22461d0b27acf9ab064104cbb5fb380eb6bd836701
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 71d13fa6015289abc893816b695e920fb59c42d96691d5cd86c3ce41c2c5e4bb34e5c6ea343094aabd39136e4e01ef1e88cd1f5e50bf97968f074844b61b3d87
|
7
|
+
data.tar.gz: 5e4e2f0f95b42796d7f165afb7009db76fbbcfa083e2552c2b7c90e7bc9442445d533cdfd498dc8a39b4734e8c0e50641ea8d77f48a429a85568fb0421e72c3c
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2018 DmitryTsepelev
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
[![Build Status](https://travis-ci.org/DmitryTsepelev/ar_lazy_preload.svg?branch=master)](https://travis-ci.org/DmitryTsepelev/ar_lazy_preload)
|
2
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/00d04595661820dfba80/maintainability)](https://codeclimate.com/github/DmitryTsepelev/ar_lazy_preload/maintainability)
|
3
|
+
[![Coverage Status](https://coveralls.io/repos/github/DmitryTsepelev/ar_lazy_preload/badge.svg?branch=master)](https://coveralls.io/github/DmitryTsepelev/ar_lazy_preload?branch=master)
|
4
|
+
|
5
|
+
# ArLazyPreload
|
6
|
+
|
7
|
+
Lazy loading associations for the ActiveRecord models. `#includes`, `#eager_load` and `#preload` are built-in methods to avoid N+1 problem, but sometimes when DB request is made we don't know what associations we are going to need later (for instance when your API allows client to define a list of loaded associations dynamically). The only possible solution for such cases is to load _all_ the associations we might need, but it can be a huge overhead.
|
8
|
+
|
9
|
+
This gem allows to set up _lazy_ preloading for associations - it won't load anything until association is called for a first time, but when it happens - it loads all the associated records for all records from the initial relation in a single query.
|
10
|
+
|
11
|
+
For example, if we define a following relation
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
users = User.lazy_preload(:posts).limit(10)
|
15
|
+
```
|
16
|
+
|
17
|
+
and use it in a following way
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
users.map(&:first_name)
|
21
|
+
```
|
22
|
+
|
23
|
+
there will be one query because we've never accessed posts:
|
24
|
+
|
25
|
+
```sql
|
26
|
+
SELECT * FROM users LIMIT 10
|
27
|
+
```
|
28
|
+
|
29
|
+
Hovever, when we try to load posts
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
users.map(&:posts)
|
33
|
+
```
|
34
|
+
|
35
|
+
there will be one more request for posts:
|
36
|
+
|
37
|
+
```sql
|
38
|
+
SELECT * FROM posts WHERE user_id in (...)
|
39
|
+
```
|
40
|
+
|
41
|
+
## Installation
|
42
|
+
|
43
|
+
Add this line to your application's Gemfile, and you're all set:
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
gem "ar_lazy_preload"
|
47
|
+
```
|
48
|
+
|
49
|
+
## License
|
50
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ar_lazy_preload/ext/base"
|
4
|
+
require "ar_lazy_preload/ext/relation"
|
5
|
+
require "ar_lazy_preload/ext/association"
|
6
|
+
require "ar_lazy_preload/ext/merger"
|
7
|
+
require "ar_lazy_preload/ext/association_relation"
|
8
|
+
|
9
|
+
module ArLazyPreload
|
10
|
+
ActiveRecord::Base.include(ArLazyPreload::Base)
|
11
|
+
|
12
|
+
ActiveRecord::Relation.prepend(ArLazyPreload::Relation)
|
13
|
+
ActiveRecord::AssociationRelation.prepend(ArLazyPreload::AssociationRelation)
|
14
|
+
ActiveRecord::Relation::Merger.prepend(ArLazyPreload::Merger)
|
15
|
+
|
16
|
+
[
|
17
|
+
ActiveRecord::Associations::CollectionAssociation,
|
18
|
+
ActiveRecord::Associations::Association
|
19
|
+
].each { |klass| klass.prepend(ArLazyPreload::Association) }
|
20
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ar_lazy_preload/association_tree_builder"
|
4
|
+
|
5
|
+
module ArLazyPreload
|
6
|
+
# This class is responsible for building context for associated records. Given a list of records
|
7
|
+
# belonging to the same context and association name it will create and attach a new context to
|
8
|
+
# the associated records based on the parent association tree.
|
9
|
+
class AssociatedContextBuilder
|
10
|
+
attr_reader :parent_context, :association_name
|
11
|
+
|
12
|
+
def initialize(parent_context:, association_name:)
|
13
|
+
@parent_context = parent_context
|
14
|
+
@association_name = association_name
|
15
|
+
end
|
16
|
+
|
17
|
+
delegate :records, :association_tree, :model, to: :parent_context
|
18
|
+
|
19
|
+
# Takes all the associated records for the records, attached to the :parent_context and creates
|
20
|
+
# a preloading context for them
|
21
|
+
def perform
|
22
|
+
return if child_association_tree.blank? || associated_records.blank?
|
23
|
+
|
24
|
+
Context.new(
|
25
|
+
model: reflection.klass,
|
26
|
+
records: associated_records,
|
27
|
+
association_tree: child_association_tree
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def child_association_tree
|
34
|
+
@child_association_tree ||= association_tree_builder.subtree_for(association_name)
|
35
|
+
end
|
36
|
+
|
37
|
+
def association_tree_builder
|
38
|
+
@association_tree_builder ||= AssociationTreeBuilder.new(association_tree)
|
39
|
+
end
|
40
|
+
|
41
|
+
def associated_records
|
42
|
+
@associated_records ||=
|
43
|
+
if reflection.collection?
|
44
|
+
record_associations.map(&:target).flatten
|
45
|
+
else
|
46
|
+
record_associations
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def reflection
|
51
|
+
@reflection = model.reflect_on_association(association_name)
|
52
|
+
end
|
53
|
+
|
54
|
+
def record_associations
|
55
|
+
@record_associations ||= records.map { |record| record.send(association_name) }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ArLazyPreload
|
4
|
+
# This class is responsible for building association subtrees from a given association tree
|
5
|
+
# For instance, given a following tree `[:users, { users: :comments }]`,
|
6
|
+
# #subtree_for will build a subtree `[:comments]` when :users argument is passed
|
7
|
+
class AssociationTreeBuilder
|
8
|
+
attr_reader :association_tree
|
9
|
+
|
10
|
+
def initialize(association_tree)
|
11
|
+
@association_tree = association_tree.select { |node| node.is_a?(Hash) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def subtree_for(association)
|
15
|
+
subtree_cache[association]
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def subtree_cache
|
21
|
+
@subtree_cache ||= Hash.new do |hash, association|
|
22
|
+
hash[association] = association_tree.map { |node| node[association] }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ar_lazy_preload/associated_context_builder"
|
4
|
+
|
5
|
+
module ArLazyPreload
|
6
|
+
# This class is responsible for holding a connection between a list of ActiveRecord::Base objects
|
7
|
+
# which have been loaded by the same instance of ActiveRecord::Relation. It also contains a tree
|
8
|
+
# of associations, which were requested to be loaded lazily.
|
9
|
+
# Calling #preload_association method will cause loading of ALL associated objects for EACH
|
10
|
+
# ecord when requested association is found in the association tree.
|
11
|
+
class Context
|
12
|
+
attr_reader :model, :records, :association_tree
|
13
|
+
|
14
|
+
# :model - ActiveRecord class which records belong to
|
15
|
+
# :records - array of ActiveRecord instances
|
16
|
+
# :association_tree - list of symbols or hashes representing a tree of preloadable associations
|
17
|
+
def initialize(model:, records:, association_tree:)
|
18
|
+
@model = model
|
19
|
+
@records = records.compact
|
20
|
+
@association_tree = association_tree
|
21
|
+
|
22
|
+
@records.each { |record| record.lazy_preload_context = self }
|
23
|
+
end
|
24
|
+
|
25
|
+
# This method checks if the association is present in the association_tree and preloads for all
|
26
|
+
# objects in the context it if needed.
|
27
|
+
def try_preload_lazily(association_name)
|
28
|
+
return unless association_needs_preload?(association_name)
|
29
|
+
|
30
|
+
preloader.preload(records, association_name)
|
31
|
+
|
32
|
+
AssociatedContextBuilder.new(
|
33
|
+
parent_context: self,
|
34
|
+
association_name: association_name
|
35
|
+
).perform
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def association_needs_preload?(association_name)
|
41
|
+
association_tree.any? do |node|
|
42
|
+
if node.is_a?(Symbol)
|
43
|
+
node == association_name
|
44
|
+
elsif node.is_a?(Hash)
|
45
|
+
node.key?(association_name)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def preloader
|
51
|
+
@preloader ||= ActiveRecord::Associations::Preloader.new
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ArLazyPreload
|
4
|
+
# ActiveRecord::Association patch with a hook for lazy preloading
|
5
|
+
module Association
|
6
|
+
def load_target
|
7
|
+
owner.try_preload_lazily(association_name)
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def association_name
|
14
|
+
@association_name ||= reflection.name
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ArLazyPreload
|
4
|
+
# ActiveRecord::AssociationRelation patch for setting up lazy_preload_values based on
|
5
|
+
# owner context
|
6
|
+
module AssociationRelation
|
7
|
+
def initialize(*args)
|
8
|
+
super(*args)
|
9
|
+
|
10
|
+
context = owner.lazy_preload_context
|
11
|
+
return if context.blank?
|
12
|
+
|
13
|
+
association_tree_builder = AssociationTreeBuilder.new(context.association_tree)
|
14
|
+
subtree = association_tree_builder.subtree_for(reflection.name)
|
15
|
+
|
16
|
+
lazy_preload!(subtree)
|
17
|
+
end
|
18
|
+
|
19
|
+
delegate :owner, :reflection, to: :proxy_association
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ArLazyPreload
|
4
|
+
# ActiveRecord::Base patch with lazy preloading support
|
5
|
+
module Base
|
6
|
+
def self.included(base)
|
7
|
+
base.class.delegate :lazy_preload, to: :all
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_accessor :lazy_preload_context
|
11
|
+
|
12
|
+
# When context has been set, this method would cause preloading association with a given name
|
13
|
+
def try_preload_lazily(association_name)
|
14
|
+
lazy_preload_context.try_preload_lazily(association_name) if lazy_preload_context.present?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ArLazyPreload
|
4
|
+
# ActiveRecord::Relation::Merger patch implementing merge functionality
|
5
|
+
# for lazy preloadable relations
|
6
|
+
module Merger
|
7
|
+
# Enhanced #merge implements merging lazy_preload_values
|
8
|
+
def merge
|
9
|
+
result = super
|
10
|
+
|
11
|
+
if other.lazy_preload_values
|
12
|
+
if other.klass == relation.klass
|
13
|
+
merge_lazy_preloads
|
14
|
+
else
|
15
|
+
reflect_and_merge_lazy_preloads
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
result
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def merge_lazy_preloads
|
25
|
+
relation.lazy_preload!(*other.lazy_preload_values)
|
26
|
+
end
|
27
|
+
|
28
|
+
def reflect_and_merge_lazy_preloads
|
29
|
+
reflection = relation.klass.reflect_on_all_associations.find do |r|
|
30
|
+
r.class_name == other.klass.name
|
31
|
+
end
|
32
|
+
return unless reflection
|
33
|
+
|
34
|
+
relation.lazy_preload!(reflection.name => other.lazy_preload_values)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ar_lazy_preload/context"
|
4
|
+
|
5
|
+
module ArLazyPreload
|
6
|
+
# ActiveRecord::Relation patch with lazy preloading support
|
7
|
+
module Relation
|
8
|
+
# Enhanced #load method will check if association has not been loaded yet and add a context
|
9
|
+
# for lazy preloading to loaded each record
|
10
|
+
def load
|
11
|
+
need_context = !loaded?
|
12
|
+
old_load_result = super
|
13
|
+
setup_lazy_preload_context if need_context
|
14
|
+
old_load_result
|
15
|
+
end
|
16
|
+
|
17
|
+
# Specify relationships to be loaded lazily when association is loaded for the first time. For
|
18
|
+
# example:
|
19
|
+
#
|
20
|
+
# users = User.lazy_preload(:posts)
|
21
|
+
# users.each do |user|
|
22
|
+
# user.first_name
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# will cause only one SQL request to load users, while
|
26
|
+
#
|
27
|
+
# users = User.lazy_preload(:posts)
|
28
|
+
# users.each do |user|
|
29
|
+
# user.posts.map(&:id)
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# will make an additional query.
|
33
|
+
def lazy_preload(*args)
|
34
|
+
check_if_method_has_arguments!(:lazy_preload, args)
|
35
|
+
spawn.lazy_preload!(*args)
|
36
|
+
end
|
37
|
+
|
38
|
+
def lazy_preload!(*args)
|
39
|
+
args.reject!(&:blank?)
|
40
|
+
args.flatten!
|
41
|
+
self.lazy_preload_values += args
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
def lazy_preload_values
|
46
|
+
@lazy_preload_values ||= []
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
attr_writer :lazy_preload_values
|
52
|
+
|
53
|
+
def setup_lazy_preload_context
|
54
|
+
return if lazy_preload_values.blank? || @records.blank?
|
55
|
+
|
56
|
+
ArLazyPreload::Context.new(
|
57
|
+
model: model,
|
58
|
+
records: @records,
|
59
|
+
association_tree: lazy_preload_values
|
60
|
+
)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
metadata
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ar_lazy_preload
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- DmitryTsepelev
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-07-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec-rails
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubocop
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: db-query-matchers
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: coveralls
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: database_cleaner
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: factory_bot
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: lazy_preload implementation for ActiveRecord models
|
112
|
+
email:
|
113
|
+
- dmitry.a.tsepelev@gmail.com
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- MIT-LICENSE
|
119
|
+
- README.md
|
120
|
+
- Rakefile
|
121
|
+
- lib/ar_lazy_preload.rb
|
122
|
+
- lib/ar_lazy_preload/associated_context_builder.rb
|
123
|
+
- lib/ar_lazy_preload/association_tree_builder.rb
|
124
|
+
- lib/ar_lazy_preload/context.rb
|
125
|
+
- lib/ar_lazy_preload/ext/association.rb
|
126
|
+
- lib/ar_lazy_preload/ext/association_relation.rb
|
127
|
+
- lib/ar_lazy_preload/ext/base.rb
|
128
|
+
- lib/ar_lazy_preload/ext/merger.rb
|
129
|
+
- lib/ar_lazy_preload/ext/relation.rb
|
130
|
+
- lib/ar_lazy_preload/version.rb
|
131
|
+
homepage: https://github.com/DmitryTsepelev/ar_lazy_preload
|
132
|
+
licenses:
|
133
|
+
- MIT
|
134
|
+
metadata: {}
|
135
|
+
post_install_message:
|
136
|
+
rdoc_options: []
|
137
|
+
require_paths:
|
138
|
+
- lib
|
139
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - ">="
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '2.3'
|
144
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
145
|
+
requirements:
|
146
|
+
- - ">="
|
147
|
+
- !ruby/object:Gem::Version
|
148
|
+
version: '0'
|
149
|
+
requirements: []
|
150
|
+
rubyforge_project:
|
151
|
+
rubygems_version: 2.7.6
|
152
|
+
signing_key:
|
153
|
+
specification_version: 4
|
154
|
+
summary: lazy_preload implementation for ActiveRecord models
|
155
|
+
test_files: []
|