module ActiveShepherd::AggregateRoot

Public Class Methods

included(base) click to toggle source
# File lib/active_shepherd/aggregate_root.rb, line 2
def self.included(base)
  base.extend(ClassMethods)
end

Public Instance Methods

aggregate_changes() click to toggle source

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
aggregate_changes=(changes) click to toggle source

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
aggregate_state() click to toggle source

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
aggregate_state=(blob) click to toggle source

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
reload_aggregate() click to toggle source

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
reverse_aggregate_changes=(changes) click to toggle source

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
valid_aggregate_changes?(changes, emit_boolean = true) click to toggle source

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

aggregate() click to toggle source

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