ii_finder 1.1.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1e833c71166437a7e1f0881641850c3b2bc6f36f9c7827a2e18d0c63ba9d3e4b
4
- data.tar.gz: 6f653a027ee5947a6c7bbcd0ce3f76999513f334b79ebd5a8b12dc907961ea2f
3
+ metadata.gz: 2fbbf6a8d97c83f3d098f3b13d93039491698409623d0137e0b170c83dedd58d
4
+ data.tar.gz: 9619799961e2416db17aca506f6ef596acd621b3fc1339aa82679b779d3f79e8
5
5
  SHA512:
6
- metadata.gz: 1b861518b33b016ccc5795cd04c6c1677a159efd43eeb023bb00ae068b00cb2ca2820c0bf35c58b136cf6ee8392995b87b4a4d5e6e8bbfc5e09f1ab7e16a422c
7
- data.tar.gz: 443dc16e940192156b4af6af1747d9f81166455870ed50215a361c61b9e0535b6ae60e14a0824ae989be6cb141e844235cec5cfbb2b210e4923694b9e792cd73
6
+ metadata.gz: 577f3b00606d238e20a9d24075a92b9b5cdc10f170637e4e6bf6dc58db3bd04bf5de13a75da050af0b7a421d1dfe6bc91b4020188f38051394c39b81133b2fa0
7
+ data.tar.gz: abd2108a7892aa866ffc8d6a86545b61df42ce7b0c10af079e4272f5194e74be5f3c7146ed3ed671a96ea5eb6240edeabe77da8e51ab675b2a05427212bb2adf
data/CHANGELOG.md CHANGED
@@ -1,8 +1,12 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 1.2.0
4
+
5
+ * Add chain feature.
6
+
3
7
  ## 1.1.2
4
8
 
5
- Try fetch prior to calling instance method.
9
+ * Try fetch prior to calling instance method.
6
10
 
7
11
  ## 1.1.1
8
12
 
data/README.md CHANGED
@@ -24,14 +24,14 @@ Then execute:
24
24
  Prepare model:
25
25
 
26
26
  ```ruby
27
- class User < ActiveRecord::Base
27
+ class Item < ActiveRecord::Base
28
28
  end
29
29
  ```
30
30
 
31
31
  Prepare finder:
32
32
 
33
33
  ```ruby
34
- class UsersFinder < IIFinder::Base
34
+ class ItemsFinder < IIFinder::Base
35
35
  parameters :name
36
36
 
37
37
  def name(value)
@@ -43,15 +43,15 @@ end
43
43
  Use finder as follows:
44
44
 
45
45
  ```ruby
46
- UsersFinder.call(name: 'NAME').to_sql
47
- #=> SELECT "users".* FROM "users" WHERE "users"."name" = 'NAME'
46
+ ItemsFinder.call(name: 'NAME').to_sql
47
+ #=> SELECT "items".* FROM "items" WHERE "items"."name" = 'NAME'
48
48
  ```
49
49
 
50
50
  You can also specify relation as first argument:
51
51
 
52
52
  ```ruby
53
- UsersFinder.call(User.where(id: [1, 2, 3]), name: 'NAME').to_sql
54
- #=> SELECT "users".* FROM "users" WHERE "users"."id" IN (1, 2, 3) AND "users"."name" = 'NAME'
53
+ ItemsFinder.call(Item.where(id: [1, 2, 3]), name: 'NAME').to_sql
54
+ #=> SELECT "items".* FROM "items" WHERE "items"."id" IN (1, 2, 3) AND "items"."name" = 'NAME'
55
55
  ```
56
56
 
57
57
  ### Finder
@@ -61,7 +61,7 @@ Finder method will not be called when the value of parameter is blank.
61
61
  If you want to receive such value, set `allow_blank` as follows:
62
62
 
63
63
  ```ruby
64
- class UsersFinder < IIFinder::Base
64
+ class ItemsFinder < IIFinder::Base
65
65
  parameters :name, allow_blank: true
66
66
 
67
67
  def name(value)
@@ -69,14 +69,14 @@ class UsersFinder < IIFinder::Base
69
69
  end
70
70
  end
71
71
 
72
- UsersFinder.call(name: '').to_sql
73
- #=> SELECT "users".* FROM "users" WHERE "users"."name" = ''
72
+ ItemsFinder.call(name: '').to_sql
73
+ #=> SELECT "items".* FROM "items" WHERE "items"."name" = ''
74
74
  ```
75
75
 
76
76
  Finder has following attributes:
77
77
 
78
78
  ```ruby
79
- class UsersFinder < IIFinder::Base
79
+ class ItemsFinder < IIFinder::Base
80
80
  parameters :name
81
81
 
82
82
  def name(value)
@@ -87,10 +87,10 @@ class UsersFinder < IIFinder::Base
87
87
  end
88
88
  end
89
89
 
