praxis 2.0.pre.22 → 2.0.pre.24
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/lib/praxis/docs/open_api/media_type_object.rb +13 -2
- data/lib/praxis/extensions/attribute_filtering/filtering_params.rb +25 -2
- data/lib/praxis/mapper/resource.rb +12 -1
- data/lib/praxis/mapper/resources/query_methods.rb +2 -2
- data/lib/praxis/mapper/resources/query_proxy.rb +1 -1
- data/lib/praxis/mapper/resources/typed_methods.rb +10 -2
- data/lib/praxis/version.rb +1 -1
- data/praxis.gemspec +1 -1
- data/spec/praxis/extensions/attribute_filtering/filtering_params_spec.rb +34 -0
- metadata +2 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f399850436ae7099b3d2bcef4f1d0648b094af1d307f47498d92c3ce275379a
|
4
|
+
data.tar.gz: 5f1fa0dbad1f3cf54de9c1a398f93f72c994fe7e61e081ab0e4af3e90f1941b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1bb3ad07b0376ea46601104c0c5539cf39c4027e787f5228366cc5d5d7ff2a0ec44b8bf516ae3692ddd4ce781e4695faf760cb46750ad052e66f0618b454b71
|
7
|
+
data.tar.gz: 0d9689af7ec169f05a39113c69deb470f70cb41425b0aca71102fd7bb32f877fb8dfca73737ec6935b3b6afcf43e79d670881344c56cffdf13ee9162126c2a05
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,19 @@
|
|
2
2
|
|
3
3
|
## next
|
4
4
|
|
5
|
+
## 2.0.pre.24
|
6
|
+
Assorted set of fixes and cleanup:
|
7
|
+
* better forwarding signature for query methods
|
8
|
+
* Fix the way with which to decide how to wrap an association (based on Enumerable isn't right, as Hashes are Enumerable as well). Wrapping decision
|
9
|
+
is now made based on the association type, and not the shape of the resulting type.
|
10
|
+
* Built handling of some multivalue and/or fuzzy matching cases in filtering params
|
11
|
+
* unrestrict mustermann's dependent version
|
12
|
+
* Support options and even passing a full type (instead of a block) in signature definitions (TypedMethods for resources)
|
13
|
+
|
14
|
+
## 2.0.pre.22
|
15
|
+
* Small fix in OpenAPI doc generation, which would detect and report more output types, even if they are only defined within the
|
16
|
+
children of anonymous types.
|
17
|
+
|
5
18
|
## 2.0.pre.22
|
6
19
|
* Introduced Resource callbacks (an includeable concern). Callbacks allow you to define methods or blocks to be executed `before`, `after` or `around` any existing method in the resource. Class-level callbacks are defined with `self.xxxxx`. These methods will be executed within the instance of the resource (i.e., in the same context of the original) and must be defined with the same parameter signature. For around methods, only blocks can be used, and to call the original (inner) one, one needs to yield.
|
7
20
|
* Introduced QueryMethods for resources (an includeable concern). QueryMethods expose handy querying methods (`.get`, `.get!`, `.all`, `.first` and `.last` ) which will reach into the underlying ORM (i.e., right now, only ActiveModelCompat is supported) to perform the desired loading of data (and subsequent wrapping of results in resource instances).
|
@@ -26,8 +26,19 @@ module Praxis
|
|
26
26
|
# NOTE2: we should just create a $ref here unless it's an anon mediatype...
|
27
27
|
return {} if type.is_a? SimpleMediaType # NOTE: skip if it's a SimpleMediaType?? ... is that correct?
|
28
28
|
|
29
|
-
the_schema = if type.anonymous? || !(type < Praxis::MediaType)
|
30
|
-
|
29
|
+
the_schema = if type.anonymous? || !(type < Praxis::MediaType)
|
30
|
+
# Avoid referencing custom/simple types (i.e. just MTs). As a corner case,
|
31
|
+
# dig into collections (which are anonymous) provided their member is not.
|
32
|
+
# This isn't germane to content attributes, but is necessary to ensure that we visit every
|
33
|
+
# non-anonymous type so that our emitted scheme covers the whole "surface area" of all
|
34
|
+
# actions.
|
35
|
+
underlying_type = type
|
36
|
+
underlying_type = underlying_type.member_type while underlying_type < Attributor::Collection
|
37
|
+
|
38
|
+
SchemaObject.new(info: type).dump_schema(
|
39
|
+
shallow: false,
|
40
|
+
allow_ref: type < Attributor::Collection && !underlying_type.anonymous?
|
41
|
+
)
|
31
42
|
else
|
32
43
|
SchemaObject.new(info: type).dump_schema(shallow: true, allow_ref: true)
|
33
44
|
end
|
@@ -250,7 +250,8 @@ module Praxis
|
|
250
250
|
next unless item[:value].presence
|
251
251
|
|
252
252
|
fuzzy_match = attr_filters[:fuzzy_match]
|
253
|
-
|
253
|
+
# If fuzzy matches aren't allowed, but there is one passed in (or in the case of a multimatch, any of the ones in it), we disallow it
|
254
|
+
errors << "Fuzzy matching for #{attr_name} is not allowed (yet '*' was found in the value)" if item[:fuzzy] && !fuzzy_match && !(item[:fuzzy].is_a?(Array) && item[:fuzzy].compact.empty?)
|
254
255
|
end
|
255
256
|
end
|
256
257
|
|
@@ -258,7 +259,29 @@ module Praxis
|
|
258
259
|
def dump
|
259
260
|
parsed_array.each_with_object([]) do |item, arr|
|
260
261
|
field = item[:name]
|
261
|
-
|
262
|
+
value = \
|
263
|
+
if item[:value].is_a?(Array)
|
264
|
+
item[:value].map.with_index do |i, idx|
|
265
|
+
case item[:fuzzy][idx]
|
266
|
+
when nil
|
267
|
+
i
|
268
|
+
when :start
|
269
|
+
"*#{i}"
|
270
|
+
when :end
|
271
|
+
"#{i}*"
|
272
|
+
end
|
273
|
+
end.join(',')
|
274
|
+
else
|
275
|
+
case item[:fuzzy]
|
276
|
+
when nil
|
277
|
+
item[:value]
|
278
|
+
when :start
|
279
|
+
"*#{item[:value]}"
|
280
|
+
when :end
|
281
|
+
"#{item[:value]}*"
|
282
|
+
end
|
283
|
+
end
|
284
|
+
arr << "#{field}#{item[:op]}#{value}"
|
262
285
|
end.join('&')
|
263
286
|
end
|
264
287
|
|
@@ -177,13 +177,24 @@ module Praxis
|
|
177
177
|
return unless association_resource_class
|
178
178
|
|
179
179
|
memoized_variables << name
|
180
|
+
|
181
|
+
# Add the call to wrap (for true collections) or simply for_record if it's a n:1 association
|
182
|
+
wrapping = \
|
183
|
+
case association_spec.fetch(:type)
|
184
|
+
when :one_to_many, :many_to_many
|
185
|
+
"@__#{name} ||= #{association_resource_class}.wrap(records)"
|
186
|
+
else
|
187
|
+
"@__#{name} ||= #{association_resource_class}.for_record(records)"
|
188
|
+
end
|
189
|
+
|
180
190
|
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
181
191
|
def #{name}
|
182
192
|
return @__#{name} if instance_variable_defined?("@__#{name}")
|
183
193
|
|
184
194
|
records = record.#{name}
|
185
195
|
return nil if records.nil?
|
186
|
-
|
196
|
+
|
197
|
+
#{wrapping}
|
187
198
|
end
|
188
199
|
RUBY
|
189
200
|
end
|
@@ -22,7 +22,7 @@ module Praxis
|
|
22
22
|
base = klass.model._add_includes(klass.model, @_includes) # includes(nil) seems to have no effect
|
23
23
|
record = base._get(condition)
|
24
24
|
|
25
|
-
record.nil? ? nil : klass.
|
25
|
+
record.nil? ? nil : klass.for_record(record)
|
26
26
|
end
|
27
27
|
|
28
28
|
def get!(condition)
|
@@ -40,17 +40,25 @@ module Praxis
|
|
40
40
|
super
|
41
41
|
end
|
42
42
|
|
43
|
-
|
43
|
+
# It can take options to be passed to the attribute's block of the constructed struct
|
44
|
+
# It can take an already existing struct instead of a block/options
|
45
|
+
def signature(method_name, same_as_type = nil, **opts, &block)
|
44
46
|
method = method_name.to_sym
|
45
47
|
@signatures ||= {}
|
48
|
+
raise "signature definition for #{method_name}: need to pass either an existing type or a block, not both" if block_given? && same_as_type
|
49
|
+
|
46
50
|
if block_given?
|
47
51
|
type =
|
48
52
|
Class.new(Attributor::Struct) do
|
49
|
-
attributes do
|
53
|
+
attributes(**opts) do
|
50
54
|
instance_eval(&block)
|
51
55
|
end
|
52
56
|
end
|
53
57
|
@signatures[method] = type
|
58
|
+
elsif same_as_type
|
59
|
+
raise "Options for signature definition for #{method_name} are not supported when passing an already existing type" unless opts.empty?
|
60
|
+
|
61
|
+
@signatures[method] = same_as_type
|
54
62
|
else
|
55
63
|
@signatures[method]
|
56
64
|
end
|
data/lib/praxis/version.rb
CHANGED
data/praxis.gemspec
CHANGED
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.add_dependency 'activesupport', '>= 3'
|
26
26
|
spec.add_dependency 'attributor', '>= 6.2'
|
27
27
|
spec.add_dependency 'mime', '~> 0'
|
28
|
-
spec.add_dependency 'mustermann', '>=1.1'
|
28
|
+
spec.add_dependency 'mustermann', '>=1.1'
|
29
29
|
spec.add_dependency 'rack', '>= 1'
|
30
30
|
spec.add_dependency 'terminal-table', '~> 1.4'
|
31
31
|
spec.add_dependency 'thor'
|
@@ -278,12 +278,46 @@ describe Praxis::Extensions::AttributeFiltering::FilteringParams do
|
|
278
278
|
expect(subject.first).to match(/Fuzzy matching for content is not allowed/)
|
279
279
|
end
|
280
280
|
end
|
281
|
+
context 'given a fuzzy string in only one of the values' do
|
282
|
+
let(:filters_string) { 'content=IAmNotFuzzy,IAmAString*' }
|
283
|
+
it 'errors out' do
|
284
|
+
expect(subject).to_not be_empty
|
285
|
+
expect(subject.first).to match(/Fuzzy matching for content is not allowed/)
|
286
|
+
end
|
287
|
+
end
|
281
288
|
context 'given a non-fuzzy string' do
|
282
289
|
let(:filters_string) { 'content=IAmAString' }
|
283
290
|
it 'validates properly' do
|
284
291
|
expect(subject).to be_empty
|
285
292
|
end
|
286
293
|
end
|
294
|
+
context 'given a non-fuzzy string for a multivalue' do
|
295
|
+
let(:filters_string) { 'content=IAmAString,IAmAnotherString' }
|
296
|
+
it 'validates properly' do
|
297
|
+
expect(subject).to be_empty
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
context '.dump' do
|
305
|
+
context 'round trips for different types' do
|
306
|
+
it 'round trips for different types of values and operators' do
|
307
|
+
str = 'one=11&two!=22&three>=33&four<=4&five<5&six>6&seven!&eight!!'
|
308
|
+
expect(described_class.load(str).dump).to eq(str)
|
309
|
+
end
|
310
|
+
it 'round trips for multivalues' do
|
311
|
+
str = 'filtername=1,2,3'
|
312
|
+
expect(described_class.load(str).dump).to eq(str)
|
313
|
+
end
|
314
|
+
it 'round trips for fuzzies' do
|
315
|
+
str = 'filtername=file*'
|
316
|
+
expect(described_class.load(str).dump).to eq(str)
|
317
|
+
end
|
318
|
+
it 'round trips for fuzzies in multivalues' do
|
319
|
+
str = 'filtername=1,*2,3*'
|
320
|
+
expect(described_class.load(str).dump).to eq(str)
|
287
321
|
end
|
288
322
|
end
|
289
323
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: praxis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.pre.
|
4
|
+
version: 2.0.pre.24
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josep M. Blanquer
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2022-
|
12
|
+
date: 2022-10-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -60,9 +60,6 @@ dependencies:
|
|
60
60
|
- - ">="
|
61
61
|
- !ruby/object:Gem::Version
|
62
62
|
version: '1.1'
|
63
|
-
- - "<="
|
64
|
-
- !ruby/object:Gem::Version
|
65
|
-
version: '2'
|
66
63
|
type: :runtime
|
67
64
|
prerelease: false
|
68
65
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -70,9 +67,6 @@ dependencies:
|
|
70
67
|
- - ">="
|
71
68
|
- !ruby/object:Gem::Version
|
72
69
|
version: '1.1'
|
73
|
-
- - "<="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '2'
|
76
70
|
- !ruby/object:Gem::Dependency
|
77
71
|
name: rack
|
78
72
|
requirement: !ruby/object:Gem::Requirement
|