[Dbix-class] filter many_to_many link table rows on foreign column values
Marco
marco.prado.bs at gmail.com
Fri Mar 18 20:17:14 GMT 2016
Excerpts from Hartmaier Alexander's message of 2016-03-18 15:20:54 +0100:
> Hi list,
> as I'm turning around in circles and not finding a solution that
> satisfies me I'm asking here for help:
>
> My schema includes devices, interfaces and lines which can be affected
> by one or more maintenances.
> A maintenance has a datetime_start and datetime_end column.
>
> device->has_many('rel_maintenance_device')->belongs_to('rel_maintenance')
You mean:
device->has_many('rel_maintenance_device')
rel_maintenance_device->belongs_to('rel_maintenance') ?
It seems a poor schema...
You really have a **many_to_many** relationship between
(devices/interfaces/lines) and scheduled maintenances.
>
> What I want to achieve is to get a list of maintenances currently active
> (datetime_start <= DateTime->now && datetime_end >= DateTime->now ).
>
> My current solution is a virtual DBIC view which joins rel_maintenance
> and filters on datetime_start and datetime_end. This has the
> disadvantage that I have to pass DateTime->now formatted for the
> currently connected database and can't just prefetch the rel.
>
> The actual resultset method looks like this:
>
> =item with_currently_active_maintenances
>
> Returns a resultset including the active maintenances affecting the devices.
>
> =cut
>
> sub with_currently_active_maintenances {
> my $self = shift;
>
> # get current day abbreviation
> my $dt_now_sql = $self->result_source->storage->datetime_parser
> ->format_datetime(DateTime->now);
>
> return $self->search_rs(undef, {
> bind => [ $dt_now_sql, $dt_now_sql ],
> join => { 'rel_currently_active_maintenances' =>
> 'rel_maintenance' },
> });
> }
>
> This does work including prefetching but fails when I have a single
> $device row object and want to determine whether it currently is in
> maintenance or not.
You mean an instance of device. It is not a fail, it is because a
ResultSet is not a Result Class, these are different animals.
>
> My next try was to add an additional relationship to the link table
> which only returns currently active maintenances:
>
> __PACKAGE__->might_have(
> 'rel_currently_active_maintenance',
> 'NAC::Model::DBIC::Table::Maintenance',
> sub {
> my $args = shift;
>
> my $dt_now_sql =
> $args->{self_resultsource}->storage->datetime_parser
> ->format_datetime(DateTime->now);
>
> return {
> "$args->{foreign_alias}.id_maintenance" => { -ident =>
> "$args->{self_alias}.fk_maintenance" },
> "$args->{foreign_alias}.datetime_start" => { '<=' =>
> $dt_now_sql },
> "$args->{foreign_alias}.datetime_end" => { '>=' =>
> $dt_now_sql },
> };
> },
> );
>
> The advantage is that a simple
> prefetch => { rel_maintenance_device => 'rel_currently_active_maintenance' }
> works and a many_to_many helper defined over those two rels also works
> perfectly.
>
> The downside is that the link table rows aren't filtered so
> rel_maintenance_device still returns all maintenances ever assigned to
> the device.
Again you don't understand the difference between a ResultSet and the
instance of a ResultClass
>
> I've also looked at DBIx::Class::ParameterizedJoinHack, which isn't
> necessary as the calling code doesn't need to pass a parameter to the
> rel as 'now' can and should be passed automatically.
>
> Am I overlooking another possibility?
> Being able to prefetch the data is essential both for performance as for
> practical reasons as I have code based on
> Catalyst::Controller::DBIC::API which serializes everything returned by
> a resultset to JSON which saves me to handcraft the Perl data structure
> for each action.
>
> From a high level want I want is a
> device->has_many('rel_currently_active_maintenances'), not a
> many_to_many helper returning that.
>
> Ideas?
Create a DBIC::Scheduler that is based on a view with the SQL:
SELECT whatever FROM maintenance WHERE datetime_start >= NOW AND
datetime_end <= NOW
and so you can join/prefetch/ everything else...
>
> Thanks, Alex
>
>
> *"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*
> T-Systems Austria GesmbH Rennweg 97-99, 1030 Wien
> Handelsgericht Wien, FN 79340b
> *"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*
> Notice: This e-mail contains information that is confidential and may be privileged.
> If you are not the intended recipient, please notify the sender and then
> delete this e-mail immediately.
> *"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*
>
--
Marco Arthur @ (M)arco Creatives
More information about the DBIx-Class
mailing list