Summary
Paginated SleekDB queries can lose previously applied criteria. This was introduced in the #508 change set, where Sleekdb\Statements\Result::count() now resets builder state.
Regression Window
- Commit chain:
#508
- First bad commit identified:
2196fa2c ([#508] Support related criteria paths in SleekDB joins)
Root Cause
Quantum\Database\Adapters\Sleekdb\Statements\Result::count() now does:
fetchFilteredResultsFromBuilder($this->getBuilder())
resetBuilderState() in finally
ModelPaginator calls count() first and later calls limit()->offset()->get() on the same model instance. After count() resets state, the later fetch runs without original query constraints.
Impact
- Filtered paginated queries may return unfiltered data.
- This can affect API/search endpoints relying on
->criteria(...) / ->criterias(...) before ->paginate(...).
Reproduction (conceptual)
- Build a model query with filter(s), e.g.
criteria('title', 'LIKE', '%token%').
- Call
paginate($perPage, $page).
- Call paginator
data().
- Observe
data() includes rows outside the filter scope.
Expected
Paginator data() should respect all query criteria defined before paginate().
Actual
Criteria can be lost after count() executes.
Proposed Fix Direction
- Preserve criteria/builder scope across
count() + data() lifecycle for SleekDB paginator flow.
- Avoid destructive reset in
count() when invoked for pagination context, or clone/snapshot state before counting.
Test Gap / Required Coverage
Add/extend unit tests to cover SleekDB paginator lifecycle:
- filtered query +
paginate() + data() retains filters
- include grouped OR criteria scenario via
criterias([...], [...])
- ensure no stale builder replay side effects.
Summary
Paginated SleekDB queries can lose previously applied criteria. This was introduced in the #508 change set, where
Sleekdb\Statements\Result::count()now resets builder state.Regression Window
#5082196fa2c([#508] Support related criteria paths in SleekDB joins)Root Cause
Quantum\Database\Adapters\Sleekdb\Statements\Result::count()now does:fetchFilteredResultsFromBuilder($this->getBuilder())resetBuilderState()infinallyModelPaginatorcallscount()first and later callslimit()->offset()->get()on the same model instance. Aftercount()resets state, the later fetch runs without original query constraints.Impact
->criteria(...)/->criterias(...)before->paginate(...).Reproduction (conceptual)
criteria('title', 'LIKE', '%token%').paginate($perPage, $page).data().data()includes rows outside the filter scope.Expected
Paginator
data()should respect all query criteria defined beforepaginate().Actual
Criteria can be lost after
count()executes.Proposed Fix Direction
count()+data()lifecycle for SleekDB paginator flow.count()when invoked for pagination context, or clone/snapshot state before counting.Test Gap / Required Coverage
Add/extend unit tests to cover SleekDB paginator lifecycle:
paginate()+data()retains filterscriterias([...], [...])