Re: Request: Support for __JOIN(c1.fkey c2)__

[prev] [thread] [next] [Date index for 2005/05/05]

From: Stepan Riha
Subject: Re: Request: Support for __JOIN(c1.fkey c2)__
Date: 15:31 on 05 May 2005
Quoting Tony Bowden :

> Thanks for this. In general I'm happy with the concept, but I'm not
> completely following the syntax. Could you take a stab at some docs
> and/or tests that show some of this in action?

Are you talking about the syntax in the perl code or the syntax in the 
__JOIN__?
  I'd love to expand the documentation on the __JOIN__, but AFAIK there ain't
none, right?

A more specific example for this can be seen in your test classes Film and
Director.  You should be able to add the following relationships to Film:

package Film;
Film->has_a(Director => 'Director');
Film->has_a(CoDirector => 'Director');

Now let's say I want to have a query for films whose director's birthday is
before a certain date.  I may be tempted to specify the following query:

Film->set_sql(directors_born_before => <<'');
    SELECT __ESSENTIAL(f)__
    FROM __TABLE(=f)__, __TABLE(Director=d)__
    WHERE __JOIN(f d)__ AND d.Birthday <= ?

However, since Film has two "has_a" relationships to the Director class, the
__JOIN__ is ambiguous and will be expanded into either "f.director = 
d.name" or
"f.codirector = d.name" (depending on how perl sorts the 
meta_info('has_a') hash
keys).

My code enhances the __JOIN__ syntax to allow you to specify which 
exact foreign
key to use in the join.  So, you'd specify "__JOIN(f.Director d)__" to get the
director (and, conversely, you'd specify "__JOIN(f.CoDirector d)__" if you
wanted to get the CoDirector):

Film->set_sql(directors_born_before => <<'');
    SELECT __ESSENTIAL(f)__
    FROM __TABLE(Film f)__, __TABLE(Director d)__
    WHERE __JOIN(f.Director d)__ AND d.Birthday <= ?

Film->set_sql(codirectors_born_before => <<'');
    SELECT __ESSENTIAL(f)__
    FROM __TABLE(Film f)__, __TABLE(Director d)__
    WHERE __JOIN(f.CoDirector d)__ AND d.Birthday <= ?

As far as testing goes, you could add the following to 19-set_sql.t:

{    # join with fkey
	Actor->has_a(film => "Film");
	Film->set_sql(
		ratename => qq{
		SELECT __ESSENTIAL(f)__
		FROM   __TABLE(=f)__, __TABLE(Actor=a)__
		WHERE  __JOIN(a.film f)__
		AND    f.rating = ?
		AND    a.name LIKE ?
		ORDER BY title
	}
	);

	my @apg = Film->search_ratename(PG => "A_");
	is @apg, 2, "2 Films with A* that are PG";
	is $apg[0]->title, "A", "A";
	is $apg[1]->title, "B", "and B";
}

BTW, I think that transform_sql should test for and complain if it's 
expanding a
has_a relationship that's ambiguous (i.e. "__JOIN(f d)__" in my example).  My
code doesn't do that check.

Also, a similar problem exists when specifying has_many relationships:

     Director->has_many( DirectedFilms => 'Film');
     Director->has_many( CoDirectedFilms => 'Film');

Again, when ambiguous, you should be able to specify the foreign key and CDBI
should croak on ambiguities:

     Director->has_many( DirectedFilms => 'Film.Director');
     Director->has_many( CoDirectedFilms => 'Film.CoDirector');

Anyway, I'm using the new __JOIN__ syntax in an enhanced AbstractSearch where
I'll be able to specify where clauses from joined tables ("Films whose title
contains $film_title and whose director's insanity equals $director_nuts and
whose codirector's instanity equals $codirector_nuts") like so:

my @films = Film->search_where( {
       'title' => { -like => "%$film_title%" },
       'director.IsInsane' => $director_nuts,
       'codirector.IsInsane' => $codirector_nuts,
} );

Which will be converted to the following SQL before CDBI has its way with it:

SELECT
    __ESSENTIAL(t_film)
FROM
    __TABLE(=t_film)__,
    __TABLE(Director=t_film_director)__,
    __TABLE(Director=t_film_codirector)__
WHERE
       __JOIN(t_film.Director t_film_director)__ AND
       __JOIN(t_film.CoDirector t_film_codirector)__ AND
       title LIKE '%voter_name%' AND
       t_film_director.isnuts = ? AND
       t_film_codirector.isnuts = ?

     - Stepan

Re: Request: Support for __JOIN(c1.fkey c2)__
merlyn (Randal L. Schwartz) 18:59 on 04 May 2005

Re: Request: Support for __JOIN(c1.fkey c2)__
Christopher Laco 20:34 on 04 May 2005

Re: Request: Support for __JOIN(c1.fkey c2)__
Tony Bowden 20:35 on 04 May 2005

Re: Request: Support for __JOIN(c1.fkey c2)__
Dave Cross 22:01 on 04 May 2005

Re: Request: Support for __JOIN(c1.fkey c2)__
Tony Bowden 20:37 on 04 May 2005

Re: Request: Support for __JOIN(c1.fkey c2)__
Stepan Riha 15:31 on 05 May 2005

Re: Request: Support for __JOIN(c1.fkey c2)__
Tony Bowden 21:27 on 05 May 2005

Generated at 16:35 on 28 Jul 2005 by mariachi v0.52