praxis 2.0.pre.8 → 2.0.pre.9

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: fa1ee705af72674f99b3b697fe5199636d6268a55696e1bcdf4a892b11b7acf3
4
- data.tar.gz: e3cc19834e9640b0ee252240013367b7e444623d19e3acb9cb3eff8c83d71223
3
+ metadata.gz: f2a11ec74ee5a52178fe7aae10c503eb61407c739c40c262386e855e1abd40ee
4
+ data.tar.gz: 71b397991329ea9726b366938de75768bedf812324e4b2d768ac7dae3f25e33e
5
5
  SHA512:
6
- metadata.gz: 958b4bf7d5684477bfb371e970f8f05871c1699a4980dc508367d5d659dc013ce049b3336d55ca1b4ca1cf617ec5b10924e92e41f18102680087ebf015fe6ce7
7
- data.tar.gz: 2bbde613a765af9769b9dba0a13860b4dc520148e4263c5b4b52acf55960f8ba0aa63870f3f31c1ef73a047c33b7ffce30477d789380617f336c0893dedf31a6
6
+ metadata.gz: 21fbd6dbb60486cea3ec5cdd18a1b4178873ff6343182f2b44a11d71cbdac1664bec005760b77511de342fc92a63abe7864c85f10ffc1c3953734a1069f2520d
7
+ data.tar.gz: 7c0f8a5c417ad9ecd76fd67e08f1f219cc274c3bbd30ec88d7ae669e0a10d4ec5585c365ad7c3a38163b3d4f367897e7129bbbda66664947e82c37dc90213f08
@@ -2,6 +2,11 @@
2
2
 
3
3
  ## next
4
4
 
5
+ ## 2.0.pre.9
6
+
7
+ - Refined OpenAPI doc generation to output only non-null attributes in the InfoObject.
8
+ - Fixed filtering params validation to properly allow null values for the "!" and "!!" operators
9
+
5
10
  ## 2.0.pre.6
6
11
 
7
12
  - Removed the explicit `links` helpers from a `MediaType`. There was too much magic and assumptions built into it. Things can still be built in a custom basis (or through a plugin) if necessary.
@@ -10,20 +10,28 @@ module Praxis
10
10
  end
11
11
 
12
12
  def dump
13
- data ={
14
- title: info.title,
15
- description: info.description,
16
- termsOfService: info.termsOfService,
17
- contact: info.contact,
18
- license: info.license,
19
- version: version,
20
- :'x-name' => info.name,
21
- :'x-logo' => {
13
+ data = { version: version }
14
+ [
15
+ :title,
16
+ :description,
17
+ :termsOfService,
18
+ :contact,
19
+ :license
20
+ ].each do |attr|
21
+ val = info.send(attr)
22
+ data[attr] = val if val
23
+ end
24
+
25
+ # Special attributes
26
+ data[:'x-name'] = info.name
27
+ if info.logo_url
28
+ data[:'x-logo'] = {
22
29
  url: info.logo_url,
23
30
  backgroundColor: "#FFFFFF",
24
31
  altText: info.title
25
32
  }
26
- }
33
+ end
34
+ data
27
35
  end
28
36
  end
29
37
  end
@@ -166,7 +166,6 @@ module Praxis
166
166
  end
167
167
 
168
168
  attr_name = match[:attribute].to_sym
169
- # TODO: we should coerce values if there's a mediatype defined?
170
169
  coerced = if media_type
171
170
  filter_components = attr_name.to_s.split('.').map(&:to_sym)
172
171
  attr, _enclosing_type = find_filter_attribute(filter_components, media_type)
@@ -217,21 +216,9 @@ module Praxis
217
216
  errors << "Operator #{item[:op]} not allowed for filter #{attr_name}"
218
217
  end
219
218
  value_type = attr_filters[:value_type]
220
- value = item[:value]
221
- if value_type && !value_type.valid_type?(value)
222
- # Allow a collection of values of the right type for multimatch (if operators are = or !=)
223
- if ['=','!='].include?(item[:op])
224
- coll_type = Attributor::Collection.of(value_type)
225
- if !coll_type.valid_type?(value)
226
- errors << "Invalid type in filter/s value for #{attr_name} " +\
227
- "(one or more of the multiple matches in #{value} are not a #{value_type.name.split('::').last})"
228
- end
229
- else
230
- errors << "Invalid type in filter value for #{attr_name} (#{value} using '#{item[:op]}' is not a #{value_type.name.split('::').last})"
231
- end
232
- end
233
-
234
219
  next unless value_type == Attributor::String
220
+
221
+ value = item[:value]
235
222
  unless value.empty?
236
223
  fuzzy_match = attr_filters[:fuzzy_match]
237
224
  if (value[-1] == '*' || value[0] == '*') && !fuzzy_match
@@ -1,3 +1,3 @@
1
1
  module Praxis
2
- VERSION = '2.0.pre.8'
2
+ VERSION = '2.0.pre.9'
3
3
  end
@@ -30,5 +30,111 @@ describe Praxis::Extensions::AttributeFiltering::FilteringParams do
30
30
  ])
