params_checker 0.2.2 → 0.2.3

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.
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ DEFAULT_MESSAGE_ERROR = 'Fields are not valid'
4
+ ERROR_TYPES = %w[general_error field_errors]
1
5
  module ParamsChecker
2
6
  class BaseParamsChecker
3
7
  include Fields
@@ -6,244 +10,265 @@ module ParamsChecker
6
10
  @params = params
7
11
  @context = context
8
12
  @is_outest_hash = is_outest_hash
9
- @formatted_params_after_default_check = {}
10
- @formatted_params_after_custom_specify_field_checks = {}
11
- @formatted_params_after_custom_all_fields_check = {}
13
+ @formatted_params_after_default_fields_check = {}
14
+ @formatted_params_after_custom_fields_check = {}
15
+ @formatted_params_after_custom_overall_check = {}
16
+ @custom_check_errors = {}
12
17
  end
13
18
 
14
- def self.init required: true, many: false
15
- raise "This field's type must be boolean." if [required, many].any? { |value| !value.in? [true, false] }
19
+ def self.init(required: true, many: false, default: nil, allow_nil: false)
20
+ raise "This field's type must be boolean." if [required, many, allow_nil].any? { |value| !value.in? [true, false] }
16
21
 
17
22
  type = many ? 'nested_hashs' : 'nested_hash'
23
+
18
24
  {
19
- type: type,
20
- required: required,
21
- many: many,
22
- class: self
25
+ type: type,
26
+ required: required,
27
+ default: default,
28
+ allow_nil: allow_nil,
29
+ many: many,
30
+ class: self
23
31
  }
24
32
  end
25
33
 
26
- def raise_error message="Invalid data"
27
- raise MyError.new(message)
34
+ def raise_error(message = DEFAULT_MESSAGE_ERROR)
35
+ raise GeneralError.new(message)
36
+ end
37
+
38
+ def add_error(message, key = nil)
39
+ raise ParamsChecker::FieldError.new({
40
+ message: message,
41
+ key: key,
42
+ })
28
43
  end
29
44
 
30
45
  def call
31
- default_check && custom_check
32
- error_exist? && add_error
46
+ default_fields_check && custom_check
47
+ error_exist? && add_errors
33
48
  formatted_params
34
- rescue => e
35
- # only add errors at the first hash, else raise error for the first hash to catch
36
- # example:
37
- # old:
38
- # {
39
- # "errors": {
40
- # "message": "Invalid data",
41
- # "details": {
42
- # "purchase_order_items": [
43
- # {
44
- # "errors": {
45
- # "message": "Material not exists.",
46
- # "details": {}
47
- # }
48
- # }
49
- # ]
50
- # }
51
- # }
52
- # }
53
- # new:
54
- # {
55
- # "errors": {
56
- # "message": "Material not exists.",
57
- # "details": {}
58
- # }
59
- # }
60
- if e.class.name == 'ParamsChecker::MyError' && is_outest_hash
61
- errors.add(:errors, {
62
- message: e,
63
- details: {}
64
- })
65
- else
66
- raise e
49
+ rescue ParamsChecker::GeneralError => e
50
+ # if is the outest hash, add error
51
+ # if is not, keep raising error, bubble up to the outest hash,
52
+ # then the outest hash will add error
53
+ unless is_outest_hash
54
+ raise e
67
55
  end
56
+
57
+ errors.add(
58
+ :errors,
59
+ {
60
+ message: e.message,
61
+ error_type: 'general_error'
62
+ }
63
+ )
68
64
  end
69
65
 
70
66
  def error_exist?
71
- !errors.empty? && errors.is_a?(Hash)
67
+ errors.present? && errors.is_a?(Hash) || @custom_check_errors.present?
68
+ end
69
+
70
+ def default_fields_check
71
+ params_is_not_a_hash = !params.is_a?(ActionController::Parameters) && !params.is_a?(Hash)
72
+
73
+ if params_is_not_a_hash
74
+ errors.add(:error, 'ParamsChecker only receive object or ActionController::Parameters as input.')
75
+ end
76
+
77
+ all_fields_of_params_are_valid?
72
78
  end
73
79
 
74
- def default_check
75
- params_is_a_hash = params.is_a?(ActionController::Parameters) || params.is_a?(Hash)
76
- errors.add(:error, "ParamsChecker only receive object or ActionController::Parameters as input.") unless params_is_a_hash
77
- params_is_a_hash && all_fields_are_valid
80
+ def custom_check
81
+ fields_check && overall_check
78
82
  end
79
83
 
80
- def all_fields_are_valid
81
- return @all_fields_are_valid if @all_fields_are_valid.present?
84
+ def all_fields_of_params_are_valid?
85
+ @all_fields_of_params_are_valid ||= field_valids.all?(true)
86
+ end
82
87
 
