1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2026-05-06 18:04:03 +00:00

Fix chaining withoutPending() with where() (#1457)

At the moment, `where()` cannot be used correctly while using
`withoutPending()`. For example, if we have a single non-pending tenant
in our DB (with ID 'foo'), queries like
`Tenant::withoutPending()->where('id', 'nonexistent')->first()`will
incorrectly return the non-pending tenant ('foo').

This is because `withoutPending()` does
`$builder->whereNull('data->pending_since')->orWhereNull('data')`. These
two aren't grouped, so `withoutPending()->where('id', 'nonexistent')`
basically translates to "WHERE data->pending_since IS NULL **OR (data IS
NULL AND id = 'nonexistent')**". So the query will include all tenants
whose `pending_since` is null (= all non-pending tenants).

Grouping `->whereNull('data->pending_since')->orWhereNull('data')` in a
closure passed to a separate `where()` fixes this issue.
This commit is contained in:
lukinovec 2026-04-22 14:32:53 +02:00 committed by GitHub
parent c32f52ce7c
commit ab2a4d8438
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 16 additions and 2 deletions

View file

@ -58,8 +58,10 @@ class PendingScope implements Scope
{ {
$builder->macro('withoutPending', function (Builder $builder) { $builder->macro('withoutPending', function (Builder $builder) {
$builder->withoutGlobalScope(static::class) $builder->withoutGlobalScope(static::class)
->whereNull($builder->getModel()->getColumnForQuery('pending_since')) ->where(function (Builder $query) {
->orWhereNull($builder->getModel()->getDataColumn()); $query->whereNull($query->getModel()->getColumnForQuery('pending_since'))
->orWhereNull($query->getModel()->getDataColumn());
});
return $builder; return $builder;
}); });

View file

@ -111,6 +111,18 @@ test('a new tenant gets created while pulling a pending tenant if the pending po
expect(Tenant::withPending()->get()->count())->toBe(1); // All tenants expect(Tenant::withPending()->get()->count())->toBe(1); // All tenants
}); });
test('withoutPending chained with where clauses returns correct results', function () {
$tenant = Tenant::create();
$pendingTenant = Tenant::createPending();
// The query returned the correct tenant
expect(Tenant::withoutPending()->where('id', $tenant->id)->first()->id)->toBe($tenant->id);
// No tenant with this ID exists, the query returns null
expect(Tenant::withoutPending()->where('id', Str::random(8) . 'nonexistent-id')->first())->toBeNull();
// withoutPending() correctly excludes the pending tenant from the query
expect(Tenant::withoutPending()->where('id', $pendingTenant->id)->first())->toBeNull();
});
test('pending tenants are included in all queries based on the include_in_queries config', function () { test('pending tenants are included in all queries based on the include_in_queries config', function () {
Tenant::createPending(); Tenant::createPending();