From: Ian B. <ia...@co...> - 2004-01-21 16:59:05
|
Brad Bollenbach wrote: > [Gah, very annoying that I can't reply on list. I'll try to get in touc= h=20 > with somebody at SourceForge today to figure out what's going wrong her= e.] >=20 > Le mardi, 20 jan 2004, =E0 12:23 Canada/Eastern, Ian Bicking a =E9crit = : >> Sidnei da Silva wrote: > [snip] >>> * Enforcing constraints in python. Brad B. was chatting to me on irc >>> yesterday and we came to agree on a api. He's writing a proposal (wit= h >>> a patch) and its going to present it soon. Basically, when you create >>> a column you would provide a callable object as a keyword 'constraint= ' >>> parameter. This constraint would then be used to enforce some >>> restrictions. >>> def foo_constraint(obj, name, value, values=3DNone): >>> # name is the column name >>> # value is the value to be set for this column >>> # values is a dict of the values to be set for other columns >>> # in the case you are creating an object or modifying more than >>> # one column at a time >>> # returns True or False >>> age =3D IntCol(constraint=3Dfoo_constraint) >>> class Col: >>> def __init__(self, name, constraint): >>> self.name =3D name >>> self.constraint =3D constraint >>> def __set__(self, obj, value): >>> if not self.constraint(obj, name, value): >>> raise ValueError, value >>> # Set the value otherwise >> >> >> We already have Python constraints available through the=20 >> validator/converter interface, which I hope to fill out some more, and= =20 >> provide some more documentation and examples. >=20 >=20 > These constraints are only useful in trivial cases though. I have at=20 > least one specific case where I need to cross-reference column values i= n=20 > the object, which may currently be set, or about to be changed to a new= =20 > value. So, there are other parameters that must be supplied to the=20 > callback. Well, what we need is a schema-level/instance level validation. The=20 validator interface allows for this, but SQLObject doesn't currently=20 call a validator for the entire instance (so there would have to be some=20 changes). So, if DBI has the values: new_value, target_object, name_of_column,=20 all_new_values, then the validator would look something like: class MyValidator(Validator): def validate(self, fields, state): # we don't know the new value or name_of_column, which doesn't # really apply in this case target_object =3D state.soObject all_new_values =3D fields Through state.soObject you can check a single column for consistency=20 with other columns, but in the case of a .set() call you won't see all=20 of the new values; in that case you may want to have symmetric=20 validators, so if A and B are dependent, then when A is changed it=20 checks B, and when B is changed it checks A. Or use an instance=20 validator, which should So, somewhere in .set() (or probably a new method, called by both .set()=20 and ._SO_setValue()) we'd check any instance validators, probably being=20 more careful that they don't see the object while it's in the middle of=20 having values set (i.e., convert and collect all the values, then set=20 them all at once). I want to use validators more heavily, and have them translate into=20 database-side constraints as well. So, for instance, ForeignKey would=20 become a validator/converter, and would also create the "REFERENCES ..."=20 portion of the SQL. An example of an instance validator might be a=20 multi-column unique constraint, which again could create the necessary SQ= L. > Essentially, I need an interface like Perl's Class::DBI: >=20 > http://search.cpan.org/~tmtm/Class-DBI-0.95/lib/Class/DBI.pm#CONSTRAINT= S >=20 > Class::DBI is excellent, but I have little knowledge of its internals,=20 > and so it may suffer from the same performance problems inherent in=20 > SQLObject, but it's definitely a project every SQLObject developer=20 > should be well aware of for a 0.6 redesign, because we might as well do= =20 > what everybody else does and steal ideas and improve upon them. DBI does seem like a good system. Maybe because (besides being in=20 Perl), it actually reminds me a lot of SQLObject ;) Though SQLObject=20 actually seems to be significantly larger in scope than DBI, which=20 doesn't seem to address transactions or caching in any way. This seems=20 particularly significant with respect to transactions, as transactions=20 are one of the things 0.6 tries to resolve more cleanly, and it's not a=20 trivial addition. > In other news, the patch is necessarily on hold until we resolve the=20 > database backend versions vs. SQLObject issue. I've got tons of tests=20 > that have errors in them. The next thing that should be checked into th= e=20 > repository is something that makes those tests pass, but that will=20 > depend on what the consensus is among the users about how to handle=20 > those versioning problems. |