Skip to content

feat(user): read many users in one call - #152

Merged
juicycleff merged 1 commit into
mainfrom
feat/batch-get-users
Nov 5, 2026
Merged

juicycleff merged 1 commit into
mainfrom
feat/batch-get-users

Conversation

@juicycleff

Copy link
Copy Markdown
Contributor

Adds user.BatchGetter, an optional interface with one method, GetUsers(ctx, userIDs), and implements it on all four built-in stores.

You get back the live users among the IDs you pass, in no particular order. Deleted and unknown IDs are simply left out, duplicates are read once, and an empty list returns straight away without a query.

Hallproof needs this. It lists an organisation's members and then wants each member's name and email, which with only GetUser means one query per member. With GetUsers it's one query for the whole organisation.

It's a separate interface, not a new method on user.Store, so a store you've written yourself keeps compiling. Callers type-assert for it and fall back to GetUser when a store doesn't have it.

Testing

  • A new GetUsersBatch case in storetest.RunConformance creates three users, deletes one, then looks up live, deleted, unknown and duplicate IDs. It also covers nil and empty input.
  • It passes on memory and sqlite with plain go test, and on postgres and mongo with -tags integration (the testcontainers Postgres, and a throwaway mongo:7 replica set).
  • go test ./..., go vet ./... and golangci-lint are clean. We didn't run the full make test-integration across every plugin package.

Postgres and SQLite bind each ID as its own parameter, so one call is capped by the driver's parameter limit (65,535 on Postgres). That's far beyond any organisation's member count, but worth knowing if you pass it a huge list.

If you list an org's members today, you have to call GetUser once per
member. GetUsers reads them all in one query on postgres, sqlite and
mongo, and in one pass under the lock on memory. It sits on its own
user.BatchGetter interface so stores outside this repo keep compiling.
Type-assert for it and fall back to GetUser when it isn't there.

Deleted and unknown IDs are left out, and a duplicate ID comes back
once. The new GetUsersBatch conformance case checks that on every
backend.
@codecov

codecov Bot commented Nov 5, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 31.81818% with 90 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
store/postgres/store.go 0.00% 31 Missing ⚠️
store/storetest/storetest.go 0.00% 31 Missing ⚠️
store/mongo/user.go 0.00% 24 Missing ⚠️
store/sqlite/store.go 87.09% 2 Missing and 2 partials ⚠️

📢 Thoughts on this report? Let us know!

@juicycleff
juicycleff merged commit d39cfc3 into main Nov 5, 2026
21 of 22 checks passed
@juicycleff
juicycleff deleted the feat/batch-get-users branch November 5, 2026 18:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant