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