ree_lib 1.0.93 → 1.0.95

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -0
  3. data/Gemfile.lock +41 -36
  4. data/lib/ree_lib/packages/ree_dao/package/ree_dao/wrappers/pg_array.rb +34 -26
  5. data/lib/ree_lib/packages/ree_dao/package/ree_dao/wrappers/pg_jsonb.rb +35 -25
  6. data/lib/ree_lib/packages/ree_enum/package/ree_enum/base_enum_mapper.rb +6 -18
  7. data/lib/ree_lib/packages/ree_enum/package/ree_enum/integer_value_enum_mapper.rb +6 -18
  8. data/lib/ree_lib/packages/ree_enum/package/ree_enum/string_value_enum_mapper.rb +6 -18
  9. data/lib/ree_lib/packages/ree_errors/Package.schema.json +10 -7
  10. data/lib/ree_lib/packages/ree_errors/package/ree_errors/auth_error.rb +8 -8
  11. data/lib/ree_lib/packages/ree_errors/package/ree_errors/build_error.rb +4 -2
  12. data/lib/ree_lib/packages/ree_errors/package/ree_errors/conflict_error.rb +8 -8
  13. data/lib/ree_lib/packages/ree_errors/package/ree_errors/error.rb +89 -6
  14. data/lib/ree_lib/packages/ree_errors/package/ree_errors/invalid_param_error.rb +9 -9
  15. data/lib/ree_lib/packages/ree_errors/package/ree_errors/not_found_error.rb +8 -8
  16. data/lib/ree_lib/packages/ree_errors/package/ree_errors/payment_required_error.rb +8 -8
  17. data/lib/ree_lib/packages/ree_errors/package/ree_errors/permission_error.rb +8 -8
  18. data/lib/ree_lib/packages/ree_errors/package/ree_errors/validation_error.rb +8 -8
  19. data/lib/ree_lib/packages/ree_errors/package/ree_errors.rb +1 -0
  20. data/lib/ree_lib/packages/ree_errors/schemas/ree_errors/auth_error.schema.json +24 -1
  21. data/lib/ree_lib/packages/ree_errors/schemas/ree_errors/build_error.schema.json +10 -0
  22. data/lib/ree_lib/packages/ree_errors/schemas/ree_errors/conflict_error.schema.json +24 -1
  23. data/lib/ree_lib/packages/ree_errors/schemas/ree_errors/invalid_param_error.schema.json +24 -1
  24. data/lib/ree_lib/packages/ree_errors/schemas/ree_errors/not_found_error.schema.json +24 -1
  25. data/lib/ree_lib/packages/ree_errors/schemas/ree_errors/payment_required_error.schema.json +24 -1
  26. data/lib/ree_lib/packages/ree_errors/schemas/ree_errors/permission_error.schema.json +24 -1
  27. data/lib/ree_lib/packages/ree_errors/schemas/ree_errors/validation_error.schema.json +24 -1
  28. data/lib/ree_lib/packages/ree_errors/spec/ree_errors/auth_error_spec.rb +22 -8
  29. data/lib/ree_lib/packages/ree_errors/spec/ree_errors/invalid_param_error_spec.rb +3 -1
  30. data/lib/ree_lib/packages/ree_errors/spec/ree_errors/locales/en.yml +6 -1
  31. data/lib/ree_lib/packages/ree_errors/spec/ree_errors/not_found_error_spec.rb +3 -1
  32. data/lib/ree_lib/packages/ree_errors/spec/ree_errors/payment_required_error_spec.rb +3 -1
  33. data/lib/ree_lib/packages/ree_errors/spec/ree_errors/permission_error_spec.rb +3 -1
  34. data/lib/ree_lib/packages/ree_errors/spec/ree_errors/validation_error_spec.rb +3 -1
  35. data/lib/ree_lib/packages/ree_i18n/Package.schema.json +7 -0
  36. data/lib/ree_lib/packages/ree_i18n/package/ree_i18n/functions/check_locale_exists.rb +12 -0
  37. data/lib/ree_lib/packages/ree_i18n/schemas/ree_i18n/functions/check_locale_exists.schema.json +33 -0
  38. data/lib/ree_lib/packages/ree_i18n/spec/ree_i18n/functions/check_locale_exists.rb +16 -0
  39. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/errors/error_with_location.rb +47 -14
  40. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/field.rb +1 -1
  41. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/fields_filter.rb +11 -20
  42. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper.rb +36 -48
  43. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/abstract_type.rb +2 -2
  44. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/any.rb +8 -8
  45. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/bool.rb +12 -12
  46. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/date.rb +14 -14
  47. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/date_time.rb +13 -13
  48. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/float.rb +14 -14
  49. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/integer.rb +13 -13
  50. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/rational.rb +14 -14
  51. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/string.rb +12 -12
  52. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/time.rb +13 -13
  53. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/wrappers/array.rb +88 -80
  54. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/benchmarks/mapper_benchmark_spec.rb +41 -1
  55. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/mapper_factory_spec.rb +17 -6
  56. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/hash_spec.rb +1 -1
  57. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/type_options_spec.rb +7 -26
  58. data/lib/ree_lib/packages/ree_roda/spec/ree_roda/services/build_swagger_from_routes_spec.rb +7 -4
  59. data/lib/ree_lib/packages/ree_roda/spec/ree_roda/services/locales/en.yml +3 -1
  60. data/lib/ree_lib/packages/ree_string/package/ree_string/functions/deconstantize.rb +1 -1
  61. data/lib/ree_lib/packages/ree_swagger/Package.schema.json +3 -0
  62. data/lib/ree_lib/packages/ree_swagger/package/ree_swagger/functions/build_parameters.rb +2 -1
  63. data/lib/ree_lib/packages/ree_swagger/package/ree_swagger/functions/build_request_body_schema.rb +12 -5
  64. data/lib/ree_lib/packages/ree_swagger/package/ree_swagger/functions/build_serializer_schema.rb +12 -5
  65. data/lib/ree_lib/packages/ree_swagger/package/ree_swagger.rb +1 -0
  66. data/lib/ree_lib/packages/ree_swagger/schemas/ree_swagger/functions/build_parameters.schema.json +8 -0
  67. data/lib/ree_lib/packages/ree_swagger/schemas/ree_swagger/functions/build_request_body_schema.schema.json +1 -1
  68. data/lib/ree_lib/packages/ree_swagger/schemas/ree_swagger/functions/build_serializer_schema.schema.json +1 -1
  69. data/lib/ree_lib/version.rb +1 -1
  70. metadata +5 -3
  71. data/lib/ree_lib/packages/ree_errors/package/ree_errors/error_factory.rb +0 -15
@@ -1,39 +1,39 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ReeMapper::Rational < ReeMapper::AbstractType
4
- contract(Any, Kwargs[name: String, location: Nilor[String]] => Rational).throws(ReeMapper::TypeError)
5
- def serialize(value, name:, location: nil)
4
+ contract(Any => Rational).throws(ReeMapper::TypeError)
5
+ def serialize(value)
6
6
  if value.is_a?(Rational)
7
7
  value
8
8
  else
9
- raise ReeMapper::TypeError.new("`#{name}` should be a rational, got `#{truncate(value.inspect)}`", location)
9
+ raise ReeMapper::TypeError.new("should be a rational, got `#{truncate(value.inspect)}`")
10
10
  end
11
11
  end
12
12
 
13
- contract(Any, Kwargs[name: String, location: Nilor[String]] => Rational).throws(ReeMapper::CoercionError, ReeMapper::TypeError)
14
- def cast(value, name:, location: nil)
13
+ contract(Any => Rational).throws(ReeMapper::CoercionError, ReeMapper::TypeError)
14
+ def cast(value)
15
15
  if value.is_a?(Rational)
16
16
  value
17
17
  elsif value.is_a?(String)
18
18
  begin
19
19
  Rational(value)
20
- rescue ArgumentError, ZeroDivisionError => e
21
- raise ReeMapper::CoercionError.new("`#{name}` is invalid rational, got `#{truncate(value.inspect)}`", location)
20
+ rescue ArgumentError, ZeroDivisionError
21
+ raise ReeMapper::CoercionError.new("is invalid rational, got `#{truncate(value.inspect)}`")
22
22
  end
23
23
  elsif value.is_a?(Numeric)
