s/Identity/Result/ in readthedocs

This commit is contained in:
Oliver Charles 2021-06-18 20:49:30 +01:00
parent 2487397a50
commit 6396ea1ceb
3 changed files with 36 additions and 35 deletions

View File

@ -11,18 +11,19 @@ though most of these primitive ``DBType``\s should already be available.
Combining ``newtype`` and ``DBType``
------------------------------------
You can define new instances of ``DBType`` by using Haskell "generalized newtype
deriving" strategy. This is useful when you have a common database type, but
need to interpret this type differently in different contexts. A very common
example here is with auto-incrementing ``id`` counters. In PostgreSQL, it's
common for a table to have a primary key that uses the ``serial`` type, which
means the key is an ``int8`` with a default value for ``INSERT``. In Rel8, we
could use ``Int64`` (as ``Int64`` is the ``DBType`` instance for ``int8``), but
we can be even clearer if we make a ``newtype`` for each *type* of id.
You can define new instances of ``DBType`` by using Haskell "generalized
newtype deriving" strategy. This is useful when you have a common database
type, but need to interpret this type differently in different contexts. A very
common example here is with auto-incrementing ``id`` counters. In PostgreSQL,
it's common for a table to have a primary key that uses the ``serial`` type,
which means the key is an ``int8`` with a default value for ``INSERT``. In
Rel8, we could use ``Int64`` (as ``Int64`` is the ``DBType`` instance for
``int8``), but we can be even clearer if we make a ``newtype`` for each *type*
of id.
If our database has users and orders, these tables might both have ids, but they
are clearly not meant to be treated as a common type. Instead, we can make these
types clearly different by writing::
If our database has users and orders, these tables might both have ids, but
they are clearly not meant to be treated as a common type. Instead, we can make
these types clearly different by writing::
newtype UserId = UserId { getUserId :: Int64 }
deriving newtype DBType
@ -57,8 +58,8 @@ In our PostgreSQL we have a few choices, but for now we'll assume that they are
stored as ``text`` values.
In order to use this type in Rel8 queries, we need to write an instance of
``DBType`` for ``OrderStatus``. One approach is to use ``parseTypeInformation``,
which allows you to refine an existing ``DBType``::
``DBType`` for ``OrderStatus``. One approach is to use
``parseTypeInformation``, which allows you to refine an existing ``DBType``::
instance DBType OrderStatus where
typeInformation = parseTypeInformation parser printer typeInformation
@ -100,9 +101,9 @@ There usage is very similar to ``ReadShow`` - simply derive ``DBType via
JSONEncoded``, and Rel8 will use ``ToJSON`` and ``FromJSON`` instances (from
``aeson``) to serialize the given type.
For example, a project might use event sourcing with a table of events. Each row
in this table is an event, but this event is stored as a JSON object. We can use
this type with Rel8 by writing::
For example, a project might use event sourcing with a table of events. Each
row in this table is an event, but this event is stored as a JSON object. We
can use this type with Rel8 by writing::
data Event = UserCreated UserCreatedData | OrderCreated OrderCreatedData
deriving stock Generic

View File

@ -58,7 +58,7 @@ Through the API reference documentation for Rel8, you might encounter the
``Sql`` type class. For example, if we look at the type of ``litExpr``, we
have::
litExpr :: Sql DBType a => a -> Expr a
litExpr :: Sql DBType a => a -> Expr a
Here ``Sql DBType a`` means that ``a`` can either be literally a type that has
an instance of ``DBType`` (like ``UserId`` or ``Bool``), *or* that same type
@ -69,6 +69,6 @@ Some functions work regardless of whether or not a value is null, and in these
cases you'll see ``Sql DBType a``. ``Sql`` can be used with any ``DBType``
subtype. For example, the type of ``div`` is::
div :: Sql DBIntegral a => Expr a -> Expr a -> Expr a
div :: Sql DBIntegral a => Expr a -> Expr a -> Expr a
Which means ``div`` works on any ``DBIntegral a``, including ``Maybe a``.

View File