83
- @all_fields_are_valid = true
84
- fields.each do |key, value|
85
- @all_fields_are_valid = false unless data_valid? key
86
- end
87
- @all_fields_are_valid
88
- end
89
-
90
- def data_valid? key
91
- if value_need_to_be_present?(key)
92
- if value_present?(key)
93
- if value_valid?(key)
94
- true
95
- else
96
- false
97
- end
98
- else
99
- errors.add(key, 'This field is required.')
100
- false
101
- end
102
- else
103
- if value_present?(key)
104
- if value_valid?(key)
105
- true
106
- else
107
- false
108
- end
109
- else
110
- true
88
+ def field_valids
89
+ @field_valids ||=
90
+ schema.map do |key, _|
91
+ set_default_value(key) if need_to_set_default_value?(key)
92
+
93
+ field_is_valid?(key)
111
94
  end
112
- end
113
95
  end
114
96
 
115
- def value_need_to_be_present? key
116
- if fields[key].key?(:default) && !fields[key][:default].nil?
117
- @params[key].nil? && @params[key] = fields[key][:default]
97
+ def field_is_valid?(key)
98
+ return value_valid?(key) if value_present?(key)
118
99
 
119
- true
120
- else
121
- fields[key][:required]
122
- end
100
+ return true unless value_need_to_be_present?(key)
101
+
102
+ errors.add(key, 'This field is required.')
103
+ false
123
104
  end
124
105
 
125
- def value_present? key
106
+ def need_to_set_default_value?(key)
107
+ value_is_nil = @params[key].nil?
108
+ schema_field_has_default_value_key = schema[key].key?(:default)
109
+ default_value_is_set = !schema[key][:default].nil?
110
+
111
+ value_is_nil &&
112
+ schema_field_has_default_value_key &&
113
+ default_value_is_set
114
+ end
115
+
116
+ def set_default_value(key)
117
+ @params[key] = schema[key][:default]
118
+ end
119
+
120
+ def value_need_to_be_present?(key)
121
+ return true if schema[key].key?(:default) && !schema[key][:default].nil?
122
+
123
+ schema[key][:required]
124
+ end
125
+
126
+ def value_present?(key)
126
127
  params.key?(key)
127
128
  end
128
129
 
129
- def value_valid? key
130
- cmd = check_base_on_field_type key
130
+ def value_valid?(key)
131
+ cmd = check_base_on_field_type(key)
131
132
  if cmd.success?
132
- @formatted_params_after_default_check[key] = cmd.result
133
+ @formatted_params_after_default_fields_check[key] = cmd.result
133
134
  else
134
- errors.add(key, cmd.errors[key])
135
+ errors.add(key, cmd.errors[key])
135
136
  end
136
137
  cmd.success?
137
138
  end
138
139
 
139
- def fields
140
- field_params = {}
141
- init.each do |key, field|
142
- field_params[key] = field
140
+ def schema
141
+ @schema ||= init.each_with_object({}) do |error, hash|
142
+ key, value = error
143
+ hash[key] = value
143
144
  end
144
- @fields ||= field_params
145
145
  end
146
146
 
147
- def check_base_on_field_type key
148
- case fields[key][:type]
147
+ def check_base_on_field_type(key)
148
+ case schema[key][:type]
149
149
  when 'num'
150
- ParamChecker::NumParamChecker.call key, fields, params
151
- when 'int'
152
- ParamChecker::IntParamChecker.call key, fields, params
150
+ ParamChecker::NumParamChecker.call(key, schema, params)
151
+ when 'int'
152
+ ParamChecker::IntParamChecker.call(key, schema, params)
153
153
  when 'char'
154
- ParamChecker::CharParamChecker.call key, fields, params
154
+ ParamChecker::CharParamChecker.call(key, schema, params)
155
155
  when 'text'
156
- ParamChecker::CharParamChecker.call key, fields, params
156
+ ParamChecker::CharParamChecker.call(key, schema, params)
157
157
  when 'arr'
158
- ParamChecker::ArrParamChecker.call key, fields, params
158
+ ParamChecker::ArrParamChecker.call(key, schema, params)
159
+ when 'hash'
160
+ ParamChecker::HashParamChecker.call(key, schema, params)
159
161
  when 'nested_hash'
160
- ParamChecker::NestedHashChecker.call key, fields, params, context
162
+ ParamChecker::NestedHashChecker.call(key, schema, params, context)
161
163
  when 'nested_hashs'
162
- ParamChecker::NestedHashsChecker.call key, fields, params, context
164
+ ParamChecker::NestedHashsChecker.call(key, schema, params, context)
163
165
  when 'date'