24
24
  Rational(value)
25
25
  else
26
- raise ReeMapper::TypeError.new("`#{name}` should be a rational, got `#{truncate(value.inspect)}`", location)
26
+ raise ReeMapper::TypeError.new("should be a rational, got `#{truncate(value.inspect)}`")
27
27
  end
28
28
  end
29
29
 
30
- contract(Any, Kwargs[name: String, location: Nilor[String]] => String)
31
- def db_dump(value, name:, location: nil)
32
- serialize(value, name: name, location: location).to_s
30
+ contract(Any => String)
31
+ def db_dump(value)
32
+ serialize(value).to_s
33
33
  end
34
34
 
35
- contract(Any, Kwargs[name: String, location: Nilor[String]] => Rational)
36
- def db_load(value, name:, location: nil)
37
- cast(value, name: name, location: location)
35
+ contract(Any => Rational)
36
+ def db_load(value)
37
+ cast(value)
38
38
  end
39
39
  end
@@ -1,27 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ReeMapper::String < ReeMapper::AbstractType
4
- contract(Any, Kwargs[name: String, location: Nilor[String]] => String).throws(ReeMapper::TypeError)
5
- def serialize(value, name:, location: nil)
4
+ contract(Any => String).throws(ReeMapper::TypeError)
5
+ def serialize(value)
6
6
  if value.is_a? String
7
7
  value
8
8
  else
9
- raise ReeMapper::TypeError.new("`#{name}` should be a string, got `#{truncate(value.inspect)}`", location)
9
+ raise ReeMapper::TypeError.new("should be a string, got `#{truncate(value.inspect)}`")
10
10
  end
11
11
  end
12
12
 
13
- contract(Any, Kwargs[name: String, location: Nilor[String]] => String).throws(ReeMapper::TypeError)
14
- def cast(value, name:, location: nil)
15
- serialize(value, name: name, location: location)
13
+ contract(Any => String).throws(ReeMapper::TypeError)
14
+ def cast(value)
15
+ serialize(value)
16
16
  end
17
17
 
18
- contract(Any, Kwargs[name: String, location: Nilor[String]] => String).throws(ReeMapper::TypeError)
19
- def db_dump(value, name:, location: nil)
20
- serialize(value, name: name, location: location)
18
+ contract(Any => String).throws(ReeMapper::TypeError)
19
+ def db_dump(value)
20
+ serialize(value)
21
21
  end
22
22
 
23
- contract(Any, Kwargs[name: String, location: Nilor[String]] => String).throws(ReeMapper::TypeError)
24
- def db_load(value, name:, location: nil)
25
- serialize(value, name: name, location: location)
23
+ contract(Any => String).throws(ReeMapper::TypeError)
24
+ def db_load(value)
25
+ serialize(value)
26
26
  end
27
27
  end
@@ -3,17 +3,17 @@
3
3
  require 'time'
4
4
 
5
5
  class ReeMapper::Time < ReeMapper::AbstractType
6
- contract(Any, Kwargs[name: String, location: Nilor[String]] => Time).throws(ReeMapper::TypeError)
7
- def serialize(value, name:, location: nil)
6
+ contract(Any => Time).throws(ReeMapper::TypeError)
7
+ def serialize(value)
8
8
  if value.class == Time
9
9
  value
10
10
  else
11
- raise ReeMapper::TypeError.new("`#{name}` should be a time, got `#{truncate(value.inspect)}`", location)
11
+ raise ReeMapper::TypeError.new("should be a time, got `#{truncate(value.inspect)}`")
12
12
  end
13
13
  end
14
14
 
15
- contract(Any, Kwargs[name: String, location: Nilor[String]] => Time).throws(ReeMapper::CoercionError, ReeMapper::TypeError)
16
- def cast(value, name:, location: nil)
15
+ contract(Any => Time).throws(ReeMapper::CoercionError, ReeMapper::TypeError)
16
+ def cast(value)
17
17
  if value.class == Time
18
18
  value
19
19
  elsif value.class == DateTime
@@ -22,20 +22,20 @@ class ReeMapper::Time < ReeMapper::AbstractType
22
22
  begin
23
23
  Time.parse(value)
24
24
  rescue ArgumentError
