squeal
squeal copied to clipboard
Writing utility query callers in Squeal 0.6
I'm trying to upgrade our set of utilities to prepare the ground for a general upgrade of our codebase to Squeal 0.6. It's going rather well, this release has a lot of great features ! I'm very excited about it.
To spare some keystroke, I like to use a series of small functions like this one (Squeal 0.5):
-- | Run a query and retrieve its first result, that must be
-- an Only x. Use `queryStatement` to call this with a `Query`
-- rather than `Manipulation`.
maybeOneOnly ::
(MonadUnliftIO m, MonadPQ schema m, ToParams p params, FromValue a b) =>
Manipulation '[] schema params (OnlyReturns a)
-- ^ Query to run, that returns a `Only` type
-> p
-- ^ Query to run
-> m (Maybe b)
-- ^ Maybe a result in the monadic context
maybeOneOnly q p = manipulateParams q p >>= (fmap . fmap) fromOnly . firstRow
I would have loved to be able to express it in Squeal 0.6 using the new type family Manipulation_
, like this:
maybeOneOnly' ::
(MonadUnliftIO m, MonadPQ db m) =>
Manipulation_ db params (Only r)
-- ^ Query to run, that returns a `Only` type
-> params
-- ^ Query to run
-> m (Maybe r)
-- ^ Maybe a result in the monadic context
maybeOneOnly' q p = manipulateParams q p >>= (fmap . fmap) fromOnly . firstRow
Sadly I must be missing something here, as the compiler yells at me:
• Couldn't match type ‘Generics.SOP.Universe.Code params’
with ‘'[TupleCodeOf params (Generics.SOP.Universe.Code params)]’
arising from a use of ‘manipulateParams’
• In the first argument of ‘(>>=)’, namely ‘manipulateParams q p’
In the expression:
manipulateParams q p >>= (fmap . fmap) fromOnly . firstRow
In an equation for ‘maybeOneOnly'’:
maybeOneOnly' q p
= manipulateParams q p >>= (fmap . fmap) fromOnly . firstRow
• Relevant bindings include
p :: params (bound at src/Fretlink/Squeal/Utils/Runners.hs:72:17)
q :: Manipulation_ db params (Only r)
(bound at src/Fretlink/Squeal/Utils/Runners.hs:72:15)
maybeOneOnly' :: Manipulation_ db params (Only r)
-> params -> m (Maybe r)
(bound at src/Fretlink/Squeal/Utils/Runners.hs:72:1)
Of course I can write it with less higher-level expressivity like this:
maybeOneOnly ::
(MonadUnliftIO m, MonadPQ db m, GenericParams db params x xs, FromValue (NullPG r) r) =>
Manipulation '[] db params (RowPG (Only r))
-- ^ Query to run, that returns a `Only` type
-> x
-- ^ Query to run
-> m (Maybe r)
-- ^ Maybe a result in the monadic context
maybeOneOnly q p = manipulateParams q p >>= (fmap . fmap) fromOnly . firstRow
But it's not as nice ! Is there a way to write this kind of things with the handy Manipulation_
type-family or am I asking too much from the type system here ?
There shouldn't be a need to change these functions, either their types signatures or their bodies, to accommodate Manipulation_
s or Query_
s. That's because a Manipulation_
calculates a Manipulation
.