使用 postgres-simple 在 FromRow 实例定义上出错

Error on a FromRow instance definition with postgres-simple

data CumulativeRevenue = CumulativeRevenue
  { payment_date :: T.Text
  , amount       :: Double
  , sum          :: Double
  } deriving (Show, Generic, Aeson.ToJSON, Aeson.FromJSON)

instance Postgres.FromRow CumulativeRevenue where
  fromRow = CumulativeRevenue
            <$> Postgres.field
            <*> Postgres.field
            <*> Postgres.field

cumulativeRevenue :: Postgres.Connection -> IO [CumulativeRevenue]
cumulativeRevenue conn = Postgres.query_ conn
  "SELECT payment_date, amount, sum(amount) OVER (ORDER by payment_date) \
  \ FROM (\
  \ SELECT CAST (payment_date as TEXT) AS payment_date, SUM(amount) AS \
  \ amount \
  \ FROM payment \
  \ GROUP BY CAST(payment_date AS TEXT) \
  \ ) p \
  \ ORDER BY payment_date \
  \"

目前,我有上面的一段代码。完整代码为here。 cumulativeRevenue 给出了一个例外,如下所示。 spock部分可以忽略。

Spock Error while handling ["cumulative"]: Incompatible {errSQLType = "numeric", errSQLTableOid = Nothing, errSQLField = "amount", errHaskellType = "Double", errMessage = "types incompatible"}

我不清楚为 CumulativeRevenue 中的金额和总和字段指定什么。有人可以帮我吗?在使用 postgres-simple 库时,有没有更简单的方法来计算从 Haskell 类型到 SQL 类型的类型转换,反之亦然?

Double 有一个 FromField 实例,但它不适用于 numeric,因为 numeric 是可变精度 as per the PostgresSQL documentation. If you look at the postgresql-simple documentation 你会看到 Ratio Integer(又名 Rational)实例 确实 支持 numeric

所以您在这里可以做的是以下两件事之一:

  1. 为您的 amount 字段使用 Rational 而不是 Double
  2. 确定你可以接受失去精度(尽管你为什么在 SQL 端使用 numeric?),然后做一些类似
  3. 的事情
import Data.Ratio

loseNumericPrecision :: Postgres.RowParser Double
loseNumericPrecision = fmap fromRational Postgres.field

并使用它代替 Postgres.field 对应于 numeric 值的字段。