25
- raise ReeMapper::CoercionError.new("`#{name}` is invalid time, got `#{truncate(value.inspect)}`", location)
25
+ raise ReeMapper::CoercionError.new("is invalid time, got `#{truncate(value.inspect)}`")
26
26
  end
27
27
  else
28
- raise ReeMapper::TypeError.new("`#{name}` should be a time, got `#{truncate(value.inspect)}`", location)
28
+ raise ReeMapper::TypeError.new("should be a time, got `#{truncate(value.inspect)}`")
29
29
  end
30
30
  end
31
31
 
32
- contract(Any, Kwargs[name: String, location: Nilor[String]] => Time).throws(ReeMapper::TypeError)
33
- def db_dump(value, name:, location: nil)
34
- serialize(value, name: name, location: location)
32
+ contract(Any => Time).throws(ReeMapper::TypeError)
33
+ def db_dump(value)
34
+ serialize(value)
35
35
  end
36
36
 
37
- contract(Any, Kwargs[name: String, location: Nilor[String]] => Time).throws(ReeMapper::CoercionError, ReeMapper::TypeError)
38
- def db_load(value, name:, location: nil)
39
- cast(value, name: name, location: location)
37
+ contract(Any => Time).throws(ReeMapper::CoercionError, ReeMapper::TypeError)
38
+ def db_load(value)
39
+ cast(value)
40
40
  end
41
41
  end
@@ -4,116 +4,124 @@ class ReeMapper::Array < ReeMapper::AbstractWrapper
4
4
  contract(
5
5
  Any,
6
6
  Kwargs[
7
- name: String,
8
7
  role: Nilor[Symbol, ArrayOf[Symbol]],
9
- fields_filters: ArrayOf[ReeMapper::FieldsFilter],
10
- location: Nilor[String],
8
+ fields_filters: Nilor[ArrayOf[ReeMapper::FieldsFilter]],
11
9
  ] => Array
12
10
  ).throws(ReeMapper::TypeError)
13
- def serialize(value, name:, role: nil, fields_filters: [], location: nil)
14
- if value.is_a?(Array)
15
- value.map.with_index {
16
- if _1.nil? && subject.null
17
- _1
18
- else
19
- subject.type.serialize(
20
- _1,
21
- name: "#{name}[#{_2}]",
22
- role: role,
23
- fields_filters: fields_filters + [subject.fields_filter],
24
- location: subject.location,
25
- )
26
- end
27
- }
28
- else
29
- raise ReeMapper::TypeError.new("`#{name}` should be an array, got `#{truncate(value.inspect)}`", location)
11
+ def serialize(value, role: nil, fields_filters: nil)
12
+ if !value.is_a?(Array)
13
+ raise ReeMapper::TypeError.new("should be an array, got `#{truncate(value.inspect)}`")
14
+ end
15
+
16
+ if subject.fields_filter
17
+ fields_filters = if fields_filters
18
+ fields_filters + [subject.fields_filter]
19
+ else
20
+ [subject.fields_filter]
21
+ end
22
+ end
23
+
24
+ value.map.with_index do |item, idx|
25
+ next nil if item.nil? && subject.null
26
+
27
+ subject.type.serialize(item, role:, fields_filters:)
28
+ rescue ReeMapper::ErrorWithLocation => e
29
+ e.prepend_field_name(idx.to_s)
30
+ e.location ||= subject.location
31
+ raise e
30
32
  end
31
33
  end
32
34
 
33
35
  contract(
34
36
  Any,
35
37
  Kwargs[
36
- name: String,
37
38
  role: Nilor[Symbol, ArrayOf[Symbol]],
38
- fields_filters: ArrayOf[ReeMapper::FieldsFilter],
39
- location: Nilor[String],
39
+ fields_filters: Nilor[ArrayOf[ReeMapper::FieldsFilter]],
40
40
  ] => Array
41
41
  ).throws(ReeMapper::TypeError)
