You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从postgresql-query调用pgQuery?求IO monad运行示例

没问题,我来帮你搞定在IO monad里直接用postgresql-query的pgQuery函数这件事。核心是要满足pgQuery需要的两个约束:HasPostgres(获取数据库连接)和MonadLogger(处理日志),下面一步步给你讲清楚,还有完整的示例代码:

第一步:理解约束对应的解决方案

pgQuery的类型签名要求两个关键约束:

  • HasPostgres m:这个类型类需要你的monad能获取PostgreSQL连接,postgresql-query库已经为ReaderT Connection m提供了实例,所以我们可以用runPgConn函数把需要连接的动作转换成目标monad。
  • MonadLogger m:这个类型类负责日志输出,monad-logger库提供了runStdoutLoggingT函数,可以把带日志的动作转换成IO,同时把日志输出到标准输出。

第二步:补全你的doIt函数

首先把你写的doIt补全,比如返回是否找到匹配的设置(根据查询结果是否非空):

doIt :: (HasPostgres m, MonadLogger m) => Text -> m Bool
doIt name = do
  (val::[Only Int]) <- pgQuery [sqlExp|select setting from pg_settings where name=#{name}|]
  -- 返回是否存在匹配的设置项
  return $ not (null val)

第三步:在IO monad中运行doIt

接下来写一个main函数,把doIt转换成IO动作,步骤包括:建立连接、处理约束、执行查询、清理连接:

首先导入所有必要的模块:

import Database.PostgreSQL.Query (pgQuery, sqlExp, HasPostgres, runPgConn)
import Database.PostgreSQL.Simple (Connection, connectPostgreSQL, Only(..), close, withPostgreSQL)
import Control.Monad.Logger (MonadLogger, runStdoutLoggingT)
import Data.Text (Text)

然后用两种方式实现IO运行:

方式1:手动管理连接

main :: IO ()
main = do
  -- 替换成你的PostgreSQL连接字符串
  let connStr = "host=localhost dbname=your_db user=your_user password=your_pass port=5432"
  
  -- 1. 建立连接
  conn <- connectPostgreSQL connStr
  
  -- 2. 结合runStdoutLoggingT(处理MonadLogger)和runPgConn(处理HasPostgres)
  result <- runStdoutLoggingT $ runPgConn conn (doIt "work_mem")
  
  -- 3. 输出结果
  putStrLn $ "查询是否找到设置: " ++ show result
  
  -- 4. 手动关闭连接
  close conn

方式2:自动管理连接(更安全)

用withPostgreSQL可以自动在动作结束后关闭连接,避免忘记清理:

main :: IO ()
main = do
  let connStr = "host=localhost dbname=your_db user=your_user password=your_pass port=5432"
  
  runStdoutLoggingT $ withPostgreSQL connStr $ \conn -> do
    -- 在withPostgreSQL的回调里执行查询
    result <- runPgConn conn (doIt "work_mem")
    -- 用liftIO把IO动作带到LoggingT monad里
    liftIO $ putStrLn $ "查询是否找到设置: " ++ show result

为什么这样可行?

  • runPgConn conn action:把需要HasPostgres约束的action(这里是doIt)转换成m a,其中m是你传入的monad(这里是LoggingT IO),因为ReaderT Connection m是HasPostgres的实例,runPgConn会把连接注入进去。
  • runStdoutLoggingT:把LoggingT IO a转换成IO a,同时处理日志输出(你会在控制台看到pgQuery生成的SQL日志)。

这样你就不需要用runSqlBuilder转成标准query,直接用pgQuery在IO里运行了。

内容的提问来源于stack exchange,提问作者RandomB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 17:57:28