n1_loader 1.2.0 → 1.3.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: 8b9b61121f94d9dba30e969c1b9a3fa9c812292d618434a98262c90aef43e6cd
4
- data.tar.gz: a1ecf5359a1a53200e354b30289566a437cf372c54ccf3f13c2e0adc2cb71640
3
+ metadata.gz: cc47894a27d425f70a38dc43b9b40053d823f4815fe8e135a7cb1cf5afbde0f3
4
+ data.tar.gz: 132d5851c19763db2f1910ebeeb6a368437aba6d3340c2c69ad2ffe348791011
5
5
  SHA512:
6
- metadata.gz: 5c545cc2033dc8e75edddd5c948eed78fc1d965464522147841d30e3c6a02aebb0b6758d3f801b020c25d62618f7ae4bbb7ff11441748f798546351b1bf34d85
7
- data.tar.gz: a60fa813399debf1ae9c8f839272a683c2a7f733ea392b4b1bd4169af55369a1d3be2fd8648a548e50093005e3d2df962437adf08f1f9fdf1338fa4ab6217df7
6
+ metadata.gz: 945258069b57bc7cd0fe26416411322886d734db0ed4eead1c88a3acced70bdb14ffc92eb9403e5d346c0853d64dc09e5afb8039a9026c9b4c09a1cc6f5fc9e8
7
+ data.tar.gz: 036e5a8a4b2d63bed2aee558164fdd042ac8c0c68b0ecdb1d5ec9f64231ca9f6841dc56cd6cdc63b87fdb9bf964e4f42089f89d9783cf2513cf81243a473150a
data/CHANGELOG.md CHANGED
@@ -1,4 +1,12 @@
1
- ## [1.2.0]
1
+ ## [1.3.0] - 2022-02-22
2
+
3
+ - add support of named arguments with `argument <name>`
4
+
5
+ BREAKING CHANGES:
6
+ - rename `n1_load` to `n1_optimized`
7
+ - rework `def self.arguments_key` to `cache_key`
8
+
9
+ ## [1.2.0] - 2022-01-14
2
10
 
3
11
  - Introduce arguments support.
4
12
 
data/README.md CHANGED
@@ -45,7 +45,7 @@ class User
45
45
  include N1Loader::Loadable
46
46
 
47
47
  # with inline loader
48
- n1_loader :orders_count do |users|
48
+ n1_optimized :orders_count do |users|
49
49
  orders_per_user = Order.where(user: users).group(:user_id).count
50
50
 
51
51
  users.each { |user| fulfill(user, orders_per_user[user.id]) }
@@ -69,7 +69,7 @@ class User
69
69
  include N1Loader::Loadable
70
70
 
71
71
  # with inline loader
72
- n1_loader :orders_count do |users|
72
+ n1_optimized :orders_count do |users|
73
73
  orders_per_user = Order.where(user: users).group(:user_id).count
74
74
 
75
75
  users.each { |user| fulfill(user, orders_per_user[user.id]) }
@@ -98,14 +98,14 @@ end
98
98
 
99
99
  class User
100
100
  include N1Loader::Loadable
101
-
102
- n1_loader :orders_count, OrdersCountLoader
101
+
102
+ n1_optimized :orders_count, OrdersCountLoader
103
103
  end
104
104
 
105
105
  class Customer
106
106
  include N1Loader::Loadable
107
-
108
- n1_loader :orders_count, OrdersCountLoader
107
+
108
+ n1_optimized :orders_count, OrdersCountLoader
109
109
  end
110
110
 
111
111
  User.new.orders_count # => works
@@ -119,7 +119,7 @@ class User
119
119
  include N1Loader::Loadable
120
120
 
121
121
  # with inline loader
122
- n1_loader :orders_count do |users|
122
+ n1_optimized :orders_count do |users|
123
123
  orders_per_user = Order.where(user: users).group(:user_id).count
124
124
 
125
125
  users.each { |user| fulfill(user, orders_per_user[user.id]) }
@@ -159,8 +159,8 @@ end
159
159
  ```ruby
160
160
  class User
161
161
  include N1Loader::Loadable
162
-
163
- n1_loader :orders_count do # no arguments passed to the block, so we can override both perform and single.
162
+
163
+ n1_optimized :orders_count do # no arguments passed to the block, so we can override both perform and single.
164
164
  def perform(users)
165
165
  orders_per_user = Order.where(user: users).group(:user_id).count
166
166
 
@@ -188,7 +188,7 @@ users.map(&:orders_count) # perform will be used once without N+1
188
188
  class User
189
189
  include N1Loader::Loadable
190
190
 
191
- n1_loader :orders_count do |users, type|
191
+ n1_optimized :orders_count do |users, type|
192
192
  orders_per_user = Order.where(type: type, user: users).group(:user_id).count
193
193
 
194
194
  users.each { |user| fulfill(user, orders_per_user[user.id]) }
@@ -212,16 +212,16 @@ you may want to override it, for example:
212
212
  class User
213
213
  include N1Loader::Loadable
214
214
 
215
- n1_loader :orders_count do
215
+ n1_optimized :orders_count do
216
+ argument :sale
217
+
218
+ cache_key { sale.id }
219
+
216
220
  def perform(users, sale)
217
221
  orders_per_user = Order.where(sale: sale, user: users).group(:user_id).count
218
222
 
219
223
  users.each { |user| fulfill(user, orders_per_user[user.id]) }
220
224
  end
221
-
222
- def self.arguments_key(sale)
223
- sale.id
224
- end
225
225
  end
226
226
  end
227
227
 
@@ -235,11 +235,13 @@ user.orders_count(Sale.first) # the cached value will be returned
235
235
 
236
236
  ### [ActiveRecord][5]
237
237
 
238
+ _Note_: Rails 7 support is coming soon! Stay tuned!
239
+
238
240
  ```ruby