42
- def cast(value, name:, role: nil, fields_filters: [], location: nil)
43
- if value.is_a?(Array)
44
- value.map.with_index {
45
- if _1.nil? && subject.null
46
- _1
47
- else
48
- subject.type.cast(
49
- _1,
50
- name: "#{name}[#{_2}]",
51
- role: role,
52
- fields_filters: fields_filters + [subject.fields_filter],
53
- location: subject.location,
54
- )
55
- end
56
- }
57
- else
58
- raise ReeMapper::TypeError.new("`#{name}` should be an array, got `#{truncate(value.inspect)}`", location)
42
+ def cast(value, role: nil, fields_filters: nil)
43
+ if !value.is_a?(Array)
44
+ raise ReeMapper::TypeError.new("should be an array, got `#{truncate(value.inspect)}`")
45
+ end
46
+
47
+ if subject.fields_filter
48
+ fields_filters = if fields_filters
49
+ fields_filters + [subject.fields_filter]
50
+ else
51
+ [subject.fields_filter]
52
+ end
53
+ end
54
+
55
+ value.map.with_index do |item, idx|
56
+ next nil if item.nil? && subject.null
57
+
58
+ subject.type.cast(item, role:, fields_filters:)
59
+ rescue ReeMapper::ErrorWithLocation => e
60
+ e.prepend_field_name(idx.to_s)
61
+ e.location ||= subject.location
62
+ raise e
59
63
  end
60
64
  end
61
65
 
62
66
  contract(
63
67
  Any,
64
68
  Kwargs[
65
- name: String,
66
69
  role: Nilor[Symbol, ArrayOf[Symbol]],
67
- fields_filters: ArrayOf[ReeMapper::FieldsFilter],
68
- location: Nilor[String],
70
+ fields_filters: Nilor[ArrayOf[ReeMapper::FieldsFilter]],
69
71
  ] => Array
70
72
  ).throws(ReeMapper::TypeError)
71
- def db_dump(value, name:, role: nil, fields_filters: [], location: nil)
72
- if value.is_a?(Array)
73
- value.map.with_index {
74
- if _1.nil? && subject.null
75
- _1
76
- else
77
- subject.type.db_dump(
78
- _1,
79
- name: "#{name}[#{_2}]",
80
- role: role,
81
- fields_filters: fields_filters + [subject.fields_filter],
82
- location: subject.location,
83
- )
84
- end
85
- }
86
- else
87
- raise ReeMapper::TypeError.new("`#{name}` should be an array, got `#{truncate(value.inspect)}`", location)
73
+ def db_dump(value, role: nil, fields_filters: nil)
74
+ if !value.is_a?(Array)
75
+ raise ReeMapper::TypeError.new("should be an array, got `#{truncate(value.inspect)}`")
76
+ end
77
+
78
+ if subject.fields_filter
79
+ fields_filters = if fields_filters
80
+ fields_filters + [subject.fields_filter]
81
+ else
82
+ [subject.fields_filter]
83
+ end
84
+ end
85
+
86
+ value.map.with_index do |item, idx|
87
+ next nil if item.nil? && subject.null
88
+
89
+ subject.type.db_dump(item, role:, fields_filters:)
90
+ rescue ReeMapper::ErrorWithLocation => e
91
+ e.prepend_field_name(idx.to_s)
92
+ e.location ||= subject.location
93
+ raise e
88
94
  end
89
95
  end
90
96
 
91
97
  contract(
92
98
  Any,
93
99
  Kwargs[
94
- name: String,
95
100
  role: Nilor[Symbol, ArrayOf[Symbol]],
96
- fields_filters: ArrayOf[ReeMapper::FieldsFilter],
97
- location: Nilor[String],
101
+ fields_filters: Nilor[ArrayOf[ReeMapper::FieldsFilter]],
98
102
  ] => Array
99
103
  ).throws(ReeMapper::TypeError)
