Matt S Trout wrote:
On Tue, May 26, 2009 at 01:49:05PM -0700, David Ihnen wrote:
Sometimes I think i'm missing something obvious.
In my application, for instance, a holiday can be assigned to a group.
A group has many donors
A donor might have many scheduled days
A scheduled day is associated with a particular schedule
In this spot in my application, the operation is "update group schedule" .
I need to say "refresh all of the randomized scheduling for all of the
schedules related to all of the donors in the group this schedule is
on." To do that I need a list of those schedules.
I first wrote that, for an update overload in my holiday class, like
this. ($old is a hash ref to a copy of the get_columns from before the
update took place)
$self->groups->donors->schedule->ivr_schedule->search(
{ 'date_start' => { '<=' => $old->{holiday} }
, -or =>
[ 'date_end' => { '>=' => $old->{holiday} }
, 'date_end' => undef
]
} );
But I got an error, something like "No such method 'donors' on class
DBIx::Class::ResultSet"
So I rewrote it...
$self->groups->search_related('donors')->search_related('schedule')->search_related('ivr_schedule'
, ...yaddayadda...
and that worked.
So it leaves me wondering if I missed something fundamental here. I
have an object which is a result set of a particular record type. If I
want the records that are related to that result set - why would I have
to call 'related_resultset' - isn't "give me the related resulset" the
only thing I could mean when I call ->relationship on a result set? If
that is so, why aren't there accessors created on the resultset for the
valid relations, to cut down on excessive verbosity that doesn't clarify?
I believe somebody tried that once.
Then they defined a relationship called 'next'.
Then they realised work would be involved and lost interest.
I don't see why it -can't- be done, just nobody's really tried. I reckon
you could do it as a schema component that wraps load_namespaces as a
start ...
Okay, so I noticed this one time before... the internal methods defined
in the classes of DBIx::Class are not in a differnet namespace to
distinguishes them from the methods that are accessors that may be
defined by merely creating column names.
None of the columns in a table, for instance, may be named the same as
any of the functions within the namespace of table objects. This
nibbled on me at one point during my current development project.
So I'm contemplating how to handle that. Obviously for flexibility and
just plain propriety we want to be able to have relationships named
single, next, and first. But if we overlay the namespace of the
resultset object with relationship names, we have the same inherent
conflict we do with the table column accessors and the table object api.
So what if we reserved part of the object namespace for relationship
accessors, prefixed with rel_ for explicit compatibility, and aliased
without the prefix if the namespace slot is available?
If you define a rel called 'next' and call it with $rs->next it carps
"AMBIGUOUS RS/REL CALL" or just a setup/compiletime warning
"RELATIONSHIP ACCESSOR 'next' MASKED BY API METHOD 'next'"
Then I could write
$self->groups->donors->schedule->ivr_schedule->search...
or more verbosely
$self->groups->rel_donors->rel_schedule->rel_ivr_schedule->search...
Which is somewhat less verbose than ->search_related, and lets me do
what I want without the rel distinction alias by default. The namespace
overlap which is more or less necessary for the purposes of conciseness
is allowed, both warning when it overlaps AND providing a mechanism to
be explicit so you can do so anyway.
A similar pattern could be attached to the table objects so that column
names are allowed to overlap with the api as well - subnamespace prefix
'col_'
Both of these subnamespace reservations have a fundamental tradeoff though.
if I had two columns named five and col_five, there an ambiguity. what
do I mean when I say col_five? Same for relationships six and rel_six.
On one hand, the prefix is already used for the add_to_RELATIONSHIP
create accessor, so its an established pattern. A solution that may
provide a lesser limitation than the above prefix is to use methods to
distinguish what is meant.
$self->col->five is obviously different from $self->col->col_five
A tradeoff remaining in that pattern is that if there is a column named
col that is inflated into an object, even overload logic wouldn't be
able to tell if you actually meant the default accessor 'col' for the
column. If you had a column named col and one named ymd...
$row->col->ymd
could mean 'get the col column, inflate it, and call the ymd method on
it' or it could mean 'get me the column ymd'. It would be more clear
programmatically in the case of
my $d = $row->col;
$d->ymd;
and could be arbitrarily documented that you must use the ->col
designator to inform the class you mean a column, though for convenience
(and backwards compatibility) we provide all non-conflicting accessors
for your use and warn you when they conflict.
Would you prefer one method over the other? I think the important thing
is that we make it so that no matter what, my column names do not
override the existing method names, *but* there is a way to get the
functionality even with the api interfering with the schema.
Hopefully this is not too long,
David
_______________________________________________
List: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/dbix-class
IRC: irc.perl.org#dbix-class
SVN: http://dev.catalyst.perl.org/repos/bast/DBIx-Class/
Searchable Archive: http://www.grokbase.com/group/[email protected]