feat(db): accept a read replica ID in DB operation commands#177
feat(db): accept a read replica ID in DB operation commands#177aprimakina wants to merge 4 commits into
Conversation
The db connection commands (connection-string, connect/psql, test-connection, schema) and the db_execute_query / db_schema MCP tools now resolve a read replica set ID as well as a service ID: it's tried as a service first, then matched against the project's read replica sets. A replica ID connects to that replica's endpoint while credentials resolve against the parent service (replicas share the primary's credentials). When --pooled is requested for a replica that has no pooler, all surfaces warn and fall back to a direct connection. Service-management commands still treat a replica ID as not found. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Read replica ID resolution now: - validates a matched replica is active and has an endpoint, returning a clear "not active" / "no endpoint" error instead of failing late at connect time. A new ErrReplicaNotFound sentinel distinguishes a real no-match (fall back to the service error) from a matched-but-unusable replica (surface it). - only scans the project's services when the service lookup failed with a 404; other failures (auth, network, 5xx) are surfaced as-is via the new common.IsNotFound helper, avoiding a wasted service-list call. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… scan
The API resolves a read replica ID through the normal service-get endpoint,
returning the replica's own endpoint plus a forked_from link to its parent
(is_standby, service_id). Use that instead of scanning the project's services:
- common.ResolveConnectionTarget turns a fetched service into a
ConnectionTarget{Connect, Credential, IsReplica}. A standby replica connects
to its own endpoint but resolves credentials (and password reset) against the
parent primary, fixing the "password authentication failed" error when
connecting to a replica by ID.
- Removes the ResolveServiceOrReplica/FindReplicaByID list-scan machinery, the
IsNotFound helper, GetReplicaConnectionDetails, ConnectToService/ConnectToTarget.
- Consolidates the pooler policy: ConnectionTarget.Details owns the
build-and-RequirePooler rule; ReplicaPoolerWarning owns the replica guard;
resolveConnectTarget handles both the by-ID replica and the interactive menu.
- getServiceDetails delegates to the shared common.GetService.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drop the redundant "in place of the service ID" and doubled "read replica" wording from the db connection commands' help and the README, and remove the read-only/lag aside from `db connect` help (kept in the MCP tool description). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
a4104cd to
57e8469
Compare
Askir
left a comment
There was a problem hiding this comment.
Naming confused me a lot here but I think otherwise its good.
What happens if you use update-password, save-password and tiger db create role with a read replica? For the record I think its fine if update-password and create role fail (its a read replica after all so read only) but it should probably have a good error. For save-password I genuinely am not sure if it should override the parents password or error out.
| } | ||
|
|
||
| service, err := getServiceDetailsFunc(cmd, cfg, args) | ||
| target, err := resolveConnectionTarget(cmd, cfg, args) |
There was a problem hiding this comment.
We have resolveConnectionTaget and resolveConnectTarget now doing wildly different things. But reading as if someone typo'd.
Maybe we could clarify these two? One is the connection chooser and returns ConnectionDetails as the result, the other one is the lookup of the ID
| type ConnectionTarget struct { | ||
| Connect api.Service | ||
| Credential api.Service | ||
| IsReplica bool | ||
| } |
There was a problem hiding this comment.
I find this poorly named, it took me a long time while reading to understand that Credential is only the CredentialService/ the service where we resolve the credentials from rather than the actual credentials.
I think it would make sense to at least call the two ConnectionService and CredentialService. Sorry for being a bit pedantic about naming, here. I try not to do that usually but I really struggled understanding what's happening here 😅
The tiger db connection commands (connection-string, connect/psql, test-connection, schema) and the MCP db_execute_query / db_schema tools now accept a read replica set ID wherever a service ID is accepted. A replica ID connects to that replica's endpoint using the parent primary's credentials (replicas share them); a primary ID behaves as before.
The API resolves a replica ID via the normal service-get endpoint, returning the replica's endpoint plus a forked_from link to its parent — so credentials (and password reset) resolve against the parent.