Where 子句与 Ecto.Query 中查询中引用的内容不对应

Where clauses are not corresponding to what is referenced in the query in Ecto.Query

这里是原文Ecto.Query

def by_id(user_id, company_id, asset_id) do

        # section 1
        from a in Asset,

        # section 2
        join: acl in AccessList, on: acl.asset_id == a.id, 
        join: c in Company, on: acl.company_id == c.id,
        join: u in User, on: acl.user_id == u.id, 

        # section 3
        where: u.id == ^user_id and c.id == ^company_id

        # section 4 
        and a.id == ^asset_id,
        # section 5
        select: %{ 
            asset_name: a.asset_name, 
            asset_id: a.id,
            inserted_at: a.inserted_at 
            }, 

        # section 6
        group_by: a.id,

        # section 6 
        order_by: a.id

    end  

重构:

 def by_query do
        from a in Asset
    end

    def by_join(query) do
        from a in query,
        join: acl in AccessList, on: acl.asset_id == a.id,
        join: c in Company, on: acl.company_id == c.id,
        join: u in User, on: acl.user_id == u.id
    end

    def by_where_user(query, user_id) do
        query = from q in query
        query
        |> where([u], u.id == ^user_id) 
    end

    def by_where_company(query, company_id) do
        query = from q in query
        query
        |> where([c], c.id == ^company_id) 
    end

    def by_where_asset(query, asset_id) do
        query = from q in query
        query
        |> where([a], a.id == ^asset_id)
    end

    def by_select(query) do
        from a in query,
        select: %{ 
            asset_name: a.asset_name, 
            asset_id: a.id,
            inserted_at: a.inserted_at 
        },
        group_by: a.id, 
        order_by: a.id
    end

然后我就这样连接了:

  query = by_query
       |> by_join
       |> by_where_user(user_id)
       |> by_where_company(company_id)
       |> by_where_asset(asset_id)
       |> by_select

现在不行了。

生成的查询不同,我可以看出问题出在 where 子句上。

    SELECT a0."asset_name", a0."id", a0."inserted_at" 
FROM "assets" AS a0 
INNER JOIN "access_lists" AS a1 ON a1."asset_id" = a0."id" 
INNER JOIN "companies" AS c2 ON a1."company_id" = c2."id" 
INNER JOIN "users" AS u3 ON a1."user_id" = u3."id" 
WHERE (a0."id" = ) 
AND (a0."id" = ) 
AND (a0."id" = ) 
GROUP BY a0."id" 
ORDER BY a0."id" [3349, 1, 5]

Where 应该是 a0c2u3

此处基于: https://hexdocs.pm/ecto/Ecto.Query.html#module-query-bindings

问题出在三个 by_where_* 子句上。没有状态,因此 Ecto 没有机会记住在其他函数中如何调用选择。处理它的最简单方法是使用另一个关联端:

def by_where_user(query, user_id) do
    from q in query
    |> where([result], result.user_id == ^user_id) 
end

def by_where_company(query, company_id) do
    from q in query
    |> where([result], result.company_id == ^company_id) 
end

def by_where_asset(query, asset_id) do
    from q in query
    |> where([result], result.asset_id == ^asset_id)
end