164
- ParamChecker::DateParamChecker.call key, fields, params
166
+ ParamChecker::DateParamChecker.call(key, schema, params)
165
167
  when 'time'
166
- ParamChecker::TimeParamChecker.call key, fields, params
168
+ ParamChecker::TimeParamChecker.call(key, schema, params)
167
169
  when 'datetime'
168
- ParamChecker::DateTimeParamChecker.call key, fields, params
169
- when 'email'
170
- ParamChecker::EmailParamChecker.call key, fields, params
170
+ ParamChecker::DateTimeParamChecker.call(key, schema, params)
171
171
  when 'boolean'
172
- ParamChecker::BooleanChecker.call key, fields, params
172
+ ParamChecker::BooleanChecker.call(key, schema, params)
173
173
  when 'file'
174
- ParamChecker::FileChecker.call key, fields, params
174
+ ParamChecker::FileChecker.call(key, schema, params)
175
175
  end
176
176
  end
177
177
 
178
- def custom_check
179
- specify_field_checks && all_fields_check
180
- end
181
-
182
- def specify_field_checks
183
- @formatted_params_after_custom_specify_field_checks = formatted_params_after_default_check
184
- fields.each do |key, value|
178
+ def fields_check
179
+ @formatted_params_after_custom_fields_check = formatted_params_after_default_fields_check
180
+ schema.each do |key, _|
185
181
  # next unless self.methods.grep(/check_#{key}/).length > 0
186
- next unless "check_#{key}".to_sym.in?(self.methods)
187
-
188
- specify_field_check(key)
182
+ need_to_check = "check_#{key}".to_sym.in?(methods)
183
+ passed_default_check = errors[key].nil?
184
+
185
+ next unless need_to_check && passed_default_check
186
+
187
+ field_check(key)
189
188
  end
190
189
  end
191
190
 
192
- def specify_field_check(key)
191
+ def field_check(key)
193
192
  check_method = "check_#{key}"
194
193
  total_parameters = method(check_method).arity
195
- # check_id(id) or check_id(id, opts)
196
- value = total_parameters == 1 ? self.send(check_method, @formatted_params_after_default_check[key])
197
- : self.send(check_method, @formatted_params_after_default_check[key], @formatted_params_after_default_check)
198
- @formatted_params_after_custom_specify_field_checks.delete(key)
199
- @formatted_params_after_custom_specify_field_checks[key] = value
194
+ # pp "========>total_parameters : ", total_parameters
195
+
196
+ value = if total_parameters == 1
197
+ # like check_name(name)
198
+ send(check_method, @formatted_params_after_default_fields_check[key])
199
+ elsif total_parameters == 2
200
+ # like check_name(name, opts)
201
+ send(check_method, @formatted_params_after_default_fields_check[key], @formatted_params_after_default_fields_check)
202
+ end
203
+
204
+ @formatted_params_after_custom_fields_check[key] = value
205
+ rescue ParamsChecker::FieldError => e
206
+ # binding.pry
207
+ key = e.data[:key].presence || key
208
+ @custom_check_errors[key] = e.data[:message]
200
209
  end
201
210
 
202
- def all_fields_check
203
- @formatted_params_after_custom_all_fields_check = check formatted_params_after_custom_specify_field_checks
211
+ def overall_check
212
+ @formatted_params_after_custom_overall_check = check(formatted_params_after_custom_fields_check)
213
+ rescue ParamsChecker::FieldError => e
214
+ key = e.data[:key]
215
+ @custom_check_errors[key] = e.data[:message]
204
216
  end
205
217
 
206
218
  def init
207
219
  {}
208
220
  end
209
221
 
210
- def check params
222
+ def check(params)
211
223
  params
212
224
  end
213
225
 
214
226
  def formatted_params
215
- formatted_params_after_custom_all_fields_check
227
+ formatted_params_after_custom_overall_check
216
228
  end
217
229
 
218
- def add_error()
219
- # only add errors skeleton at the outest hash
220
- return unless is_outest_hash
230
+ def add_errors
231
+ # only add errors at the outest hash
232
+ # return unless is_outest_hash
233
+
234
+ field_errors = errors.each_with_object({}) do |error, hash|
235
+ key, value = error
236
+ value = value.is_a?(Array) ? value[0] : value
237
+ hash[key] = value
221
238
 
222
- details = {}
223
- errors.each do |key, value|
224
- details[key] = value
225
- errors.delete(key)
239
+ errors.delete(key)
226
240
  end
