active_record_custom_preloader 0.3.0 → 0.4.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
  SHA1:
3
- metadata.gz: 99ce25238e6af5cdf1e5ded9fb5a20cb538eea30
4
- data.tar.gz: 6e51a7f912349423c01112afd78b06f0a59806a4
3
+ metadata.gz: ea88d7f2390b0e45e10bd34521c31856bc6ef72f
4
+ data.tar.gz: 465b71a9c3155369e73188a617bbaadad847322a
5
5
  SHA512:
6
- metadata.gz: 4f732ec7ac341a988cfbe4163211a0f85176980c31b9581641d5ad9ace75f045a9f021837f2329e7dd7c0748ee97b132825ddc4364066878f319e49dcf152cc1
7
- data.tar.gz: af9a8f4e709aac03f81b250ac96a4f61289c640e59127dfd5a092a81805e5ffa82ba8c24e77c49b59ffca9aa9a369c94d77f4019e2d0e80bdb349237aa2ef120
6
+ metadata.gz: 57180386f8368ab09c39033d093a8952de62143dd81d98d62c37c355c75e098b27a24684f70fcfb4802d1ee7d09d29ada1ccfde0ee27acb25b9e028e2828d741
7
+ data.tar.gz: 8ce168e2bcc13fe4dee152d6727103eddb57c67c601e7f4daa0904f795c8db257ce3286d2f56741c3c9e48fbb1c9b4f0314554eadb8048a71fefa7f85d98f7ac
data/README.md CHANGED
@@ -31,6 +31,8 @@ Or install it yourself as:
31
31
  ## Usage
32
32
 
33
33
  ```ruby
34
+ require 'active_record_custom_preloader/railtie'
35
+
34
36
  class Person < ActiveRecord::Base
35
37
  add_custom_loader :_stats, class_name: 'StatsPreloader'
36
38
  end
@@ -59,6 +61,67 @@ person.clear_custom_preloaded_value(:_stats) # will clear preloaded value for _s
59
61
  person._stats # will preload again and return value
60
62
  ```
61
63
 
64
+ you can use `ActiveRecordCustomPreloader::WithMultipleForeignKeysLoading` module
65
+ for preloading active_record models which are related to parent record by multiple keys
66
+ ```ruby
67
+ require 'active_record_custom_preloader/railtie'
68
+
69
+ class Employee < ActiveRecord::Base
70
+ # columns: id, name, department_id, position_id
71
+ add_custom_loader :_contract, class_name: 'EmployeeContractPreloader'
72
+ end
73
+
74
+ class Contract < ActiveRecord::Base
75
+ # columns: id, text, employee_department_id, position_id
76
+ end
77
+
78
+ class EmployeeContractPreloader < ActiveRecordCustomPreloader::Preloader
79
+ include ActiveRecordCustomPreloader::WithMultipleForeignKeysLoading
80
+ self.model_class_name = 'Contract'
81
+ self.association_foreign_keys_names = [:employee_department_id, :position_id]
82
+
83
+ def record_foreign_keys(record)
84
+ [record.department_id, record.position_id]
85
+ end
86
+ end
87
+ ```
88
+
89
+ also you can use `ActiveRecordCustomPreloader::WithContextDependentLoading` module
90
+ for preloading active_record models which should be filtered by some external context
91
+ ```ruby
92
+ require 'active_record_custom_preloader/railtie'
93
+
94
+ class User < ActiveRecord::Base
95
+ # columns: id, name, pricelist_id
96
+ end
97
+
98
+ class Discount < ActiveRecord::Base
99
+ # columns id, user_pricelist_id, product_id, percentage
100
+ end
101
+
102
+ class Product < ActiveRecord::Base
103
+ # columns: id, name, price
104
+ add_loader :_discount, class_name: 'ProductDiscountPreloader'
105
+ end
106
+
107
+ class ProductDiscountPreloader < ActiveRecordCustomPreloader::Preloader
108
+ include ActiveRecordCustomPreloader::WithContextDependentLoading
109
+ self.to_many = true
110
+ self.association_group_key = :user_pricelist_id
111
+ self.record_group_key = :pricelist_id
112
+
113
+ def scoped_collection(records)
114
+ product_ids = records.map(&:id)
115
+ pricelist_id = args.fetch(:pricelist_id)
116
+ Discount.where(user_pricelist_id: pricelist_id, product_id: product_ids)
117
+ end
118
+ end
119
+
120
+ user = User.first
121
+ products = Product.limit(10).custom_preload(:_discount, pricelist_id: user.pricelist_id)
122
+ products.first._discount # will return array with zero or more Discount records
123
+ ```
124
+
62
125
  ## Development
63
126
 
64
127
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -75,4 +138,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
75
138
 
76
139
  ## Code of Conduct
77
140
 
78
- Everyone interacting in the ActiveRecordCustomPreloader project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/active_record_custom_preloader/blob/master/CODE_OF_CONDUCT.md).
141
+ Everyone interacting in the ActiveRecordCustomPreloader project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/senid231/active_record_custom_preloader/blob/master/CODE_OF_CONDUCT.md).
@@ -12,5 +12,44 @@ module ActiveRecordCustomPreloader
12
12
  ActiveRecordCustomPreloader::AssociationsPreloader.new
13
13
  end
14
14
  end
