perf: lazy-load Workspace relationships to reduce N+1 queries

Add explicit $with = [] to prevent any auto-eager-loading of the 30+
relationships defined on the Workspace model. Provide scopeWithCommon()
for eager-loading core tenant relationships (users, members, teams,
workspacePackages, namespaces) and scopeWithCommonCounts() as a lighter
alternative using withCount() for listing pages.

Fixes #21

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude 2026-03-24 13:37:42 +00:00
parent c51e4310b1
commit 3976e52f43
No known key found for this signature in database
GPG key ID: AF404715446AEB41

View file

@ -54,6 +54,17 @@ class Workspace extends Model
{
use HasFactory;
/**
* Relationships that should be eager-loaded by default.
*
* Explicitly empty to prevent N+1 queries when listing workspaces.
* Use scopeWithCommon() to eager-load the most frequently needed
* relationships, or call ->with() explicitly for specific use cases.
*
* @var array<int, string>
*/
protected $with = [];
protected static function newFactory(): WorkspaceFactory
{
return WorkspaceFactory::new();
@ -778,6 +789,47 @@ class Workspace extends Model
return $query->orderBy('sort_order');
}
/**
* Scope to eager-load the most commonly needed relationships.
*
* Use this when listing workspaces or rendering dashboards to avoid
* N+1 queries. Only loads core tenant relationships that are almost
* always needed; module-specific relationships (social, analytics,
* trust, notify, commerce, etc.) should be loaded explicitly.
*
* Example: Workspace::withCommon()->paginate(20)
*/
public function scopeWithCommon($query)
{
return $query->with([
'users',
'members',
'teams',
'workspacePackages',
'namespaces',
]);
}
/**
* Scope to add commonly needed relationship counts.
*
* Lighter alternative to withCommon() when only counts are needed
* (e.g. admin listing pages). Uses withCount() to add _count
* columns without loading full relationship collections.
*
* Example: Workspace::withCommonCounts()->paginate(20)
*/
public function scopeWithCommonCounts($query)
{
return $query->withCount([
'users',
'members',
'teams',
'workspacePackages',
'invitations',
]);
}
/**
* Convert to array format used by WorkspaceService.
*/