ams_lazy_relationships 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +1 -1
- data/CHANGELOG.md +21 -0
- data/Gemfile.lock +8 -9
- data/README.md +1 -1
- data/RELEASE.md +3 -2
- data/Rakefile +2 -1
- data/ams_lazy_relationships.gemspec +1 -2
- data/lib/ams_lazy_relationships.rb +2 -0
- data/lib/ams_lazy_relationships/core/evaluation.rb +8 -1
- data/lib/ams_lazy_relationships/core/lazy_relationship_meta.rb +0 -12
- data/lib/ams_lazy_relationships/core/lazy_relationship_method.rb +9 -1
- data/lib/ams_lazy_relationships/core/relationship_wrapper_methods.rb +1 -5
- data/lib/ams_lazy_relationships/loaders/association.rb +16 -22
- data/lib/ams_lazy_relationships/loaders/base.rb +48 -0
- data/lib/ams_lazy_relationships/loaders/direct.rb +15 -21
- data/lib/ams_lazy_relationships/loaders/simple_belongs_to.rb +7 -17
- data/lib/ams_lazy_relationships/loaders/simple_has_many.rb +11 -18
- data/lib/ams_lazy_relationships/version.rb +1 -1
- metadata +8 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1ec3f81fd1d54428b4881ba8ec0631dbf2587d0b136f9fe9baecd29b9ac9d627
|
4
|
+
data.tar.gz: 9e7f106d42380915cfa2c0a475be0403951a8c632675d3cd5b4d8b3b0e25ec37
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ae977d3dcbde64175dd581ac341fa7db034dd7347ebd486d5c0b09808215cf7742ad8126cc6ca6c946406453d44a32125805488c6131ef981b777e40bdac0e18
|
7
|
+
data.tar.gz: 4a772034ef0eaa1aaf8d50fde4452e1a5e0ded1ddf00571838c159950e6a23e3185e5ff5c5c427def22909744e83928ebf6a204f52973c34047a025442892d6f
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,26 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## [v0.1.5](https://github.com/Bajena/ams_lazy_relationships/tree/v0.1.5) (2020-01-08)
|
4
|
+
[Full Changelog](https://github.com/Bajena/ams_lazy_relationships/compare/v0.1.4...v0.1.5)
|
5
|
+
|
6
|
+
**Closed issues:**
|
7
|
+
|
8
|
+
- Extract a base class for the loaders [\#39](https://github.com/Bajena/ams_lazy_relationships/issues/39)
|
9
|
+
- "Association" loader loads unnecessary records on AR 5.2.3+ [\#37](https://github.com/Bajena/ams_lazy_relationships/issues/37)
|
10
|
+
- undefined method `load\_all\_lazy\_relationships' for nil:NilClass [\#30](https://github.com/Bajena/ams_lazy_relationships/issues/30)
|
11
|
+
- Convert loaders to use strings instead of records as main keys [\#24](https://github.com/Bajena/ams_lazy_relationships/issues/24)
|
12
|
+
|
13
|
+
**Merged pull requests:**
|
14
|
+
|
15
|
+
- Improve tests for nested serializer lookup [\#43](https://github.com/Bajena/ams_lazy_relationships/pull/43) ([stokarenko](https://github.com/stokarenko))
|
16
|
+
- Extract a base class for lazy loaders [\#40](https://github.com/Bajena/ams_lazy_relationships/pull/40) ([Bajena](https://github.com/Bajena))
|
17
|
+
- Filter out preloaded records in `Association` preloader [\#36](https://github.com/Bajena/ams_lazy_relationships/pull/36) ([Bajena](https://github.com/Bajena))
|
18
|
+
- Synchronize lazy relationships [\#35](https://github.com/Bajena/ams_lazy_relationships/pull/35) ([stokarenko](https://github.com/stokarenko))
|
19
|
+
- Fix nested serializer lookup [\#34](https://github.com/Bajena/ams_lazy_relationships/pull/34) ([stokarenko](https://github.com/stokarenko))
|
20
|
+
- Fix batch loader dependency [\#33](https://github.com/Bajena/ams_lazy_relationships/pull/33) ([stokarenko](https://github.com/stokarenko))
|
21
|
+
- Bump rack from 2.0.6 to 2.0.8 [\#32](https://github.com/Bajena/ams_lazy_relationships/pull/32) ([dependabot[bot]](https://github.com/apps/dependabot))
|
22
|
+
- Bump loofah from 2.2.3 to 2.3.1 [\#31](https://github.com/Bajena/ams_lazy_relationships/pull/31) ([dependabot[bot]](https://github.com/apps/dependabot))
|
23
|
+
|
3
24
|
## [v0.1.4](https://github.com/Bajena/ams_lazy_relationships/tree/v0.1.4) (2019-06-02)
|
4
25
|
[Full Changelog](https://github.com/Bajena/ams_lazy_relationships/compare/v0.1.3...v0.1.4)
|
5
26
|
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
ams_lazy_relationships (0.1.
|
4
|
+
ams_lazy_relationships (0.1.5)
|
5
5
|
active_model_serializers
|
6
6
|
batch-loader (~> 1)
|
7
7
|
|
@@ -53,7 +53,7 @@ GEM
|
|
53
53
|
activesupport
|
54
54
|
coderay (1.1.2)
|
55
55
|
concurrent-ruby (1.1.4)
|
56
|
-
crass (1.0.
|
56
|
+
crass (1.0.5)
|
57
57
|
db-query-matchers (0.9.0)
|
58
58
|
activesupport (>= 4.0, <= 6.0)
|
59
59
|
rspec (~> 3.0)
|
@@ -78,8 +78,8 @@ GEM
|
|
78
78
|
parser (>= 2.5, != 2.5.1.1)
|
79
79
|
jaro_winkler (1.5.2)
|
80
80
|
json (2.1.0)
|
81
|
-
jsonapi-renderer (0.2.
|
82
|
-
loofah (2.
|
81
|
+
jsonapi-renderer (0.2.2)
|
82
|
+
loofah (2.3.1)
|
83
83
|
crass (~> 1.0.2)
|
84
84
|
nokogiri (>= 1.5.9)
|
85
85
|
memory_profiler (0.9.13)
|
@@ -88,7 +88,7 @@ GEM
|
|
88
88
|
minitest (5.11.3)
|
89
89
|
multi_json (1.13.1)
|
90
90
|
multipart-post (2.0.0)
|
91
|
-
nokogiri (1.10.
|
91
|
+
nokogiri (1.10.5)
|
92
92
|
mini_portile2 (~> 2.4.0)
|
93
93
|
octokit (4.13.0)
|
94
94
|
sawyer (~> 0.8.0, >= 0.5.3)
|
@@ -103,7 +103,7 @@ GEM
|
|
103
103
|
pry-nav (0.2.4)
|
104
104
|
pry (>= 0.9.10, < 0.11.0)
|
105
105
|
public_suffix (3.0.3)
|
106
|
-
rack (2.0.
|
106
|
+
rack (2.0.8)
|
107
107
|
rack-test (1.1.0)
|
108
108
|
rack (>= 1.0, < 3)
|
109
109
|
rails-dom-testing (2.0.3)
|
@@ -185,7 +185,6 @@ DEPENDENCIES
|
|
185
185
|
ams_lazy_relationships!
|
186
186
|
appraisal
|
187
187
|
benchmark-memory (~> 0.1)
|
188
|
-
bundler (~> 1.17)
|
189
188
|
db-query-matchers
|
190
189
|
github_changelog_generator
|
191
190
|
pry
|
@@ -197,9 +196,9 @@ DEPENDENCIES
|
|
197
196
|
rubocop-rspec (= 1.20.1)
|
198
197
|
simplecov
|
199
198
|
simplecov-lcov
|
200
|
-
sqlite3
|
199
|
+
sqlite3
|
201
200
|
undercover
|
202
201
|
with_model (~> 2.0)
|
203
202
|
|
204
203
|
BUNDLED WITH
|
205
|
-
1.17.
|
204
|
+
1.17.3
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
[![Build Status](https://travis-ci.
|
1
|
+
[![Build Status](https://travis-ci.com/Bajena/ams_lazy_relationships.svg?branch=master)](https://travis-ci.com/Bajena/ams_lazy_relationships)
|
2
2
|
[![Maintainability](https://api.codeclimate.com/v1/badges/c21b988e09db63396309/maintainability)](https://codeclimate.com/github/Bajena/ams_lazy_relationships/maintainability)
|
3
3
|
[![Test Coverage](https://api.codeclimate.com/v1/badges/c21b988e09db63396309/test_coverage)](https://codeclimate.com/github/Bajena/ams_lazy_relationships/test_coverage)
|
4
4
|
|
data/RELEASE.md
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
# Release steps
|
2
2
|
1. Bump VERSION constant
|
3
|
-
2. Generate changelog and update
|
3
|
+
2. Generate changelog and update
|
4
4
|
```shell
|
5
5
|
CHANGELOG_GITHUB_TOKEN=<token> bundle exec rake changelog
|
6
6
|
```
|
7
7
|
3. Run `bundle` to regenerate Gemfile.lock
|
8
|
-
4.
|
8
|
+
4. Commit & push a new tag
|
9
|
+
5. Build and push to rubygems
|
9
10
|
```shell
|
10
11
|
gem build ams_lazy_relationships
|
11
12
|
gem push ams_lazy_relationships-x.y.z.gem
|
data/Rakefile
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require "bundler/gem_tasks"
|
4
4
|
require "rspec/core/rake_task"
|
5
5
|
require "github_changelog_generator/task"
|
6
|
+
require "ams_lazy_relationships/version"
|
6
7
|
|
7
8
|
RSpec::Core::RakeTask.new(:spec)
|
8
9
|
|
@@ -11,5 +12,5 @@ task default: :spec
|
|
11
12
|
GitHubChangelogGenerator::RakeTask.new :changelog do |config|
|
12
13
|
config.user = "Bajena"
|
13
14
|
config.project = "ams_lazy_relationships"
|
14
|
-
config.future_release = "
|
15
|
+
config.future_release = "v#{AmsLazyRelationships::VERSION}"
|
15
16
|
end
|
@@ -39,7 +39,6 @@ Gem::Specification.new do |spec|
|
|
39
39
|
spec.add_development_dependency "activerecord"
|
40
40
|
# A Ruby library for testing against different versions of dependencies
|
41
41
|
spec.add_development_dependency "appraisal"
|
42
|
-
spec.add_development_dependency "bundler", "~> 1.17"
|
43
42
|
# Rspec matchers for SQL query counts
|
44
43
|
spec.add_development_dependency "db-query-matchers"
|
45
44
|
spec.add_development_dependency "github_changelog_generator"
|
@@ -52,7 +51,7 @@ Gem::Specification.new do |spec|
|
|
52
51
|
spec.add_development_dependency "rubocop-rspec", "= 1.20.1"
|
53
52
|
spec.add_development_dependency "simplecov"
|
54
53
|
spec.add_development_dependency "simplecov-lcov"
|
55
|
-
spec.add_development_dependency "sqlite3"
|
54
|
+
spec.add_development_dependency "sqlite3"
|
56
55
|
# Detect untested code blocks in recent changes
|
57
56
|
spec.add_development_dependency "undercover"
|
58
57
|
# Dynamically build an Active Record model (with table) within a test context
|
@@ -49,8 +49,15 @@ module AmsLazyRelationships::Core
|
|
49
49
|
return unless lrm.reflection
|
50
50
|
|
51
51
|
Array.wrap(batch_records).each do |r|
|
52
|
-
|
52
|
+
deep_load_for_yielded_record(r, lrm, level)
|
53
53
|
end
|
54
54
|
end
|
55
|
+
|
56
|
+
def deep_load_for_yielded_record(batch_record, lrm, level)
|
57
|
+
serializer = serializer_for(batch_record, lrm.reflection.options)
|
58
|
+
return unless serializer
|
59
|
+
|
60
|
+
serializer.send(:load_all_lazy_relationships, batch_record, level + 1)
|
61
|
+
end
|
55
62
|
end
|
56
63
|
end
|
@@ -19,17 +19,5 @@ module AmsLazyRelationships::Core
|
|
19
19
|
end
|
20
20
|
|
21
21
|
attr_reader :name, :loader, :reflection, :load_for
|
22
|
-
|
23
|
-
# @return [ActiveModel::Serializer] AMS Serializer class for the relationship
|
24
|
-
def serializer_class
|
25
|
-
return @serializer_class if defined?(@serializer_class)
|
26
|
-
|
27
|
-
@serializer_class =
|
28
|
-
if AmsLazyRelationships::Core.ams_version <= Gem::Version.new("0.10.0.rc2")
|
29
|
-
reflection[:association_options][:serializer]
|
30
|
-
else
|
31
|
-
reflection.options[:serializer]
|
32
|
-
end
|
33
|
-
end
|
34
22
|
end
|
35
23
|
end
|
@@ -39,7 +39,15 @@ module AmsLazyRelationships::Core
|
|
39
39
|
@lazy_relationships[name] = lrm
|
40
40
|
|
41
41
|
define_method :"lazy_#{name}" do
|
42
|
-
|
42
|
+
# We need to evaluate the promise right before serializer tries
|
43
|
+
# to touch it. Otherwise the various side effects can happen:
|
44
|
+
# 1. AMS will attempt to serialize nil values with a specific V1 serializer
|
45
|
+
# 2. `lazy_association ? 'exists' : 'missing'` expression will always
|
46
|
+
# equal to 'exists'
|
47
|
+
# 3. `lazy_association&.id` expression can raise NullPointer exception
|
48
|
+
#
|
49
|
+
# Calling `__sync` will evaluate the promise.
|
50
|
+
self.class.send(:load_lazy_relationship, lrm, object).__sync
|
43
51
|
end
|
44
52
|
end
|
45
53
|
|
@@ -30,11 +30,7 @@ module AmsLazyRelationships::Core
|
|
30
30
|
real_relationship_options = options.except(*lazy_relationship_option_keys)
|
31
31
|
|
32
32
|
block ||= lambda do |serializer|
|
33
|
-
#
|
34
|
-
# to serialize it. Otherwise AMS will attempt to serialize nil values
|
35
|
-
# with a specific V1 serializer.
|
36
|
-
# Calling `itself` will evaluate the promise.
|
37
|
-
serializer.public_send("lazy_#{name}").tap(&:itself)
|
33
|
+
serializer.public_send("lazy_#{name}")
|
38
34
|
end
|
39
35
|
|
40
36
|
public_send(type, name.to_sym, real_relationship_options, &block)
|
@@ -1,10 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "ams_lazy_relationships/loaders/base"
|
4
|
+
|
3
5
|
module AmsLazyRelationships
|
4
6
|
module Loaders
|
5
7
|
# Lazy loads (has_one/has_many/has_many_through/belongs_to) ActiveRecord
|
6
8
|
# associations for ActiveRecord models
|
7
|
-
class Association
|
9
|
+
class Association < Base
|
8
10
|
# @param model_class_name [String] The name of AR class for which the
|
9
11
|
# associations are loaded. E.g. When loading comment.blog_post
|
10
12
|
# it'd be "BlogPost".
|
@@ -15,31 +17,13 @@ module AmsLazyRelationships
|
|
15
17
|
@association_name = association_name
|
16
18
|
end
|
17
19
|
|
18
|
-
# Lazy loads and yields the data when evaluating
|
19
|
-
# @param record [Object] an object for which we're loading the data
|
20
|
-
# @param block [Proc] a block to execute when data is evaluated.
|
21
|
-
# Loaded data is yielded as a block argument.
|
22
|
-
def load(record, &block)
|
23
|
-
BatchLoader.for(record).batch(key: batch_key, replace_methods: false) do |records, loader|
|
24
|
-
data = load_data(records, loader)
|
25
|
-
|
26
|
-
block&.call(data)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
20
|
private
|
31
21
|
|
32
22
|
attr_reader :model_class_name, :association_name
|
33
23
|
|
34
24
|
def load_data(records, loader)
|
35
|
-
# It may happen that same record comes here twice (e.g. wrapped
|
36
|
-
# in a decorator and non-wrapped). In this case Associations::Preloader
|
37
|
-
# stores duplicated records in has_many relationships for some reason.
|
38
|
-
# Calling uniq(&:id) solves the problem.
|
39
|
-
records_to_preload = records.uniq(&:id)
|
40
|
-
|
41
25
|
::ActiveRecord::Associations::Preloader.new.preload(
|
42
|
-
records_to_preload, association_name
|
26
|
+
records_to_preload(records), association_name
|
43
27
|
)
|
44
28
|
|
45
29
|
data = []
|
@@ -52,8 +36,18 @@ module AmsLazyRelationships
|
|
52
36
|
data = data.flatten.compact.uniq
|
53
37
|
end
|
54
38
|
|
55
|
-
def batch_key
|
56
|
-
"#{model_class_name}/#{association_name}"
|
39
|
+
def batch_key(_)
|
40
|
+
@batch_key ||= "#{model_class_name}/#{association_name}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def records_to_preload(records)
|
44
|
+
# It may happen that same record comes here twice (e.g. wrapped
|
45
|
+
# in a decorator and non-wrapped). In this case Associations::Preloader
|
46
|
+
# stores duplicated records in has_many relationships for some reason.
|
47
|
+
# Calling uniq(&:id) solves the problem.
|
48
|
+
records.uniq(&:id).reject do |r|
|
49
|
+
r.association(association_name).loaded?
|
50
|
+
end
|
57
51
|
end
|
58
52
|
end
|
59
53
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AmsLazyRelationships
|
4
|
+
module Loaders
|
5
|
+
# A base class for all the loaders. A correctly defined loader requires
|
6
|
+
# the `load_data` and `batch_key` methods.
|
7
|
+
class Base
|
8
|
+
# Lazy loads and yields the data when evaluating
|
9
|
+
# @param record [Object] an object for which we're loading the data
|
10
|
+
# @param block [Proc] a block to execute when data is evaluated.
|
11
|
+
# Loaded data is yielded as a block argument.
|
12
|
+
def load(record, &block)
|
13
|
+
BatchLoader.for(record).batch(
|
14
|
+
key: batch_key(record),
|
15
|
+
# Replacing methods can be costly, especially on objects with lots
|
16
|
+
# of methods (like AR methods). Let's disable it.
|
17
|
+
# More info:
|
18
|
+
# https://github.com/exAspArk/batch-loader/tree/v1.4.1#replacing-methods
|
19
|
+
replace_methods: false
|
20
|
+
) do |records, loader|
|
21
|
+
data = load_data(records, loader)
|
22
|
+
|
23
|
+
block&.call(data)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
# Loads required data for all records gathered by the batch loader.
|
30
|
+
# Assigns data to records by calling the `loader` lambda.
|
31
|
+
# @param records [Array<Object>] Array of all gathered records.
|
32
|
+
# @param loader [Proc] Proc used for assigning the batch loaded data to
|
33
|
+
# records. First argument is the record and the second is the data
|
34
|
+
# loaded for it.
|
35
|
+
# @returns [Array<Object>] Array of loaded objects
|
36
|
+
def load_data(_records, _loader)
|
37
|
+
raise "Implement in child"
|
38
|
+
end
|
39
|
+
|
40
|
+
# Computes a batching key based on currently evaluated record
|
41
|
+
# @param record [Object]
|
42
|
+
# @returns [String] Batching key
|
43
|
+
def batch_key(_record)
|
44
|
+
raise "Implement in child"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -1,9 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "ams_lazy_relationships/loaders/base"
|
4
|
+
|
3
5
|
module AmsLazyRelationships
|
4
6
|
module Loaders
|
5
7
|
# Lazy loads data in a "dumb" way - just executes the provided block when needed
|
6
|
-
class Direct
|
8
|
+
class Direct < Base
|
7
9
|
# @param relationship_name [Symbol] used for building cache key. Also if the
|
8
10
|
# `load_block` param is `nil` the loader will just call `relationship_name`
|
9
11
|
# method on the record being processed.
|
@@ -14,30 +16,22 @@ module AmsLazyRelationships
|
|
14
16
|
@load_block = load_block
|
15
17
|
end
|
16
18
|
|
17
|
-
# Lazy loads and yields the data when evaluating
|
18
|
-
# @param record [Object] an object for which we're loading the data
|
19
|
-
# @param block [Proc] a block to execute when data is evaluated.
|
20
|
-
# Loaded data is yielded as a block argument.
|
21
|
-
def load(record, &block)
|
22
|
-
BatchLoader.for(record).batch(key: cache_key(record), replace_methods: false) do |records, loader|
|
23
|
-
data = []
|
24
|
-
records.each do |r|
|
25
|
-
value = calculate_value(r)
|
26
|
-
data << value
|
27
|
-
loader.call(r, value)
|
28
|
-
end
|
29
|
-
|
30
|
-
data = data.flatten.compact.uniq
|
31
|
-
|
32
|
-
block&.call(data)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
19
|
private
|
37
20
|
|
38
21
|
attr_reader :relationship_name, :load_block
|
39
22
|
|
40
|
-
def
|
23
|
+
def load_data(records, loader)
|
24
|
+
data = []
|
25
|
+
records.each do |r|
|
26
|
+
value = calculate_value(r)
|
27
|
+
data << value
|
28
|
+
loader.call(r, value)
|
29
|
+
end
|
30
|
+
|
31
|
+
data = data.flatten.compact.uniq
|
32
|
+
end
|
33
|
+
|
34
|
+
def batch_key(record)
|
41
35
|
"#{record.class}/#{relationship_name}"
|
42
36
|
end
|
43
37
|
|
@@ -1,10 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "ams_lazy_relationships/loaders/base"
|
4
|
+
|
3
5
|
module AmsLazyRelationships
|
4
6
|
module Loaders
|
5
7
|
# Batch loads parent ActiveRecord records for given record by foreign key.
|
6
8
|
# Useful when the relationship is not a standard ActiveRecord relationship.
|
7
|
-
class SimpleBelongsTo
|
9
|
+
class SimpleBelongsTo < Base
|
8
10
|
# @param association_class_name [String] The name of AR class being the parent
|
9
11
|
# record of the records being loaded. E.g. When loading comment.blog_post
|
10
12
|
# it'd be "BlogPost".
|
@@ -18,25 +20,11 @@ module AmsLazyRelationships
|
|
18
20
|
@foreign_key = foreign_key.to_sym
|
19
21
|
end
|
20
22
|
|
21
|
-
# Lazy loads and yields the data when evaluating
|
22
|
-
# @param record [Object] an object for which we're loading the belongs to data
|
23
|
-
# @param block [Proc] a block to execute when data is evaluated
|
24
|
-
# Loaded data is yielded as a block argument.
|
25
|
-
def load(record, &block)
|
26
|
-
BatchLoader.for(record).batch(key: cache_key(record), replace_methods: false) do |records, loader|
|
27
|
-
data = load_data(records)
|
28
|
-
|
29
|
-
block&.call(data)
|
30
|
-
|
31
|
-
resolve(records, data, loader)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
23
|
private
|
36
24
|
|
37
25
|
attr_reader :association_class_name, :foreign_key
|
38
26
|
|
39
|
-
def load_data(records)
|
27
|
+
def load_data(records, loader)
|
40
28
|
data_ids = records.map(&foreign_key).compact.uniq
|
41
29
|
data = if data_ids.present?
|
42
30
|
association_class_name.constantize.where(id: data_ids)
|
@@ -44,6 +32,8 @@ module AmsLazyRelationships
|
|
44
32
|
[]
|
45
33
|
end
|
46
34
|
|
35
|
+
resolve(records, data, loader)
|
36
|
+
|
47
37
|
data
|
48
38
|
end
|
49
39
|
|
@@ -56,7 +46,7 @@ module AmsLazyRelationships
|
|
56
46
|
end
|
57
47
|
end
|
58
48
|
|
59
|
-
def
|
49
|
+
def batch_key(record)
|
60
50
|
"#{record.class}/#{association_class_name}"
|
61
51
|
end
|
62
52
|
end
|
@@ -1,10 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "ams_lazy_relationships/loaders/base"
|
4
|
+
|
3
5
|
module AmsLazyRelationships
|
4
6
|
module Loaders
|
5
7
|
# Batch loads ActiveRecord records belonging to given record by foreign key.
|
6
8
|
# Useful when the relationship is not a standard ActiveRecord relationship.
|
7
|
-
class SimpleHasMany
|
9
|
+
class SimpleHasMany < Base
|
8
10
|
# @param association_class_name [String] Name of the ActiveRecord class
|
9
11
|
# e.g. in case when loading blog_post.comments it'd be "Comment"
|
10
12
|
# @param foreign_key [Symbol] association's foreign key.
|
@@ -14,31 +16,18 @@ module AmsLazyRelationships
|
|
14
16
|
@foreign_key = foreign_key.to_sym
|
15
17
|
end
|
16
18
|
|
17
|
-
# Lazy loads and yields the data when evaluating
|
18
|
-
# @param record [Object] an object for which we're loading the has many data
|
19
|
-
# @param block [Proc] a block to execute when data is evaluated.
|
20
|
-
# Loaded data is yielded as a block argument.
|
21
|
-
def load(record, &block)
|
22
|
-
key = "#{record.class}/#{association_class_name}"
|
23
|
-
BatchLoader.for(record).batch(key: key, replace_methods: false) do |records, loader|
|
24
|
-
data = load_data(records)
|
25
|
-
|
26
|
-
block&.call(data)
|
27
|
-
|
28
|
-
resolve(records, data, loader)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
19
|
private
|
33
20
|
|
34
21
|
attr_reader :association_class_name, :foreign_key
|
35
22
|
|
36
|
-
def load_data(records)
|
23
|
+
def load_data(records, loader)
|
37
24
|
# Some records use UUID class as id - it's safer to cast them to strings
|
38
25
|
record_ids = records.map { |r| r.id.to_s }
|
39
26
|
association_class_name.constantize.where(
|
40
27
|
foreign_key => record_ids
|
41
|
-
)
|
28
|
+
).tap do |data|
|
29
|
+
resolve(records, data, loader)
|
30
|
+
end
|
42
31
|
end
|
43
32
|
|
44
33
|
def resolve(records, data, loader)
|
@@ -48,6 +37,10 @@ module AmsLazyRelationships
|
|
48
37
|
loader.call(r, data[r.id.to_s] || [])
|
49
38
|
end
|
50
39
|
end
|
40
|
+
|
41
|
+
def batch_key(record)
|
42
|
+
"#{record.class}/#{association_class_name}"
|
43
|
+
end
|
51
44
|
end
|
52
45
|
end
|
53
46
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ams_lazy_relationships
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Bajena
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-01-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: active_model_serializers
|
@@ -66,20 +66,6 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: bundler
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - "~>"
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '1.17'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - "~>"
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '1.17'
|
83
69
|
- !ruby/object:Gem::Dependency
|
84
70
|
name: db-query-matchers
|
85
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -238,16 +224,16 @@ dependencies:
|
|
238
224
|
name: sqlite3
|
239
225
|
requirement: !ruby/object:Gem::Requirement
|
240
226
|
requirements:
|
241
|
-
- - "
|
227
|
+
- - ">="
|
242
228
|
- !ruby/object:Gem::Version
|
243
|
-
version:
|
229
|
+
version: '0'
|
244
230
|
type: :development
|
245
231
|
prerelease: false
|
246
232
|
version_requirements: !ruby/object:Gem::Requirement
|
247
233
|
requirements:
|
248
|
-
- - "
|
234
|
+
- - ">="
|
249
235
|
- !ruby/object:Gem::Version
|
250
|
-
version:
|
236
|
+
version: '0'
|
251
237
|
- !ruby/object:Gem::Dependency
|
252
238
|
name: undercover
|
253
239
|
requirement: !ruby/object:Gem::Requirement
|
@@ -325,6 +311,7 @@ files:
|
|
325
311
|
- lib/ams_lazy_relationships/core/relationship_wrapper_methods.rb
|
326
312
|
- lib/ams_lazy_relationships/loaders.rb
|
327
313
|
- lib/ams_lazy_relationships/loaders/association.rb
|
314
|
+
- lib/ams_lazy_relationships/loaders/base.rb
|
328
315
|
- lib/ams_lazy_relationships/loaders/direct.rb
|
329
316
|
- lib/ams_lazy_relationships/loaders/simple_belongs_to.rb
|
330
317
|
- lib/ams_lazy_relationships/loaders/simple_has_many.rb
|
@@ -351,8 +338,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
351
338
|
- !ruby/object:Gem::Version
|
352
339
|
version: '0'
|
353
340
|
requirements: []
|
354
|
-
|
355
|
-
rubygems_version: 2.5.2.3
|
341
|
+
rubygems_version: 3.0.6
|
356
342
|
signing_key:
|
357
343
|
specification_version: 4
|
358
344
|
summary: ActiveModel Serializers addon for eliminating N+1 queries problem from the
|