salestation 5.0.1 → 5.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: 9f13d59875d14de627bc0a9acb2f52ac9e09ac1fac38b8741199aa6342852ca8
4
- data.tar.gz: 505233565865a9f2e527deaed88e1b89788b1bfbfab873ec15b0a85dd5fe1503
3
+ metadata.gz: 2e5fcc23d8c9f54b0aaa72e76f5f38d791c92330a462427bf5a16e8abe18a14b
4
+ data.tar.gz: fe02f21991d869abd3c6eb71c2bbc7163c36a61f0e7850384fe9b4030a01f868
5
5
  SHA512:
6
- metadata.gz: 3f26ae48f7f8169d0457938205dc3c08136bcb112a445e071beb2e6d2a792d4b47ebb1afe2497f7e18bcb08bf4daa70168ff85665f59ee07e8e37eafc4771990
7
- data.tar.gz: 0fde7366029cf2123d7a7b51c524e412f638eb6da3fc2285675bdd8ce89e6572b0c6d80d8d7244ed7c018dc9c2d292bea19301e3f446b827a5fe381b94c144cf
6
+ metadata.gz: c877ea4130f851227bb93461deef52e72b27c92c504cd8bc837d866d43be045ae632036772a571c8dbc01239afa455d8440bdcd90bcbad52732fcc2cd732b3dd
7
+ data.tar.gz: a74f378182c0306e5b88b13adf8c25a48ba6bb4efc13ae1e5392b97c3392ede261bb0445cef7e36110fc11e78adda79fe000896769e9c300a19329a48a469b5b
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ .rspec_persistence
data/README.md CHANGED
@@ -104,6 +104,14 @@ Multiple extractors can be merged together. If two or more extractors use the sa
104
104
 
105
105
  `coercions` can optionally be provided to `BodyParamExtractor` and `QueryParamExtractor`. These can be used to transform the values of the extracted parameters.
106
106
 
107
+ #### ParamExtractor
108
+
109
+ ParamExtractor, which is also used by `BodyParamExtractor` and `QueryParamExtractor`,
110
+ extracts only the content of such root level keys that are specified when creating the
111
+ extractor instance. All other root level keys are discarded. Everything inside the
112
+ whitelisted root level keys is automatically whitelisted.
113
+
114
+
107
115
  Define a route
108
116
 
109
117
  ```ruby
@@ -12,37 +12,73 @@ module Salestation
12
12
  def initialize
13
13
  @fields = []
14
14
  @field_error_types = {}
15
+ @field_error_messages = {}
15
16
  end
16
17
 
17
- def on(field)
18
- @fields << field
18
+ def on(*nested_fields)
19
+ @fields << nested_fields
19
20
  self
20
21
  end
21
22
 
22
23
  def with_type(*types)
23
- @field_error_types[@fields.last] = types
24
+ @field_error_types[field_to_key(@fields.last)] = types
25
+ self
26
+ end
27
+
28
+ def with_message(*messages)
29
+ @field_error_messages[field_to_key(@fields.last)] = messages
24
30
  self
25
31
  end
26
32
 
27
33
  def matches?(actual)
28
34
  @fields.all? do |field|
29
- check_field_exists(field, actual) &&
30
- check_field_error_types(field, actual)
35
+ check_field_exists(actual, *field) &&
36
+ check_field_error_types(field, actual) &&
37
+ check_field_error_messages(field, actual)
31
38
  end
32
39
  end
33
40
 
34
41
  private
35
42
 
36
- def check_field_exists(field, actual)
37
- actual[:error_details].key?(field)
43
+ def check_field_exists(actual, field, *nested_fields)
44
+ actual[:error_details].key?(field) &&
45
+ (
46
+ nested_fields.empty? ||
47
+ actual[:error_details][field].any? do |nested_hash|
48
+ check_field_exists(nested_hash, *nested_fields)
49
+ end
50
+ )
38
51
  end
39
52
 
40
53
  def check_field_error_types(field, actual)
41
- return true unless @field_error_types[field]
54
+ return true unless @field_error_types[field_to_key(field)]
55
+
56
+ actual_error_types = fetch_field_attribute_nested(actual, :type, *field)
57
+ (@field_error_types[field_to_key(field)] - actual_error_types).empty?
58
+ end
59
+
60
+ def check_field_error_messages(field, actual)
61
+ return true unless @field_error_messages[field_to_key(field)]
42
62
 
43
- actual_error_types = actual[:error_details].fetch(field).map { |f| f.fetch(:type) }
63
+ actual_error_messages = fetch_field_attribute_nested(actual, :message, *field)
64
+ (@field_error_messages[field_to_key(field)] - actual_error_messages).empty?
65
+ end
66
+
67
+
68
+ def fetch_field_attribute_nested(actual, attribute, field, *nested_fields)
69
+ if nested_fields.empty?
70
+ actual[:error_details].fetch(field).map { |f| f.fetch(attribute) }
71
+ else
72
+ actual[:error_details][field]
73
+ .lazy
74
+ .map { |error_hash| fetch_field_attribute_nested(error_hash, attribute, *nested_fields) }
75
+ .reject(&:nil?)
76
+ .first
77
+ end
78
+ end
44
79
 
45
- (@field_error_types[field] - actual_error_types).empty?
80
+ def field_to_key(fields)
81
+ fields.join('->').to_sym
46
82
  end
47
83
  end
48
84
  end
@@ -44,6 +44,23 @@ module Salestation
44
44
  # .on(:phone_number).with_type(Glia::Errors::INVALID_FORMAT_ERROR)
45
45
  # )
46
46
  #
47
+ # also has support for nested errors:
48
+ # nesting can be represented by calling `on` method with multiple arguments, for example when
49
+ # you have a hash like
50
+ # {
51
+ # nested: {
52
+ # name: ''
53
+ # }
54
+ # }
55
+ # Then you can call it like glia_input_validation_error.on(:nested, :name)
56
+ #
57
+ # expect(result).to be_failure
58
+ # .with_invalid_input
59
+ # .containing(
60
+ # glia_input_validation_error
61
+ # .on(:nested, :name).with_type(Glia::Errors::INVALID_VALUE_ERROR)
62
+ # )
63
+ #
47
64
  # Everything after be_failure is optional. You could also use `.containing`
48
65
  # multiple times like this:
49
66
  #
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require "symbolizer"
2
3
 
3
4
  module Salestation
4
5
  class Web < Module
@@ -192,35 +193,18 @@ module Salestation
192
193
  end
193
194
 
194
195
  def self.extract(filters, request_hash)
195
- filters.each_with_object({}) do |filter, extracted_data|
196
- case filter
197
- when Symbol
198
- stringified_key = filter.to_s
199
- extracted_data[filter] = request_hash[stringified_key] if request_hash.key?(stringified_key)
200
- if extracted_data[filter].is_a?(Array)
201
- extracted_data[filter] = extracted_data[filter].map{ |hash|
202
- if hash.is_a?(Hash)
203
- hash.transform_keys(&:to_sym) if hash.is_a?(Hash)
204
- else
205
- hash
206
- end
207
- }
208
- end
209
- when Hash
210
- filter.each do |key, nested_filters|
211
- stringified_key = key.to_s
212
- if request_hash.key?(stringified_key)
213
- value = request_hash.fetch(stringified_key)
214
- extracted_data[key] =
215
- if !value.is_a?(Hash)
216
- value
217
- else
218
- extract(nested_filters, value)
219
- end
220
- end
221
- end
222
- end
223
- end
196
+ # Filter as a hash is used in some existing implementations that did not expect full
197
+ # recursive symbolizing of keys. In this case hash objects at the highest level of object
198
+ # are represented as hash of filter keys. This is no longer needed, but we support it
199
+ # to avoid a breaking change.
200
+
201
+ filters_flat = filters
202
+ .flat_map {|filter| filter.is_a?(Hash) ? filter.keys : filter}
203
+ .map(&:to_s)
204
+
205
+ request_hash = request_hash.select {|k,v| filters_flat.include?(k)}
206
+
207
+ Symbolizer.symbolize(request_hash)
224
208
  end
225
209
  end
226
210
 
data/salestation.gemspec CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "salestation"
7
- spec.version = "5.0.1"
7
+ spec.version = "5.2.0"
8
8
  spec.authors = ["Glia TechMovers"]
9
9
  spec.email = ["techmovers@glia.com"]
10
10
 
@@ -30,4 +30,5 @@ Gem::Specification.new do |spec|
30
30
  spec.add_dependency 'dry-struct'
31
31
  spec.add_dependency 'dry-types'
32
32
  spec.add_dependency 'http-accept', '~> 2.1'
33
+ spec.add_dependency 'symbolizer'
33
34
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: salestation
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.1
4
+ version: 5.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Glia TechMovers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-06-10 00:00:00.000000000 Z
11
+ date: 2022-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -150,6 +150,20 @@ dependencies:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
152
  version: '2.1'
153
+ - !ruby/object:Gem::Dependency
154
+ name: symbolizer
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
153
167
  description: ''
154
168
  email:
155
169
  - techmovers@glia.com