I'm trying to construct an Opaleye query that matches the following SQL:
select * ,
(select array_agg(tags.tagname)
from articles_tags
inner join tags on tags.id = articles_tags.tag_fk
where articles_tags.article_fk = articles.id
)
from articles
The tables involved (simplified) are:
articles: (id, title, content)
articles_tags: (article_fk, tag_fk)
tags: (id, tagname)
My goal is to query for articles that have one or more tags attached, and retrieve all attached tags as an array.
So far, I got the following elementary queries:
-- | Query all article-tag relations.
allTaggedArticlesQ :: OE.Select TaggedArticleR
allTaggedArticlesQ = OE.selectTable taggedArticlesTable
-- | Query article-tag relations for the given articles.
taggedArticlesQ :: OE.SelectArr PA.ArticleIdField TaggedArticleR
taggedArticlesQ = proc articleId -> do
ta <- allTaggedArticlesQ -< ()
OE.restrict -< articleFk ta .=== articleId
returnA -< ta
-- | Join article-ids and tag names for the given subset of articles.
articleTagNamesQ :: OE.SelectArr PA.ArticleIdField ArticleTagR
articleTagNamesQ = proc articleIds -> do
ta <- taggedArticlesQ -< articleIds
tags <- PT.allTagsQ -< ()
OE.restrict -< PT.tagKey tags .=== tagFk ta
returnA -< ArticleTag (articleFk ta) (PT.tagName tags)
However, I cannot get the aggregation to work: The following does not type-check, and I do not understand how to compose this aggregation with the above query:
-- | Aggregate all tag names for all given articles
articleTagsQ :: PA.ArticleIdField -> OE.Select (PA.ArticleIdField, F (OE.SqlArray OE.SqlText))
articleTagsQ = OE.aggregate
( pArticleTag
ArticleTag
{ atArticleFk = OE.groupBy,
atTagname = OE.arrayAgg
}
) OE.selectTable articleTagNamesQ
In some blog posts and GitHub issues, I found a remark that the aggregation does not play nice with Product-Profunctors and Arrows and, therefore, cannot be included in an arrow query. Yet, I am relatively new to Haskell and haven't really understood the theory behind these two libraries (there does not seem to be a beginner-friendly documentation); therefore, I cannot come up with the general structure how to combine queries with aggregation. There are some examples by William Yao here, but I don't understand the general concept, so I can't apply these examples to my problem.
I would highly appreciate if someone can provide insight on how to compose aggregation with regular queries in Opaleye, thanks!