@@ -113,3 +113,116 @@ this type with Rel8 by writing::
114Here we used ``JSONBEncoded``, which will serialize to PostgreSQL ``jsonb``
114Here we used ``JSONBEncoded``, which will serialize to PostgreSQL ``jsonb``
115(binary JSON) type, which is generally the best choice.
115(binary JSON) type, which is generally the best choice.
123+Now that we've seen how types are bridged between a database and Haskell via
124+``DBType``, we can start looking at how expressions are modelled. In Rel8, any
125+expression will be a value of the form ``Expr a``, where ``a`` is the type of
126+the expression. For example, the SQL expression ``user.id = 42`` is an ``Expr
127+Bool``, and the subexpressions ``user.id`` and ``42`` might be ``Expr
130+``Expr``\s are usually created by combining other ``Expr``\s together, like
131+using numeric operations like `+` and `*`, or by quoting Haskell values into
132+queries with ``lit``. Continuing with the example of ``user.id = 42``, we can
133+write this in Rel8 as::
135+ userId ==. lit (UserId 42)
137+Here it's assumed that a ``userId :: Expr UserId`` expression is already in
138+scope, and we can compare that against another ``Expr UserId`` using the ``==.``
139+operator (which is like Haskell's normal ``==`` operator, but lifted to work on
140+``Expr``). The expression ``lit (UserId 42)`` quotes the Haskell term ``UserId
141+42`` literally as the SQL expression ``42``. This particular encoding is chosen
142+because ``UserId`` is simply a ``newtype`` around ``Int64``.
147+So far we've only talked about ``DBType``, which represents database types
148+*excluding* ``null``. Rel8 chooses this encoding because ``null`` is rather
149+special in SQL, and doesn't really constitute a distinct type. For example,
150+there is no SQL notion of "stacking" nulls - which is to say a type like ``Maybe
151+(Maybe UserId))`` has no real analogous type in SQL.
153+Of course, as ``null`` is pervasive in SQL queries, Rel8 does support ``null`` -
154+simply wrap up your type in ``Maybe``. ``Nothing`` will be translated as
155+``null``, and ``Just`` is used to represent non-null values.
157+Rel8 comes with a set of functions to work with ``null`` values thash should
158+feel familiar to Haskell programmers:
160+* ``null`` creates null values (you can also use ``lit Nothing``).
161+* ``nullify`` turns an ``Expr a`` into a ``Expr (Maybe a)`` (like ``Just``).
162+* ``nullable`` allows you to eliminate null values, like the ``maybe`` function.
163+* ``isNull`` and ``isNonNull`` work like ``isNothing`` and ``isJust``,
165+* ``mapNullable`` is like ``fmap`` for ``Maybe``, and allows you to map over
167+* ``liftOpNullable`` is like ``liftA2`` for ``Maybe``, and allows you to combine
168+ expressions together, given a way to combine non-null expressions.
170+``SQL`` and null-polymorphic expressions
171+----------------------------------------
173+Through the API reference documentation for Rel8, you might encounter the
174+``Sql`` type class. For example, if we look at the type of ``litExpr``, we
177+ litExpr :: Sql DBType a => a -> Expr a
179+Here ``Sql DBType a`` means that ``a`` can either be literally a type that has
180+an instance of ``DBType`` (like ``UserId`` or ``Bool``), *or* that same type
181+wrapped in ``Maybe`` (so ``Maybe UserId`` or ``Maybe Bool``). ``Maybe`` here
182+encodes the SQL concept of ``null``.
184+Some functions work regardless of whether or not a value is null, and in these
185+cases you'll see ``Sql DBType a``. ``Sql`` can be used with any ``DBType``
186+subtype. For example, the type of ``div`` is::
188+ div :: Sql DBIntegral a => Expr a -> Expr a -> Expr a
190+Which means ``div`` works on any ``DBIntegral a``, including ``Maybe a``.
192+The ``DBType`` subtypes
193+=======================
209+``DBSemigroup`` and ``DBMonoid``
210+--------------------------------
216+``DBNum``, ``DBIntegral`` and ``DBFractional``
217+----------------------------------------------