Skip to content

Instantly share code, notes, and snippets.

@mbj
Created August 15, 2011 22:18
Show Gist options
  • Save mbj/1148020 to your computer and use it in GitHub Desktop.
Save mbj/1148020 to your computer and use it in GitHub Desktop.
dm-validations proposal for a better command query seperation

Traditional

resource = Resource.new attributes
resource.valid?                  # => true | false
resource.save                    # => true | false Will raise adapter errors in case of Inconsistency
resource.errors                  # => ErrorSet (cached) will not reflect adapter errors
resource.attribute=invalid_value
resource.errors                  # Same error Set as above, will not reflect attribute change

Problems:

  • Command query seperation is low
  • Errors must not reflect the latest validation results
  • No central point to catch exceptions from adapters

New interface ExternalValidationState (mbj)

Naming is not authoritative.

The traditional API is left untouched. Only Resource#validate will be called more often.

  • ErrorSet will be upgraded to something like ValidationState
  • Resource#valid? is implemented as resource.validate.valid?
  • Resource#errors is aliased to Resource#validate, it does not cache anymore
  • Resource#{save,delete,update} is left untouched
  • before :valid? will be depreciated. IMHO it hides bad model design.
  • No way to navigate from a resource to an outdated validation result anymore.
resource = Resource.new attributes
state = resource.validate    # Resource#validate returns a more powerful ErrorSet (ValidationState?)
# This state carries the same information like #errors before, 
# but can also be responsible to persist the resource with 
# adapter exception converison.
state.save                   # => true | false

Store errors in PersistenceState (emdash)

Emmanuel: Pls enter your idea here!!!

# This ValidationState has exactly the same interface like ErrorSet plus a few additions for persistance.
class ValidationState
# Paste implementation of ErrorSet HERE
alias :valid? :empty?
def save
return false unless valid?
begin
return resource.save
rescue ListOfAdapterSpecificConfigurableExceptions => exception
add(transform_exception(exception))
false
end
end
private
def transform_exception(exception)
if exception.respond_to?(:foo)
Violation.new(resource,exception.foo)
else
Violation.new(resource,"repository error: #{exception.message}")
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment