hoodoo 1.11.0 → 1.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/lib/hoodoo/active/active_record/finder.rb +16 -17
- data/lib/hoodoo/active/active_record/search_helper.rb +118 -29
- data/lib/hoodoo/active/active_record/support.rb +45 -0
- data/lib/hoodoo/client/paginated_enumeration.rb +1 -1
- data/lib/hoodoo/services/middleware/middleware.rb +85 -12
- data/lib/hoodoo/services/services/interface.rb +66 -8
- data/lib/hoodoo/version.rb +1 -1
- data/spec/active/active_record/finder_spec.rb +131 -11
- data/spec/active/active_record/search_helper_spec.rb +500 -273
- data/spec/active/active_record/support_spec.rb +22 -0
- data/spec/client/paginated_enumeration_spec.rb +41 -42
- data/spec/monkey/patch/newrelic_middleware_analytics_spec.rb +60 -0
- data/spec/monkey/patch/newrelic_traced_amqp_spec.rb +2 -2
- data/spec/new_relic/agent/method_tracer.rb +35 -0
- data/spec/services/middleware/middleware_spec.rb +74 -0
- data/spec/services/services/interface_spec.rb +26 -0
- metadata +43 -39
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
YWNkMjFhNmMwODQ2OGYxYjZmNDI1ZGIxZGJmNzg3YjQyY2I5ZDMxYw==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 30fd454d84a35502e8c324645a1c8c981521aa7e
|
4
|
+
data.tar.gz: fae766337e9034cf46e9c030c64d5d6ea0609827
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
ZGE3N2RhNWZlOGMwMDQ2MWVmNzNhMzQ3MWEwZTRiZDhjMjBkMDNjNDdhZjdh
|
11
|
-
ZjYxOGUwYTk1NDFlYTJmY2VhNGYxYWI5ODk5YzdmNDNkOThjYTE=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
MmQzNzQxZWI0OTQ2YjI2Nzg1ODAxMzA0ODVlNmM0ODRmMTE2YTY0YmEwYzA2
|
14
|
-
YTdjMzZkMTY4NWRlNjlmMzdhNTc1NDdiYWM4OTQ1YjNkNzQzNjYzZTlmNDFl
|
15
|
-
Nzc3Mzk5ZmFhMDIxOTk0NmY2MzIyMTc2MGQ2YjFlYWQ5MDQxMGQ=
|
6
|
+
metadata.gz: be4607dfff0f5f798b48eb83abbd3985562df696570137f1c7c9fa7fbaad5df227659c274c758c323fb12901365d665c9a1642d743c17103708cb1509b23db3f
|
7
|
+
data.tar.gz: 0c35e38a6740d1e689c361fcf2f0ab07bac09540eb46a9bb1d7ac2f3ab40319c3711b26741fe85c0836e5b1d277208c9c06152f3aa5369745c936714de7a4bf7
|
@@ -20,8 +20,8 @@ module Hoodoo
|
|
20
20
|
#
|
21
21
|
# It is _STRONGLY_ _RECOMMENDED_ that you use the likes of:
|
22
22
|
#
|
23
|
-
# * Hoodoo::ActiveRecord::Finder::ClassMethods
|
24
|
-
# * Hoodoo::ActiveRecord::Finder::ClassMethods
|
23
|
+
# * Hoodoo::ActiveRecord::Finder::ClassMethods#acquire_in
|
24
|
+
# * Hoodoo::ActiveRecord::Finder::ClassMethods#list_in
|
25
25
|
#
|
26
26
|
# ...to retrieve model data related to resource instances and participate
|
27
27
|
# "for free" in whatever plug-in ActiveRecord modules are mixed into the
|
@@ -428,20 +428,14 @@ module Hoodoo
|
|
428
428
|
finder = all.offset( list_parameters.offset ).limit( list_parameters.limit )
|
429
429
|
finder = finder.order( list_parameters.sort_data )
|
430
430
|
|
431
|
-
# DRY up the 'each' loops below. Use a Proc not a method because any
|
432
|
-
# methods we define will end up being defined on the including Model,
|
433
|
-
# increasing the chance of a name collision.
|
434
|
-
#
|
435
|
-
dry_proc = Proc.new do | data, attr, proc |
|
436
|
-
value = data[ attr ]
|
437
|
-
proc.call( attr, value ) unless value.nil?
|
438
|
-
end
|
439
|
-
|
440
431
|
search_map = self.nz_co_loyalty_hoodoo_search_with
|
441
432
|
|
442
433
|
unless search_map.nil?
|
443
|
-
search_map.each do | attr,
|
444
|
-
|
434
|
+
search_map.each do | attr, finder_args_proc |
|
435
|
+
value = list_parameters.search_data[ attr ]
|
436
|
+
next if value.nil?
|
437
|
+
|
438
|
+
args = finder_args_proc.call( attr, value )
|
445
439
|
finder = finder.where( *args ) unless args.nil?
|
446
440
|
end
|
447
441
|
end
|
@@ -449,8 +443,11 @@ module Hoodoo
|
|
449
443
|
filter_map = self.nz_co_loyalty_hoodoo_filter_with
|
450
444
|
|
451
445
|
unless filter_map.nil?
|
452
|
-
filter_map.each do | attr,
|
453
|
-
|
446
|
+
filter_map.each do | attr, finder_args_proc |
|
447
|
+
value = list_parameters.filter_data[ attr ]
|
448
|
+
next if value.nil?
|
449
|
+
|
450
|
+
args = finder_args_proc.call( attr, value )
|
454
451
|
finder = finder.where.not( *args ) unless args.nil?
|
455
452
|
end
|
456
453
|
end
|
@@ -714,7 +711,8 @@ module Hoodoo
|
|
714
711
|
# which assist with filling in non-nil values for this Hash.
|
715
712
|
#
|
716
713
|
def search_with( hash )
|
717
|
-
self.nz_co_loyalty_hoodoo_search_with
|
714
|
+
self.nz_co_loyalty_hoodoo_search_with ||= Hoodoo::ActiveRecord::Support.framework_search_and_filter_data()
|
715
|
+
self.nz_co_loyalty_hoodoo_search_with.merge!( Hoodoo::ActiveRecord::Support.process_to_map( hash ) )
|
718
716
|
end
|
719
717
|
|
720
718
|
# As #search_with, but used in +where.not+ queries.
|
@@ -735,7 +733,8 @@ module Hoodoo
|
|
735
733
|
# +map+:: As #search_with.
|
736
734
|
#
|
737
735
|
def filter_with( hash )
|
738
|
-
self.nz_co_loyalty_hoodoo_filter_with
|
736
|
+
self.nz_co_loyalty_hoodoo_filter_with ||= Hoodoo::ActiveRecord::Support.framework_search_and_filter_data()
|
737
|
+
self.nz_co_loyalty_hoodoo_filter_with.merge!( Hoodoo::ActiveRecord::Support.process_to_map( hash ) )
|
739
738
|
end
|
740
739
|
|
741
740
|
# Deprecated interface replaced by #acquire. Instead of:
|
@@ -14,8 +14,9 @@ module Hoodoo
|
|
14
14
|
module Finder
|
15
15
|
|
16
16
|
# Help build up Hash maps to pass into Hoodoo::ActiveRecord::Finder
|
17
|
-
# methods Hoodoo::ActiveRecord::Finder#search_with and
|
18
|
-
# Hoodoo::ActiveRecord::Finder#filter_with.
|
17
|
+
# methods Hoodoo::ActiveRecord::Finder::ClassMethods#search_with and
|
18
|
+
# Hoodoo::ActiveRecord::Finder::ClassMethods#filter_with. Used also
|
19
|
+
# by the default framework search scopes.
|
19
20
|
#
|
20
21
|
# The usage pattern is as follows, using "sh" as a local variable
|
21
22
|
# just for brevity - it isn't required:
|
@@ -31,7 +32,7 @@ module Hoodoo
|
|
31
32
|
# end
|
32
33
|
#
|
33
34
|
# The helper methods just provide values to pass into the Hash used
|
34
|
-
# with the search/
|
35
|
+
# with the search/filter Hoodoo::ActiveRecord::Finder methods, so
|
35
36
|
# they're optional and compatible with calls that write it out "by
|
36
37
|
# hand".
|
37
38
|
#
|
@@ -48,15 +49,16 @@ module Hoodoo
|
|
48
49
|
# will be case sensitive only if your database is configured for
|
49
50
|
# case sensitive matching by default.
|
50
51
|
#
|
51
|
-
# Results in a <tt>foo = bar</tt> query.
|
52
|
+
# Results in a <tt>foo = bar AND foo IS NOT NULL</tt> query.
|
52
53
|
#
|
53
54
|
# +model_field_name+:: If the model attribute name differs from the
|
54
55
|
# search key you want to use in the URI, give
|
55
56
|
# the model attribute name here, else omit.
|
56
57
|
#
|
57
58
|
# Returns a value that can be asssigned to a URI query string key in
|
58
|
-
# the Hash given to
|
59
|
-
# Hoodoo::ActiveRecord::Finder#
|
59
|
+
# the Hash given to
|
60
|
+
# Hoodoo::ActiveRecord::Finder::ClassMethods#search_with or
|
61
|
+
# Hoodoo::ActiveRecord::Finder::ClassMethods#filter_with.
|
60
62
|
#
|
61
63
|
def self.cs_match( model_field_name = nil )
|
62
64
|
Proc.new { | attr, value |
|
@@ -70,15 +72,17 @@ module Hoodoo
|
|
70
72
|
# which are split into an array then processed by AREL back to
|
71
73
|
# something SQL-safe.
|
72
74
|
#
|
73
|
-
# Results in a <tt>foo IN bar,baz,boo</tt>
|
75
|
+
# Results in a <tt>foo IN (bar,baz,boo) AND foo IS NOT NULL</tt>
|
76
|
+
# query.
|
74
77
|
#
|
75
78
|
# +model_field_name+:: If the model attribute name differs from the
|
76
79
|
# search key you want to use in the URI, give
|
77
80
|
# the model attribute name here, else omit.
|
78
81
|
#
|
79
82
|
# Returns a value that can be asssigned to a URI query string key in
|
80
|
-
# the Hash given to
|
81
|
-
# Hoodoo::ActiveRecord::Finder#
|
83
|
+
# the Hash given to
|
84
|
+
# Hoodoo::ActiveRecord::Finder::ClassMethods#search_with or
|
85
|
+
# Hoodoo::ActiveRecord::Finder::ClassMethods#filter_with.
|
82
86
|
#
|
83
87
|
def self.cs_match_csv( model_field_name = nil )
|
84
88
|
Proc.new { | attr, value |
|
@@ -92,17 +96,20 @@ module Hoodoo
|
|
92
96
|
# Case-sensitive match of a series of values given as an Array.
|
93
97
|
# Normally, query string information comes in as a String so the
|
94
98
|
# use cases for this are quite unusual; you probably want to use
|
95
|
-
#
|
99
|
+
# Hoodoo::ActiveRecord::Finder::SearchHelper::cs_match_csv most of
|
100
|
+
# the time.
|
96
101
|
#
|
97
|
-
# Results in a <tt>foo IN bar,baz,boo</tt>
|
102
|
+
# Results in a <tt>foo IN (bar,baz,boo) AND foo IS NOT NULL</tt>
|
103
|
+
# query.
|
98
104
|
#
|
99
105
|
# +model_field_name+:: If the model attribute name differs from the
|
100
106
|
# search key you want to use in the URI, give
|
101
107
|
# the model attribute name here, else omit.
|
102
108
|
#
|
103
109
|
# Returns a value that can be asssigned to a URI query string key in
|
104
|
-
# the Hash given to
|
105
|
-
# Hoodoo::ActiveRecord::Finder#
|
110
|
+
# the Hash given to
|
111
|
+
# Hoodoo::ActiveRecord::Finder::ClassMethods#search_with or
|
112
|
+
# Hoodoo::ActiveRecord::Finder::ClassMethods#filter_with.
|
106
113
|
#
|
107
114
|
def self.cs_match_array( model_field_name = nil )
|
108
115
|
Proc.new { | attr, value |
|
@@ -113,8 +120,11 @@ module Hoodoo
|
|
113
120
|
}
|
114
121
|
end
|
115
122
|
|
116
|
-
# As
|
117
|
-
# for a
|
123
|
+
# As Hoodoo::ActiveRecord::Finder::SearchHelper::cs_match, but
|
124
|
+
# adds wildcards at the front and end of the string for a
|
125
|
+
# case-sensitive-all-wildcard match.
|
126
|
+
#
|
127
|
+
# Results in a <tt>foo LIKE bar AND foo IS NOT NULL</tt> query.
|
118
128
|
#
|
119
129
|
def self.csaw_match( model_field_name = nil )
|
120
130
|
Proc.new { | attr, value |
|
@@ -127,19 +137,22 @@ module Hoodoo
|
|
127
137
|
|
128
138
|
# Case-insensitive match which should be fairly database independent
|
129
139
|
# but will run relatively slowly as a result. If you are using
|
130
|
-
# PostgreSQL, consider using the faster
|
140
|
+
# PostgreSQL, consider using the faster
|
141
|
+
# Hoodoo::ActiveRecord::Finder::SearchHelper::ci_match_postgres method
|
131
142
|
# instead.
|
132
143
|
#
|
133
|
-
# Results in a <tt>lower(foo) = bar</tt> query
|
134
|
-
# a String and converted to lower case by Ruby
|
144
|
+
# Results in a <tt>lower(foo) = bar AND foo IS NOT NULL</tt> query
|
145
|
+
# with +bar+ coerced to a String and converted to lower case by Ruby
|
146
|
+
# first.
|
135
147
|
#
|
136
148
|
# +model_field_name+:: If the model attribute name differs from the
|
137
149
|
# search key you want to use in the URI, give
|
138
150
|
# the model attribute name here, else omit.
|
139
151
|
#
|
140
152
|
# Returns a value that can be asssigned to a URI query string key in
|
141
|
-
# the Hash given to
|
142
|
-
# Hoodoo::ActiveRecord::Finder#
|
153
|
+
# the Hash given to
|
154
|
+
# Hoodoo::ActiveRecord::Finder::ClassMethods#search_with or
|
155
|
+
# Hoodoo::ActiveRecord::Finder::ClassMethods#filter_with.
|
143
156
|
#
|
144
157
|
def self.ci_match_generic( model_field_name = nil )
|
145
158
|
Proc.new { | attr, value |
|
@@ -150,8 +163,11 @@ module Hoodoo
|
|
150
163
|
}
|
151
164
|
end
|
152
165
|
|
153
|
-
# As
|
154
|
-
# the string for a
|
166
|
+
# As Hoodoo::ActiveRecord::Finder::SearchHelper::ci_match_generic,
|
167
|
+
# but adds wildcards at the front and end of the string for a
|
168
|
+
# case-insensitive-all-wildcard match.
|
169
|
+
#
|
170
|
+
# Results in a <tt>foo LIKE %bar% AND foo IS NOT NULL</tt> query.
|
155
171
|
#
|
156
172
|
def self.ciaw_match_generic( model_field_name = nil )
|
157
173
|
Proc.new { | attr, value |
|
@@ -164,17 +180,20 @@ module Hoodoo
|
|
164
180
|
|
165
181
|
# Case-insensitive match which requires PostgreSQL but should run
|
166
182
|
# quickly. If you need a database agnostic solution, consider using
|
167
|
-
# the slower
|
183
|
+
# the slower
|
184
|
+
# Hoodoo::ActiveRecord::Finder::SearchHelper::ci_match_generic method
|
185
|
+
# instead.
|
168
186
|
#
|
169
|
-
# Results in a <tt>foo ILIKE bar</tt> query.
|
187
|
+
# Results in a <tt>foo ILIKE bar AND foo IS NOT NULL</tt> query.
|
170
188
|
#
|
171
189
|
# +model_field_name+:: If the model attribute name differs from the
|
172
190
|
# search key you want to use in the URI, give
|
173
191
|
# the model attribute name here, else omit.
|
174
192
|
#
|
175
193
|
# Returns a value that can be asssigned to a URI query string key in
|
176
|
-
# the Hash given to
|
177
|
-
# Hoodoo::ActiveRecord::Finder#
|
194
|
+
# the Hash given to
|
195
|
+
# Hoodoo::ActiveRecord::Finder::ClassMethods#search_with or
|
196
|
+
# Hoodoo::ActiveRecord::Finder::ClassMethods#filter_with.
|
178
197
|
#
|
179
198
|
def self.ci_match_postgres( model_field_name = nil )
|
180
199
|
Proc.new { | attr, value |
|
@@ -184,8 +203,11 @@ module Hoodoo
|
|
184
203
|
}
|
185
204
|
end
|
186
205
|
|
187
|
-
# As
|
188
|
-
# the string for a
|
206
|
+
# As Hoodoo::ActiveRecord::Finder::SearchHelper::ci_match_postgres,
|
207
|
+
# but adds wildcards at the front and end of the string for a
|
208
|
+
# case-insensitive-all-wildcard match.
|
209
|
+
#
|
210
|
+
# Results in a <tt>foo ILIKE %bar% AND foo IS NOT NULL</tt> query.
|
189
211
|
#
|
190
212
|
def self.ciaw_match_postgres( model_field_name = nil )
|
191
213
|
Proc.new { | attr, value |
|
@@ -194,8 +216,75 @@ module Hoodoo
|
|
194
216
|
[ "#{ column } ILIKE ? AND #{ column } IS NOT NULL", "%#{ value }%" ]
|
195
217
|
}
|
196
218
|
end
|
197
|
-
end
|
198
219
|
|
220
|
+
# Case-sensitive less-than (default-style comparison). *WARNING:* This
|
221
|
+
# will be case sensitive only if your database is configured for
|
222
|
+
# case sensitive matching by default.
|
223
|
+
#
|
224
|
+
# If comparing non-string column types be sure to pass in a value of an
|
225
|
+
# appropriate matching type (e.g. compare dates with DateTimes), else
|
226
|
+
# returned results will be incorrect but errors may not arise depending
|
227
|
+
# on database engine in use.
|
228
|
+
#
|
229
|
+
# Results in a <tt>foo < bar AND foo IS NOT NULL</tt> query.
|
230
|
+
#
|
231
|
+
# +model_field_name+:: If the model attribute name differs from the
|
232
|
+
# search key you want to use in the URI, give
|
233
|
+
# the model attribute name here, else omit.
|
234
|
+
#
|
235
|
+
# Returns a value that can be asssigned to a URI query string key in
|
236
|
+
# the Hash given to
|
237
|
+
# Hoodoo::ActiveRecord::Finder::ClassMethods#search_with or
|
238
|
+
# Hoodoo::ActiveRecord::Finder::ClassMethods#filter_with.
|
239
|
+
#
|
240
|
+
def self.cs_lt( model_field_name = nil )
|
241
|
+
Proc.new { | attr, value |
|
242
|
+
column = model_field_name || attr
|
243
|
+
|
244
|
+
[ "#{ column } < ? AND #{ column } IS NOT NULL", value ]
|
245
|
+
}
|
246
|
+
end
|
247
|
+
|
248
|
+
# As Hoodoo::ActiveRecord::Finder::SearchHelper::cs_lt, but
|
249
|
+
# compares with less-than-or-equal-to.
|
250
|
+
#
|
251
|
+
# Results in a <tt>foo <= bar AND foo IS NOT NULL</tt> query.
|
252
|
+
#
|
253
|
+
def self.cs_lte( model_field_name = nil )
|
254
|
+
Proc.new { | attr, value |
|
255
|
+
column = model_field_name || attr
|
256
|
+
|
257
|
+
[ "#{ column } <= ? AND #{ column } IS NOT NULL", value ]
|
258
|
+
}
|
259
|
+
end
|
260
|
+
|
261
|
+
# As Hoodoo::ActiveRecord::Finder::SearchHelper::cs_lt, but
|
262
|
+
# compares with greater-than.
|
263
|
+
#
|
264
|
+
# Results in a <tt>foo > bar AND foo IS NOT NULL</tt> query.
|
265
|
+
#
|
266
|
+
def self.cs_gt( model_field_name = nil )
|
267
|
+
Proc.new { | attr, value |
|
268
|
+
column = model_field_name || attr
|
269
|
+
|
270
|
+
[ "#{ column } > ? AND #{ column } IS NOT NULL", value ]
|
271
|
+
}
|
272
|
+
end
|
273
|
+
|
274
|
+
# As Hoodoo::ActiveRecord::Finder::SearchHelper::cs_lt, but
|
275
|
+
# compares with greater-than-or-equal-to.
|
276
|
+
#
|
277
|
+
# Results in a <tt>foo >= bar AND foo IS NOT NULL</tt> query.
|
278
|
+
#
|
279
|
+
def self.cs_gte( model_field_name = nil )
|
280
|
+
Proc.new { | attr, value |
|
281
|
+
column = model_field_name || attr
|
282
|
+
|
283
|
+
[ "#{ column } >= ? AND #{ column } IS NOT NULL", value ]
|
284
|
+
}
|
285
|
+
end
|
286
|
+
|
287
|
+
end
|
199
288
|
end
|
200
289
|
end
|
201
290
|
end
|
@@ -35,6 +35,51 @@ module Hoodoo
|
|
35
35
|
#
|
36
36
|
class Support
|
37
37
|
|
38
|
+
# Returns a (newly generated) Hash of search keys mapping to helper Procs
|
39
|
+
# which are in the same format as would be passed to
|
40
|
+
# Hoodoo::ActiveRecord::Finder::ClassMethods#search_with or
|
41
|
+
# Hoodoo::ActiveRecord::Finder::ClassMethods#filter_with, describing the
|
42
|
+
# default framework search parameters. The middleware defines keys, but
|
43
|
+
# each ORM adapter module must specify how those keys actually get used
|
44
|
+
# to search inside supported database engines.
|
45
|
+
#
|
46
|
+
def self.framework_search_and_filter_data
|
47
|
+
|
48
|
+
# The middleware includes framework-level mappings between URI query
|
49
|
+
# string search keys and data validators and processors which convert
|
50
|
+
# types where necessary. For example, 'created_at' must be given a
|
51
|
+
# valid ISO 8601 subset string and a parsed DateTime will end up in
|
52
|
+
# the parsed search hash.
|
53
|
+
#
|
54
|
+
# Services opt out of framework-level searching at an interface level
|
55
|
+
# which means the Finder code herein, under normal flow, will never
|
56
|
+
# be asked to process something the interface omits. There is thus no
|
57
|
+
# need to try and break encapsulation and come up with a way to read
|
58
|
+
# the service interface's omissions. Instead, map everything.
|
59
|
+
#
|
60
|
+
# This could actually be useful if someone manually drives the #list
|
61
|
+
# mechanism with hand-constructed search or filter data that quite
|
62
|
+
# intentionally includes framework level parameters even if their own
|
63
|
+
# service interface for some reason opts out of allowing them to be
|
64
|
+
# exposed to API callers.
|
65
|
+
#
|
66
|
+
# Note that the #search_with / #filter_with DSL declaration in an
|
67
|
+
# appropriately extended model can be used to override the default
|
68
|
+
# values wired in below, because the defaults are established by
|
69
|
+
# design _before_ the model declarations are processed.
|
70
|
+
#
|
71
|
+
mapping = {
|
72
|
+
'created_after' => Hoodoo::ActiveRecord::Finder::SearchHelper.cs_gt( :created_at ),
|
73
|
+
'created_before' => Hoodoo::ActiveRecord::Finder::SearchHelper.cs_lt( :created_at )
|
74
|
+
}
|
75
|
+
|
76
|
+
if mapping.keys.length != ( mapping.keys | Hoodoo::Services::Middleware::FRAMEWORK_QUERY_DATA.keys ).length
|
77
|
+
raise 'Hoodoo::ActiveRecord::Support#framework_search_and_filter_data: Mismatch between internal mapping and Hoodoo::Services::Middleware::FRAMEWORK_QUERY_DATA'
|
78
|
+
end
|
79
|
+
|
80
|
+
return mapping
|
81
|
+
end
|
82
|
+
|
38
83
|
# Takes a Hash of possibly-non-String keys and with +nil+ values or
|
39
84
|
# Proc instances appropriate for Hoodoo::ActiveRecord::Finder#search_with
|
40
85
|
# / #filter_with. Returns a similar Hash with all-String keys and a Proc
|
@@ -52,7 +52,7 @@ module Hoodoo
|
|
52
52
|
if results.size > 0
|
53
53
|
|
54
54
|
if results.platform_errors.has_errors?
|
55
|
-
raise
|
55
|
+
raise 'Hoodoo::Client::PaginatedEnumeration#enumerate_all: Unexpected internal state combination of results set and results error indication'
|
56
56
|
end
|
57
57
|
|
58
58
|
# Yield a resource at a time to the caller
|
@@ -175,6 +175,48 @@ module Hoodoo; module Services
|
|
175
175
|
}
|
176
176
|
} )
|
177
177
|
|
178
|
+
# A validation Proc for FRAMEWORK_QUERY_DATA - see that for details. This
|
179
|
+
# one ensures that the value is a valid ISO 8601 subset date/time string
|
180
|
+
# and evaluates to the parsed version of that string if so.
|
181
|
+
#
|
182
|
+
FRAMEWORK_QUERY_VALUE_DATE_PROC = -> ( value ) {
|
183
|
+
Hoodoo::Utilities.valid_iso8601_subset_datetime?( value ) ?
|
184
|
+
Hoodoo::Utilities.rationalise_datetime( value ) :
|
185
|
+
nil
|
186
|
+
}
|
187
|
+
|
188
|
+
# Out-of-box search and filter query keys. Interfaces can override the
|
189
|
+
# support for these inside the Hoodoo::Services::Interface.to_list block
|
190
|
+
# using Hoodoo::Services::Interface::ToListDSL.do_not_search and
|
191
|
+
# Hoodoo::Services::Interface::ToListDSL.do_not_filter.
|
192
|
+
#
|
193
|
+
# Keys, in order, are:
|
194
|
+
#
|
195
|
+
# * Query key to detect records with a +created_at+ date that is after the
|
196
|
+
# given value, in supporting resource; if used as a filter instead of a
|
197
|
+
# search string, would find records on-or-before the date.
|
198
|
+
#
|
199
|
+
# * Query key to detect records with a +created_at+ date that is before
|
200
|
+
# the given value, in supporting resource; if used as a filter instead
|
201
|
+
# of a search string, would find records on-or-after the date.
|
202
|
+
#
|
203
|
+
# Values are either a validation Proc or +nil+ for no validation. The
|
204
|
+
# Proc takes the search query value as its sole input paraeter and must
|
205
|
+
# evaluate to the input value either unmodified or in some canonicalised
|
206
|
+
# form if it is valid, else to +nil+ if the input value is invalid. The
|
207
|
+
# canonicalisation is typically used to coerce a URI query string based
|
208
|
+
# String type into a more useful comparable entity such as an Integer or
|
209
|
+
# DateTime.
|
210
|
+
#
|
211
|
+
# *IMPORTANT* - if this list is changed, any database support modules -
|
212
|
+
# e.g. in Hoodoo::ActiveRecord::Support - will need any internal mapping
|
213
|
+
# of "framework query keys to module-appropriate query code" updating.
|
214
|
+
#
|
215
|
+
FRAMEWORK_QUERY_DATA = {
|
216
|
+
'created_after' => FRAMEWORK_QUERY_VALUE_DATE_PROC,
|
217
|
+
'created_before' => FRAMEWORK_QUERY_VALUE_DATE_PROC,
|
218
|
+
}
|
219
|
+
|
178
220
|
# Utility - returns the execution environment as a Rails-like environment
|
179
221
|
# object which answers queries like +production?+ or +staging?+ with +true+
|
180
222
|
# or +false+ according to the +RACK_ENV+ environment variable setting.
|
@@ -2770,21 +2812,52 @@ module Hoodoo; module Services
|
|
2770
2812
|
end
|
2771
2813
|
end
|
2772
2814
|
|
2773
|
-
search
|
2774
|
-
|
2775
|
-
|
2815
|
+
search = query_hash[ 'search' ] || {}
|
2816
|
+
framework_search = FRAMEWORK_QUERY_DATA.keys - interface.to_list.do_not_search
|
2817
|
+
bad_search_keys = search.keys - framework_search - interface.to_list.search
|
2818
|
+
|
2819
|
+
framework_search.each do | search_key |
|
2820
|
+
next unless search.has_key?( search_key )
|
2821
|
+
|
2822
|
+
search_value = search[ search_key ]
|
2823
|
+
validator = FRAMEWORK_QUERY_DATA[ search_key ]
|
2824
|
+
canonical = validator.call( search_value )
|
2825
|
+
|
2826
|
+
if canonical.nil?
|
2827
|
+
bad_search_keys << search_key
|
2828
|
+
else
|
2829
|
+
search[ search_key ] = canonical
|
2830
|
+
end
|
2831
|
+
end
|
2832
|
+
|
2833
|
+
filter = query_hash[ 'filter' ] || {}
|
2834
|
+
framework_filter = FRAMEWORK_QUERY_DATA.keys - interface.to_list.do_not_filter
|
2835
|
+
bad_filter_keys = filter.keys - framework_filter - interface.to_list.filter
|
2836
|
+
|
2837
|
+
framework_filter.each do | filter_key |
|
2838
|
+
next unless filter.has_key?( filter_key )
|
2839
|
+
|
2840
|
+
filter_value = filter[ filter_key ]
|
2841
|
+
validator = FRAMEWORK_QUERY_DATA[ filter_key ]
|
2842
|
+
canonical = validator.call( filter_value )
|
2843
|
+
|
2844
|
+
if canonical.nil?
|
2845
|
+
bad_filter_keys << filter_key
|
2846
|
+
else
|
2847
|
+
filter[ filter_key ] = canonical
|
2848
|
+
end
|
2849
|
+
end
|
2776
2850
|
|
2777
|
-
|
2778
|
-
|
2779
|
-
malformed << "filter: #{ unrecognised_filter_keys.join(', ') }" unless unrecognised_filter_keys.empty?
|
2851
|
+
embeds = query_hash[ '_embed' ] || []
|
2852
|
+
bad_embeds = embeds - interface.embeds
|
2780
2853
|
|
2781
|
-
|
2782
|
-
|
2783
|
-
malformed << "_embed: #{ unrecognised_embeds.join(', ') }" unless unrecognised_embeds.empty?
|
2854
|
+
references = query_hash[ '_reference' ] || []
|
2855
|
+
bad_references = references - interface.embeds # (sic.)
|
2784
2856
|
|
2785
|
-
|
2786
|
-
|
2787
|
-
malformed <<
|
2857
|
+
malformed << "search: #{ bad_search_keys.join( ', ' ) }" unless bad_search_keys.empty?
|
2858
|
+
malformed << "filter: #{ bad_filter_keys.join( ', ' ) }" unless bad_filter_keys.empty?
|
2859
|
+
malformed << "_embed: #{ bad_embeds.join( ', ' ) }" unless bad_embeds.empty?
|
2860
|
+
malformed << "_reference: #{ bad_references.join( ', ' ) }" unless bad_references.empty?
|
2788
2861
|
|
2789
2862
|
return response.add_error(
|
2790
2863
|
'platform.malformed',
|