lib/nxt_schema/node/schema.rb in nxt_schema-0.1.2 vs lib/nxt_schema/node/schema.rb in nxt_schema-1.0.0
- old
+ new
@@ -1,147 +1,21 @@
module NxtSchema
module Node
class Schema < Node::Base
- def initialize(name:, type: NxtSchema::Types::Strict::Hash, parent_node:, **options, &block)
- @template_store = TemplateStore.new
- super
- end
+ include HasSubNodes
- def apply(input, parent_node: self.parent_node, context: nil)
- self.input = input
- register_node(context)
+ DEFAULT_TYPE = NxtSchema::Types::Strict::Hash
- self.parent_node = parent_node
- self.schema_errors = { schema_errors_key => [] }
- self.validation_errors = { schema_errors_key => [] }
- self.value_store = {}
- self.value = transform_keys(input)
-
- if maybe_criteria_applies?(value)
- self.value_store = value
- else
- self.value = value_or_default_value(value)
-
- unless maybe_criteria_applies?(value)
- self.value = coerce_value(value)
-
- # TODO: We should not allow additional keys to be present per default?!
- # TODO: Handle this here
-
-
-
- sanitized_keys.each do |key|
- node = template_store[key]
-
- if allowed_additional_key?(key)
- value_store[key] = input[key]
- elsif node.presence? || input.key?(key)
- node.apply(input[key], parent_node: self, context: context).schema_errors?
- value_store[key] = node.value
- schema_errors[key] = node.schema_errors
- validation_errors[key] = node.validation_errors
- else
- evaluate_optional_option(node, input, key)
- end
- end
-
- self.value_store = coerce_value(value_store)
- self.value = value_store
- end
- end
-
- self_without_empty_schema_errors
- rescue Dry::Types::ConstraintError, Dry::Types::CoercionError => error
- add_schema_error(error.message)
- self_without_empty_schema_errors
- ensure
- mark_as_applied
+ def initialize(name:, type: DEFAULT_TYPE, parent_node:, **options, &block)
+ super
end
- def optional(name, type, **options, &block)
- raise_invalid_options_presence_options if options[:presence]
-
- node(name, type, options.merge(optional: true), &block)
+ def optional(name, node_or_type_of_node, **options, &block)
+ node(name, node_or_type_of_node, **options.merge(optional: true), &block)
end
- def present(name, type, **options, &block)
- raise_invalid_options_presence_options if options[:optional]
-
- node(name, type, options.merge(presence: true), &block)
- end
-
- private
-
- def evaluate_optional_option(node, hash, key)
- optional_option = node.options[:optional]
-
- if optional_option.respond_to?(:call)
- # Validator is added to the schema node!
- add_validators(validator(:optional_node, optional_option, key))
- elsif !optional_option
- error_message = ErrorMessages.resolve(
- locale,
- :required_key_missing,
- key: key,
- target: hash
- )
-
- add_schema_error(error_message)
- end
- end
-
- def transform_keys(hash)
- return hash unless key_transformer && hash.respond_to?(:transform_keys!)
-
- hash.transform_keys! { |key| Callable.new(key_transformer).bind(key).call(key) }
- end
-
- def key_transformer
- @key_transformer ||= root.options.fetch(:transform_keys) { false }
- end
-
- def sanitized_keys
- return template_store.keys if additional_keys_from_input.empty? || ignore_additional_keys?
- return template_store.keys + additional_keys_from_input if additional_keys_allowed?
-
- if restrict_additional_keys?
- error_message = ErrorMessages.resolve(
- locale,
- :additional_keys_detected,
- keys: additional_keys_from_input,
- target: input
- )
-
- add_schema_error(error_message)
-
- template_store.keys
- else
- raise Errors::InvalidOptionsError, "Invalid option for additional keys: #{additional_keys_strategy}"
- end
- end
-
- def allowed_additional_key?(key)
- additional_keys_from_input.include?(key)
- end
-
- def additional_keys_from_input
- (input&.keys || []) - template_store.keys
- end
-
- def additional_keys_allowed?
- additional_keys_strategy.to_s == 'allow'
- end
-
- def ignore_additional_keys?
- additional_keys_strategy.to_s == 'ignore'
- end
-
- def restrict_additional_keys?
- additional_keys_strategy.to_s == 'restrict'
- end
-
- def raise_invalid_options_presence_options
- raise InvalidOptionsError, 'Options :presence and :optional exclude each other'
+ def omnipresent(name, node_or_type_of_node, **options, &block)
+ node(name, node_or_type_of_node, **options.merge(omnipresent: true), &block)
end
end
end
end