15
+
16
+ # custom preload with optional args
17
+ # usage:
18
+ #
19
+ # class IncomingStatisticPreloader < ActiveRecordCustomPreloader::Preloader
20
+ # def preload(records)
21
+ # StatsApi.fetch(:incoming, group_by: args.fetch(:group_by))
22
+ # end
23
+ # end
24
+ #
25
+ # class OutgoingStatisticPreloader < ActiveRecordCustomPreloader::Preloader
26
+ # def preload(records)
27
+ # ids = records.map(&:id)
28
+ # api_result = StatsApi.fetch(:incoming, person_ids: ids, group: args.fetch(:group))
29
+ # values = api_result.group_by(&:person_id)
30
+ # records.each do |record|
31
+ # value = values[record.id] || []
32
+ # record._set_custom_preloaded_value(name, value)
33
+ # end
34
+ # end
35
+ # end
36
+ #
37
+ # class Person < ActiveRecord::Base
38
+ # add_loader :_incoming_stats, class_name: 'IncomingStatisticPreloader'
39
+ # add_loader :_outgoing_stats, class_name: 'OutgoingStatisticPreloader'
40
+ # end
41
+ #
42
+ # Person.limit(10).custom_preload(:_incoming_stats, :_outgoing_stats, group: 'hour')
43
+ # # is syntax sugar for
44
+ # Person.limit(10).preload(
45
+ # ActiveRecordCustomPreloader::PreloadWithOptions.new(:_incoming_stats, group: 'hour'),
46
+ # ActiveRecordCustomPreloader::PreloadWithOptions.new(:_outgoing_stats, group: 'hour')
47
+ # )
48
+ #
49
+ def custom_preload(*names)
50
+ args = names.extract_options!
51
+ preloads = names.map { |name| PreloadWithOptions.new(name, args) }
52
+ preload(*preloads)
53
+ end
15
54
  end
16
55
  end
@@ -1,3 +1,3 @@
1
1
  module ActiveRecordCustomPreloader
2
- VERSION = '0.3.0'
2
+ VERSION = '0.4.0'
3
3
  end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+ require 'active_support/concern'
3
+
4
+ # Usage example:
5
+ #
6
+ # class User < ApplicationRecord
7
+ # # columns: id, name, pricelist_id
8
+ # end
9
+ #
10
+ # class Pricelist < ApplicationRecord
11
+ # # columns: id, name
12
+ # end
13
+ #
14
+ # class Discount < ApplicationRecord
15
+ # # columns id, user_pricelist_id, product_id, percentage
16
+ # end
17
+ #
18
+ # class Product < ApplicationRecord
19
+ # # columns: id, name, price
20
+ # add_loader :_discount, class_name: 'ProductDiscountPreloader'
21
+ # end
22
+ #
23
+ # class ProductDiscountPreloader < ActiveRecordCustomPreloader::Preloader
24
+ # include ActiveRecordCustomPreloader::WithContextDependentLoading
25
+ # self.to_many = true
26
+ # self.association_group_key = :user_pricelist_id
27
+ # self.record_group_key = :pricelist_id
28
+ #
29
+ # def scoped_collection(records)
30
+ # product_ids = records.map(&:id)
31
+ # pricelist_id = args.fetch(:pricelist_id)
32
+ # Discount.where(user_pricelist_id: pricelist_id, product_id: product_ids)
33
+ # end
34
+ # end
35
+ #
36
+ # user = User.first
37
+ # products = Product.limit(10).custom_preload(:_discount, pricelist_id: user.pricelist_id)
38
+ # products.first._discount # will return array with zero or more Discount records
39
+ #
40
+ module ActiveRecordCustomPreloader
41
+ module WithContextDependentLoading
42
+ extend ActiveSupport::Concern
43
+
44
+ included do
45
+ # should be true for has_many and false for has_one.
46
+ # [optional] (default false)
47
+ class_attribute :to_many, instance_writer: false
48
+ self.to_many = false
49
+
50
+ # by this method association records will be grouped
51
+ # [required]
52
+ class_attribute :association_group_key, instance_writer: false
53
+
54
+ # by this method grouped association records will be matched with parent record
55
+ # [required]
56
+ class_attribute :record_group_key, instance_writer: false
57
+ end
58
+
59
+ # should return associations scope.
60
+ # must be overridden.
61
+ def scoped_collection(_parent_records)
62
+ raise NotImplementedError.new 'override #scoped_collection in a subclass'
63
+ end
64
+
65
+ # returns associations for provided parent_record.
66
+ # array for has_many and model or nil for has_one.
67
+ def associations_by_record(grouped_associations, parent_record)
68
+ key = parent_record.public_send(record_group_key)
69
+ associations = grouped_associations[key]
70
+ to_many ? associations || [] : associations&.first
71
+ end
72
+
73
+ def fetch_association(parent_records)
74
+ scope = scoped_collection(parent_records)
75
+ scope.to_a.group_by(&association_group_key)
76
+ end
77
+
78
+ def preload(parent_records)
79
+ grouped_associations = fetch_association(parent_records)
80
+ parent_records.each do |parent_record|
81
+ value = associations_by_record(grouped_associations, parent_record)
82
+ parent_record._set_custom_preloaded_value(name, value)
83
+ end
84
+ end
85
+
86
+ end
87
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_record_custom_preloader
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Talakevich
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-01-09 00:00:00.000000000 Z
11
+ date: 2019-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -105,6 +105,7 @@ files:
105
105
  - lib/active_record_custom_preloader/railtie.rb
106
106
  - lib/active_record_custom_preloader/relation_patch.rb
107
107
  - lib/active_record_custom_preloader/version.rb
108
+ - lib/active_record_custom_preloader/with_context_dependent_loading.rb
108
109
  - lib/active_record_custom_preloader/with_multiple_foreign_keys_loading.rb
109
110
  homepage: https://github.com/senid231/active_record_custom_preloader
110
111
  licenses: