|
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.
|