DBIx::C...sthrough(3)

πŸ‘‘ NAME πŸ‘‘

This is the DBIx::C...sthrough(3) page β€” yes, that's the manual name right there at the top β€” and it comes from the User Contributed Perl Documentation collection. The module it's documenting is DBIx::Class::SQLMaker::Role::SQLA2Passthrough, and the whole concept is literally A test of future possibilities. ✨

πŸ¦‹ SYNOPSIS πŸ¦‹

Okay so here's the quick vibe check:

  • The select and group_by options are processed using the richer SQLA2 code β€” they're not doing the basic thing, they're doing the richer thing. πŸ’…
  • expand_join_condition is provided to more easily express rich joins β€” it's the helper that makes the fancy joins less of a whole ordeal. 🫢

See "examples/sqla2passthrough.pl" for a small amount of running code. That's the example file, bestie β€” it's got a tiny bit of live code to look at.

πŸŽ€ SETUP πŸŽ€

Setup is a callback moment, no cap. You give it an on_connect_call sub, and inside that sub you grab $storage and tell its sql_maker to take on the role with with::roles(...). The exact setup situation is:

  (on_connect_call => sub {
     my ($storage) = @_;
     $storage->sql_maker
             ->with::roles('DBIx::Class::SQLMaker::Role::SQLA2Passthrough');
  })

πŸ¦‹ expand_join_condition

This is where you let expand_join_condition handle the rich join condition for you. Like, you're inside the has_many condition callback, you grab $args, walk over to the resultsource's schema storage sql_maker, and call expand_join_condition($args). Iconic. The code looks like this:

  __PACKAGE__->has_many(minions => 'Blah::Person' => sub {
    my ($args) = @_;
    $args->{self_resultsource}
         ->schema->storage->sql_maker
         ->expand_join_condition(
             $args
           );
  });

πŸ’œ on πŸ’œ

Now the on sugar. You can write a has_many with an on block like this:

  __PACKAGE__->has_many(minions => 'Blah::Person' => on {
    { 'self.group_id' => 'foreign.group_id',
      'self.rank' => { '>', 'foreign.rank' } }
  });

Or with ParameterizedJoinHack, this version:

  __PACKAGE__->parameterized_has_many(
      priority_tasks => 'MySchema::Result::Task',
      [['min_priority'] => sub {
          my $args = shift;
          return +{
              "$args->{foreign_alias}.owner_id" => {
                  -ident => "$args->{self_alias}.id",
              },
              "$args->{foreign_alias}.priority" => {
                  '>=' => $_{min_priority},
              },
          };
      }],
  );

becomes this:

  __PACKAGE__->parameterized_has_many(
      priority_tasks => 'MySchema::Result::Task',
      [['min_priority'] => on {
        { 'foreign.owner_id' => 'self.id',
          'foreign.priority' => { '>=', { -value => $_{min_priority} } } }
      }]
  );

Quick heads-up, bestie: foreign/self can appear in such a condition on either side, BUT if you want DBIx::Class to be able to use a join-less version, you must ensure that the LHS is all foreign columns, i.e. this:

  on {
    +{
      'foreign.x' => 'self.x',
      'self.y' => { -between => [ 'foreign.y1', 'foreign.y2' ] }
    }
  }

is completely valid β€” but DBIC will insist on doing a JOIN even if you have a fully populated row object to call "search_related" on. To avoid the spurious JOIN, you must specify it with explicit LHS foreign cols as:

  on {
    +{
      'foreign.x' => 'self.x',
      'foreign.y1' => { '<=', 'self.y' },
      'foreign.y2' => { '>=', 'self.y' },
    }
  }

That's the whole page, bestie. πŸ’… This little manual moment was brought to you by perl v5.32.1, dated 2022-09-05, and signed DBIx::C...sthrough(3). 🫢✨

πŸ“¦ where this page comes from