lib/avromatic/model/validation.rb in avromatic-1.0.0 vs lib/avromatic/model/validation.rb in avromatic-2.0.0
- old
+ new
@@ -1,54 +1,75 @@
+# frozen_string_literal: true
+
module Avromatic
module Model
module Validation
extend ActiveSupport::Concern
+ include ActiveModel::Validations
- module ClassMethods
+ EMPTY_ARRAY = [].freeze
- # Returns an array of messages
- def validate_nested_value(value)
- case value
- when Avromatic::Model::Attributes
- validate_record_value(value)
- when Array
- value.flat_map.with_index do |element, index|
- validate_nested_value(element).map do |message|
- "[#{index}]#{message}"
- end
- end
- when Hash
- value.flat_map do |key, map_value|
- # keys for the Avro map type are always strings and do not require
- # validation
- validate_nested_value(map_value).map do |message|
- "['#{key}']#{message}"
- end
- end
- else
- []
+ def self.missing_nested_attributes(attribute, value)
+ if value.is_a?(Array)
+ results = []
+ value.each_with_index do |element, index|
+ nested_results = missing_nested_attributes("#{attribute}[#{index}]", element)
+ results.concat(nested_results)
end
+ results
+ elsif value.is_a?(Hash)
+ results = []
+ value.each do |key, element|
+ nested_results = missing_nested_attributes("#{attribute}['#{key}']", element)
+ results.concat(nested_results)
+ end
+ results
+ elsif value.respond_to?(:missing_avro_attributes)
+ value.missing_avro_attributes.map do |missing_child_attribute|
+ "#{attribute}.#{missing_child_attribute}"
+ end
+ else
+ EMPTY_ARRAY
end
+ end
- private
-
- def validate_complex(field_name)
- validate do |instance|
- value = instance.send(field_name)
- messages = self.class.validate_nested_value(value)
- messages.each { |message| instance.errors.add(field_name.to_sym, message) }
+ included do
+ # Support the ActiveModel::Validations interface for backwards compatibility
+ validate do |model|
+ model.missing_avro_attributes.each do |missing_attribute|
+ errors.add(:base, "#{missing_attribute} can't be nil")
end
end
+ end
- def validate_record_value(record)
- if record && record.invalid?
- record.errors.map do |key, message|
- ".#{key} #{message}".gsub(' .', '.')
- end
+ def avro_validate!
+ results = missing_avro_attributes
+ if results.present?
+ raise Avromatic::Model::ValidationError.new("#{self.class.name}(#{attributes.inspect}) cannot be " \
+ "serialized because the following attributes are nil: #{results.join(', ')}")
+ end
+ end
+
+ def missing_avro_attributes
+ return @missing_attributes if instance_variable_defined?(:@missing_attributes)
+
+ missing_attributes = []
+
+ self.class.attribute_definitions.each_value do |attribute_definition|
+ value = send(attribute_definition.name)
+ field = attribute_definition.field
+ if value.nil? && field.type.type_sym != :null && attribute_definition.required?
+ missing_attributes << field.name
else
- []
+ missing_attributes.concat(Avromatic::Model::Validation.missing_nested_attributes(field.name, value))
end
end
+
+ unless self.class.config.mutable
+ @missing_attributes = missing_attributes.deep_freeze
+ end
+
+ missing_attributes
end
end
end
end