ii_finder 1.1.2 → 1.2.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: 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