Skip to content

[Rust] Capability based DbContext#5307

Open
kistz wants to merge 4 commits into
clockworklabs:masterfrom
kistz:capability-based-dbctx
Open

[Rust] Capability based DbContext#5307
kistz wants to merge 4 commits into
clockworklabs:masterfrom
kistz:capability-based-dbctx

Conversation

@kistz

@kistz kistz commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Description of Changes

An evolution of #4707 where i explored adding a db_read_only method to DbContext. (hence i would appreciate your thoughts @gefjon )
This was the wrong appraoch in retrospect because there are still some annoyances with this.
Furthermore there is really no benefit to adding the associated type DbView and is just making the ergonomics worse.

So here is the new approach which solved all my problems:
Making a trait for every capability which the various contexts are providing because the Databse is only one of them.
These capabilities are (and pretty much the whole relevant div for this pr because the impl blocks are trivial) and should be self explanatory:

pub trait CtxDbRead {
    fn db_read_only(&self) -> &LocalReadOnly;
}
pub trait CtxDbWrite: CtxDbRead {
    fn db(&self) -> &Local;
}
pub trait CtxWithSender {
    fn sender(&self) -> Identity;
}
pub trait CtxWithTimestamp {
    fn timestamp(&self) -> Timestamp;
}
pub trait CtxWithHttp {
    fn http(&self) -> &HttpClient;
}

Why is this relevant?

Lets look at an example building on the previous pr:
You have abstracted your code in a trait which you can call for every context e.g. authorization.
Now this does not work because the sender method is not available on DbContext.

impl<Db: CtxDbRead> Authorization for Db {
  fn test(&self,args:Args) {
   self.db_read_only().do_i_have_perms().find(self.sender()); //ERROR: no sender method
}

Now this is really annoying since you now have to pass additional parameters to the method.
Instead we can now specific these capabilities in the type system:

impl<Db: CtxDbRead+CtxWithSender> Authorization for Db {
  fn test(&self,args:Args) {
   self.db_read_only().do_i_have_perms().find(self.sender()); //WORKS NOW YAY
}

Additonally there could be also a + CtxWithTimestamp if you wanted to for example store a last logged in date or smth (you get the idea)
Now this is far better because .sender is available for ViewContext for example so you can authorize with the same method.

Alternatives/Bikeshedding

I chose the names CtxWith because really the Contexts are the common denominator and not the Database.
Thats also the reason why its CtxDbRead because you are expressing: "All context where i get read access to the databse (e.g. everything).
Other names have felt worse.

Also the deprecation can be removed but i think this approach is strictly superior and i dont think there are currently many people relying on it.

API and ABI breaking changes

None. one deprecation for the old DbContext but this can also be removed if desired.

Expected complexity level and risk

  1. Additive change with extremly minimal surface

Testing

  • Works for my project

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