100
- def db_load(value, name:, role: nil, fields_filters: [], location: nil)
101
- if value.is_a?(Array)
102
- value.map.with_index {
103
- if _1.nil? && subject.null
104
- _1
105
- else
106
- subject.type.db_load(
107
- _1,
108
- name: "#{name}[#{_2}]",
109
- role: role,
110
- fields_filters: fields_filters + [subject.fields_filter],
111
- location: subject.location,
112
- )
113
- end
114
- }
115
- else
116
- raise ReeMapper::TypeError.new("`#{name}` should be an array, got `#{truncate(value.inspect)}`", location)
104
+ def db_load(value, role: nil, fields_filters: nil)
105
+ if !value.is_a?(Array)
106
+ raise ReeMapper::TypeError.new("should be an array, got `#{truncate(value.inspect)}`")
107
+ end
108
+
109
+ if subject.fields_filter
110
+ fields_filters = if fields_filters
111
+ fields_filters + [subject.fields_filter]
112
+ else
113
+ [subject.fields_filter]
114
+ end
115
+ end
116
+
117
+ value.map.with_index do |item, idx|
118
+ next nil if item.nil? && subject.null
119
+
120
+ subject.type.db_load(item, role:, fields_filters:)
121
+ rescue ReeMapper::ErrorWithLocation => e
122
+ e.prepend_field_name(idx.to_s)
123
+ e.location ||= subject.location
124
+ raise e
117
125
  end
118
126
  end
119
127
  end
@@ -1,6 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
  require 'benchmark'
3
3
 
4
+ no_contracts = Ree::Contracts.no_contracts?
5
+ Ree.disable_contracts
6
+
4
7
  package_require "ree_mapper"
5
8
 
6
9
  RSpec.xdescribe 'Mapper Benchmark' do
@@ -25,7 +28,44 @@ RSpec.xdescribe 'Mapper Benchmark' do
25
28
  obj = { my_field: { my_field: { my_field: 1 } } }
26
29
 
27
30
  _benchmark_res = Benchmark.bmbm do |x|
28
- x.report('cast') { 1000.times { mapper.cast(obj) } }
31
+ x.report('cast') { 100000.times { mapper.cast(obj) } }
29
32
  end
30
33
  end
34
+
35
+ xit do
36
+ Ree.disable_contracts
37
+ require "ruby-prof"
38
+ package_require "ree_mapper"
39
+
40
+ mapper = ReeMapper::BuildMapperFactory.new.call(
41
+ strategies: [
42
+ ReeMapper::BuildMapperStrategy.new.call(method: :cast, dto: Hash),
43
+ ]
44
+ ).call.use(:cast) do
45
+ hash :my_field do
46
+ hash :my_field do
47
+ integer :my_field
48
+ end
49
+ end
50
+ end
51
+
52
+ obj = { my_field: { my_field: { my_field: 1 } } }
53
+
54
+ result = RubyProf::Profile.profile do
55
+ mapper.cast(obj)
56
+ end
57
+
58
+ RubyProf::FlatPrinter.new(result).print(STDOUT)
59
+ end
31
60
  end
61
+
62
+ if !no_contracts
63
+ Ree.enable_contracts
64
+ end
65
+
66
+ # version main
67
+ # cast 0.369019 0.001180 0.370199 ( 0.370515)
68
+ # cast 0.356124 0.001060 0.357184 ( 0.357502)
69
+ # version 1.0.93
70
+ # cast 0.791664 0.004125 0.795789 ( 0.796938)
71
+ # cast 0.782544 0.016745 0.799289 ( 0.799759)
@@ -82,12 +82,17 @@ RSpec.describe ReeMapper::MapperFactory do
82
82
  describe '.register_wrapper' do
83
83
  let(:round_wrapper) {
84
84
  Class.new(ReeMapper::AbstractWrapper) do
85
- def serialize(value, name:, location: nil, **opts)
85
+ def serialize(value, **opts)
86
86
  if !value.is_a?(Numeric)
87
- raise ReeMapper::TypeError.new("`#{name}` should be a number, got `#{truncate(value.inspect)}`", location)
87
+ raise ReeMapper::TypeError.new("should be a number, got `#{truncate(value.inspect)}`")
88
88
  end
89
89
 
90
- subject.type.serialize(value.round, name: name, location: subject.location, **opts)
90
+ begin
91
+ subject.type.serialize(value.round, **opts)
92
+ rescue ReeMapper::ErrorWithLocation => e
93
+ e.location ||= subject.location
94
+ raise e
95
+ end
91
96
  end
92
97
  end
93
98
  }
@@ -102,12 +107,18 @@ RSpec.describe ReeMapper::MapperFactory do
102
107
 
103
108
  it 'allow to register caster and serializer with the same name' do
