Skip to content

[ActiveRecord] 'join' should accept a list of models #36

@claudiopro

Description

@claudiopro

Summary

Currently, the 'join' clause of find_all() and other finder methods accepts a single model class. For greater profit, we should also accept a list of model classes, to be joined in sequence.

Today, in order to fully expand the relationships:

ShoppingSession 1 <---> N Purchase 1 <---> 1 Product 1 <---> 1 Brand
                              1
                              ^
                               `-> 1 Shop

we can only invoke 'join' on one model, e.g. Product, and then expand on Brand and Shop separately, in an expensive O(n) loop:

if (
    $shopping_session->has_many(Purchase::class, array(
        'join' => Product::class
    ))
) {
    $purchases = $shopping_session->purchases;
    array_walk($purchases, function ($p) {
        $p->product->belongs_to(Brand::class);
        $p->belongs_to(Shop::class);
    });
}

The following call would yield the same result:

if (
    $shopping_session->has_many(Purchase::class, array(
        'join' => array(Product::class, Shop::class)
    ))
) {
    $purchases = $shopping_session->purchases;
    array_walk($purchases, function ($p) {
        $p->product->belongs_to(Brand::class);
    });
}

A more concise form would also save us the additional nested belongs_to(Brand::class):

$shopping_session->has_many(Purchase::class, array(
    'join' => array(array(Product::class => Brand::class), Shop::class)
));

What the former means is:

  • join Purchase with Product and Shop
  • join Product with Brand

resulting into a similar query:

SELECT
    pu.*,
    pr.*,
    sh.*,
    br.*
FROM
    purchases pu
JOIN products pr ON
    pu.product_id = pr.id
JOIN brands br ON
    pr.brand_id = br.id
JOIN shops sh ON
    pu.shop_id = sh.id
WHERE
    pu.session_id = @session_id;

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions