[sqlalchemy] Re: Pre-commit validation spanning multiple tables/ORM classes

2009-09-22 Thread King Simon-NFHD78

 -Original Message-
 From: sqlalchemy@googlegroups.com 
 [mailto:sqlalch...@googlegroups.com] On Behalf Of Randall Nortman
 Sent: 22 September 2009 16:31
 To: sqlalchemy
 Subject: [sqlalchemy] Pre-commit validation spanning multiple 
 tables/ORM classes
 

[SNIP]

 
 So if I do this with a SessionExtension.before_commit(), I would have
 to iterate through the new, dirty, and deleted instances lists,
 inspect the type of each instance, and do whatever is required.  I am
 not sure, though, how to handle the case of a change in membership in
 the parent/child relationship -- the child instance that is present in
 the dirty list will have only the new parent on it -- how do I find
 out what the old parent was, so I can validate it?  If a flush has
 already occurred, the old value is already lost in the context of the
 current transaction, and I think that if I open a new transaction
 inside a before_commit() validator I'm just asking for trouble.  Do I
 need to instrument the Child class with a descriptor that tracks
 changes to the parent and remembers the old parent?  Or can I set the
 cascade option in such a way that the old parent will end up in the
 dirty list, even though there are no changes to its underlying table,
 and in fact it may never have been explicitly loaded into the
 session?  (I must admit to be somewhat unsure of what the different
 cascade options do -- but they don't seem to be useful for tracking
 something like this.)
 

I can't answer most of your question, but as far as finding out what the
old parent was, could you use the get_history function?

http://www.sqlalchemy.org/docs/05/reference/orm/mapping.html#sqlalchemy
.orm.attributes.get_history

Hope that helps,

Simon

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Pre-commit validation spanning multiple tables/ORM classes

2009-09-22 Thread bojanb

My issue with SQLA validators is that they don't allow inconsistent
state even on fields of a single object, which makes multi-field
validation impossible.

Eg. imagine you have fields tax_id and country_code on a customer
object. For country code 'us', tax_id should be 9 digits long; for
country code 'ca', tax_id should be 15 digits long . If you create
appropriate validators on both fields, you will never be able to
change either the tax_id or country_code of any customer object.

The solution would be to allow inconsistent objects but do validation
just before commit. I've been planning on implementing such validation
for a project I'm working on, so any suggestions are welcome.

On Sep 22, 5:30 pm, Randall Nortman wondercl...@gmail.com wrote:
 In my application, I have a set of tables that model parts of what are
 conceptually composite objects, and I need to validate that the state
 of the objects is coherent before committing them to the database.  In
 the course of building up the network of objects, the state may be
 temporarily inconsistent (because it will, in general, be impossible
 to maintain consistency at every step of the process), but I want to
 make sure it is consistent by the time it hits the database.  I think
 the answer is to make a SessionExtension and use before_commit(), but
 I still have some questions about exactly how that works.

 To make the question concrete, I have a one-to-many relationship, and
 the relevant state is the state of the parent+children composite.  Any
 change to a child's attributes needs to trigger re-validation of the
 parent, and obviously any change in membership in the collection of
 children needs to trigger revalidation.  In particular, if a child
 moves from one parent to another, then *both* parents must be re-
 validated before the transaction is committed.  All this validation
 needs to occur even though the parent table is not modified in any of
 those cases.  And I think I will likely want this to work also in a
 many-to-many relationship, where any change to the association table
 should trigger validation of all related (or newly unrelated) objects.

 Furthermore, I want to work with these objects as individual Parent
 and Child objects, not a single ParentWithChildren object.  Or at a
 minimum, I want to be able to pass around and modify Child objects on
 their own; if I get the Children every time I ask for the Parent,
 that's fine.

 The @validates decorator is largely useless for this purpose, as it
 validates a particular attribute of a particular class, and it gets
 called at the wrong time, and in the case of collections, only gets
 called on append events, not remove events (afaict).

 So if I do this with a SessionExtension.before_commit(), I would have
 to iterate through the new, dirty, and deleted instances lists,
 inspect the type of each instance, and do whatever is required.  I am
 not sure, though, how to handle the case of a change in membership in
 the parent/child relationship -- the child instance that is present in
 the dirty list will have only the new parent on it -- how do I find
 out what the old parent was, so I can validate it?  If a flush has
 already occurred, the old value is already lost in the context of the
 current transaction, and I think that if I open a new transaction
 inside a before_commit() validator I'm just asking for trouble.  Do I
 need to instrument the Child class with a descriptor that tracks
 changes to the parent and remembers the old parent?  Or can I set the
 cascade option in such a way that the old parent will end up in the
 dirty list, even though there are no changes to its underlying table,
 and in fact it may never have been explicitly loaded into the
 session?  (I must admit to be somewhat unsure of what the different
 cascade options do -- but they don't seem to be useful for tracking
 something like this.)

 And lastly, what do I do inside before_commit() if I want to prevent
 the commit from proceeding?  Do I just raise an exception?  Any
 particular type of exception, or is it my choice?

 Sorry for the long question, and thanks for any assistance,

 Randall
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Pre-commit validation spanning multiple tables/ORM classes

2009-09-22 Thread Michael Bayer

bojanb wrote:

 My issue with SQLA validators is that they don't allow inconsistent
 state even on fields of a single object, which makes multi-field
 validation impossible.

meaning, you set A.a and you can't depend on A.b being correct yet ?  
Well sure.  How would you have it done ?  Something has to trigger the
validate event at some point. So if you need to wait for all of A.a,
A.b, A.c, etc. to be setup first, then sure you'd throw your validation
into before_flush() or mapper extension before_insert()/before_update() -
or just tailor your classes' interface as needed, such as A.set_values(a,
b, c).   Personally I opt for the latter since its simple and produces an
immediate validation effect rather than waiting for a flush.




--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Pre-commit validation spanning multiple tables/ORM classes

2009-09-22 Thread bojanb

 meaning, you set A.a and you can't depend on A.b being correct yet ?  
 Well sure.  How would you have it done ?  Something has to trigger the
 validate event at some point.     So if you need to wait for all of A.a,
 A.b, A.c, etc. to be setup first, then sure you'd throw your validation
 into before_flush() or mapper extension before_insert()/before_update() -
 or just tailor your classes' interface as needed, such as A.set_values(a,
 b, c).   Personally I opt for the latter since its simple and produces an
 immediate validation effect rather than waiting for a flush.

What I meant to say is that validators don't fit well with something
that I'm attempting to do. I'll probably implement a little validation
framework that will do validations just before a flush. I'll be sure
to post it here if its interesting enough!
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---