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]

Reply via email to