mutations 0.5.9 → 0.5.10
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.
- data/README.md +6 -6
- data/lib/mutations/array_filter.rb +23 -19
- data/lib/mutations/boolean_filter.rb +6 -6
- data/lib/mutations/command.rb +31 -31
- data/lib/mutations/errors.rb +10 -10
- data/lib/mutations/exception.rb +2 -2
- data/lib/mutations/hash_filter.rb +35 -31
- data/lib/mutations/input_filter.rb +8 -8
- data/lib/mutations/integer_filter.rb +5 -5
- data/lib/mutations/model_filter.rb +10 -10
- data/lib/mutations/outcome.rb +1 -1
- data/lib/mutations/string_filter.rb +10 -10
- data/lib/mutations/version.rb +1 -1
- data/mutations.gemspec +1 -1
- data/spec/array_filter_spec.rb +36 -28
- data/spec/boolean_filter_spec.rb +7 -7
- data/spec/command_spec.rb +42 -42
- data/spec/errors_spec.rb +19 -19
- data/spec/hash_filter_spec.rb +28 -19
- data/spec/inheritance_spec.rb +8 -8
- data/spec/integer_filter_spec.rb +11 -11
- data/spec/model_filter_spec.rb +21 -21
- data/spec/mutations_spec.rb +2 -2
- data/spec/simple_command.rb +3 -3
- data/spec/string_filter_spec.rb +18 -18
- metadata +1 -1
data/README.md
CHANGED
@@ -7,7 +7,7 @@ Compose your business logic into commands that sanitize and validate input. Writ
|
|
7
7
|
## Installation
|
8
8
|
|
9
9
|
gem install mutations
|
10
|
-
|
10
|
+
|
11
11
|
Or add it to your Gemfile:
|
12
12
|
|
13
13
|
gem 'mutations'
|
@@ -23,12 +23,12 @@ class UserSignup < Mutations::Command
|
|
23
23
|
string :email, matches: EMAIL_REGEX
|
24
24
|
string :name
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
# These inputs are optional
|
28
28
|
optional do
|
29
29
|
boolean :newsletter_subscribe
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
# The execute method is called only if the inputs validate. It does your business action.
|
33
33
|
def execute
|
34
34
|
user = User.create!(inputs)
|
@@ -54,7 +54,7 @@ end
|
|
54
54
|
Some things to note about the example:
|
55
55
|
|
56
56
|
* We don't need attr_accessible or strong_attributes to protect against mass assignment attacks
|
57
|
-
* We're guaranteed that within execute, the inputs will be the correct data types, even if they needed some coercion (all strings are stripped by default, and strings like "1" / "0" are converted to true/false for newsletter_subscribe)
|
57
|
+
* We're guaranteed that within execute, the inputs will be the correct data types, even if they needed some coercion (all strings are stripped by default, and strings like "1" / "0" are converted to true/false for newsletter_subscribe)
|
58
58
|
* We don't need ActiveRecord validations
|
59
59
|
* We don't need callbacks on our models -- everything is in the execute method (helper methods are also encouraged)
|
60
60
|
* We don't use accepts_nested_attributes_for, even though multiple ActiveRecord models are created
|
@@ -119,7 +119,7 @@ class CreateComment < Mutations::Command
|
|
119
119
|
model :article
|
120
120
|
string :comment, max_length: 500
|
121
121
|
end
|
122
|
-
|
122
|
+
|
123
123
|
def execute; ...; end
|
124
124
|
end
|
125
125
|
|
@@ -186,7 +186,7 @@ Your execute method has access to the inputs passed into it:
|
|
186
186
|
```ruby
|
187
187
|
self.inputs # white-listed hash of all inputs passed to run. Hash has indifferent access.
|
188
188
|
```
|
189
|
-
|
189
|
+
|
190
190
|
If you define an input called _email_, then you'll have these three methods:
|
191
191
|
|
192
192
|
```ruby
|
@@ -5,57 +5,61 @@ module Mutations
|
|
5
5
|
class: nil, # A constant or string indicates that each element of the array needs to be one of these classes
|
6
6
|
arrayize: false # true will convert "hi" to ["hi"]. "" converts to []
|
7
7
|
}
|
8
|
-
|
8
|
+
|
9
9
|
def initialize(name, opts = {}, &block)
|
10
10
|
super(opts)
|
11
|
-
|
11
|
+
|
12
12
|
@name = name
|
13
13
|
@element_filter = nil
|
14
|
-
|
14
|
+
|
15
15
|
if block_given?
|
16
16
|
instance_eval &block
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
raise ArgumentError.new("Can't supply both a class and a filter") if @element_filter && self.options[:class]
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
def string(options = {})
|
23
23
|
@element_filter = StringFilter.new(options)
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def integer(options = {})
|
27
27
|
@element_filter = IntegerFilter.new(options)
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
|
+
def float(options = {})
|
31
|
+
@element_filter = FloatFilter.new(options)
|
32
|
+
end
|
33
|
+
|
30
34
|
def boolean(options = {})
|
31
35
|
@element_filter = BooleanFilter.new(options)
|
32
36
|
end
|
33
|
-
|
37
|
+
|
34
38
|
def hash(options = {}, &block)
|
35
39
|
@element_filter = HashFilter.new(options, &block)
|
36
40
|
end
|
37
|
-
|
41
|
+
|
38
42
|
# Advanced types
|
39
43
|
def model(name, options = {})
|
40
44
|
@element_filter = ModelFilter.new(name.to_sym, options)
|
41
45
|
end
|
42
|
-
|
46
|
+
|
43
47
|
def array(options = {}, &block)
|
44
48
|
@element_filter = ArrayFilter.new(nil, options, &block)
|
45
49
|
end
|
46
|
-
|
50
|
+
|
47
51
|
def filter(data)
|
48
52
|
# Handle nil case
|
49
53
|
if data.nil?
|
50
54
|
return [nil, nil] if options[:nils]
|
51
55
|
return [nil, :nils]
|
52
56
|
end
|
53
|
-
|
57
|
+
|
54
58
|
if !data.is_a?(Array) && options[:arrayize]
|
55
59
|
return [[], nil] if data == ""
|
56
60
|
data = Array(data)
|
57
61
|
end
|
58
|
-
|
62
|
+
|
59
63
|
if data.is_a?(Array)
|
60
64
|
errors = ErrorArray.new
|
61
65
|
filtered_data = []
|
@@ -63,14 +67,14 @@ module Mutations
|
|
63
67
|
data.each_with_index do |el, i|
|
64
68
|
el_filtered, el_error = filter_element(el)
|
65
69
|
el_error = ErrorAtom.new(@name, el_error, index: i) if el_error.is_a?(Symbol)
|
66
|
-
|
70
|
+
|
67
71
|
errors << el_error
|
68
72
|
found_error = true if el_error
|
69
73
|
if !found_error
|
70
74
|
filtered_data << el_filtered
|
71
75
|
end
|
72
76
|
end
|
73
|
-
|
77
|
+
|
74
78
|
if found_error
|
75
79
|
[data, errors]
|
76
80
|
else
|
@@ -80,22 +84,22 @@ module Mutations
|
|
80
84
|
return [data, :array]
|
81
85
|
end
|
82
86
|
end
|
83
|
-
|
87
|
+
|
84
88
|
# Returns [filtered, errors]
|
85
89
|
def filter_element(data)
|
86
|
-
|
90
|
+
|
87
91
|
if @element_filter
|
88
92
|
data, el_errors = @element_filter.filter(data)
|
89
93
|
return [data, el_errors] if el_errors
|
90
94
|
elsif options[:class]
|
91
95
|
class_const = options[:class]
|
92
96
|
class_const = class_const.constantize if class_const.is_a?(String)
|
93
|
-
|
97
|
+
|
94
98
|
if !data.is_a?(class_const)
|
95
99
|
return [data, :class]
|
96
100
|
end
|
97
101
|
end
|
98
|
-
|
102
|
+
|
99
103
|
[data, nil]
|
100
104
|
end
|
101
105
|
end
|
@@ -3,23 +3,23 @@ module Mutations
|
|
3
3
|
@default_options = {
|
4
4
|
nils: false # true allows an explicit nil to be valid. Overrides any other options
|
5
5
|
}
|
6
|
-
|
6
|
+
|
7
7
|
BOOL_MAP = {"true" => true, "1" => true, "false" => false, "0" => false}
|
8
|
-
|
8
|
+
|
9
9
|
def filter(data)
|
10
|
-
|
10
|
+
|
11
11
|
# Handle nil case
|
12
12
|
if data.nil?
|
13
13
|
return [nil, nil] if options[:nils]
|
14
14
|
return [nil, :nils]
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
# If data is true or false, we win.
|
18
18
|
return [data, nil] if data == true || data == false
|
19
|
-
|
19
|
+
|
20
20
|
# If data is a Fixnum, like 1, let's convert it to a string first
|
21
21
|
data = data.to_s if data.is_a?(Fixnum)
|
22
|
-
|
22
|
+
|
23
23
|
# If data's a string, try to convert it to a boolean. If we can't, it's invalid.
|
24
24
|
if data.is_a?(String)
|
25
25
|
res = BOOL_MAP[data.downcase]
|
data/lib/mutations/command.rb
CHANGED
@@ -11,51 +11,51 @@
|
|
11
11
|
|
12
12
|
module Mutations
|
13
13
|
class Command
|
14
|
-
|
14
|
+
|
15
|
+
##
|
15
16
|
##
|
16
|
-
##
|
17
17
|
##
|
18
18
|
class << self
|
19
19
|
def required(&block)
|
20
20
|
self.input_filters.required(&block)
|
21
|
-
|
21
|
+
|
22
22
|
self.input_filters.required_keys.each do |key|
|
23
|
-
define_method(key) do
|
23
|
+
define_method(key) do
|
24
24
|
@filtered_input[key]
|
25
25
|
end
|
26
|
-
|
27
|
-
define_method("#{key}_present?") do
|
26
|
+
|
27
|
+
define_method("#{key}_present?") do
|
28
28
|
@filtered_input.has_key?(key)
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
define_method("#{key}=") do |v|
|
32
32
|
@filtered_input[key] = v
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
def optional(&block)
|
38
38
|
self.input_filters.optional(&block)
|
39
|
-
|
39
|
+
|
40
40
|
self.input_filters.optional_keys.each do |key|
|
41
|
-
define_method(key) do
|
41
|
+
define_method(key) do
|
42
42
|
@filtered_input[key]
|
43
43
|
end
|
44
|
-
|
45
|
-
define_method("#{key}_present?") do
|
44
|
+
|
45
|
+
define_method("#{key}_present?") do
|
46
46
|
@filtered_input.has_key?(key)
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
define_method("#{key}=") do |v|
|
50
50
|
@filtered_input[key] = v
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
54
|
-
|
54
|
+
|
55
55
|
def run(*args)
|
56
56
|
new(*args).execute!
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
def run!(*args)
|
60
60
|
m = run(*args)
|
61
61
|
if m.success?
|
@@ -64,12 +64,12 @@ module Mutations
|
|
64
64
|
raise ValidationException.new(m.errors)
|
65
65
|
end
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
# Validates input, but doesn't call execute. Returns an Outcome with errors anyway.
|
69
69
|
def validate(*args)
|
70
70
|
new(*args).validation_outcome
|
71
71
|
end
|
72
|
-
|
72
|
+
|
73
73
|
def input_filters
|
74
74
|
@input_filters ||= begin
|
75
75
|
if Command == self.superclass
|
@@ -79,9 +79,9 @@ module Mutations
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
end
|
82
|
-
|
82
|
+
|
83
83
|
end
|
84
|
-
|
84
|
+
|
85
85
|
# Instance methods
|
86
86
|
def initialize(*args)
|
87
87
|
if args.length == 0
|
@@ -91,24 +91,24 @@ module Mutations
|
|
91
91
|
raise ArgumentError.new("All arguments must be hashes") unless @original_hash.is_a?(Hash)
|
92
92
|
@original_hash = @original_hash.with_indifferent_access
|
93
93
|
end
|
94
|
-
|
94
|
+
|
95
95
|
args.each do |a|
|
96
96
|
raise ArgumentError.new("All arguments must be hashes") unless a.is_a?(Hash)
|
97
97
|
@original_hash.merge!(a)
|
98
98
|
end
|
99
|
-
|
99
|
+
|
100
100
|
@filtered_input, @errors = self.input_filters.filter(@original_hash)
|
101
101
|
end
|
102
|
-
|
102
|
+
|
103
103
|
def input_filters
|
104
104
|
self.class.input_filters
|
105
105
|
end
|
106
|
-
|
106
|
+
|
107
107
|
def execute!
|
108
108
|
return Outcome.new(false, nil, @errors) if @errors
|
109
|
-
|
109
|
+
|
110
110
|
# IDEA/TODO: run validate block
|
111
|
-
|
111
|
+
|
112
112
|
r = execute
|
113
113
|
if @errors # Execute can add errors
|
114
114
|
return Outcome.new(false, nil, @errors)
|
@@ -116,7 +116,7 @@ module Mutations
|
|
116
116
|
return Outcome.new(true, r, nil)
|
117
117
|
end
|
118
118
|
end
|
119
|
-
|
119
|
+
|
120
120
|
# Runs input thru the filter and sets @filtered_input and @errors
|
121
121
|
def validation_outcome
|
122
122
|
if @errors
|
@@ -125,14 +125,14 @@ module Mutations
|
|
125
125
|
Outcome.new(true, nil, nil)
|
126
126
|
end
|
127
127
|
end
|
128
|
-
|
128
|
+
|
129
129
|
# add_error("name", :too_short)
|
130
130
|
# add_error("colors.foreground", :not_a_color) # => to create errors = {colors: {foreground: :not_a_color}}
|
131
131
|
# or, supply a custom message:
|
132
132
|
# add_error("name", :too_short, "The name 'blahblahblah' is too short!")
|
133
133
|
def add_error(key, kind, message = nil)
|
134
134
|
raise ArgumentError.new("Invalid kind") unless kind.is_a?(Symbol)
|
135
|
-
|
135
|
+
|
136
136
|
@errors ||= ErrorHash.new
|
137
137
|
cur_errors = @errors
|
138
138
|
parts = key.to_s.split(".")
|
@@ -147,16 +147,16 @@ module Mutations
|
|
147
147
|
end
|
148
148
|
@errors
|
149
149
|
end
|
150
|
-
|
150
|
+
|
151
151
|
def merge_errors(hash)
|
152
152
|
@errors ||= ErrorHash.new
|
153
153
|
@errors.merge!(hash)
|
154
154
|
end
|
155
|
-
|
155
|
+
|
156
156
|
def inputs
|
157
157
|
@filtered_input
|
158
158
|
end
|
159
|
-
|
159
|
+
|
160
160
|
def execute
|
161
161
|
# Meant to be overridden
|
162
162
|
end
|
data/lib/mutations/errors.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
module Mutations
|
2
|
-
|
2
|
+
|
3
3
|
# Offers a non-localized, english only, non configurable way to get error messages. This probably isnt good enough for users as-is.
|
4
4
|
class DefaultErrorMessageCreator
|
5
|
-
|
5
|
+
|
6
6
|
MESSAGES = Hash.new("is invalid").tap do |h|
|
7
7
|
h.merge!(
|
8
8
|
# General
|
9
9
|
nils: "can't be nil",
|
10
10
|
required: "is required",
|
11
|
-
|
11
|
+
|
12
12
|
# Datatypes
|
13
13
|
string: "isn't a string",
|
14
14
|
integer: "isn't an integer",
|
@@ -16,26 +16,26 @@ module Mutations
|
|
16
16
|
hash: "isn't a hash",
|
17
17
|
array: "isn't an array",
|
18
18
|
model: "isn't the right class",
|
19
|
-
|
19
|
+
|
20
20
|
# String
|
21
21
|
empty: "can't be blank",
|
22
22
|
max_length: "is too long",
|
23
23
|
min_length: "is too short",
|
24
24
|
matches: "isn't in the right format",
|
25
25
|
in: "isn't an option",
|
26
|
-
|
26
|
+
|
27
27
|
# Array
|
28
28
|
class: "isn't the right class",
|
29
|
-
|
29
|
+
|
30
30
|
# Integer
|
31
31
|
min: "is too small",
|
32
32
|
max: "is too big",
|
33
|
-
|
33
|
+
|
34
34
|
# Model
|
35
35
|
new_records: "isn't a saved model"
|
36
36
|
)
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
# key: the name of the field, eg, :email. Could be nil if it's an array element
|
40
40
|
# error_symbol: the validation symbol, eg, :matches or :required
|
41
41
|
# options:
|
@@ -49,7 +49,7 @@ module Mutations
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
-
|
52
|
+
|
53
53
|
class ErrorAtom
|
54
54
|
|
55
55
|
# NOTE: in the future, could also pass in:
|
@@ -138,7 +138,7 @@ module Mutations
|
|
138
138
|
list
|
139
139
|
end
|
140
140
|
end
|
141
|
-
|
141
|
+
|
142
142
|
class ErrorArray < Array
|
143
143
|
def symbolic
|
144
144
|
map {|e| e && e.symbolic }
|
data/lib/mutations/exception.rb
CHANGED
@@ -3,22 +3,22 @@ module Mutations
|
|
3
3
|
@default_options = {
|
4
4
|
nils: false, # true allows an explicit nil to be valid. Overrides any other options
|
5
5
|
}
|
6
|
-
|
6
|
+
|
7
7
|
attr_accessor :optional_inputs
|
8
8
|
attr_accessor :required_inputs
|
9
|
-
|
9
|
+
|
10
10
|
def initialize(opts = {}, &block)
|
11
11
|
super(opts)
|
12
|
-
|
12
|
+
|
13
13
|
@optional_inputs = {}
|
14
14
|
@required_inputs = {}
|
15
15
|
@current_inputs = @required_inputs
|
16
|
-
|
16
|
+
|
17
17
|
if block_given?
|
18
18
|
instance_eval &block
|
19
19
|
end
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
def dup
|
23
23
|
dupped = HashFilter.new
|
24
24
|
@optional_inputs.each_pair do |k, v|
|
@@ -29,96 +29,100 @@ module Mutations
|
|
29
29
|
end
|
30
30
|
dupped
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
def required(&block)
|
34
34
|
# TODO: raise if nesting is wrong
|
35
35
|
@current_inputs = @required_inputs
|
36
36
|
instance_eval &block
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
def optional(&block)
|
40
40
|
# TODO: raise if nesting is wrong
|
41
41
|
@current_inputs = @optional_inputs
|
42
42
|
instance_eval &block
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
45
|
def required_keys
|
46
46
|
@required_inputs.keys
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
def optional_keys
|
50
50
|
@optional_inputs.keys
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
# Basic types:
|
54
54
|
def string(name, options = {})
|
55
55
|
@current_inputs[name.to_sym] = StringFilter.new(options)
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
def integer(name, options = {})
|
59
59
|
@current_inputs[name.to_sym] = IntegerFilter.new(options)
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
|
+
def float(name, options = {})
|
63
|
+
@current_inputs[name.to_sym] = FloatFilter.new(options)
|
64
|
+
end
|
65
|
+
|
62
66
|
def boolean(name, options = {})
|
63
67
|
@current_inputs[name.to_sym] = BooleanFilter.new(options)
|
64
68
|
end
|
65
|
-
|
69
|
+
|
66
70
|
def hash(name, options = {}, &block)
|
67
71
|
@current_inputs[name.to_sym] = HashFilter.new(options, &block)
|
68
72
|
end
|
69
|
-
|
73
|
+
|
70
74
|
# Advanced types
|
71
75
|
def model(name, options = {})
|
72
76
|
name_sym = name.to_sym
|
73
77
|
@current_inputs[name_sym] = ModelFilter.new(name_sym, options)
|
74
78
|
end
|
75
|
-
|
79
|
+
|
76
80
|
def array(name, options = {}, &block)
|
77
81
|
name_sym = name.to_sym
|
78
82
|
@current_inputs[name.to_sym] = ArrayFilter.new(name_sym, options, &block)
|
79
83
|
end
|
80
|
-
|
84
|
+
|
81
85
|
def filter(data)
|
82
|
-
|
86
|
+
|
83
87
|
# Handle nil case
|
84
88
|
if data.nil?
|
85
89
|
return [nil, nil] if options[:nils]
|
86
90
|
return [nil, :nils]
|
87
91
|
end
|
88
|
-
|
92
|
+
|
89
93
|
# Ensure it's a hash
|
90
94
|
return [data, :hash] unless data.is_a?(Hash)
|
91
|
-
|
95
|
+
|
92
96
|
# We always want a hash with indiffernet access
|
93
97
|
unless data.is_a?(HashWithIndifferentAccess)
|
94
98
|
data = data.with_indifferent_access
|
95
99
|
end
|
96
|
-
|
100
|
+
|
97
101
|
errors = ErrorHash.new
|
98
102
|
filtered_data = HashWithIndifferentAccess.new
|
99
103
|
wildcard_filterer = nil
|
100
|
-
|
104
|
+
|
101
105
|
[[@required_inputs, true], [@optional_inputs, false]].each do |(inputs, is_required)|
|
102
106
|
inputs.each_pair do |key, filterer|
|
103
|
-
|
107
|
+
|
104
108
|
# If we are doing wildcards, then record so and move on
|
105
109
|
if key == :*
|
106
110
|
wildcard_filterer = filterer
|
107
111
|
next
|
108
112
|
end
|
109
|
-
|
113
|
+
|
110
114
|
data_element = data[key]
|
111
|
-
|
115
|
+
|
112
116
|
# First, discard optional nils/empty params
|
113
117
|
data.delete(key) if !is_required && data.has_key?(key) && filterer.discard_nils? && data_element.nil?
|
114
118
|
data.delete(key) if !is_required && data.has_key?(key) && filterer.discard_empty? && data_element == ""
|
115
|
-
|
119
|
+
|
116
120
|
default_used = false
|
117
121
|
if !data.has_key?(key) && filterer.has_default?
|
118
122
|
data_element = filterer.default
|
119
123
|
default_used = true
|
120
124
|
end
|
121
|
-
|
125
|
+
|
122
126
|
if data.has_key?(key) || default_used
|
123
127
|
sub_data, sub_error = filterer.filter(data_element)
|
124
128
|
|
@@ -133,17 +137,17 @@ module Mutations
|
|
133
137
|
end
|
134
138
|
end
|
135
139
|
end
|
136
|
-
|
140
|
+
|
137
141
|
if wildcard_filterer
|
138
142
|
filtered_keys = data.keys - filtered_data.keys
|
139
|
-
|
143
|
+
|
140
144
|
filtered_keys.each do |key|
|
141
145
|
data_element = data[key]
|
142
|
-
|
146
|
+
|
143
147
|
# First, discard optional nils/empty params
|
144
148
|
next if data.has_key?(key) && wildcard_filterer.discard_nils? && data_element.nil?
|
145
149
|
next if data.has_key?(key) && wildcard_filterer.discard_empty? && data_element == ""
|
146
|
-
|
150
|
+
|
147
151
|
sub_data, sub_error = wildcard_filterer.filter(data_element)
|
148
152
|
if sub_error.nil?
|
149
153
|
filtered_data[key] = sub_data
|
@@ -153,7 +157,7 @@ module Mutations
|
|
153
157
|
end
|
154
158
|
end
|
155
159
|
end
|
156
|
-
|
160
|
+
|
157
161
|
if errors.any?
|
158
162
|
[data, errors]
|
159
163
|
else
|
@@ -1,36 +1,36 @@
|
|
1
1
|
module Mutations
|
2
2
|
class InputFilter
|
3
3
|
@default_options = {}
|
4
|
-
|
4
|
+
|
5
5
|
def self.default_options
|
6
6
|
@default_options
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
attr_accessor :options
|
10
|
-
|
10
|
+
|
11
11
|
def initialize(opts = {})
|
12
12
|
self.options = (self.class.default_options || {}).merge(opts)
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
# returns -> [sanitized data, error]
|
16
16
|
# If an error is returned, then data will be nil
|
17
17
|
def filter(data)
|
18
18
|
[data, nil]
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
def has_default?
|
22
22
|
options.has_key?(:default)
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
def default
|
26
26
|
options[:default]
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
# Only relevant for optional params
|
30
30
|
def discard_nils?
|
31
31
|
!options[:nils]
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
def discard_empty?
|
35
35
|
options[:discard_empty]
|
36
36
|
end
|