Question

I am trying to use one of the example queries from Esqueleto but I cannot get it to compile. The only variation is that I am using it without a join.

I have a table that looks like this:

sqlite> select * from my_table;
id|category|amount
1|A|1.0
2|A|2.0
3|B|2.0
4|B|8.0

And I would like to do this:

select category,sum(amount) from my_table group by category;
category|sum(amount)
A|3.0
B|10.0

This is my query:

import qualified Database.Esqueleto as E

r <- runDB $
    E.select $ E.from $ \t  -> do
        E.groupBy $ t E.^. MyTableCategory
        let sum' = E.sum_ (t E.^. MyTableAmount)
        E.orderBy [E.desc sum']
        return (t E.^. MyTableCategory, sum' )

I get this error:

No instance for (PersistField b0) arising from a use of `E.select'
The type variable `b0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
  instance PersistField Account -- Defined in `Model'
  instance PersistField AccountCategory -- Defined in `Model'
  instance PersistField MyTable -- Defined in `Model'
  ...plus 37 others
In the expression: E.select
In the second argument of `($)', namely
  `E.select
   $ E.from
     $ \ t
         -> do { E.groupBy $ t E.^. MyTableCategory;
                 let ...;
                 .... }'
In a stmt of a 'do' block:
  r <- runDB
       $ E.select
         $ E.from
           $ \ t
               -> do { E.groupBy $ t E.^. MyTableCategory;
                       let ...;
                       .... }

Where do I provide the type information for E.select? Should the compiler be able to infer from t E.^.MyTableCategory? I also tried using the countRows / groupBy example here (https://hackage.haskell.org/package/esqueleto-1.4.1/docs/Database-Esqueleto.html) but similar issue (the only difference is that I don't have a join)

Appreciate your help.

Thanks!

Was it helpful?

Solution

The from table parameters types are sometimes deduced from the result type which must be explicit.

Other ambiguities arise about the monad type usually.

It is useful to enclose the query in a specific function to solve some ambiguities.

I cannot certify your esqueleto query conformity now but

Try this:

{-# LANGUAGE PackageImports, ConstraintKinds #-}

import Import
import "esqueleto" Database.Esqueleto as E
import "monad-logger" Control.Monad.Logger (MonadLogger)
import "resourcet" Control.Monad.Trans.Resource (MonadResourceBase)

type TCategory = Text  -- change it if its different
type TAmount = Double

myQuery :: (PersistQuery (SqlPersist m), MonadLogger m , MonadResourceBase m) =>

                        SqlPersist m [(E.Value TCategory, E.Value (Maybe TAmount))] -- corrected
myQuery = do

  -- your query

  E.select $ E.from $ \t  -> do
        E.groupBy $ t E.^. MyTableCategory
        let sum' = E.sum_ (t E.^. MyTableAmount)  
        E.orderBy [E.desc sum']
        return (t E.^. MyTableCategory, sum' )  

-- within your handler:

    pairListResult <- runDB myQuery

    forM_ pairListResult $ \(E.Value categ, E.Value maybeAmount) -> do -- whatever

Update: it compiles

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top