Skip to content

Type aggregate properties: withSum, withAvg, withMin, withMax, withExists #644

@alies-dev

Description

@alies-dev

Problem

After calling withSum(), withAvg(), withMin(), withMax(), or withExists(), Laravel dynamically adds properties to the model following the pattern {relation}_{function}_{column}. These are currently unresolved by the plugin.

$user = User::withCount('posts')
    ->withSum('posts', 'views')
    ->withAvg('posts', 'rating')
    ->withExists('posts')
    ->first();

$user->posts_count;       // ❌ unresolved (see #503)
$user->posts_sum_views;   // ❌ unresolved
$user->posts_avg_rating;  // ❌ unresolved
$user->posts_exists;      // ❌ unresolved

Expected types

Method Property pattern Type
withCount {rel}_count int<0, max>
withSum {rel}_sum_{col} numeric-string|null
withAvg {rel}_avg_{col} numeric-string|null
withMin {rel}_min_{col} string|null
withMax {rel}_max_{col} string|null
withExists {rel}_exists bool

Also covers loadCount, loadSum, loadAvg, loadMin, loadMax, loadExists on the Model.

Implementation ideas

Two complementary approaches:

  1. Static property provider — extend ModelRelationshipPropertyHandler to recognize _count suffix (strip → find relation → return int<0, max>). This works without seeing the withCount() call, purely from the property name pattern + model's relation methods.

  2. Flow-sensitive tracking (ambitious) — an AfterMethodCallAnalysisInterface handler that observes withSum('posts', 'views') calls and records the resulting property name + type. This enables precise typing for _sum_*, _avg_*, etc. where the property name depends on both the relation and column arguments.

Approach 1 is sufficient for _count and _exists. Approach 2 is needed for _sum_*, _avg_*, _min_*, _max_*.

Related

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