canonical / canonical/postgresql-single-kernel-library
Easier access to client-relation data
- Dominant language
- Python
- Stars
- 4
- Forks
- 3
- Avg merge
- 3d 17h
- Merged PRs (30d)
- 26
Description
## Request
Raised as a drive-by nit on #216 ([comment](https://github.com/canonical/postgresql-single-kernel-library/pull/216#discussion_r3832000709), anchored on `DatabaseManager.set_rel_to_db_mapping`'s `rel_databases` round-trip and the per-field fetches in `collect_user_relations`): "Not sure it is helpful but what we did in opensearch and valkey is to have something like [this](https://github.com/canonical/opensearch-single-kernel-library/blob/2/edge/opensearch_single_kernel/core/external_clients_relation.py) which makes it easier to access data of relation. But this is a nit."
Today the client-relation data reads across `DatabaseManager` are untyped field fetches (`fetch_relation_field(relation.id, "database")`, raw `relation.data.values()` loops) rather than one named accessor.
An implementation of the typed-models shape below was explored in #227.
## Candidate shapes
akram09 pointed at one pattern for both kernels; the two kernels actually ship different shapes, so both are candidates:
- **RelationState-style wrapper** (what opensearch ships): this repo already carries the base class (`core/relation_state.py`, subclassed by `PostgreSQLPeer`/`PostgreSQLApplication`) — a client-relation sibling adds no dependencies and mirrors the sibling-kernel pattern cited in the review. akram09's own instinct points this way too (#226: "This can easily go in the state").
- **Shared dpcharmlibs typed models** (what valkey and etcd ship): pydantic request/response models from data-platform-charmlibs — maintained shared schemas instead of bespoke per-field properties, at the cost of adding the dependency.
## Design constraint any shape must respect
Provider-published fields are leader-only reads through the data-platform library and feed the per-unit `user_hash` sync check (`are_units_in_sync`, written per-unit by `managers/config.py`): an accessor exposing a merged view of both relation sides would make the hash leadership-dependent and break unit-sync. An accessor scoped to the requirer-side request payload avoids that.
## Scope
In: the requirer-side request reads in `DatabaseManager`. Out unless separately decided: provider-published fields, which stay behind the leader gate on `DatabaseProvides`.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with the requirer-side request reads in DatabaseManager, then compare core/relation_state.py and the typed-model exploration in #227. Check managers/config.py, are_units_in_sync, and DatabaseProvides to preserve the leader-only boundary. Done means an agreed accessor shape exposes only the requirer-side payload without changing provider-published fields or unit-sync behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- postgresql, python
- Domain
- databases
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100