227
- errors.add(:errors, {
228
- message: 'Invalid data',
229
- details: details
230
- })
241
+
242
+ @custom_check_errors.each do |key, value|
243
+ field_errors[key] = value
244
+ end
245
+
246
+ errors.add(
247
+ :errors,
248
+ {
249
+ message: DEFAULT_MESSAGE_ERROR,
250
+ error_type: 'fields_errors',
251
+ field_errors: field_errors
252
+ }
253
+ )
231
254
  end
232
255
 
233
- attr_accessor :params, :context,
234
- :formatted_params_after_default_check,
235
- :formatted_params_after_custom_specify_field_checks,
236
- :formatted_params_after_custom_all_fields_check,
237
- :is_outest_hash
256
+ attr_accessor :params,
257
+ :context,
258
+ :formatted_params_after_default_fields_check,
259
+ :formatted_params_after_custom_fields_check,
260
+ :formatted_params_after_custom_overall_check,
261
+ :is_outest_hash,
262
+ # :message,
263
+ :custom_check_errors
238
264
  end
239
265
  end
240
266
 
241
-
242
- # return true if value_need_to_be_present?(key) && value_present?(key) && value_valid?(key)
243
- # return false if value_need_to_be_present?(key) && value_present?(key) && !value_valid?(key)
244
- # return false if value_need_to_be_present?(key) && !value_present?(key) && value_valid?(key)
245
- # return false if value_need_to_be_present?(key) && !value_present?(key) && !value_valid?(key)
246
- # return true if !value_need_to_be_present?(key) && value_present?(key) && value_valid?(key)
247
- # return false if !value_need_to_be_present?(key) && value_present?(key) && !value_valid?(key)
248
- # return true if !value_need_to_be_present?(key) && !value_present?(key) && value_valid?(key)
249
- # return true if !value_need_to_be_present?(key) && !value_present?(key) && !value_valid?(key)
267
+ # return true if value_need_to_be_present?(key) && value_present?(key) && value_valid?(key)
268
+ # return false if value_need_to_be_present?(key) && value_present?(key) && !value_valid?(key)
269
+ # return false if value_need_to_be_present?(key) && !value_present?(key) && value_valid?(key)
270
+ # return false if value_need_to_be_present?(key) && !value_present?(key) && !value_valid?(key)
271
+ # return true if !value_need_to_be_present?(key) && value_present?(key) && value_valid?(key)
272
+ # return false if !value_need_to_be_present?(key) && value_present?(key) && !value_valid?(key)
273
+ # return true if !value_need_to_be_present?(key) && !value_present?(key) && value_valid?(key)
274
+ # return true if !value_need_to_be_present?(key) && !value_present?(key) && !value_valid?(key)
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Constants
4
+ ERROR_MESSAGES = {
5
+ required: 'This field is required.',
6
+ blank: 'This field cannot be blank.',
7
+ empty: 'This field cannot be empty.',
8
+
9
+ type: {
10
+ string: "This field's type must be string.",
11
+ file: "This field's type must be file.",
12
+ hash: "This field's type must be hash.",
13
+ nested_hash: "This field's type must be object or ActionController::Parameters.",
14
+ array: "This field's type must be array.",
15
+ integer: "This field's type must be integer.",
16
+ numeric: "This field's type must be numeric.",
17
+ boolean: "This field's type must be boolean.",
18
+ date: 'Invalid date.',
19
+ time: 'Invalid time.',
20
+ datetime: 'Invalid datetime.'
21
+ },
22
+
23
+ length: {
24
+ text: 'Invalid text length.',
25
+ char: 'Invalid char length.'
26
+ },
27
+
28
+ value: {
29
+ numeric: 'Invalid numeric value.',
30
+ integer: 'Invalid integer value.'
31
+ }
32
+ }.freeze
33
+
34
+ def get_integer_value_error_message(min: -2_000_000_000_000, max: 2_000_000_000_000)
35
+ "This integer field's value must be in range from #{min} to #{max}."
36
+ end
37
+
38
+ def get_numeric_value_error_message(min: -2_000_000_000_000, max: 2_000_000_000_000)
39
+ "This numeric field's value must be in range from #{min} to #{max}."
40
+ end
41
+
42
+ def get_string_length_error_message(min_length: 0, max_length: 30_000)
43
+ "This string field's length must be in range from #{min_length} to #{max_length}."
44
+ end
45
+ end
@@ -1,6 +1,10 @@
1
1
  module ParamsChecker
2
2
  class Engine < ::Rails::Engine
3
3
  isolate_namespace ParamsChecker
4
+
5
+ config.generators do |g|
6
+ g.test_framework :rspec
7
+ end
4
8
  end
5
9
  class NotEngine
6
10
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ParamsChecker
4
+ class FieldError < StandardError
5
+ attr_accessor :data
6
+
7
+ def initialize(data)
8
+ @data = data
9
+ end
10
+ end
11
+ end