239
241
  class User < ActiveRecord::Base
240
242
  include N1Loader::Loadable
241
-
242
- n1_loader :orders_count do |users|
243
+
244
+ n1_optimized :orders_count do |users|
243
245
  orders_per_user = Order.where(user: users).group(:user_id).count
244
246
 
245
247
  users.each { |user| fulfill(user, orders_per_user[user.id]) }
@@ -266,8 +268,8 @@ users.map(&:orders_count)
266
268
  ```ruby
267
269
  class User < ActiveRecord::Base
268
270
  include N1Loader::Loadable
269
-
270
- n1_loader :orders_count do |users|
271
+
272
+ n1_optimized :orders_count do |users|
271
273
  orders_per_user = Order.where(user: users).group(:user_id).count
272
274
 
273
275
  users.each { |user| fulfill(user, orders_per_user[user.id]) }
@@ -4,7 +4,7 @@ module N1Loader
4
4
  module ArLazyPreload
5
5
  module Loadable
6
6
  module ClassMethods # :nodoc:
7
- def n1_load(name, loader = nil, &block)
7
+ def n1_optimized(name, loader = nil, &block)
8
8
  name, loader_name, loader_variable_name = super
9
9
 
10
10
  define_method(loader_name) do
@@ -45,7 +45,7 @@ module N1Loader
45
45
  respond_to?("#{name}_loader")
46
46
  end
47
47
 
48
- def n1_load(name, loader = nil, &block) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
48
+ def n1_optimized(name, loader = nil, &block) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
49
49
  loader ||= Class.new(N1Loader::Loader) do
50
50
  if block&.arity&.positive?
51
51
  define_method(:perform, &block)
@@ -6,8 +6,27 @@ module N1Loader
6
6
  # Subclasses must define +perform+ method that accepts single argument
7
7
  # and returns hash where key is the element and value is what we want to load.
8
8
  class Loader
9
- def self.arguments_key(*args)
10
- args.map(&:object_id)
9
+ class << self
10
+ attr_reader :arguments
11
+
12
+ # Defines an argument that can be accessed within the loader.
13
+ #
14
+ # First defined argument will have the value of first passed argument,
15
+ # meaning the order is important.
16
+ def argument(name)
17
+ @arguments ||= []
18
+ index = @arguments.size
19
+ define_method(name) { args[index] }
20
+ @arguments << name
21
+ end
22
+
23
+ # Defines a custom cache key that is calculated for passed arguments.
24
+ def cache_key(&block)
25
+ define_method(:cache_key) do
26
+ check_arguments!
27
+ instance_exec(&block)
28
+ end
29
+ end
11
30
  end
12
31
 
13
32
  def initialize(elements, *args)
@@ -24,10 +43,21 @@ module N1Loader
24
43
  loaded[element]
25
44
  end
26
45
 
46
+ def cache_key
47
+ args.map(&:object_id)
48
+ end
49
+
27
50
  private
28
51
 
29
52
  attr_reader :elements, :args
30
53
 
54
+ def check_arguments!
55
+ return unless (required = self.class.arguments)
56
+ return if required.size == args.size
57
+
58
+ raise MissingArgument, "Loader defined #{required.size} arguments but #{args.size} were given"
59
+ end
60
+
31
61
  def perform(_elements)
32
62
  raise NotImplemented, "Subclasses have to implement the method"
33
63
  end
@@ -36,9 +66,11 @@ module N1Loader
36
66
  @loaded[element] = value
37
67
  end
38
68
 
39
- def loaded
69
+ def loaded # rubocop:disable Metrics/AbcSize
40
70
  return @loaded if @loaded
41
71
 
72
+ check_arguments!
73
+
42
74
  @loaded = {}.compare_by_identity
43
75
 
44
76
  if elements.size == 1 && respond_to?(:single)
@@ -11,7 +11,9 @@ module N1Loader
11
11
  end
12
12
 
13
13
  def with(*args)
14
- loaders[loader_class.arguments_key(*args)] ||= loader_class.new(elements, *args)
14
+ loader = loader_class.new(elements, *args)
15
+
16
+ loaders[loader.cache_key] ||= loader
15
17
  end
16
18
 
17
19
  private
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module N1Loader
4
- VERSION = "1.2.0"
4
+ VERSION = "1.3.0"
5
5
  end
data/lib/n1_loader.rb CHANGED
@@ -12,4 +12,5 @@ module N1Loader # :nodoc:
12
12
  class NotImplemented < Error; end
13
13
  class NotLoaded < Error; end
14
14
  class NotFilled < Error; end
15
+ class MissingArgument < Error; end
15
16
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: n1_loader
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evgeniy Demin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-14 00:00:00.000000000 Z
11
+ date: 2022-02-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord