Repository navigation
Conversation
`count=true` is a reserved key next to sort, limit and start. Bind.count/1 takes the query Bind.query/3 built, with the caller's scopes piped after it, and selects how many rows it matches: filters, joins and cursor stay, sort, limit and preloads drop. It counts a subquery, so a scope's distinct, group_by or select never changes the number. Version 0.14.0. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
🟢 Approval recommended
The additions are small, correctly integrated with existing param/query handling, and covered by focused tests, with no objective issues found.
0 open findings
What changed in this PR
This PR adds row-counting support to Bind, an Elixir library that builds Ecto queries from request params. API clients can now learn how many rows a listing matches without paging through them. It introduces one reserved param key (count) and two public functions, plus documentation and a version bump.
Changes:
- Adds
Bind.count?/1to detectcount=true/count=1from a params map or query string. - Adds
Bind.count/1, which transforms aBind.query/3result (plus any piped scopes) into a count query by droppingorder_by/limit/offset/preloadand wrapping the remainder in a subquery that selectscount(), keeping filters/joins/cursor intact. - Documents the feature (README "Counting" section, fixes the
Bind.query(params, schema)signature) and bumps the version to0.14.0.
| File | Description |
|---|---|
lib/bind.ex |
Implements count?/1 and count/1 with the subquery-based counting logic. |
test/count_test.exs |
New tests covering flag detection, retained filters/cursor/scopes, dropped sort/limit/preloads, and the distinct subquery case. |
README.md |
Adds a "Counting" section and corrects the Bind.query(params, schema) API signature. |
mix.exs |
Bumps version from 0.13.0 to 0.14.0. |
🧠 Review effort: Balanced
Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.
| query | ||
| |> exclude(:order_by) | ||
| |> exclude(:limit) | ||
| |> exclude(:offset) |
There was a problem hiding this comment.
The count keeps the pagination cursor, so a paginating client gets a shrinking total.
start is added as a WHERE on id, so exclude(:offset) drops nothing here.
On page 2+ the number is only the rows after the cursor.
If the goal is a listing size, count the filters without the cursor.
hanafrommitte
left a comment
There was a problem hiding this comment.
The count query itself is correct, but it keeps the pagination cursor.
start is a WHERE on id, not an offset, so excluding :offset drops nothing.
A client that pages and asks for count gets a partial total on page 2+.
Drop the cursor for a listing size, or say the number shrinks as you page.
1 suggestion inline — none are blocking.
…om page one Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Kept the cursor and said so: the @doc and README now state that with |
API clients need the size of a listing without paging through it, e.g. how many favorites a user has. This adds the one reserved key and the one function bind needs for that.
What changes
count=true(orcount=1) is a reserved key likesort,limitandstart.Bind.count?/1reads it from a params map or a query string.Bind.count/1takes the queryBind.query/3built, with any scopes the caller piped after it, and returns a query that selects how many rows it matches. Filters, joins and the cursor stay; sort, limit and preloads drop. Run it withRepo.one/1.distinct,group_byorselectnever changes the number.Tests
test/count_test.exscovers the flag in both param shapes, filters kept, sort and limit dropped (including the implicit default limit of 10), cursor kept, scopes and preloads piped afterquery/3, and the subquery form around adistinct.Consumers: mitteai/mitte.ai (list endpoints answer
?count=true) and the fs.list tool in socket-service, in follow-up PRs.🤖 Generated with Claude Code