Module: FakeDynamo::Validation

Included in:
DB, Filter, Item, Key, Table
Defined in:
lib/fake_dynamo/validation.rb

Instance Method Summary collapse

Instance Method Details

#add_errors(message) ⇒ Object



17
18
19
# File 'lib/fake_dynamo/validation.rb', line 17

def add_errors(message)
  @api_errors << message
end

#api_configObject



114
115
116
# File 'lib/fake_dynamo/validation.rb', line 114

def api_config
  @api_config ||= YAML.load_file(api_config_path)
end

#api_config_pathObject



118
119
120
# File 'lib/fake_dynamo/validation.rb', line 118

def api_config_path
  File.join File.expand_path(File.dirname(__FILE__)), 'api.yml'
end

#api_input_spec(operation) ⇒ Object



110
111
112
# File 'lib/fake_dynamo/validation.rb', line 110

def api_input_spec(operation)
  api_config[:operations][operation][:input]
end

#available_operationsObject



32
33
34
# File 'lib/fake_dynamo/validation.rb', line 32

def available_operations
  api_config[:operations].keys
end

#param(attribute, parents) ⇒ Object



106
107
108
# File 'lib/fake_dynamo/validation.rb', line 106

def param(attribute, parents)
  (parents + [attribute]).join('.')
end

#validate!(&block) ⇒ Object



6
7
8
9
10
11
12
13
14
# File 'lib/fake_dynamo/validation.rb', line 6

def validate!(&block)
  @api_errors = []
  yield
  unless @api_errors.empty?
    plural = @api_errors.size == 1 ? '' : 's'
    message = "#{@api_errors.size} error#{plural} detected: #{@api_errors.join('; ')}"
    raise ValidationException, message
  end
end

#validate_input(operation, data) ⇒ Object



36
37
38
39
40
# File 'lib/fake_dynamo/validation.rb', line 36

def validate_input(operation, data)
  api_input_spec(operation).each do |attribute, spec|
    validate_spec(attribute, data[attribute], spec, [])
  end
end

#validate_key_data(data, key_schema) ⇒ Object



143
144
145
146
147
148
149
150
151
152
# File 'lib/fake_dynamo/validation.rb', line 143

def validate_key_data(data, key_schema)
  validate_type(data['HashKeyElement'], key_schema.hash_key)

  if key_schema.range_key
    range_key = data['RangeKeyElement'] or raise ValidationException, "Missing the key RangeKeyElement in the Key"
    validate_type(range_key, key_schema.range_key)
  elsif data['RangeKeyElement']
    raise ValidationException, "RangeKeyElement is not present in the schema"
  end
end

#validate_key_schema(data, key_schema) ⇒ Object



133
134
135
136
137
138
139
140
141
# File 'lib/fake_dynamo/validation.rb', line 133

def validate_key_schema(data, key_schema)
  key = data[key_schema.hash_key.name] or raise ValidationException, "Missing the key #{key_schema.hash_key.name} in the item"
  validate_type(key, key_schema.hash_key)

  if key_schema.range_key
    range_key = data[key_schema.range_key.name] or raise ValidationException, "Missing the key #{key_schema.range_key.name} in the item"
    validate_type(range_key, key_schema.range_key)
  end
end

#validate_operation(operation) ⇒ Object



28
29
30
# File 'lib/fake_dynamo/validation.rb', line 28

def validate_operation(operation)
  raise UnknownOperationException, "Unknown operation: #{operation}" unless available_operations.include? operation
end

#validate_payload(operation, data) ⇒ Object



21
22
23
24
25
26
# File 'lib/fake_dynamo/validation.rb', line 21

def validate_payload(operation, data)
  validate! do
    validate_operation(operation)
    validate_input(operation, data)
  end
end

#validate_spec(attribute, data, spec, parents) ⇒ Object



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
# File 'lib/fake_dynamo/validation.rb', line 42

def validate_spec(attribute, data, spec, parents)
  if not data
    if spec.include?(:required)
      add_errors("value null at '#{param(attribute, parents)}' failed to satisfy the constraint: Member must not be null")
    end
    return
  end

  spec.each do |constrain|
    case constrain
    when :string
      add_errors("The parameter '#{param(attribute, parents)}' must be a string") unless data.kind_of? String
    when :long
      add_errors("The parameter '#{param(attribute, parents)}' must be a long") unless data.kind_of? Integer
    when :integer
      add_errors("The parameter '#{param(attribute, parents)}' must be a integer") unless data.kind_of? Integer
    when :boolean
      add_errors("The parameter '#{param(attribute, parents)}' must be a boolean") unless (data.kind_of? TrueClass or data.kind_of? FalseClass)
    when Hash
      new_parents = parents + [attribute]
      case constrain.keys.first
      when :pattern
        pattern = constrain[:pattern]
        unless data =~ pattern
          add_errors("The parameter '#{param(attribute, parents)}' should match the pattern #{pattern}")
        end
      when :within
        range = constrain[:within]
        unless range.include? data.size
          add_errors("The parameter '#{param(attribute, parents)}' value '#{data}' should be within #{range} characters")
        end
      when :enum
        enum = constrain[:enum]
        unless enum.include? data
          add_errors("Value '#{data}' at '#{param(attribute, parents)}' failed to satisfy the constraint: Member must satisfy enum values set: #{enum}")
        end
      when :structure
        structure = constrain[:structure]
        structure.each do |attribute, spec|
          validate_spec(attribute, data[attribute], spec, new_parents)
        end
      when :map
        map = constrain[:map]
        raise "#{param(attribute, parents)} must be a Hash" unless data.kind_of? Hash
        data.each do |key, value|
          validate_spec(key, key, map[:key], new_parents)
          validate_spec(key, value, map[:value], new_parents)
        end
      when :list
        raise "#{param(attribute, parents)} must be a Array" unless data.kind_of? Array
        data.each do |element|
          validate_spec(element, element, constrain[:list], new_parents)
        end
      else
        raise "Unhandled constraint #{constrain}"
      end
    when :required
      # handled earlier
    else
      raise "Unhandled constraint #{constrain}"
    end
  end
end

#validate_type(value, attribute) ⇒ Object



122
123
124
125
126
127
128
129
130
131
# File 'lib/fake_dynamo/validation.rb', line 122

def validate_type(value, attribute)
  if attribute.kind_of?(Attribute)
    expected_type = value.keys.first
    if expected_type != attribute.type
      raise ValidationException, "Type mismatch for key #{attribute.name}"
    end
  else
    raise 'Unknown attribute'
  end
end