如何使用Esqueleto做一个“SELECT ... IN(SELECT ...)”?
问题描述:
考虑到以下两种模式和GET /articles/:slug/comments
请求,我想根据其slug
检索属于文章的评论。如何使用Esqueleto做一个“SELECT ... IN(SELECT ...)”?
Article json sql=articles
slug Slug
title Text
description Text
body Text
createdAt UTCTime default=now()
updatedAt UTCTime Maybe default=NULL
userId UserId
UniqueSlug slug
Comment json sql=comments
body Text
createdAt UTCTime default=now()
updatedAt UTCTime Maybe default=NULL
articleId ArticleId
userId UserId
使用持久性的rawSql
,我们可以做到这一点如下
getCommentsForArticle :: Slug -> App (Cmts [Entity Comment])
getCommentsForArticle slug = do
comments <- runDb $ rawSql stm [toPersistValue slug]
return (Cmts comments)
where stm = "SELECT ?? FROM comments \
\WHERE article_id IN (\
\SELECT id FROM articles WHERE slug = ?)"
然而,由于我想保持Haskell和SQL之间的类型安全,我想改写这个使用esqueleto
。这是我正在努力的部分。通过阅读文档,sub_select似乎是工作的工具。下面是我有:
getCommentsForArticle :: Slug -> App (Cmts [Comment])
getCommentsForArticle slug = do
comments <- E.select $
E.from $ \cmts -> do
let subQuery =
E.from $ \arts -> do
E.where_ $ arts ^. ArticleSlug ==. E.val slug
return (arts ^. ArticleId)
E.where_ $ cmts ^. CommentArticleId ==. E.sub_select subQuery
return cmts
return $ Cmts comments
我也注意到了in_ operator,但我无法弄清楚如何使用它也不是,如果它比sub_select更合适。
我错过了什么?语法是否正确?谢谢。
答
你会想这样的事情
getCommentsForArticle slug = do
c <- select $ from $ \cmts -> do
let a = subList_select from $ \arts -> do
where_ $ arts ^. ArticleSlug ==. val slug
return $ arts ^. ArticleId
where_ $ cmts ^. CommentArticleId `in_` a
return cmts
return $ Cmts c
无关,但'SELECT * ...'是一个糟糕的风格:)。为什么不使用SQLite或任何其他SQL DB?他们都很好打字;) – Igor
@Igor由不良风格你的意思是不只选择什么是必需的?根据你的第二个问题,我编辑了这个问题来指定我正在使用'persistent'和'postgresql'。 –
是的。为什么不在需要SQL时使用SQL? – Igor