在有 none 的许多中选择一些

Selecting some of One where there're none of Many

我正在尝试查找没有任何用户名的域,即免费域。希望有一个不需要 2 个单独查询的解决方案,但我也 运行 遇到类型系统问题。

-- error Couldn't match type 'IO [Domain]' with '[[Domain]]', points to beginning of filter

            Just term -> do
                usernames <- query @Username
                    |> filterWhere (#name, term) |> fetch >>= collectionFetchRelated #domainId
                domains <- search |> filter \x->case find (\y->get #domainId x == get #domainId y) usernames of
                    Just _ -> True
                    Nothing -> False
                render IndexView {..}

错误 -- error Couldn't match type 'IO [Domain]' with '[[Domain]]', points to beginning of filter 由于此处的箭头符号而发生:

                domains <- search |> filter \x->case find (\y->get #domainId x == get #domainId y) usernames of
                    Just _ -> True
                    Nothing -> False

因为这没有做任何 IO,它需要使用 let:

                let domains = search |> filter \x->case find (\y->get #domainId x == get #domainId y) usernames of
                    Just _ -> True
                    Nothing -> False

现在 domains 的类型是 [[Domain]](域列表的列表)。可能我们想要 [Domain](只是一个普通的域列表)。

我们可以使用 concat 来达到这个目的:

                let domains = search
                        |> filter ( \x-> case find (\y->get #domainId x == get #domainId y) usernames of
                                Just _ -> True
                                 Nothing -> False
                            )
                        |> concat

现在类型错误应该消失了。


Hopefully there's a solution to this that doesn't require 2 separate queries

是的,这也可以通过手写查询实现:

domains <- sqlQuery "SELECT domains.* FROM domains WHERE (SELECT COUNT(*) FROM usernames WHERE usernames.domain_id = domains.id AND usernames.name = ?) = 0" [term]