Haskell Esqueleto将列子集投影到自定义记录列表中

Haskell Esqueleto将列子集投影到自定义记录列表中,haskell,tuples,record,esqueleto,Haskell,Tuples,Record,Esqueleto,在我所看到的所有示例中,结果都被投影到元组列表或to中 例如: previousLogItems <- select $ from $ \li -> do orderBy [desc (li ^. LogItemId)] limit 10 return (li ^. LogItemId, li ^. LogItemTitle) 更新 不工作代码的示例: data Custom = Custom { title :: Text

在我所看到的所有示例中,结果都被投影到元组列表或to中

例如:

previousLogItems <- select $ from $ \li -> do
        orderBy [desc (li ^. LogItemId)]
        limit 10
        return (li ^. LogItemId, li ^. LogItemTitle)
更新

不工作代码的示例:

data Custom = Custom
  { title :: Text
  , id    :: Int
  } deriving (Eq, Show, Generic)

daily :: Servant.Handler [Custom]
daily = do
  lis <- liftIO $ runDB $
            select $ from $ \li -> do
                    orderBy [desc (li ^. LogItemId)]
                    limit 25
                    return (Custom (li ^. LogItemTitle) (li ^. LogItemId))
  return lis
daily :: Servant.Handler [Custom]
daily = do
  lis <- liftIO $ runDB $
            select $ from $ \li -> do
                    orderBy [desc (li ^. LogItemId)]
                    limit 25
                    return (Custom <$> (li ^. LogItemTitle) <*> (li ^. LogItemId))
  return lis
daily::Servant.Handler[自定义]
每日=做
丽斯多
orderBy[desc(li^.LogItemId)]
限制25
返回(自定义(li^.LogItemTitle)(li^.LogItemId))
返回lis
错误:

• Couldn't match expected type ‘Text’
              with actual type ‘SqlExpr (Database.Esqueleto.Value Text)’
• In the first argument of ‘Custom’, namely ‘(li ^. LogItemTitle)’
  In the first argument of ‘return’, namely
    ‘(Custom (li ^. LogItemTitle) (li ^. LogItemId))’
  In a stmt of a 'do' block:
    return (Custom (li ^. LogItemTitle) (li ^. LogItemId))
• Couldn't match type ‘Database.Esqueleto.Value Text’ with ‘Text’
  Expected type: SqlExpr Text
    Actual type: SqlExpr (Database.Esqueleto.Value Text)
• In the second argument of ‘(<$>)’, namely ‘(li ^. LogItemTitle)’
  In the first argument of ‘(<*>)’, namely
    ‘Custom <$> (li ^. LogItemTitle)’
  In the first argument of ‘return’, namely
    ‘(Custom <$> (li ^. LogItemTitle) <*> (li ^. LogItemId))’


• Couldn't match type ‘Database.Esqueleto.Value (Key LogItem)’
                 with ‘Int’
  Expected type: SqlExpr Int
    Actual type: SqlExpr (Database.Esqueleto.Value (Key LogItem))
• In the second argument of ‘(<*>)’, namely ‘(li ^. LogItemId)’
  In the first argument of ‘return’, namely
    ‘(Custom <$> (li ^. LogItemTitle) <*> (li ^. LogItemId))’
  In a stmt of a 'do' block:
    return (Custom <$> (li ^. LogItemTitle) <*> (li ^. LogItemId))
•无法将类型“Database.Esqueleto.Value Text”与“Text”匹配
应为类型:SqlExpr Text
实际类型:SqlExpr(Database.Esqueleto.Value文本)
•在“()”的第二个参数中,即“(li^.LogItemTitle)”
在“()”的第一个参数中,即
'自定义(li^.LogItemTitle)'
在“return”的第一个参数中,即
“(自定义(li^.LogItemTitle)(li^.LogItemId))”
•无法匹配类型“Database.Esqueleto.Value(Key LogItem)”
带“Int”
应为类型:SqlExpr Int
实际类型:SqlExpr(Database.Esqueleto.Value(Key LogItem))
•在“()”的第二个参数中,即“(li^.LogItemId)”
在“return”的第一个参数中,即
“(自定义(li^.LogItemTitle)(li^.LogItemId))”
在“do”块的stmt中:
返回(自定义(li^.LogItemTitle)(li^.LogItemId))

埃斯奎莱托在这里实际做的事情有点复杂。以下是
选择的类型:

select :: (SqlSelect a r, MonadIO m) => SqlQuery a -> SqlReadT m [r]
这将获取一个
SqlQuery a
(一个包装您
返回的值的monad),并返回一个
SqlReadT m[r]
(一个包装结果列表的monad)。当您
返回
您的
自定义
类型时,会发生以下情况:

  • esqueleto将
    a
    类型转换为persistent的内部SQL表示形式
  • persistent执行查询并返回结果列表
  • esqueleto将结果列表从persistent的内部SQL表示转换为
    [r]

  • 要使此功能适用于自定义类型,您需要实例化并定义与持久类型之间的转换函数:

    data Custom' = Custom' (Value Text) (Value Int)
    
    data Custom = Custom
      { title :: Text
      , id    :: Int
      }
    
    instance SqlSelect Custom' Custom where
      sqlSelectCols esc (Custom' a b) = (mconcat [ta, ", ", tb], va ++ vb)
        where
          (ta, va) = sqlSelectCols esc a
          (tb, vb) = sqlSelectCols esc b
      sqlSelectColCount _ = 2
      sqlSelectProcessRow [PersistText a, PersistInt64 b] = Right $ Custom a b
      sqlSelectProcessRow _ = Left "Error: Incorrect rows to translate to Custom"
    
    (请注意,我实际上无法测试上述任何一项,因此它可能有bug)


    需要注意的是,在上面的示例中,
    a
    r
    类型不同(
    Custom'
    vs
    Custom
    )。这是因为在
    select
    中,您正在处理的所有值都是
    Value
    类型,而不是它们的实际类型。

    我们不能在这里执行
    fmap
    ?我想您可能需要实例化。我可能会看看元组实例的定义方式,然后从那里开始。@WillemVanOnsem我想知道一种直接返回自定义记录的方法。没有去元组然后去自定义类型的低效性。是的,但我想的是
    自定义(li^.LogItemTitle)(li^.LogItemId)
    。但是现在我无法测试它:(@WillemVanOnsem我认为提升它是不够的。
    select::(SqlSelect a r,MonadIO m)=>SqlQuery a->SqlReadT m[r]
    ,从我所能看到的,有一个从返回类型
    a
    到SQL表达式到最终类型
    r
    的实际转换。