feat: add username and email user search filters (#27922)

## Summary

User search can now resolve exact `email:` and `username:` terms through
`GET /api/v2/users` instead of only supporting fuzzy free-text matches.
The database query already had exact email and username filters; this
wires the public search parser and API handler to those filters so
clients can ask for a single user by email without fetching every user
or depending on substring matching.

This is the API half of coder/terraform-provider-coderd#403: that
provider PR adds `data.coderd_user.email`, and this PR gives it an
efficient exact lookup path.

## Testing

- `go test ./coderd/searchquery -run '^TestSearchUsers$' -count=1`
- `go test ./coderd -run '^TestGetUsersFilter$' -count=1`
- Live API test:
  - Built local enterprise Coder from this branch.
- Started Coder on `http://127.0.0.1:39991` against a clean Postgres
database.
  - Created `lookup-target@example.com`.
- Verified `GET /api/v2/users?q=email:LOOKUP-TARGET@EXAMPLE.COM&limit=2`
returned exactly one user:

```json
{
  "count": 1,
  "users": [
    {
      "id": "efc6f909-ce0a-4731-bd2f-6e4df417aaa7",
      "username": "lookup-target",
      "email": "lookup-target@example.com"
    }
  ]
}
```

---

![flow.ai](https://img.shields.io/badge/Built_with-flow.ai-6366f1)
![Codex](https://img.shields.io/badge/GPT--5-000000)

---------

Co-authored-by: Ethan Dickson <ethanndickson@gmail.com>
This commit is contained in:
Wyatt Fry
2026-08-16 18:18:02 +05:00
committed by GitHub
co-authored by Ethan Dickson
parent af90d8e2be
commit a005e5cd22
10 changed files with 160 additions and 52 deletions
+18
View File
@@ -425,6 +425,24 @@ func UsersFilter(
return u.Username == "before1"
},
},
{
Name: "ExactUsername",
Filter: codersdk.UsersRequest{
SearchQuery: "username:" + strings.ToUpper(users[0].Username),
},
FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool {
return strings.EqualFold(u.Username, users[0].Username)
},
},
{
Name: "ExactEmail",
Filter: codersdk.UsersRequest{
SearchQuery: "email:" + strings.ToUpper(users[0].Email),
},
FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool {
return strings.EqualFold(u.Email, users[0].Email)
},
},
{
Name: "NameNoMatch",
Filter: codersdk.UsersRequest{