adapter-priority

Priority: adapter-provided values and comparator helpers

Overview

Project.Priority is intentionally a free-form string. Upstream systems use different vocabularies for priority (for example: P1, critical, high, 1, urgent), so adapters should map their upstream priority into a meaningful string for the normalized model and not attempt to coerce into a single repo-wide enum.

The generic in-memory adapter treats the Priority value as opaque for filtering and will use lexicographic ordering by default when sorting by sort=priority.

Comparator helpers

The internal/adapter/memory package exposes small helpers to make it easy to install a semantic ordering for priority values.

  • SemanticPriorityComparator(order []string) func(a,b string) bool
    • Returns a comparator that orders priorities according to order. The first element is considered highest priority. Unknown values are considered lower priority than any known value.
  • DefaultPriorityOrder and DefaultSemanticPriorityComparator
    • A common ordering: critical, high, medium, low.
  • InstallDefaultPriorityComparator()
    • Convenience function that sets the package-wide comparator to the default semantic ordering.
  • SetPriorityComparator(cmp func(a,b string) bool)
    • Set the package-wide comparator to a custom function. Passing nil restores default lexicographic behavior.

How adapters should use priority

  1. Map upstream priority to a stable, human-meaningful string when building the normalized model.Project (for example: critical, high, low, or an upstream raw value like P1).
  2. If you want semantic sorting across projects from multiple upstream systems, either call InstallDefaultPriorityComparator() at startup or supply your own ordering via SetPriorityComparator(SemanticPriorityComparator(...)).

Example

In your adapter or server initialization code:

1
2
3
4
5
6
7
8
import "git.home.luguber.info/go-test-project/internal/adapter/memory"

// Use the repository's default semantic ordering (critical > high > medium > low)
memory.InstallDefaultPriorityComparator()

// Or install a custom ordering for your adapter's vocabulary:
cmp := memory.SemanticPriorityComparator([]string{"urgent", "high", "normal", "low"})
memory.SetPriorityComparator(cmp)

Notes and edge-cases

  • Unknown or adapter-specific priority values sort after known values when using the semantic comparator. If you need a different policy for unknown values, provide a custom comparator.
  • SetPriorityComparator(nil) restores the default lexicographic ordering.
  • The comparator is package-global (process-wide). If you run multiple adapters with different desired orderings in the same process, install the comparator that makes sense for your global view or provide adapter-specific sorting in handlers instead of relying on the package-wide comparator.

Troubleshooting

  • If sorting by priority gives an unexpected order, print the Project.Priority values of the returned projects to check mapping consistency across adapters.

API: /statuses

The example server exposes a convenience endpoint to list known project status strings discovered in the adapter’s current in-memory store.

  • GET /statuses
    • Response: 200 OK
    • Body: JSON object with statuses array, e.g. { "statuses": ["active", "planned"] }

This endpoint is meant to help frontends discover the set of status values returned by upstream adapters. The order is the sequence in which the values were first encountered in the adapter’s dataset. If you need a canonical ordering, sort the array on the client or request an API change.

API: /priorities

The example server exposes a convenience endpoint to list known project priority strings discovered in the adapter’s current in-memory store.

  • GET /priorities
    • Response: 200 OK
    • Body: JSON object with priorities array, e.g. { "priorities": ["critical", "high", "medium"] }

Like /statuses, the order is the sequence in which priority values were first encountered. Clients should sort or apply semantic comparators as needed.

Examples

Use these examples against the example service started from cmd/exampleservice.

Query projects with a single priority:

1
2
# fish shell
curl -s "http://localhost:8080/projects?priority=high" | jq .

Query projects with multiple priorities (OR semantics):

1
2
# fish shell
curl -s "http://localhost:8080/projects?priority=high,critical" | jq .

Discover available priorities and statuses:

1
2
3
# fish shell
curl -s http://localhost:8080/priorities | jq .
curl -s http://localhost:8080/statuses | jq .

Note: use jq to pretty-print JSON; these commands assume the example server is running on port 8080.

Multi-field examples

Filter by a single status:

1
2
# fish shell
curl -s "http://localhost:8080/projects?status=active" | jq .

Filter by multiple statuses (OR semantics within the field):

1
2
# fish shell
curl -s "http://localhost:8080/projects?status=active,planned" | jq .

Filter by a single person (team member):

1
2
# fish shell
curl -s "http://localhost:8080/projects?person_id=person-1" | jq .

Filter by multiple persons (OR semantics within the field):

1
2
# fish shell
curl -s "http://localhost:8080/projects?person_id=person-1,person-2" | jq .

Combine fields (AND across different fields). For example, projects that are either active or planned and have priority high or critical:

1
2
# fish shell
curl -s "http://localhost:8080/projects?status=active,planned&priority=high,critical" | jq .

Semantics:

  • Multiple values in a single query parameter (comma-separated) are treated as OR (match any). For example, status=active,planned returns projects whose status is either active or planned.
  • Different query parameters combine with AND. For example, status=active&person_id=person-1 returns projects that are active and have person-1 on the team.