90
- UsersFinder.call(name: 'NAME')
91
- #=> relation: #<User::ActiveRecord_Relation:
90
+ ItemsFinder.call(name: 'NAME')
91
+ #=> relation: #<Item::ActiveRecord_Relation:
92
92
  # criteria: {:name=>'NAME'}
93
- # model: User
93
+ # model: Item
94
94
  # table: #<Arel::Table ...>
95
95
  ```
96
96
 
@@ -102,7 +102,7 @@ IIFinder.configure do |config|
102
102
  config.merge_relation = false
103
103
  end
104
104
 
105
- class UsersFinder < IIFinder::Base
105
+ class ItemsFinder < IIFinder::Base
106
106
  parameters :name
107
107
 
108
108
  def name(value)
@@ -110,8 +110,8 @@ class UsersFinder < IIFinder::Base
110
110
  end
111
111
  end
112
112
 
113
- UsersFinder.call(name: 'NAME').to_sql
114
- #=> SELECT "users".* FROM "users" WHERE "users"."name" = 'NAME'
113
+ ItemsFinder.call(name: 'NAME').to_sql
114
+ #=> SELECT "items".* FROM "items" WHERE "items"."name" = 'NAME'
115
115
  ```
116
116
 
117
117
  #### Callbacks
@@ -125,7 +125,7 @@ Following callbacks are available.
125
125
  For example:
126
126
 
127
127
  ```ruby
128
- class UsersFinder < IIFinder::Base
128
+ class ItemsFinder < IIFinder::Base
129
129
  after_call :default_order
130
130
 
131
131
  def default_order
@@ -133,14 +133,59 @@ class UsersFinder < IIFinder::Base
133
133
  end
134
134
  end
135
135
 
136
- UsersFinder.call.to_sql
137
- #=> SELECT "users".* FROM "users" ORDER BY "users"."id" DESC
136
+ ItemsFinder.call.to_sql
137
+ #=> SELECT "items".* FROM "items" ORDER BY "items"."id" DESC
138
138
  ```
139
139
 
140
140
  Note that finder does not handle the return value of callback.
141
141
  When you want to update `@relation` in the callback,
142
142
  reassign `@relation` or use methods like `where!` or `order!`.
143
143
 
144
+ #### Chain
145
+
146
+ You can chain multiple finders by using `chain`. For example:
147
+
148
+ ```ruby
149
+ class NameFinder < IIFinder::Base
150
+ parameters :name
151
+
152
+ def name(value)
153
+ @relation.where(name: value)
154
+ end
155
+ end
156
+
157
+ class AgeFinder < IIFinder::Base
158
+ parameters :age
159
+
160
+ def age(value)
161
+ @relation.where(age: value)
162
+ end
163
+ end
164
+
165
+ class ItemsFinder < IIFinder::Base
166
+ chain NameFinder, AgeFinder
167
+ end
168
+
169
+ ItemsFinder.call(Item.all, name: 'name', age: 10).to_sql
170
+ #=> SELECT "items".* FROM "items" WHERE "items"."name" = 'name' AND "items"."age" = 10
171
+ ```
172
+
173
+ You can also use method or block to find finder class dynamically:
174
+
175
+ ```ruby
176
+ class ItemFinder < IIFinder::Base
177
+ chain -> { NameFinder }
178
+ end
179
+
180
+ class ItemFinder < IIFinder::Base
181
+ chain :chain_finder
182
+
183
+ def chain_finder
184
+ NameFinder
185
+ end
186
+ end
187
+ ```
188
+
144
189
  ### Lookup for model
145
190
 
146
191
  Finder lookups related model by its class name when the first argument of `call` is not relation.
@@ -148,30 +193,30 @@ So the name of finder class should be composed of the name of model class.
148
193
  For example:
149
194
 
150
195
  ```ruby
151
- class User < ActiveRecord::Base
196
+ class Item < ActiveRecord::Base
152
197
  end
153
198
 
154
- class UsersFinder < IIFinder::Base
199
+ class ItemsFinder < IIFinder::Base
155
200
  end
156
201
 
157
- IIFinder::Base.lookup(UsersFinder)
158
- #=> User
202
+ IIFinder::Base.lookup(ItemsFinder)
203
+ #=> Item
159
204
  ```
160
205
 
161
206
  Note that superclass of finder is also looked up until related model is found.
162
207
 
163
208
  ```ruby
164
- class User < ActiveRecord::Base
209
+ class Item < ActiveRecord::Base
165
210
  end
166
211
 
167
- class UsersFinder < IIFinder::Base
212
+ class ItemsFinder < IIFinder::Base
168
213
  end
169
214
 
170
- class InheritedUsersFinder < UsersFinder
215
+ class InheritedItemsFinder < ItemsFinder
171
216
  end
172
217
 
173
- IIFinder::Base.lookup(InheritedUsersFinder)
174
- #=> User
218
+ IIFinder::Base.lookup(InheritedItemsFinder)
219
+ #=> Item
175
220
  ```
176
221
 
177
222
  ### Scope for model
@@ -179,12 +224,12 @@ IIFinder::Base.lookup(InheritedUsersFinder)
179
224
  In case you want to call finder from model, include `IIFinder::Scope` into model as follows:
180
225
 
181
226
  ```ruby
182
- class User < ActiveRecord::Base
227
+ class Item < ActiveRecord::Base
183
228
  include IIFinder::Scope
184
229
  end
185
230
 
186
- User.finder_scope(name: 'NAME').to_sql
187
- #=> SELECT "users".* FROM "users" WHERE "users"."name" = 'NAME'
231
+ Item.finder_scope(name: 'NAME').to_sql
232
+ #=> SELECT "items".* FROM "items" WHERE "items"."name" = 'NAME'
188
233
  ```
189
234
 
190
235
  ### Logging
@@ -199,7 +244,7 @@ IIFinder::LogSubscriber.attach_to :ii_finder
199
244
  This subscriber will write logs in debug mode as the following example:
200
245
 
201
246
  ```
202
- Called UsersFinder with {:id=>1} (Duration: 9.9ms, Allocations: 915)
247
+ Called ItemsFinder with {:id=>1} (Duration: 9.9ms, Allocations: 915)
203
248
  ```
204
249
 
205
250
  ## Contributing
@@ -5,6 +5,7 @@ require_relative 'parameters'
5
5
  require_relative 'callbacks'
6
6
  require_relative 'instrumentation'
7
7
  require_relative 'lookup'
8
+ require_relative 'chain'
8
9
 
9
10
  module IIFinder
10
11
  class Base
@@ -13,5 +14,6 @@ module IIFinder
13
14
  include Callbacks
14
15
  include Instrumentation
15
16
  include Lookup
17
+ include Chain
16
18
  end
17
19
  end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IIFinder
4
+ module Chain
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ class_attribute :_chains
9
+ self._chains = []
10
+ end
11
+
12
+ def call
13
+ lookup.each do |finder|
14
+ merge_relation!(finder.call(*@_args))
15
+ end
16
+ super
17
+ end
18
+
19
+ def lookup
20
+ self.class._chains.map do |finder|
21
+ if finder.is_a?(Symbol) && respond_to?(finder, true)
22
+ send(finder)
23
+ elsif finder.is_a?(Proc)
24
+ instance_exec(&finder)
25
+ else
26
+ finder
27
+ end
28
+ end.flatten.compact
29
+ end
30
+
31
+ class_methods do
32
+ def chain(*finders, &block)
33
+ self._chains = _chains + finders
34
+ self._chains << block if block
35
+ end
36
+ end
37
+ end
38
+ end
@@ -9,6 +9,7 @@ module IIFinder
9
9
  end
10
10
 
11
11
  def initialize(*args)
12
+ @_args = args;
12
13
  if args.size == 0 || args.size == 1
13
14
  @model = self.class.lookup
14
15
  raise IIFinder::Error.new("could not find model for #{self.class}") unless @model
@@ -26,7 +27,7 @@ module IIFinder
26
27
  self.class._parameters.each do |param|
27
28
  value = fetch_criteria(param.name)
28
29
  if value.present? || param.allow_blank?
29
- call_method(param.name, value)
30
+ merge_relation!(send(param.name, value))
30
31
  end
31
32
  end
32
33
 
@@ -41,11 +42,9 @@ module IIFinder
41
42
  end
42
43
  end
43
44
 
44
- def call_method(name, value)
45
- result = send(name, value)
46
-
47
- if result.respond_to?(:merge) && Config.merge_relation
48
- @relation = @relation.merge(result)
45
+ def merge_relation!(relation)
46
+ if relation.respond_to?(:merge) && Config.merge_relation
47
+ @relation = @relation.merge(relation)
49
48
  end
50
49
  end
51
50
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module IIFinder
4
- VERSION = '1.1.2'
4
+ VERSION = '1.2.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ii_finder
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yoshikazu Kaneta
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-08-25 00:00:00.000000000 Z
11
+ date: 2021-11-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -120,6 +120,7 @@ files:
120
120
  - lib/ii_finder.rb
121
121
  - lib/ii_finder/base.rb
122
122
  - lib/ii_finder/callbacks.rb
123
+ - lib/ii_finder/chain.rb
123
124
  - lib/ii_finder/config.rb
124
125
  - lib/ii_finder/core.rb
125
126
  - lib/ii_finder/errors.rb
@@ -148,7 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
148
149
  - !ruby/object:Gem::Version
149
150
  version: '0'
150
151
  requirements: []
151
- rubygems_version: 3.1.6
152
+ rubygems_version: 3.1.2
152
153
  signing_key:
153
154
  specification_version: 4
154
155
  summary: A base finder to support building relations from parameters