1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
|
# frozen_string_literal: true
module Aws
# @api private
class ParamValidator
include Seahorse::Model::Shapes
EXPECTED_GOT = "expected %s to be %s, got value %s (class: %s) instead."
# @param [Seahorse::Model::Shapes::ShapeRef] rules
# @param [Hash] params
# @return [void]
def self.validate!(rules, params)
new(rules).validate!(params)
end
# @param [Seahorse::Model::Shapes::ShapeRef] rules
# @option options [Boolean] :validate_required (true)
def initialize(rules, options = {})
@rules = rules || begin
shape = StructureShape.new
shape.struct_class = EmptyStructure
ShapeRef.new(shape: shape)
end
@validate_required = options[:validate_required] != false
@input = options[:input].nil? ? true : !!options[:input]
end
# @param [Hash] params
# @return [void]
def validate!(params)
errors = []
structure(@rules, params, errors, 'params') if @rules
raise ArgumentError, error_messages(errors) unless errors.empty?
end
private
def structure(ref, values, errors, context)
# ensure the value is hash like
return unless correct_type?(ref, values, errors, context)
if ref.eventstream
# input eventstream is provided from event signals
values.each do |value|
# each event is structure type
case value[:message_type]
when 'event'
val = value.dup
val.delete(:message_type)
structure(ref.shape.member(val[:event_type]), val, errors, context)
when 'error' # Error is unmodeled
when 'exception' # Pending
raise Aws::Errors::EventStreamParserError.new(
':exception event validation is not supported')
end
end
else
shape = ref.shape
# ensure required members are present
if @validate_required
shape.required.each do |member_name|
input_eventstream = ref.shape.member(member_name).eventstream && @input
if values[member_name].nil? && !input_eventstream
param = "#{context}[#{member_name.inspect}]"
errors << "missing required parameter #{param}"
end
end
end
# validate non-nil members
values.each_pair do |name, value|
unless value.nil?
# :event_type is not modeled
# and also needed when construct body
next if name == :event_type
if shape.member?(name)
member_ref = shape.member(name)
shape(member_ref, value, errors, context + "[#{name.inspect}]")
else
errors << "unexpected value at #{context}[#{name.inspect}]"
end
end
end
end
end
def list(ref, values, errors, context)
# ensure the value is an array
unless values.is_a?(Array)
errors << expected_got(context, "an Array", values)
return
end
# validate members
member_ref = ref.shape.member
values.each.with_index do |value, index|
shape(member_ref, value, errors, context + "[#{index}]")
end
end
def map(ref, values, errors, context)
unless Hash === values
errors << expected_got(context, "a hash", values)
return
end
key_ref = ref.shape.key
value_ref = ref.shape.value
values.each do |key, value|
shape(key_ref, key, errors, "#{context} #{key.inspect} key")
shape(value_ref, value, errors, context + "[#{key.inspect}]")
end
end
def shape(ref, value, errors, context)
case ref.shape
when StructureShape then structure(ref, value, errors, context)
when ListShape then list(ref, value, errors, context)
when MapShape then map(ref, value, errors, context)
when StringShape
unless value.is_a?(String)
errors << expected_got(context, "a String", value)
end
when IntegerShape
unless value.is_a?(Integer)
errors << expected_got(context, "an Integer", value)
end
when FloatShape
unless value.is_a?(Float)
errors << expected_got(context, "a Float", value)
end
when TimestampShape
unless value.is_a?(Time)
errors << expected_got(context, "a Time object", value)
end
when BooleanShape
unless [true, false].include?(value)
errors << expected_got(context, "true or false", value)
end
when BlobShape
unless value.is_a?(String)
if streaming_input?(ref)
unless io_like?(value, _require_size = false)
errors << expected_got(
context,
"a String or IO like object that supports read and rewind",
value
)
end
elsif !io_like?(value, _require_size = true)
errors << expected_got(
context,
"a String or IO like object that supports read, rewind, and size",
value
)
end
end
else
raise "unhandled shape type: #{ref.shape.class.name}"
end
end
def correct_type?(ref, value, errors, context)
if ref.eventstream && @input
errors << "instead of providing value directly for eventstreams at input,"\
" expected to use #signal events per stream"
return false
end
case value
when Hash then true
when ref.shape.struct_class then true
when Enumerator then ref.eventstream && value.respond_to?(:event_types)
else
errors << expected_got(context, "a hash", value)
false
end
end
def io_like?(value, require_size = true)
value.respond_to?(:read) && value.respond_to?(:rewind) &&
(!require_size || value.respond_to?(:size))
end
def streaming_input?(ref)
(ref["streaming"] || ref.shape["streaming"])
end
def error_messages(errors)
if errors.size == 1
errors.first
else
prefix = "\n - "
"parameter validator found #{errors.size} errors:" +
prefix + errors.join(prefix)
end
end
def expected_got(context, expected, got)
EXPECTED_GOT % [context, expected, got.inspect, got.class.name]
end
end
end
|