@ -5,7 +5,7 @@ Getting Started
In this section, we'll take a look at using Rel8 to work with a small database
for Haskell packages. We'll take a look at idiomatic usage of Rel8, mapping
tables to Haskell, and then look at writing some simple queries.
tables to Haskell, and then look at writing some simple queries.
Before we get started, we'll be using the following language extensions and
imports throughout this guide::
@ -70,7 +70,7 @@ Following these steps for ``author``, we have::
{ authorId :: Column f Int64
, name :: Column f Text
, url :: Column f (Maybe Text)
}
}
deriving stock (Generic)
deriving anyclass (Rel8able)
@ -81,7 +81,7 @@ in our project, it would be too easy to accidentally mix them up and create
nonsensical joins. As Haskell programmers, we often solve this problem by
creating ``newtype`` wrappers, and we can also use this technique with Rel8::
newtype AuthorId = AuthorId { toInt64 :: Int64 }
newtype AuthorId = AuthorId { toInt64 :: Int64 }
deriving newtype (DBEq, DBType, Eq, Show)
Now we can write our final schema mapping. First, the ``author`` table::
@ -90,7 +90,7 @@ Now we can write our final schema mapping. First, the ``author`` table::
{ authorId :: Column f AuthorId
, authorName :: Column f Text
, authorUrl :: Column f (Maybe Text)
}
}
deriving stock (Generic)
deriving anyclass (Rel8able)
@ -99,7 +99,7 @@ And similarly, the ``project`` table::
data Project f = Project
{ projectAuthorId :: Column f AuthorId
, projectName :: Column f Text
}
}
deriving stock (Generic)
deriving anyclass (Rel8able
@ -107,8 +107,8 @@ To show query results in this documentation, we'll also need ``Show`` instances:
Unfortunately these definitions look a bit scary, but they are essentially just
``deriving (Show)``::
deriving stock instance f ~ Identity => Show (Author f)
deriving stock instance f ~ Identity => Show (Project f)
deriving stock instance f ~ Result => Show (Author f)
deriving stock instance f ~ Result => Show (Project f)
These data types describe the structural mapping of the tables, but we also
need to specify a ``TableSchema`` for each table. A ``TableSchema`` contains
@ -169,7 +169,7 @@ database heavy applications.
In Rel8, ``SELECT`` statements are built using the ``Query`` monad. You can
think of this monad like the ordinary ``[]`` (List) monad - but this isn't
required knowledge.
required knowledge.
To start, we'll look at one of the simplest queries possible - a basic ``SELECT
* FROM`` statement. To select all rows from a table, we use ``each``, and
@ -193,17 +193,17 @@ expressions of type ``a``\".
To execute this ``Query``, we pass it to ``select``::
>>> :t select c (each projectSchema)
select c (each projectSchema) :: MonadIO m => m [Project Identity]
select c (each projectSchema) :: MonadIO m => m [Project Result]
When we ``select`` things containing ``Expr``s, Rel8 builds a new response
table with the ``Identity`` interpretation. This means you'll get back plain
table with the ``Result`` interpretation. This means you'll get back plain
Haskell values. Studying ``projectAuthorId`` again, we have::
>>> let aProjectIdentity = undefined :: Project Identity
>>> :t projectAuthorId aProjectIdentity
projectAuthorId aProjectIdentity :: AuthorId
>>> let aProjectResult = undefined :: Project Result
>>> :t projectAuthorId aProjectResult
projectAuthorId aProjectResult :: AuthorId
Here ``Column Identity AuthorId`` reduces to just ``AuthorId``, with no
Here ``Column Result AuthorId`` reduces to just ``AuthorId``, with no
wrappping type at all.
Putting this all together, we can run our first query::
@ -343,8 +343,8 @@ focus on the /type/ of that query::
where
>>> :t select c authorsAndProjects
select c authorsAndProjects
:: MonadIO m => m [(Author Identity, Project Identity)]
select c authorsAndProjects
:: MonadIO m => m [(Author Result, Project Result)]
Our query gives us a single list of pairs of authors and projects. However,
@ -352,7 +352,7 @@ with our domain knowledge of the schema, this isn't a great type - what we'd
rather have is a list of pairs of authors and /lists/ of projects. That is,
what we'd like is::
[(Author Identity, [Project Identity])]
[(Author Result, [Project Result])]
This would be a much better type! Rel8 can produce a query with this type by
simply wrapping the call to ``projectsForAuthor`` with either ``some`` or