[英]Haskell Esqueleto project subset of columns to list of custom records
在所有示例中,我看到esqueleto的结果被投影到元组列表或实体记录中 。
例如:
previousLogItems <- select $ from $ \li -> do
orderBy [desc (li ^. LogItemId)]
limit 10
return (li ^. LogItemId, li ^. LogItemTitle)
在esqueleto中是否有任何方法可以将列的子集投影到自定义记录(不同于实体)而不是元组? 这样做没有从元组到自定义记录的额外投影。
例如,假设从数据库中获取所有数据是低效的,因此我们只想将数据库中的WindowTitle和BeginTime列投影到具有足够名称的自定义记录中。
更新
不工作代码的示例:
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
错误:
• 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))
更新
不工作代码的示例:
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
错误:
• 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))
esqueleto实际上在这里做的事情有点复杂。 以下是select
的类型:
select :: (SqlSelect a r, MonadIO m) => SqlQuery a -> SqlReadT m [r]
这需要一个SqlQuery a
(一个monad包装你return
的值),并返回一个SqlReadT m [r]
(包含结果列表的monad)。 return
Custom
类型时,会发生以下情况:
a
类型转换为持久性的内部SQL表示 [r]
要使这适用于自定义类型,您需要实例化SqlSelect ,并定义与持久类型之间的转换函数:
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"
(请注意,我实际上无法测试上述任何内容,因此可能存在错误)
需要注意的一点是,在上面的例子中, a
和r
类型不相同( Custom'
与Custom
)。 这是因为在select
,您使用的所有值都是Value
类型,而不是它们的实际类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.