module ActiveShepherd::AggregateRoot
Public Class Methods
# File lib/active_shepherd/aggregate_root.rb, line 2 def self.included(base) base.extend(ClassMethods) end
Public Instance Methods
Public: Returns the list of changes to the aggregate that would persist if save were called on the aggregate root.
Examples
@project.aggregate_changes # => { name: ["Clean House", "Clean My House"], todos: [{ text: ["Take out trash", "Take out the trash" ...
Returns all changes in the aggregate
# File lib/active_shepherd/aggregate_root.rb, line 52 def aggregate_changes ActiveShepherd::Methods::QueryChanges.query_changes aggregate end
Public: Given a serializable blob of changes (Hash, Array, and String) objects, apply those changes to
Examples:
@project.aggregate_changes = { name: ["Clean House", "Clean My House"] }
Returns nothing. Raises ActiveShepherd::InvalidChangesError if the changes supplied do not
pass #valid_aggregate_changes? (see below)
Raises ActiveShepherd::BadChangeError if a particular attribute change
cannot be applied.
Raises an ActiveShepherd::AggregateMismatchError if any objects in the
aggregate are being asked to change attributes that do not exist.
# File lib/active_shepherd/aggregate_root.rb, line 26 def aggregate_changes=(changes) changes_errors = ActiveShepherd::ChangesValidator.new(self).validate changes unless changes_errors.empty? raise ActiveShepherd::InvalidChangesError, "changes hash is invalid: "\ "#{changes_errors.join(', ')}" end # The validation process actually runs the changes internally. This means # we don't have to explicitly invoke # #apply_changes here. # XXX: remove when ChangesValidator does this ActiveShepherd::Methods::ApplyChanges.apply_changes aggregate, changes end
Public: Returns the entire state of the aggregate as a serializable blob. All id values (primary keys) are extracted.
Examples
@project.aggregate_state # => { name: "Clean House", todos: [{ text: "Take out trash" ...
Returns serializable blob.
# File lib/active_shepherd/aggregate_root.rb, line 78 def aggregate_state ActiveShepherd::Methods::QueryState.query_state aggregate end
Public: Injects the entire state of the aggregate from a serializable blob.
Examples:
@project.aggregate_state = { name: "Clean House", todos: [{ text: "Take out trash" ...
Returns nothing. Raises an AggregateMismatchError if the blob contains references to objects
or attributes that do not exist in this aggregate.
# File lib/active_shepherd/aggregate_root.rb, line 65 def aggregate_state=(blob) ActiveShepherd::Methods::ApplyState.apply_state aggregate, blob end
Public: Reloads the entire aggregate by invoking reload on each of the records in the aggregate.
# File lib/active_shepherd/aggregate_root.rb, line 84 def reload_aggregate reload raise "NYI" end
Public: Reverses the effect of aggregate_changes=
# File lib/active_shepherd/aggregate_root.rb, line 39 def reverse_aggregate_changes=(changes) self.aggregate_changes = ActiveShepherd::DeepReverseChanges.new(changes).reverse end
Public: Validates a set of changes for the aggregate root.
* Does deep_reverse(deep_reverse(changes)) == changes? * Assuming the model is currently valid, if the changes were applied, would the aggregate be valid? * If I apply the changes, and then apply deep_reverse(changes), does #aggregate_state change?
See ActiveShepherd.deep_reverse
Examples:
@project.valid_aggregate_changes?(@project.aggregate_changes) # => true
Returns true if and only if the supplied changes pass muster.
# File lib/active_shepherd/aggregate_root.rb, line 105 def valid_aggregate_changes?(changes, emit_boolean = true) validator = ActiveShepherd::ChangesValidator.new(self) errors = validator.validate changes emit_boolean ? errors.blank? : errors ensure reload_aggregate end
Private Instance Methods
Private: returns the behind the scenes object that does all the work
# File lib/active_shepherd/aggregate_root.rb, line 7 def aggregate @aggregate ||= ActiveShepherd::Aggregate.new(self) end