在 IHP 中处理复杂的查询结果而无需手动指定列?

Dealing with complex query results in IHP without having to manually specify columns?

https://ihp.digitallyinduced.com/Guide/database.html 的“处理复杂查询结果”部分展示了如何在查询数据库类型时通过创建如下类型来“包含额外数据”:

data PostWithCommentsCount = PostWithCommentsCount
    { id :: Id Post
    , title :: Text
    , commentsCount :: Int
    }
    deriving (Eq, Show)

这很好用,但缺点是您需要手动指定 posts 的所有列以包含在新的 PostWithCommentsCount 类型中:

instance FromRow PostWithCommentsCount where
    fromRow =
        PostWithCommentsCount
            <$> field
            <*> field
            <*> field

fetchPostsWithCommentsCount :: (?modelContext :: ModelContext) => IO [PostWithCommentsCount]
fetchPostsWithCommentsCount = do
    trackTableRead "posts" -- This is needed when using auto refresh, so auto refresh knows that your action is accessing the posts table
    sqlQuery "SELECT posts.id, posts.title, (SELECT COUNT(*) FROM comments WHERE comments.post_id = posts.id) AS comments_count FROM posts" ()

随着时间的推移维护起来很繁琐,如果 posts table 中的更改意味着您还必须更改此手动查询。我认为如果类型看起来像这样会更好:

data PostWithCommentsCount = PostWithCommentsCount
    { post :: Post
    , commentsCount :: Int
    }
    deriving (Eq, Show)

这样我就不必手动指定我感兴趣的 posts 的所有列 - 我会得到整个 Post。目前有办法实现吗?

是的,如果您使用以下 FromRow 实例,这是可能的:

instance FromRow PostWithCommentsCount where
    fromRow = do
        post <- fromRow
        commentsCount <- field
        pure PostWithCommentsCount { post, commentsCount }

你也可以用上面的运算符写成这样:


instance FromRow PostWithCommentsCount where
    fromRow = PostWithCommentsCount
        <$> fromRow
        <*> field