You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Is your feature request related to a problem? Please describe.
The usage of transactions could benefit from syntax helpers.
Right now without having a monadic expression, methods have to thread the DBTransaction.
classX{publicasyncf(tran?: DBTransaction){if(tran==null){returnthis.db.withTransactionF((tran)=>this.f.apply(this,[...arguments,tran]));}// use tran}}
Describe the solution you'd like
Instead something like this could be possible:
classX{
@transaction(this.db)publicasyncg(tran: DBTransaction){// use tran}}
This is currently not possible until decorators are able to change the method signatures. That is, currently TS decorators are not allowed to change method signatures so then tran here is actually required by the caller.
At the same time, the TypedDescriptor should be used to allow a union of different methods. Any method that takes the tran: DBTransaction at the very end of the function is allowed. The usage of withTransactionF and withTransactionG is the only ones allowed, as one must do it inside an async function or an async generator function.
At the same time, this syntax enhancement only works for functions with a very specific signature.
Describe alternatives you've considered
The main alternative is a monadic API. Monads have a bind function where M a -> (a -> M b) -> M b.
Here the Transaction is the monadic context, that functions are bound to.
If we were in Haskell we could do:
tran >>= (\s -> return s) >> put "key" "value" >> get "key"
What is the monad actually wrapping? It's not the database... I suppose it is the state. Then the state can be interrogated there. But the get and put would be transactional methods. It could really wrap anything.
To allow do syntax to be possible, one must make our ; the equivalent of the bind operator.
class X {
public async f(): DBTransaction<void> {
put();
get();
return;
}
}
Then put and get represent transactional operators, that can only composed with an existing monad.
This isn't idiomatic JS atm, so it's not really possible.
The other way is to use this and then use class decorator mixins that enable the context of the function to be augmented with operators that make it transactional. But that adds even more magic.
Once method signatures can be changed, then it would be worthwhile for application placed decorators to do this. It could also work if instead of parameters, we had keyword/named parameters. Which would make a @transaction decorator alot more robust.
Another way is to allow users to define their decorator functions easily, so that way they can address different kind of function signatures. Like have the transaction be the first parameter, last parameter or anywhere in between.
Without method signature changes, you would need to use tran! inside the function to ensure that TS understands that's it is in fact always defined.
functiontransaction(db: {a: string}){return(target: any,key: string,descriptor: TypedPropertyDescriptor<(tran: string)=>any>)=>{constf=descriptor.value;if(typeoff!=='function'){thrownewTypeError(`${key} is not a function`);}descriptor.value=function(tran: string){returnthis.db.withTransactionF((tran)=>f.apply(this,[...arguments,tran]));};returndescriptor;};}
The text was updated successfully, but these errors were encountered:
We are making this work inside PK. We have a way of overloading the decorator signatures, and with parameter decorators, we can specify where the context should be located. However since our context interface also contains other properties like signal and timer, right now it's still a thing inside PK, and cannot be factored out to independent library. Could be useful if we had an open interface for the context and allowed one to share the context map. MatrixAI/Polykey#297
Is your feature request related to a problem? Please describe.
The usage of transactions could benefit from syntax helpers.
Right now without having a monadic expression, methods have to thread the
DBTransaction
.Describe the solution you'd like
Instead something like this could be possible:
This is currently not possible until decorators are able to change the method signatures. That is, currently TS decorators are not allowed to change method signatures so then
tran
here is actually required by the caller.At the same time, the
TypedDescriptor
should be used to allow a union of different methods. Any method that takes thetran: DBTransaction
at the very end of the function is allowed. The usage ofwithTransactionF
andwithTransactionG
is the only ones allowed, as one must do it inside an async function or an async generator function.At the same time, this syntax enhancement only works for functions with a very specific signature.
Describe alternatives you've considered
The main alternative is a monadic API. Monads have a
bind
function whereM a -> (a -> M b) -> M b
.Here the
Transaction
is the monadic context, that functions are bound to.If we were in Haskell we could do:
What is the monad actually wrapping? It's not the database... I suppose it is the state. Then the state can be interrogated there. But the
get
andput
would be transactional methods. It could really wrap anything.To allow do syntax to be possible, one must make our
;
the equivalent of thebind
operator.Then
put
andget
represent transactional operators, that can only composed with an existing monad.This isn't idiomatic JS atm, so it's not really possible.
The other way is to use
this
and then use class decorator mixins that enable the context of the function to be augmented with operators that make it transactional. But that adds even more magic.Once method signatures can be changed, then it would be worthwhile for application placed decorators to do this. It could also work if instead of parameters, we had keyword/named parameters. Which would make a
@transaction
decorator alot more robust.Another way is to allow users to define their decorator functions easily, so that way they can address different kind of function signatures. Like have the transaction be the first parameter, last parameter or anywhere in between.
Without method signature changes, you would need to use
tran!
inside the function to ensure that TS understands that's it is in fact always defined.Additional context
The text was updated successfully, but these errors were encountered: