[Dbix-class] Explicit ASTs (ping nate)
Nate Wiger
nwiger at scea.com
Tue Sep 5 19:45:32 CEST 2006
Sam Vilain wrote:
> Matt S Trout wrote:
>> foo = 'yay' AND bar LIKE 'wooho%'
>>
>> becoming
>>
>> [ -op, 'AND',
>> [ -op, '=', [ -name, 'foo' ], [ -bind, 'yay' ] ],
>> [ -op, 'LIKE', [ -name, 'bar' ], [ -bind, 'wooho%' ] ],
>> ],
>
> Would it hurt *that* much to bless these fragments, to make it easier in
> places?
I'm curious about that myself. If we want to really be able to supply
callbacks, relations, etc, it seems that we need something like this
(and this is completely off the top of my head after a long weekend on
vacation):
foo = 'yay' AND bar LIKE 'wooho%'
becoming:
$s->and(
$s->eq( $s->bind( $s->name('foo'), 'yay') ),
$s->like( $s->bind( $s->name('bar'), 'wooho%') ),
),
and a function call like
COUNT( * )
would become
$s->count('*')
From there, a person could subclass SQL::Abstract and provide their own
custom site "count()" function that did something special. Or an XPath
version/etc. Or a $s->name() that does the weird quoting MySQL wants.
An intermediate parsing tree is a good idea, but then again I could see
as much benefit from being able to just insert into a node using Perl
methods, kinda like how JS handles the XML DOM (although less crappy).
Otherwise we pretty much have to rewrite SQL to support all the myriad
variations.
Here's one expanded example I could think of:
SELECT d.id, d.breed FROM dog_breeds d
WHERE d.size > 100 AND d.color IN ('brown','black','grey')
LIMIT 100;
That might be something like:
$s->select(
$s->table('dog_breeds', 'd'), # dog_breeds d
$s->list( # for commas
$s->name('id', 'd'), # d.id, d.breed
$s->name('breed', 'd'), # now we know d = d
),
$s->where( # will give "WHERE"
$s->and(
$s->where(\%data_struct),
$s->in($s->name('color', 'd'), @members),
),
),
);
Ooops, forgot the limit:
if (my $l = $cgi->param('limit')) {
$s->append($s->limit($l));
}
And we really wanted an extra column back:
my $n = $s->find('from');
$n->append($s->name('color', 'd'));
And why don't we get all the d members to set types:
my @m = $s->members('d');
for (@m) {
if ($_->name eq 'id') {
$_->type('integer');
}
}
Finally, render the SQL:
my($stmt, @bind) = $s->render;
Just a thought. Great thread BTW.
-Nate
More information about the Dbix-class
mailing list