Skip to content

feat: add pools for resolving groups of names by key - #9

Merged
dragonee merged 1 commit into
mainfrom
feat/pools
Jul 8, 2026
Merged

feat: add pools for resolving groups of names by key#9
dragonee merged 1 commit into
mainfrom
feat/pools

Conversation

@dragonee

@dragonee dragonee commented Jul 8, 2026

Copy link
Copy Markdown
Member

Summary

Introduces pools — a named list of names sharing one field (service), resolvable as a group.

A pool is defined in a separate pools.yml:

-
  name: Everyone
  field: email
  names:
    - michal@makimo.pl
    - alice@makimo.pl

Given a pool and an asked service, PoolService resolves every member through the existing QueryService.

Domain (domain/WhoseName/)

  • Pool — value object: getField(): string, getNames(): array.
  • PoolQueryRepository — interface: findByName(string): Pool (empty Pool on a miss, like IdentityQueryRepository).
  • PoolService — takes PoolQueryRepository + QueryService:
    • whatAreTheNamesOf($pool, $service)one answer per member, index-aligned, each string|array|null, mirroring QueryService::whatAreTheNamesOf so nulls are kept and callers get 207 semantics.
    • whoseNamesAreThere($pool, $service) — those answers flattened into a distinct list (arrays spread in, nulls and duplicates dropped).
    • When the asked service is the pool's own field, its names are returned verbatim.

Infrastructure

  • PoolYamlFileRepository — replicates YamlFileRepository's mtime-based cache, indexing pools by name.

API

  • GET /api/whose-name/pool?p=&q= — per-member: [{"username": ...}, …], 200/207/404 (parallels the batch query endpoint).
  • GET /api/whose-name/pool/names?p=&q= — flattened distinct: {"names": [...]}, 200/404.

Both are GET and lenient (empty p/q404, not 422), matching the single query endpoint. Route closures stay thin HTTP↔domain maps; all logic lives in PoolService.

Wiring & docs

  • WHOSENAME_POOLS_YAML config (default tests/pools.yml) + PoolQueryRepository => PoolYamlFileRepository binding.
  • README Pools section; ADL docs/adl/2026-07-08-pool-endpoints-status-and-shape.md records the per-member-vs-flattened split, the lenient 404-on-empty choice, and rejected alternatives.

Testing

Full suite passes via ./vendor/bin/sail test51 passed, 2 skipped (pre-existing filesystem-atime skips). New coverage:

  • Domain — per-member shape, null kept vs dropped, dedup, same-field shortcut, empty pool.
  • Infrastructure — find, empty pool, cache persistence/invalidation, missing file, plus an end-to-end PoolService + real repos test.
  • Application — both endpoints (200/207/404, same-field, dedup).

Note

Builds on the merged multi-name feature, so it carries the string|array|null return type. The PHP 8.0-FPM / Laravel-upgrade decision (Laravel 9 doesn't run on PHP 8.5) still applies at deploy time.

🤖 Generated with Claude Code

A pool is a named list of names sharing one field (service), defined in a
separate pools.yml. Given a pool and an asked service, the service resolves
every member through the existing QueryService.

- Domain: Pool (getField/getNames), PoolQueryRepository (findByName), and
  PoolService (QueryService injected). `whatAreTheNamesOf` returns one answer
  per member, index-aligned and string|array|null, mirroring
  QueryService::whatAreTheNamesOf so callers get 207 semantics.
  `whoseNamesAreThere` flattens those answers into a distinct list (arrays
  spread in, nulls and duplicates dropped). When the asked service is the
  pool's own field, its names are returned verbatim.
- Infrastructure: PoolYamlFileRepository replicates YamlFileRepository's
  mtime-based caching, indexing pools by name.
- API: GET /whose-name/pool (per-member, 200/207/404) and
  GET /whose-name/pool/names (flattened distinct, 200/404). Both GET and
  lenient like the single query endpoint.
- Wiring: WHOSENAME_POOLS_YAML config + PoolQueryRepository binding.
- Docs: README Pools section and an ADL for the endpoint status/shape.

Tests cover the domain (per-member shape, null kept vs dropped, dedup,
same-field shortcut), the repository (find, cache, missing file), an
end-to-end integration, and both endpoints.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dragonee
dragonee merged commit 3bc45ca into main Jul 8, 2026
1 check passed
@dragonee
dragonee deleted the feat/pools branch July 8, 2026 20:07
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