104
109
  caster_round_wrapper = Class.new(ReeMapper::AbstractWrapper) do
105
- def cast(value, name:, location: nil, **opts)
106
- value = subject.type.cast(value, name: name, location: subject.location, **opts)
110
+ def cast(value, **opts)
111
+ value = begin
112
+ subject.type.cast(value, **opts)
113
+ rescue ReeMapper::ErrorWithLocation => e
114
+ e.location ||= subject.location
115
+ raise e
116
+ end
107
117
 
108
118
  if !value.is_a?(Numeric)
109
- raise ReeMapper::TypeError.new("`#{name}` should be a number, got `#{truncate(value.inspect)}`", location)
119
+ raise ReeMapper::TypeError.new("should be a number, got `#{truncate(value.inspect)}`")
110
120
  end
121
+
111
122
  value.round
112
123
  end
113
124
  end
@@ -27,7 +27,7 @@ RSpec.describe 'Mapper Hash' do
27
27
  }
28
28
 
29
29
  it {
30
- expect { mapper.cast({ point: 1 }) }.to raise_error(ReeMapper::TypeError, /Missing required field `x` for `point`/)
30
+ expect { mapper.cast({ point: 1 }) }.to raise_error(ReeMapper::TypeError, /`point\[x\]` is missing required field/)
31
31
  }
32
32
 
33
33
  it {
@@ -116,37 +116,18 @@ RSpec.describe 'ReeMapper::MapperFactory type options' do
116
116
  }
117
117
  end
118
118
 
119
- context 'with invalid only' do
119
+ context "with empty nested filter" do
120
120
  let(:mapper) {
121
121
  mapper_factory.call.use(:cast) {
122
- point :point
123
- }
124
- }
125
-
126
- it {
127
- expect {
128
- mapper.cast({}, only: {})
129
- }.to raise_error(
130
- ReeMapper::ArgumentError,
131
- "Invalid `only` format"
132
- )
133
- }
134
- end
135
-
136
- context 'with invalid except' do
137
- let(:mapper) {
138
- mapper_factory.call.use(:cast) {
139
- point :point
122
+ hash :point_wrap do
123
+ point :point
124
+ end
140
125
  }
141
126
  }
142
127
 
143
128
  it {
144
- expect {
145
- mapper.cast({}, except: {})
146
- }.to raise_error(
147
- ReeMapper::ArgumentError,
148
- "Invalid `except` format"
149
- )
129
+ expect(mapper.cast({ point_wrap: { point: { x: 1, y: 1, z: 1 } } }, only: [point_wrap: [:point]]))
130
+ .to eq({ point_wrap: { point: { x: 1, y: 1, z: 1 } } })
150
131
  }
151
132
  end
152
133
  end
@@ -193,7 +174,7 @@ RSpec.describe 'ReeMapper::MapperFactory type options' do
193
174
  }
194
175
 
195
176
  it {
196
- expect { mapper.cast({}) }.to raise_error(ReeMapper::TypeError, /Missing required field `number` for `root`/)
177
+ expect { mapper.cast({}) }.to raise_error(ReeMapper::TypeError, /`number` is missing required field/)
197
178
  }
198
179
 
199
180
  it {
@@ -17,19 +17,22 @@ RSpec.describe :build_swagger_from_routes do
17
17
  package do
18
18
  depends_on :ree_actions
19
19
  depends_on :ree_dao
20
+ depends_on :ree_errors
20
21
  end
21
22
  end
22
23
 
23
24
  class ReeRodaTestSwagger::Cmd
24
25
  include ReeActions::DSL
25
26
 
26
- action :cmd
27
+ action :cmd do
28
+ link :invalid_param_error, from: :ree_errors
29
+ end
27
30
 
28
31
  ActionCaster = build_mapper.use(:cast) do
29
32
  integer :id
30
33
  end
31
34
 
32
- InvalidErr = ReeErrors::ValidationError.build(:invalid, "invalid")
35
+ InvalidErr = invalid_param_error(:invalid, "invalid")
33
36
 
34
37
  contract(Any, Any => Any).throws(InvalidErr)
35
38
  def call(access, attrs)
@@ -71,7 +74,7 @@ RSpec.describe :build_swagger_from_routes do
71
74
  it {
72
75
  swagger = build_swagger_from_routes(routes, "test", "test", "1.0", "https://example.com")
73
76
 
74
- expect(swagger.dig(:paths, "/api/actions", :post, :responses, 422, :description))
75
- .to eq("- type: **validation**, code: **invalid**, message: **invalid**")
77
+ expect(swagger.dig(:paths, "/api/actions", :post, :responses, 400, :description))
78
+ .to eq("- type: **invalid_param**, code: **invalid**, message: **invalid param**")
76
79
  }
77
80
  end
@@ -1,2 +1,4 @@
1
1
  en:
2
- invalid: "invalid"
2
+ ree_roda_test_swagger:
3
+ errors:
4
+ invalid: "invalid param"
@@ -7,7 +7,7 @@ class ReeString::Deconstantize
7
7
 
8
8
  doc(<<~DOC)
9
9
  Removes the rightmost segment from the constant expression in the string.
10
-
10
+
11
11
  deconstantize('Net::HTTP') # => "Net"
12
12
  deconstantize('::Net::HTTP') # => "::Net"
13
13
  deconstantize('String') # => ""
@@ -7,6 +7,9 @@
7
7
  "ree_swagger"
8
8
  ],
9
9
  "depends_on": [
10
+ {
11
+ "name": "ree_array"
12
+ },
10
13
  {
11
14
  "name": "ree_dto"
12
15
  },
@@ -6,6 +6,7 @@ class ReeSwagger::BuildParameters
6
6
  fn :build_parameters do
7
7
  link :get_caster_definition
8
8
  link :build_request_body_schema
9
+ link :wrap, from: :ree_array
9
10
  end
10
11
 
11
12
  ObjectPathParamError = Class.new(StandardError)
@@ -36,7 +37,7 @@ class ReeSwagger::BuildParameters
36
37
  name: field.name_as_str,
37
38
  in: is_path_param ? 'path' : 'query',
38
39
  required: is_path_param || !field.optional,
39
- schema: build_request_body_schema(field.type, [], [field.fields_filter]) || {}
40
+ schema: build_request_body_schema(field.type, [], wrap(field.fields_filter)) || {}
40
41
  }
41
42
 
42
43
  schema[:style] = 'deepObject' if field.type.type.nil?
@@ -10,9 +10,9 @@ class ReeSwagger::BuildRequestBodySchema
10
10
  contract(
11
11
  ReeMapper::Mapper,
12
12
  ArrayOf[Symbol],
13
- ArrayOf[ReeMapper::FieldsFilter] => Nilor[Hash]
13
+ Nilor[ArrayOf[ReeMapper::FieldsFilter]] => Nilor[Hash]
14
14
  )
15
- def call(mapper, path_params = [], fields_filters = [])
15
+ def call(mapper, path_params = [], fields_filters = nil)
16
16
  if mapper.type
17
17
  return get_caster_definition(mapper.type, method(:call).to_proc)
18
18
  end
@@ -20,7 +20,7 @@ class ReeSwagger::BuildRequestBodySchema
20
20
  required_fields = []
21
21
 
22
22
  properties = mapper.fields.each_with_object({}) do |(_name, field), acc|
23
- next unless fields_filters.all? { _1.allow?(field.name) }
23
+ next unless fields_filters.nil? || fields_filters.all? { _1.allow?(field.name) }
24
24
 
25
25
  next if path_params.include?(field.name)
26
26
 
@@ -34,8 +34,15 @@ class ReeSwagger::BuildRequestBodySchema
34
34
  required_fields << field.name.to_s if !field.optional
35
35
  field_mapper = field.type
36
36
 
37
- nested_fields_filters = fields_filters.map { _1.filter_for(field.name) }
38
- nested_fields_filters += [field.fields_filter]
37
+ nested_fields_filters = fields_filters&.filter_map { _1.filter_for(field.name) }
38
+
39
+ if field.fields_filter
40
+ nested_fields_filters = if nested_fields_filters
41
+ nested_fields_filters + [field.fields_filter]
42
+ else
43
+ [field.fields_filter]
44
+ end
45
+ end
39
46
 
40
47
  swagger_type = call(field_mapper, [], nested_fields_filters)
41
48