A number of discussions on this mailing list centre around how to manage 
data integrity around multiple related objects. The classic example is a 
transaction in a double-entry accounting system, where a transaction must 
have at least two entries and all the entries of a transaction must sum to 
zero:


class Transaction < Sequel::Model
  one_to_many :entries

  def validate
    super
    validates_min_length 2, :entries
    errors.add(:entries, "must sum to zero") if 
entries.inject(0){|s,e|s+e.amount} != 0
  end
end

class Entry < Sequel::Model
  many_to_one :transaction
end


This won't work because the entries can't be created until the transaction 
is saved (we need a primary key for the transaction to associate the 
entries). The usual recommendation is to use the 'nested_attributes' plugin 
to create the transaction and the entries all together, but this is only 
part of the story.

I would like to be able to do things like the following:


trans = Transaction.first(...)
DB.transaction do
  trans.entries[0].amount += 10
  trans.entries[0].save
  trans.entries[1].amount -= 10
  trans.entries[1].save
end


I would like the (database) transaction to be rolled back if and only if 
the amounts don't balance, and the only time to check this is at the point 
that the transaction is about to be committed, because until then Sequel 
doesn't know if there are more changes to come.

Hence my suggestion / feature request is to have a 'before_commit' hook 
that allows me to implement deferred validations, that are checked once all 
changes have been made to a set of related objects and are about to be 
committed. This then allows Sequel to mirror the behaviour of deferred 
constraints, in databases that support them, or emulate them in databases 
that don't.


Another possible use case for a 'before_commit' hook might be to 
automatically save any unsaved objects when exiting a transaction block, to 
avoid the need to explicitly call 'save'. I'm not sure yet whether this is 
a good idea but having a 'before_commit' hook would make it easy to 
experiment with.

-- 
You received this message because you are subscribed to the Google Groups 
"sequel-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sequel-talk.
For more options, visit https://groups.google.com/d/optout.

Reply via email to