4This cookbook exists to help you easily form Rel8 queries. It's main purpose is
5to help those familiar with SQL to translate their queries into Rel8
11To select from a table, use ``each``.
16To perform an inner join against two queries, use ``where_`` with a join
17condition. For example, the following SQL:
21 SELECT * FROM table_a JOIN table_b ON table_a.x = table_b.y
28 where_ $ tableAX a ==. tableBY b
33A ``LEFT JOIN`` query is performed by using ``optional``.
35For example, the query:
39 SELECT * FROM table_a LEFT JOIN table_b ON table_a.x = table_b.y
48 where_ $ tableAX a ==. tableBY b
52Note that ``maybeB`` here will be a ``MaybeTable``, which is the Rel8
53``Query``-equivalent of ``Maybe``. This allows you to observe if a left join
54has succeeded or failed.
59A ``Query`` by default has no ordering - just like in SQL. If you rows back in
60a certain order, you can use ``orderBy`` with an ``Order``.
62For example, the query:
66 SELECT * FROM my_table ORDER BY my_table.id ASC, my_table.x DESC NULLS FIRST
71 orderBy (mconcat [ myTableId >$< asc, myTableX >$< nullsFirst desc ]) $
74Note that we use ``>$<`` (from ``Data.Functor.Contravariant``) to select table
75columns, and we can use `mconcat` to combine orderings.
77If all columns of a table have an ordering, you can also use ``ascTable`` and
78``descTable``. For example::
80 myQuery = orderBy ascTable $ each myTableSchema
85Aggregations in Rel8 work by using ``aggregate``, which takes a ``Query
86(Aggregate a)`` and gives you back a ``Query a``.
92 SELECT sum(foo), count(distinct bar) FROM table_a
96 myQuery = aggregate do
98 return $ liftF2 (,) (sum (foo a)) (countDistinct (bar a))
100where ``liftF2`` comes from ``Data.Functor.Apply`` from the ``semigroupoids``
103Combining aggregations
104----------------------
106As ``Aggregate`` is an instance of ``Apply`` (which is very similar to
107``Applicative``), individual aggregations can be combined. For example, one way
108to take the average rating would be to write the query:
112 SELECT sum(rating.score) / count(rating.score) FROM rating
114In Rel8, we can write this as::
116 myQuery = aggregate do
117 rating <- each ratingSchema
118 return $ liftF2 (/) (sum (score rating)) (count (score rating))
120You can also use ``RebindableSyntax`` and ``ApplicativeDo``::
122 {-# language ApplicativeDo, RebindableSyntax #-}
124 import Data.Functor.Apply ((<.>))
126 myQuery = aggregate do
127 rating <- each ratingSchema
129 scoreSum <- sum (score rating)
130 numberOfRatings <- count (score rating)
131 return (scoreSum / numberOfRatings)
134For large aggregations, this can often make queries easier to read.
139Rel8 has a fairly unique feature in that it's able to return not just lists of
140rows, but can also return *tree*\s.
142To understand what this means, we'll consider a small example query for blog
143posts. We want our query to return:
1451. The latest 5 blog posts.
1462. For each blog post, all tags.
1473. For each blog post, the latest 3 comments.
149In Rel8, we can write this query as::
152 post <- each postSchema
155 tag <- each tagSchema
156 where_ (tagPostId tag ==. postId post)
157 return (listAgg (tagName tag))
162 orderBy (commentCreatedAt >$< desc) do
163 comment <- each commentSchema
164 where (commentPostId comment ==. postId post)
166 return (post, tags, latestComments)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list