-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Guidance on using scoped
with multiple Polysemy.Error e effects
#2
Comments
It looks to me like it should work by using a type application to specify which error to use, as in: withTransaction @DomainError do ... unless you're actually keeping May I ask – why are you running |
There are definitely cases where we want to be able to throw either a For context: it's a standard http web server, and we want most route handlers to be transactional. As for the second question...because it's the first thing I got to work 😅. Is there a better way to do it? |
Here's an example of an actual
As you can see, we've had to add |
oh, now I see what you are trying to achieve – I didn't look close enough 🙈 For your purpose, the actual exception is irrelevant, since you only want to react to something aborting the computation. onException act rollback then any error will be caught. |
After thinking about this some more I realized that your database effects probably use some thread-local state to associate queries with the connection pool on which the transaction is started, is that right? |
Nothing so complicated, as far as I know (unless
And its place in the interpreter stack:
|
I see…then how do you ensure that multiple threads don't get their transactions tangled up? |
The sinking feeling in my gut implies that maybe we don't 😅. I guess it's a good thing I reached out--I didn't even consider that issue. |
right 🙂 acquireConnection ::
Member ConnectionPool r =>
(Connection -> Sem r a) ->
Sem r a
acquireConnection use =
conn <- ConnectionPool.exclusiveConnection
bracketOnError Psql.begin (const Psql.rollback) \ () -> do
a <- use conn
Psql.commit
pure a
runScopedDB ::
Member ConnectionPool r =>
InterpreterFor (Scoped Connection DBBeam) r
runScopedDB =
interpretScoped acquireConnection \ conn -> \case
DBBeam pg -> runBeamPostgres conn pg
but this isn't enough for your case, since (a) you're not using withDB ::
Member (Scoped res DBBeam) r =>
(() -> Sem r a) ->
Sem r a
withDB use =
scoped (use ())
runStores :: InterpreterFor (Scoped () (Bundle [Store1, Store2])) r
runStores =
interpretScoped withDB \ () -> \case
Bundle Here (Store.Query q) ->
dBBeam (runQuery q)
Bundle (There Here) (Store.Query q) ->
dBBeam (runQuery q)
It's not very comfortable, but maybe you can figure something out 🙂 |
Oh dear. Perhaps it would be better to ditch the |
I do use the The |
I'll give it a shot! |
I'm afraid I have to admit I don't think I have the requisite noggin power to implement the how do I interpret a Test.Hspec.spec :: Spec
Test.Hspec.spec = do
describe "state test" $ do
it "does something stateful" $ do
actual <- runM
$ (doSomethingWithAnEffectIWantToMockAsState :: Sem r String)
& runScopedAs (pure ()) (\() -> runState [] . (storeToState :: Sem (Store ': r) String -> Sem (State [Int] ': r) String))
let expectedState = []
actual `shouldBe` (expectedState, "the actual result") ...doesn't typecheck, because |
It is indeed not possible to do that with the existing interpreters. An important issue you should be aware of is that this won't work at all with handleStoreToState :: Member (State [Int]) r => Store m a -> Sem r a
handleStoreToState =
undefined
scope ::
Member (Sync [a]) r =>
(() -> Sem (State [a] : r) x) ->
Sem r x
scope use = do
(s, a) <- runState [] (use ())
a <$ Sync.putTry s
foo :: Sem r ()
foo = do
r :: Maybe [Int] <- interpretSync $ interpretScopedWith @'[State [Int]] scope (const handleStoreToState) do
-- test body
Sync.try
embed (print r) As to the |
Ah, of course--that makes sense. Thank you so much, I really appreciate the time. |
my pleasure! btw, I just released a new version of |
@adlaika Did you end up sticking to the stores approach? I'm looking to do the exact same and then stumbled into this issue |
FYI I implemented a variant that's a bit more ergonomic while redesigning my should be possible to be generalized/used with other backends. |
I've used
Scoped
to write a database transaction effect:...which works great! However, I'm not sure how to extend it to use two different
Polysemy.Error
members:blows up with
Can you point me in the right direction?
Thanks!
The text was updated successfully, but these errors were encountered: