[Rust] Add possibility to be generic over DbContext (#4707)

# Description of Changes

This patch aims to improve the situation for the need of a generic
function over multiple `ctxs`.
The `DbContext` was introduced for this but due to the associated type
amibguity when trying to implement it another mmethod is needed.

This pr implements a `db_read_only()` method which always results in a
`LocalReadOnly` hence Rust can infer the types of a the returned type
(which prior to this was either `__view , __query and a 3rd one i cent
remember right now 😓`.

I have chosen to be defensive by implementing it as `unstable` but i can
also remove this if that is desired.

It allows the following pattern which has been workig great in my
project so its time to contribute it :>

```rust
pub(crate) trait YourTableNameRead {
   // Your methods which only need read access
  fn test(&self,args);

}

// The read version is a supertrait to give access to the read methods.
pub(crate) trait YourTableNameWrite: YourTableNameRead {
  // Your methods which need read-write access
}

// The read version gets implemented for every DbContext since we can always read.
impl<Db: DbContext> YourTableNameRead for Db {
  fn test(&self,args) {
   self.db_read_only().table_name().whatever(args);
}

// By constraining the associated type to Local we only get this for writeable ctxs.
impl<Db: DbContext<DbView = Local>> YourTableNameWrite for Db {}

```

These allow you to do on the calling site:
```rust
use YourTableNameRead;

#[view|reducer|procedure]
fn my_func(ctx: Reducer|(Anon)View|Tx, args ) {
   ctx.test(args);
}
```



# API and ABI breaking changes

None

# Expected complexity level and risk

1. Minor api and qol adition which is furthermore unstable.

# Testing

- [x] Works in my project

---------

Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
This commit is contained in:
Kilian Strunz
2026-05-04 20:46:47 +02:00
committed by GitHub
parent 4a20c81d0b
commit 309cf55604
+33 -2
View File
@@ -1459,9 +1459,14 @@ pub trait DbContext {
///
/// This method is provided for times when a programmer wants to be generic over the `DbContext` type.
/// Concrete-typed code is expected to read the `.db` field off the particular `DbContext` implementor.
/// Currently, being this generic is only meaningful in clients,
/// as `ReducerContext` is the only implementor of `DbContext` within modules.
fn db(&self) -> &Self::DbView;
/// Get a read-only view into the tables.
///
/// This method is provided for times when a programmer wants to be generic over the `DbContext` type.
/// Concrete-typed code is expected to read the `.db` field off the particular `DbContext` implementor.
#[cfg(feature = "unstable")]
fn db_read_only(&self) -> &LocalReadOnly;
}
impl DbContext for AnonymousViewContext {
@@ -1470,6 +1475,11 @@ impl DbContext for AnonymousViewContext {
fn db(&self) -> &Self::DbView {
&self.db
}
#[cfg(feature = "unstable")]
fn db_read_only(&self) -> &LocalReadOnly {
&self.db
}
}
impl DbContext for ReducerContext {
@@ -1478,6 +1488,11 @@ impl DbContext for ReducerContext {
fn db(&self) -> &Self::DbView {
&self.db
}
#[cfg(feature = "unstable")]
fn db_read_only(&self) -> &LocalReadOnly {
self.db.get_read_only()
}
}
#[cfg(feature = "unstable")]
@@ -1487,6 +1502,10 @@ impl DbContext for TxContext {
fn db(&self) -> &Self::DbView {
&self.db
}
fn db_read_only(&self) -> &LocalReadOnly {
self.db.get_read_only()
}
}
impl DbContext for ViewContext {
@@ -1495,6 +1514,11 @@ impl DbContext for ViewContext {
fn db(&self) -> &Self::DbView {
&self.db
}
#[cfg(feature = "unstable")]
fn db_read_only(&self) -> &LocalReadOnly {
&self.db
}
}
// `ProcedureContext` is *not* a `DbContext`
@@ -1508,6 +1532,13 @@ impl DbContext for ViewContext {
#[non_exhaustive]
pub struct Local {}
impl Local {
#[cfg(feature = "unstable")]
fn get_read_only(&self) -> &LocalReadOnly {
&LocalReadOnly {}
}
}
/// The [JWT] of an [`AuthCtx`].
///
/// [JWT]: https://en.wikipedia.org/wiki/JSON_Web_Token