31
31
  end
32
32
  end
33
+
34
+ context 'with an associated MediaType' do
35
+ let(:params_for_post_media_type) do
36
+ # Note wrap the filter_params (.for) type in an attribute (which then we discard), so it will
37
+ # construct it propertly by applying the block. Seems easier than creating the type alone, and
38
+ # then manually apply the block
39
+ Attributor::Attribute.new(described_class.for(Post)) do
40
+ filter 'id', using: ['=', '!=', '!']
41
+ end.type
42
+ end
43
+
44
+ context 'with a single value' do
45
+ let(:str) { 'id=1' }
46
+ it 'coerces its value to the associated mediatype attribute type' do
47
+ parsed = params_for_post_media_type.load(str).parsed_array
48
+ expect(parsed.first).to eq(:name=>:id, :op=>"=", :value=>1)
49
+ expect(Post.attributes[:id].type.valid_type?(parsed.first[:value])).to be_truthy
50
+ end
51
+ end
52
+
53
+ context 'with multimatch' do
54
+ let(:str) { 'id=1,2,3' }
55
+ it 'coerces ALL csv values to the associated mediatype attribute type' do
56
+ parsed = params_for_post_media_type.load(str).parsed_array
57
+ expect(parsed.first).to eq(:name=>:id, :op=>"=", :value=>[1, 2, 3])
58
+ parsed.first[:value].each do |val|
59
+ expect(Post.attributes[:id].type.valid_type?(val)).to be_truthy
60
+ end
61
+ end
62
+ end
63
+
64
+ context 'with a single value that is null' do
65
+ let(:str) { 'id!' }
66
+ it 'properly loads it as null' do
67
+ parsed = params_for_post_media_type.load(str).parsed_array
68
+ expect(parsed.first).to eq(:name=>:id, :op=>"!", :value=>nil)
69
+ end
70
+ end
71
+ end
72
+
73
+ end
74
+
75
+ context '.validate' do
76
+ let(:filtering_params_type) do
77
+ # Note wrap the filter_params (.for) type in an attribute (which then we discard), so it will
78
+ # construct it propertly by applying the block. Seems easier than creating the type alone, and
79
+ # then manually apply the block
80
+ Attributor::Attribute.new(described_class.for(Post)) do
81
+ filter 'id', using: ['=', '!=']
82
+ filter 'title', using: ['=', '!='], fuzzy: true
83
+ filter 'content', using: ['=', '!=']
84
+ end.type
85
+ end
86
+ let(:loaded_params) { filtering_params_type.load(filters_string) }
87
+ subject { loaded_params.validate(filters_string) }
88
+
89
+ context 'errors' do
90
+ context 'given attributes that do not exist in the type' do
91
+ let(:filters_string) { 'NotAnExistingAttribute=Foobar*'}
92
+ it 'raises an error' do
93
+ expect{subject}.to raise_error(/NotAnExistingAttribute.*does not exist/)
94
+ end
95
+ end
96
+
97
+ context 'given unallowed attributes' do
98
+ let(:filters_string) { 'href=Foobar*'}
99
+ it 'raises an error' do
100
+ expect(subject).to_not be_empty
101
+ matches_error = subject.any? {|err| err =~ /Filtering by href is not allowed/}
102
+ expect(matches_error).to be_truthy
103
+ end
104
+ end
105
+
106
+ context 'given unallowed operator' do
107
+ let(:filters_string) { 'title>Foobar*'}
108
+ it 'raises an error' do
109
+ expect(subject).to_not be_empty
110
+ expect(subject.first).to match(/Operator > not allowed for filter title/)
111
+ end
112
+ end
113
+ end
114
+ context 'fuzzy matches' do
115
+ context 'when allowed' do
116
+ context 'given a fuzzy string' do
117
+ let(:filters_string) { 'title=IAmAString*'}
118
+ it 'validates properly' do
119
+ expect(subject).to be_empty
120
+ end
121
+ end
122
+ end
123
+ context 'when NOT allowed' do
124
+ context 'given a fuzzy string' do
125
+ let(:filters_string) { 'content=IAmAString*'}
126
+ it 'errors out' do
127
+ expect(subject).to_not be_empty
128
+ expect(subject.first).to match(/Fuzzy matching for content is not allowed/)
129
+ end
130
+ end
131
+ context 'given a non-fuzzy string' do
132
+ let(:filters_string) { 'content=IAmAString'}
133
+ it 'validates properly' do
134
+ expect(subject).to be_empty
135
+ end
136
+ end
137
+ end
138
+ end
33
139
  end
34
140
  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.8
4
+ version: 2.0.pre.9
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: 2020-10-26 00:00:00.000000000 Z
12
+ date: 2020-11-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -758,7 +758,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
758
758
  - !ruby/object:Gem::Version
759
759
  version: 1.3.1
760
760
  requirements: []
761
- rubygems_version: 3.0.3
761
+ rubygems_version: 3.1.2
762
762
  signing_key:
763
763
  specification_version: 4
764
764
  summary: Building APIs the way you want it.