Adds guide for adding Orville to an existing reader context

This commit is contained in:
David Vollbracht 2023-12-20 08:08:59 -06:00
parent 16c6ecad11
commit 117d17c83e
41 changed files with 1008 additions and 15 deletions

1
.gitignore vendored
View File

@ -35,3 +35,4 @@ orville-docsite/site-builder/_site
# Ignore directories created by samples
orville-docsite/samples/getting-started/orville-getting-started
orville-docsite/samples/adding-orville-new-readert/src
orville-docsite/samples/adding-orville-existing-readert/src

View File

@ -38,6 +38,8 @@
<a href="./how-tos/how-to-add-orville-to-your-application-monad.html">How To Add Orville to Your Application Monad</a>
<a href="./how-tos/how-to-add-orville-to-an-existing-reader-context.html">How To Add Orville to an Existing Reader Context</a>
<a href="./how-tos/how-to-marshall-a-haskell-record.html">How To Marshall a Haskell Record (Upcoming)</a>
<a href="./how-tos/how-to-add-custom-marshalling-validations.html">How Add Custom Marshalling Validations (Upcoming)</a>

View File

@ -38,6 +38,8 @@
<a href="../how-tos/how-to-add-orville-to-your-application-monad.html">How To Add Orville to Your Application Monad</a>
<a href="../how-tos/how-to-add-orville-to-an-existing-reader-context.html">How To Add Orville to an Existing Reader Context</a>
<a href="../how-tos/how-to-marshall-a-haskell-record.html">How To Marshall a Haskell Record (Upcoming)</a>
<a href="../how-tos/how-to-add-custom-marshalling-validations.html">How Add Custom Marshalling Validations (Upcoming)</a>

View File

@ -38,6 +38,8 @@
<a href="../how-tos/how-to-add-orville-to-your-application-monad.html">How To Add Orville to Your Application Monad</a>
<a href="../how-tos/how-to-add-orville-to-an-existing-reader-context.html">How To Add Orville to an Existing Reader Context</a>
<a href="../how-tos/how-to-marshall-a-haskell-record.html">How To Marshall a Haskell Record (Upcoming)</a>
<a href="../how-tos/how-to-add-custom-marshalling-validations.html">How Add Custom Marshalling Validations (Upcoming)</a>

View File

@ -38,6 +38,8 @@
<a href="../how-tos/how-to-add-orville-to-your-application-monad.html">How To Add Orville to Your Application Monad</a>
<a href="../how-tos/how-to-add-orville-to-an-existing-reader-context.html">How To Add Orville to an Existing Reader Context</a>
<a href="../how-tos/how-to-marshall-a-haskell-record.html">How To Marshall a Haskell Record (Upcoming)</a>
<a href="../how-tos/how-to-add-custom-marshalling-validations.html">How Add Custom Marshalling Validations (Upcoming)</a>

View File

@ -38,6 +38,8 @@
<a href="../how-tos/how-to-add-orville-to-your-application-monad.html">How To Add Orville to Your Application Monad</a>
<a href="../how-tos/how-to-add-orville-to-an-existing-reader-context.html">How To Add Orville to an Existing Reader Context</a>
<a href="../how-tos/how-to-marshall-a-haskell-record.html">How To Marshall a Haskell Record (Upcoming)</a>
<a href="../how-tos/how-to-add-custom-marshalling-validations.html">How Add Custom Marshalling Validations (Upcoming)</a>

View File

@ -0,0 +1,353 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Orville - How To Add Orville to an Existing Reader Context</title>
<link rel="stylesheet" href="../css/syntax.css" />
<link rel="stylesheet" href="../css/default.css" />
</head>
<body>
<section class="leftbar">
<header>
<h1 class="logo">
<a href="../">
<img alt="Orville Logo" src="../images/orville-waving-pennant.svg" />
</a>
</h1>
</header>
<nav>
<h3><a href="../">Home</a></h3>
<h3>Tutorials</h3>
<a href="../tutorials/getting-started.html">Getting Started</a>
<a href="../tutorials/using-sql-marshaller.html">Using SqlMarshaller</a>
<a href="../tutorials/using-migrations.html">Using Migrations</a>
<a href="../tutorials/using-plans.html">Using Plans</a>
<a href="../tutorials/using-json.html">Using JSON</a>
<h3>How-To Guides</h3>
<a href="../how-tos/how-to-add-orville-to-your-application-monad.html">How To Add Orville to Your Application Monad</a>
<a href="../how-tos/how-to-add-orville-to-an-existing-reader-context.html">How To Add Orville to an Existing Reader Context</a>
<a href="../how-tos/how-to-marshall-a-haskell-record.html">How To Marshall a Haskell Record (Upcoming)</a>
<a href="../how-tos/how-to-add-custom-marshalling-validations.html">How Add Custom Marshalling Validations (Upcoming)</a>
<a href="../how-tos/how-to-marshall-a-haskell-sum-type.html">How To Marshall a Haskell Sum Type (Upcoming)</a>
<a href="../how-tos/how-to-set-up-an-auto-incrementing-id-column.html">How To Set Up An Auto-incrementing Id Column (Upcoming)</a>
<a href="../how-tos/how-to-execute-raw-sql.html">How To Execute Raw SQL (Upcoming)</a>
<h3>Futher Explanation</h3>
<a href="../explanations/the-monad-orville-typeclass.html">The MonadOrville Typeclass (Upcoming)</a>
<a href="../explanations/building-sql-expressions.html">Building SQL Expressions (Upcoming)</a>
<a href="../explanations/fighting-n-plus-one-queries-with-plans.html">Fighting N+1 Queries with Plans (Upcoming)</a>
<h3>API Reference</h3>
<a href="https://hackage.haskell.org/package/orville-postgresql">See Hackage</a>
<h3>Other Links</h3>
<a href="../contact.html">Contact</a>
</nav>
<footer>
Site proudly generated by
<a href="http://jaspervdj.be/hakyll">Hakyll</a>
</footer>
</section>
<main role="main">
<h1>How To Add Orville to an Existing Reader Context</h1>
<article>
<section>
<p>This guide will show you how to add Orville to a monad that is already using
<code>ReaderT</code> in its monad stack. It builds conceptually on top of <a href="how-to-add-orville-to-your-application-monad.html">the previous
guide</a>, which assumed there
was not already a <code>ReaderT</code> in the application monad stack. Its recommended
that you read that guide before this one.</p>
<p>The file listing below shows a simple application with its own <code>Application</code>
monad that already has a reader context. When there is already a reader context
in the application stack its generally perferrable to incorporate Orville into
the existing reader context rather than adding a new <code>ReaderT</code> layer atop the
one thats already there.</p>
<div class="codeblock-label">
Main.hs (Before) : haskell
</div>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE GeneralizedNewtypeDeriving #-}</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">Main</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> ( main</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> ) <span class="kw">where</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Control.Monad.IO.Class</span> <span class="kw">as</span> <span class="dt">MIO</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Control.Monad.Reader</span> <span class="kw">as</span> <span class="dt">Reader</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">ApplicationContext</span> <span class="ot">=</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">ApplicationContext</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a> {<span class="ot"> applicationGreeting ::</span> <span class="dt">String</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a> }</span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">Application</span> a <span class="ot">=</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a> <span class="dt">Application</span> (<span class="dt">Reader.ReaderT</span> <span class="dt">ApplicationContext</span> <span class="dt">IO</span> a)</span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a> ( <span class="dt">Functor</span></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a> , <span class="dt">Applicative</span></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a> , <span class="dt">Monad</span></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a> , <span class="dt">MIO.MonadIO</span></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a> )</span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a><span class="ot">getGreeting ::</span> <span class="dt">Application</span> <span class="dt">String</span></span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a>getGreeting <span class="ot">=</span></span>
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a> <span class="dt">Application</span> (Reader.asks applicationGreeting)</span>
<span id="cb1-26"><a href="#cb1-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-27"><a href="#cb1-27" aria-hidden="true" tabindex="-1"></a><span class="ot">runApplication ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Application</span> a <span class="ot">-&gt;</span> <span class="dt">IO</span> a</span>
<span id="cb1-28"><a href="#cb1-28" aria-hidden="true" tabindex="-1"></a>runApplication greeting (<span class="dt">Application</span> io) <span class="ot">=</span></span>
<span id="cb1-29"><a href="#cb1-29" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span></span>
<span id="cb1-30"><a href="#cb1-30" aria-hidden="true" tabindex="-1"></a> context <span class="ot">=</span></span>
<span id="cb1-31"><a href="#cb1-31" aria-hidden="true" tabindex="-1"></a> <span class="dt">ApplicationContext</span></span>
<span id="cb1-32"><a href="#cb1-32" aria-hidden="true" tabindex="-1"></a> { applicationGreeting <span class="ot">=</span> greeting</span>
<span id="cb1-33"><a href="#cb1-33" aria-hidden="true" tabindex="-1"></a> }</span>
<span id="cb1-34"><a href="#cb1-34" aria-hidden="true" tabindex="-1"></a> <span class="kw">in</span></span>
<span id="cb1-35"><a href="#cb1-35" aria-hidden="true" tabindex="-1"></a> Reader.runReaderT io context</span>
<span id="cb1-36"><a href="#cb1-36" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-37"><a href="#cb1-37" aria-hidden="true" tabindex="-1"></a><span class="ot">myApplication ::</span> <span class="dt">Application</span> ()</span>
<span id="cb1-38"><a href="#cb1-38" aria-hidden="true" tabindex="-1"></a>myApplication <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb1-39"><a href="#cb1-39" aria-hidden="true" tabindex="-1"></a> greeting <span class="ot">&lt;-</span> getGreeting</span>
<span id="cb1-40"><a href="#cb1-40" aria-hidden="true" tabindex="-1"></a> MIO.liftIO <span class="op">.</span> <span class="fu">putStrLn</span> <span class="op">$</span> greeting</span>
<span id="cb1-41"><a href="#cb1-41" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-42"><a href="#cb1-42" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb1-43"><a href="#cb1-43" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span></span>
<span id="cb1-44"><a href="#cb1-44" aria-hidden="true" tabindex="-1"></a> runApplication <span class="st">&quot;Hello Application&quot;</span> myApplication</span></code></pre></div>
<p>As in <a href="how-to-add-orville-to-your-application-monad.html">the last guide</a>, we
will first add an <code>OrvilleState</code> to our application monad. In this case well
add it as a new field to the existing <code>ApplicationContext</code>.</p>
<div class="codeblock-label">
Main.hs : diff
</div>
<div class="sourceCode" id="cb2"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">*** Main.hs (Old)</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">--- Main.hs (New)</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="dt">***************</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="dt">*** 7,8 ****</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="dt">--- 7,9 ----</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a> import qualified Control.Monad.Reader as Reader</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="va">+ import qualified Orville.PostgreSQL as O</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="dt">***************</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a><span class="dt">*** 11,12 ****</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a><span class="dt">--- 12,14 ----</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a> { applicationGreeting :: String</span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a><span class="va">+ , applicationOrvilleState :: O.OrvilleState</span></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a> }</span></code></pre></div>
<p>This requires that the new <code>applicationOrvilleState</code> field be populated in the
<code>runApplication</code> function using a <code>ConnectionPool</code>. The <code>ConnectionPool</code> is
created in the <code>main</code> function and passed in where <code>runApplication</code> is called.</p>
<div class="codeblock-label">
Main.hs : diff
</div>
<div class="sourceCode" id="cb3"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">*** Main.hs (Old)</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">--- Main.hs (New)</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="dt">***************</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="dt">*** 28,32 ****</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="st">! runApplication :: String -&gt; Application a -&gt; IO a</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="st">! runApplication greeting (Application io) =</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a> let</span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a> context =</span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a><span class="dt">--- 28,37 ----</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a><span class="va">! runApplication :: O.ConnectionPool -&gt; String -&gt; Application a -&gt; IO a</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a><span class="va">! runApplication pool greeting (Application io) =</span></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a> let</span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a><span class="va">+ orvilleState =</span></span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a><span class="va">+ O.newOrvilleState</span></span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a><span class="va">+ O.defaultErrorDetailLevel</span></span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a><span class="va">+ pool</span></span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a><span class="va">+ </span></span>
<span id="cb3-20"><a href="#cb3-20" aria-hidden="true" tabindex="-1"></a> context =</span>
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true" tabindex="-1"></a><span class="dt">***************</span></span>
<span id="cb3-22"><a href="#cb3-22" aria-hidden="true" tabindex="-1"></a><span class="dt">*** 34,35 ****</span></span>
<span id="cb3-23"><a href="#cb3-23" aria-hidden="true" tabindex="-1"></a><span class="dt">--- 39,41 ----</span></span>
<span id="cb3-24"><a href="#cb3-24" aria-hidden="true" tabindex="-1"></a> { applicationGreeting = greeting</span>
<span id="cb3-25"><a href="#cb3-25" aria-hidden="true" tabindex="-1"></a><span class="va">+ , applicationOrvilleState = orvilleState</span></span>
<span id="cb3-26"><a href="#cb3-26" aria-hidden="true" tabindex="-1"></a> }</span>
<span id="cb3-27"><a href="#cb3-27" aria-hidden="true" tabindex="-1"></a><span class="dt">***************</span></span>
<span id="cb3-28"><a href="#cb3-28" aria-hidden="true" tabindex="-1"></a><span class="dt">*** 44,46 ****</span></span>
<span id="cb3-29"><a href="#cb3-29" aria-hidden="true" tabindex="-1"></a> main :: IO ()</span>
<span id="cb3-30"><a href="#cb3-30" aria-hidden="true" tabindex="-1"></a><span class="st">! main =</span></span>
<span id="cb3-31"><a href="#cb3-31" aria-hidden="true" tabindex="-1"></a><span class="st">! runApplication &quot;Hello Application&quot; myApplication</span></span>
<span id="cb3-32"><a href="#cb3-32" aria-hidden="true" tabindex="-1"></a><span class="dt">--- 50,62 ----</span></span>
<span id="cb3-33"><a href="#cb3-33" aria-hidden="true" tabindex="-1"></a> main :: IO ()</span>
<span id="cb3-34"><a href="#cb3-34" aria-hidden="true" tabindex="-1"></a><span class="va">! main = do</span></span>
<span id="cb3-35"><a href="#cb3-35" aria-hidden="true" tabindex="-1"></a><span class="va">! pool &lt;-</span></span>
<span id="cb3-36"><a href="#cb3-36" aria-hidden="true" tabindex="-1"></a><span class="va">! O.createConnectionPool</span></span>
<span id="cb3-37"><a href="#cb3-37" aria-hidden="true" tabindex="-1"></a><span class="va">! O.ConnectionOptions</span></span>
<span id="cb3-38"><a href="#cb3-38" aria-hidden="true" tabindex="-1"></a><span class="va">! { O.connectionString = &quot;host=localhost user=postgres password=postgres&quot;</span></span>
<span id="cb3-39"><a href="#cb3-39" aria-hidden="true" tabindex="-1"></a><span class="va">! , O.connectionNoticeReporting = O.DisableNoticeReporting</span></span>
<span id="cb3-40"><a href="#cb3-40" aria-hidden="true" tabindex="-1"></a><span class="va">! , O.connectionPoolStripes = O.OneStripePerCapability</span></span>
<span id="cb3-41"><a href="#cb3-41" aria-hidden="true" tabindex="-1"></a><span class="va">! , O.connectionPoolLingerTime = 10</span></span>
<span id="cb3-42"><a href="#cb3-42" aria-hidden="true" tabindex="-1"></a><span class="va">! , O.connectionPoolMaxConnections = O.MaxConnectionsPerStripe 1</span></span>
<span id="cb3-43"><a href="#cb3-43" aria-hidden="true" tabindex="-1"></a><span class="va">! }</span></span>
<span id="cb3-44"><a href="#cb3-44" aria-hidden="true" tabindex="-1"></a><span class="va">! </span></span>
<span id="cb3-45"><a href="#cb3-45" aria-hidden="true" tabindex="-1"></a><span class="va">! runApplication pool &quot;Hello Application&quot; myApplication</span></span></code></pre></div>
<p>Now we must declare an instance of <code>HasOrvilleState</code> to allow Orville access to
the <code>OrvilleState</code> state that is stored in our custom <code>ApplicationContext</code>
field. The <code>askOrvilleState</code> function is generally quite easy to implement.
Its the equivalent of the <code>ask</code> function from the <code>Reader</code> module. In this
example we use the <code>asks</code> function from the <code>Reader</code> module to access the
<code>applicationOrvilleState</code> field in the reader context.</p>
<p>The <code>localOrvilleState</code> function is the equivalent of the <code>local</code> function from
the <code>Reader</code> module. Its slightly more complicated to implemented because we
have adapt the function that Orville passes to <code>localOrvilleState</code> (which has type
<code>OrvilleState -&gt; OrvilleState</code>) so that the function is applied within the
<code>ApplicationContext</code>. The adapted function is then passed <code>Reader.local</code> to
complete our implementation of <code>localOrvilleState</code>. Weve included a type
signature for <code>mkLocalContext</code> in the example so you can clearly see the type
of function being passed to <code>Reader.local</code>, but this is not necessary for the
code to compile.</p>
<div class="codeblock-label">
Main.hs : diff
</div>
<div class="sourceCode" id="cb4"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">*** Main.hs (Old)</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">--- Main.hs (New)</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="dt">***************</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="dt">*** 24,25 ****</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="dt">--- 24,39 ----</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="va">+ instance O.HasOrvilleState Application where</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="va">+ askOrvilleState =</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="va">+ Application (Reader.asks applicationOrvilleState)</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="va">+ </span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a><span class="va">+ localOrvilleState f (Application reader) =</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a><span class="va">+ let</span></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a><span class="va">+ mkLocalContext :: ApplicationContext -&gt; ApplicationContext</span></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a><span class="va">+ mkLocalContext ctx =</span></span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a><span class="va">+ ctx</span></span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a><span class="va">+ { applicationOrvilleState = f (applicationOrvilleState ctx)</span></span>
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a><span class="va">+ }</span></span>
<span id="cb4-18"><a href="#cb4-18" aria-hidden="true" tabindex="-1"></a><span class="va">+ in</span></span>
<span id="cb4-19"><a href="#cb4-19" aria-hidden="true" tabindex="-1"></a><span class="va">+ Application (Reader.local mkLocalContext reader)</span></span>
<span id="cb4-20"><a href="#cb4-20" aria-hidden="true" tabindex="-1"></a><span class="va">+ </span></span>
<span id="cb4-21"><a href="#cb4-21" aria-hidden="true" tabindex="-1"></a> getGreeting :: Application String</span></code></pre></div>
<p>Once we have defined our instance of <code>HasOrvilleState</code> we can add
<code>MonadOrville</code> and <code>MonadOrvilleControl</code> to the list of derived instances for
<code>Application</code>.</p>
<div class="codeblock-label">
Main.hs : diff
</div>
<div class="sourceCode" id="cb5"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">*** Main.hs (Old)</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">--- Main.hs (New)</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="dt">***************</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="dt">*** 22,23 ****</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="dt">--- 22,25 ----</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a> , MIO.MonadIO</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="va">+ , O.MonadOrville</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a><span class="va">+ , O.MonadOrvilleControl</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a> )</span></code></pre></div>
<p>Now our <code>Application</code> monad is fully equipped with Orville capabilities! <a href="how-to-add-orville-to-your-application-monad.html">The
previous guide</a> showed how
to add a first table and Orville operation as well. That part is exactly the
same from this point, so we wont include it again here. Well conclude this
guide with the final listing of <code>Main.hs</code> with all our changes applied.</p>
<div class="codeblock-label">
Main.hs (After) : haskell
</div>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE GeneralizedNewtypeDeriving #-}</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">Main</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a> ( main</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a> ) <span class="kw">where</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Control.Monad.IO.Class</span> <span class="kw">as</span> <span class="dt">MIO</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Control.Monad.Reader</span> <span class="kw">as</span> <span class="dt">Reader</span></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Orville.PostgreSQL</span> <span class="kw">as</span> <span class="dt">O</span></span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">ApplicationContext</span> <span class="ot">=</span></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">ApplicationContext</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a> {<span class="ot"> applicationGreeting ::</span> <span class="dt">String</span></span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a> ,<span class="ot"> applicationOrvilleState ::</span> <span class="dt">O.OrvilleState</span></span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a> }</span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">Application</span> a <span class="ot">=</span></span>
<span id="cb6-17"><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a> <span class="dt">Application</span> (<span class="dt">Reader.ReaderT</span> <span class="dt">ApplicationContext</span> <span class="dt">IO</span> a)</span>
<span id="cb6-18"><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span></span>
<span id="cb6-19"><a href="#cb6-19" aria-hidden="true" tabindex="-1"></a> ( <span class="dt">Functor</span></span>
<span id="cb6-20"><a href="#cb6-20" aria-hidden="true" tabindex="-1"></a> , <span class="dt">Applicative</span></span>
<span id="cb6-21"><a href="#cb6-21" aria-hidden="true" tabindex="-1"></a> , <span class="dt">Monad</span></span>
<span id="cb6-22"><a href="#cb6-22" aria-hidden="true" tabindex="-1"></a> , <span class="dt">MIO.MonadIO</span></span>
<span id="cb6-23"><a href="#cb6-23" aria-hidden="true" tabindex="-1"></a> , <span class="dt">O.MonadOrville</span></span>
<span id="cb6-24"><a href="#cb6-24" aria-hidden="true" tabindex="-1"></a> , <span class="dt">O.MonadOrvilleControl</span></span>
<span id="cb6-25"><a href="#cb6-25" aria-hidden="true" tabindex="-1"></a> )</span>
<span id="cb6-26"><a href="#cb6-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-27"><a href="#cb6-27" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">O.HasOrvilleState</span> <span class="dt">Application</span> <span class="kw">where</span></span>
<span id="cb6-28"><a href="#cb6-28" aria-hidden="true" tabindex="-1"></a> askOrvilleState <span class="ot">=</span></span>
<span id="cb6-29"><a href="#cb6-29" aria-hidden="true" tabindex="-1"></a> <span class="dt">Application</span> (Reader.asks applicationOrvilleState)</span>
<span id="cb6-30"><a href="#cb6-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-31"><a href="#cb6-31" aria-hidden="true" tabindex="-1"></a> localOrvilleState f (<span class="dt">Application</span> reader) <span class="ot">=</span></span>
<span id="cb6-32"><a href="#cb6-32" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span></span>
<span id="cb6-33"><a href="#cb6-33" aria-hidden="true" tabindex="-1"></a><span class="ot"> mkLocalContext ::</span> <span class="dt">ApplicationContext</span> <span class="ot">-&gt;</span> <span class="dt">ApplicationContext</span></span>
<span id="cb6-34"><a href="#cb6-34" aria-hidden="true" tabindex="-1"></a> mkLocalContext ctx <span class="ot">=</span></span>
<span id="cb6-35"><a href="#cb6-35" aria-hidden="true" tabindex="-1"></a> ctx</span>
<span id="cb6-36"><a href="#cb6-36" aria-hidden="true" tabindex="-1"></a> { applicationOrvilleState <span class="ot">=</span> f (applicationOrvilleState ctx)</span>
<span id="cb6-37"><a href="#cb6-37" aria-hidden="true" tabindex="-1"></a> }</span>
<span id="cb6-38"><a href="#cb6-38" aria-hidden="true" tabindex="-1"></a> <span class="kw">in</span></span>
<span id="cb6-39"><a href="#cb6-39" aria-hidden="true" tabindex="-1"></a> <span class="dt">Application</span> (Reader.local mkLocalContext reader)</span>
<span id="cb6-40"><a href="#cb6-40" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-41"><a href="#cb6-41" aria-hidden="true" tabindex="-1"></a><span class="ot">getGreeting ::</span> <span class="dt">Application</span> <span class="dt">String</span></span>
<span id="cb6-42"><a href="#cb6-42" aria-hidden="true" tabindex="-1"></a>getGreeting <span class="ot">=</span></span>
<span id="cb6-43"><a href="#cb6-43" aria-hidden="true" tabindex="-1"></a> <span class="dt">Application</span> (Reader.asks applicationGreeting)</span>
<span id="cb6-44"><a href="#cb6-44" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-45"><a href="#cb6-45" aria-hidden="true" tabindex="-1"></a><span class="ot">runApplication ::</span> <span class="dt">O.ConnectionPool</span> <span class="ot">-&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Application</span> a <span class="ot">-&gt;</span> <span class="dt">IO</span> a</span>
<span id="cb6-46"><a href="#cb6-46" aria-hidden="true" tabindex="-1"></a>runApplication pool greeting (<span class="dt">Application</span> io) <span class="ot">=</span></span>
<span id="cb6-47"><a href="#cb6-47" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span></span>
<span id="cb6-48"><a href="#cb6-48" aria-hidden="true" tabindex="-1"></a> orvilleState <span class="ot">=</span></span>
<span id="cb6-49"><a href="#cb6-49" aria-hidden="true" tabindex="-1"></a> O.newOrvilleState</span>
<span id="cb6-50"><a href="#cb6-50" aria-hidden="true" tabindex="-1"></a> O.defaultErrorDetailLevel</span>
<span id="cb6-51"><a href="#cb6-51" aria-hidden="true" tabindex="-1"></a> pool</span>
<span id="cb6-52"><a href="#cb6-52" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-53"><a href="#cb6-53" aria-hidden="true" tabindex="-1"></a> context <span class="ot">=</span></span>
<span id="cb6-54"><a href="#cb6-54" aria-hidden="true" tabindex="-1"></a> <span class="dt">ApplicationContext</span></span>
<span id="cb6-55"><a href="#cb6-55" aria-hidden="true" tabindex="-1"></a> { applicationGreeting <span class="ot">=</span> greeting</span>
<span id="cb6-56"><a href="#cb6-56" aria-hidden="true" tabindex="-1"></a> , applicationOrvilleState <span class="ot">=</span> orvilleState</span>
<span id="cb6-57"><a href="#cb6-57" aria-hidden="true" tabindex="-1"></a> }</span>
<span id="cb6-58"><a href="#cb6-58" aria-hidden="true" tabindex="-1"></a> <span class="kw">in</span></span>
<span id="cb6-59"><a href="#cb6-59" aria-hidden="true" tabindex="-1"></a> Reader.runReaderT io context</span>
<span id="cb6-60"><a href="#cb6-60" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-61"><a href="#cb6-61" aria-hidden="true" tabindex="-1"></a><span class="ot">myApplication ::</span> <span class="dt">Application</span> ()</span>
<span id="cb6-62"><a href="#cb6-62" aria-hidden="true" tabindex="-1"></a>myApplication <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb6-63"><a href="#cb6-63" aria-hidden="true" tabindex="-1"></a> greeting <span class="ot">&lt;-</span> getGreeting</span>
<span id="cb6-64"><a href="#cb6-64" aria-hidden="true" tabindex="-1"></a> MIO.liftIO <span class="op">.</span> <span class="fu">putStrLn</span> <span class="op">$</span> greeting</span>
<span id="cb6-65"><a href="#cb6-65" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-66"><a href="#cb6-66" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb6-67"><a href="#cb6-67" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb6-68"><a href="#cb6-68" aria-hidden="true" tabindex="-1"></a> pool <span class="ot">&lt;-</span></span>
<span id="cb6-69"><a href="#cb6-69" aria-hidden="true" tabindex="-1"></a> O.createConnectionPool</span>
<span id="cb6-70"><a href="#cb6-70" aria-hidden="true" tabindex="-1"></a> <span class="dt">O.ConnectionOptions</span></span>
<span id="cb6-71"><a href="#cb6-71" aria-hidden="true" tabindex="-1"></a> { O.connectionString <span class="ot">=</span> <span class="st">&quot;host=localhost user=postgres password=postgres&quot;</span></span>
<span id="cb6-72"><a href="#cb6-72" aria-hidden="true" tabindex="-1"></a> , O.connectionNoticeReporting <span class="ot">=</span> <span class="dt">O.DisableNoticeReporting</span></span>
<span id="cb6-73"><a href="#cb6-73" aria-hidden="true" tabindex="-1"></a> , O.connectionPoolStripes <span class="ot">=</span> <span class="dt">O.OneStripePerCapability</span></span>
<span id="cb6-74"><a href="#cb6-74" aria-hidden="true" tabindex="-1"></a> , O.connectionPoolLingerTime <span class="ot">=</span> <span class="dv">10</span></span>
<span id="cb6-75"><a href="#cb6-75" aria-hidden="true" tabindex="-1"></a> , O.connectionPoolMaxConnections <span class="ot">=</span> <span class="dt">O.MaxConnectionsPerStripe</span> <span class="dv">1</span></span>
<span id="cb6-76"><a href="#cb6-76" aria-hidden="true" tabindex="-1"></a> }</span>
<span id="cb6-77"><a href="#cb6-77" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-78"><a href="#cb6-78" aria-hidden="true" tabindex="-1"></a> runApplication pool <span class="st">&quot;Hello Application&quot;</span> myApplication</span></code></pre></div>
</section>
</article>
</main>
</body>
</html>

View File

@ -38,6 +38,8 @@
<a href="../how-tos/how-to-add-orville-to-your-application-monad.html">How To Add Orville to Your Application Monad</a>
<a href="../how-tos/how-to-add-orville-to-an-existing-reader-context.html">How To Add Orville to an Existing Reader Context</a>
<a href="../how-tos/how-to-marshall-a-haskell-record.html">How To Marshall a Haskell Record (Upcoming)</a>
<a href="../how-tos/how-to-add-custom-marshalling-validations.html">How Add Custom Marshalling Validations (Upcoming)</a>
@ -145,9 +147,9 @@ job. In order to use functions from the Orville package directly in your monad
it will need to provide instances for the three typeclasses that make up a
complete Orville monad - <code>MonadOrville</code>, <code>MonadOrvilleControl</code> and
<code>HasOrvilleState</code>. Luckily, its a simple matter of adding these three
typeclasses the the deriving list for <code>Application</code>. If youre not using
<code>GHC2021</code> youll need the <code>GeneralizedNewtypeDeriving</code> language extension, as
in the example in this guide.</p>
typeclasses the deriving list for <code>Application</code>. If youre not using <code>GHC2021</code>
youll need the <code>GeneralizedNewtypeDeriving</code> language extension, as in the
example in this guide.</p>
<div class="codeblock-label">
Main.hs : diff
</div>

View File

@ -38,6 +38,8 @@
<a href="../how-tos/how-to-add-orville-to-your-application-monad.html">How To Add Orville to Your Application Monad</a>
<a href="../how-tos/how-to-add-orville-to-an-existing-reader-context.html">How To Add Orville to an Existing Reader Context</a>
<a href="../how-tos/how-to-marshall-a-haskell-record.html">How To Marshall a Haskell Record (Upcoming)</a>
<a href="../how-tos/how-to-add-custom-marshalling-validations.html">How Add Custom Marshalling Validations (Upcoming)</a>

View File

@ -38,6 +38,8 @@
<a href="../how-tos/how-to-add-orville-to-your-application-monad.html">How To Add Orville to Your Application Monad</a>
<a href="../how-tos/how-to-add-orville-to-an-existing-reader-context.html">How To Add Orville to an Existing Reader Context</a>
<a href="../how-tos/how-to-marshall-a-haskell-record.html">How To Marshall a Haskell Record (Upcoming)</a>
<a href="../how-tos/how-to-add-custom-marshalling-validations.html">How Add Custom Marshalling Validations (Upcoming)</a>

View File

@ -38,6 +38,8 @@
<a href="../how-tos/how-to-add-orville-to-your-application-monad.html">How To Add Orville to Your Application Monad</a>
<a href="../how-tos/how-to-add-orville-to-an-existing-reader-context.html">How To Add Orville to an Existing Reader Context</a>
<a href="../how-tos/how-to-marshall-a-haskell-record.html">How To Marshall a Haskell Record (Upcoming)</a>
<a href="../how-tos/how-to-add-custom-marshalling-validations.html">How Add Custom Marshalling Validations (Upcoming)</a>

View File

@ -38,6 +38,8 @@
<a href="../how-tos/how-to-add-orville-to-your-application-monad.html">How To Add Orville to Your Application Monad</a>
<a href="../how-tos/how-to-add-orville-to-an-existing-reader-context.html">How To Add Orville to an Existing Reader Context</a>
<a href="../how-tos/how-to-marshall-a-haskell-record.html">How To Marshall a Haskell Record (Upcoming)</a>
<a href="../how-tos/how-to-add-custom-marshalling-validations.html">How Add Custom Marshalling Validations (Upcoming)</a>

View File

@ -38,6 +38,8 @@
<a href="./how-tos/how-to-add-orville-to-your-application-monad.html">How To Add Orville to Your Application Monad</a>
<a href="./how-tos/how-to-add-orville-to-an-existing-reader-context.html">How To Add Orville to an Existing Reader Context</a>
<a href="./how-tos/how-to-marshall-a-haskell-record.html">How To Marshall a Haskell Record (Upcoming)</a>
<a href="./how-tos/how-to-add-custom-marshalling-validations.html">How Add Custom Marshalling Validations (Upcoming)</a>

View File

@ -38,6 +38,8 @@
<a href="../how-tos/how-to-add-orville-to-your-application-monad.html">How To Add Orville to Your Application Monad</a>
<a href="../how-tos/how-to-add-orville-to-an-existing-reader-context.html">How To Add Orville to an Existing Reader Context</a>
<a href="../how-tos/how-to-marshall-a-haskell-record.html">How To Marshall a Haskell Record (Upcoming)</a>
<a href="../how-tos/how-to-add-custom-marshalling-validations.html">How Add Custom Marshalling Validations (Upcoming)</a>

View File

@ -38,6 +38,8 @@
<a href="../how-tos/how-to-add-orville-to-your-application-monad.html">How To Add Orville to Your Application Monad</a>
<a href="../how-tos/how-to-add-orville-to-an-existing-reader-context.html">How To Add Orville to an Existing Reader Context</a>
<a href="../how-tos/how-to-marshall-a-haskell-record.html">How To Marshall a Haskell Record (Upcoming)</a>
<a href="../how-tos/how-to-add-custom-marshalling-validations.html">How Add Custom Marshalling Validations (Upcoming)</a>

View File

@ -38,6 +38,8 @@
<a href="../how-tos/how-to-add-orville-to-your-application-monad.html">How To Add Orville to Your Application Monad</a>
<a href="../how-tos/how-to-add-orville-to-an-existing-reader-context.html">How To Add Orville to an Existing Reader Context</a>
<a href="../how-tos/how-to-marshall-a-haskell-record.html">How To Marshall a Haskell Record (Upcoming)</a>
<a href="../how-tos/how-to-add-custom-marshalling-validations.html">How Add Custom Marshalling Validations (Upcoming)</a>

View File

@ -38,6 +38,8 @@
<a href="../how-tos/how-to-add-orville-to-your-application-monad.html">How To Add Orville to Your Application Monad</a>
<a href="../how-tos/how-to-add-orville-to-an-existing-reader-context.html">How To Add Orville to an Existing Reader Context</a>
<a href="../how-tos/how-to-marshall-a-haskell-record.html">How To Marshall a Haskell Record (Upcoming)</a>
<a href="../how-tos/how-to-add-custom-marshalling-validations.html">How Add Custom Marshalling Validations (Upcoming)</a>

View File

@ -38,6 +38,8 @@
<a href="../how-tos/how-to-add-orville-to-your-application-monad.html">How To Add Orville to Your Application Monad</a>
<a href="../how-tos/how-to-add-orville-to-an-existing-reader-context.html">How To Add Orville to an Existing Reader Context</a>
<a href="../how-tos/how-to-marshall-a-haskell-record.html">How To Marshall a Haskell Record (Upcoming)</a>
<a href="../how-tos/how-to-add-custom-marshalling-validations.html">How Add Custom Marshalling Validations (Upcoming)</a>

View File

@ -0,0 +1,14 @@
*** Main.hs (Old)
--- Main.hs (New)
***************
*** 7,8 ****
--- 7,9 ----
import qualified Control.Monad.Reader as Reader
+ import qualified Orville.PostgreSQL as O
***************
*** 11,12 ****
--- 12,14 ----
{ applicationGreeting :: String
+ , applicationOrvilleState :: O.OrvilleState
}

View File

@ -0,0 +1,45 @@
*** Main.hs (Old)
--- Main.hs (New)
***************
*** 28,32 ****
! runApplication :: String -> Application a -> IO a
! runApplication greeting (Application io) =
let
context =
--- 28,37 ----
! runApplication :: O.ConnectionPool -> String -> Application a -> IO a
! runApplication pool greeting (Application io) =
let
+ orvilleState =
+ O.newOrvilleState
+ O.defaultErrorDetailLevel
+ pool
+
context =
***************
*** 34,35 ****
--- 39,41 ----
{ applicationGreeting = greeting
+ , applicationOrvilleState = orvilleState
}
***************
*** 44,46 ****
main :: IO ()
! main =
! runApplication "Hello Application" myApplication
--- 50,62 ----
main :: IO ()
! main = do
! pool <-
! O.createConnectionPool
! O.ConnectionOptions
! { O.connectionString = "host=localhost user=postgres password=postgres"
! , O.connectionNoticeReporting = O.DisableNoticeReporting
! , O.connectionPoolStripes = O.OneStripePerCapability
! , O.connectionPoolLingerTime = 10
! , O.connectionPoolMaxConnections = O.MaxConnectionsPerStripe 1
! }
!
! runApplication pool "Hello Application" myApplication

View File

@ -0,0 +1,21 @@
*** Main.hs (Old)
--- Main.hs (New)
***************
*** 24,25 ****
--- 24,39 ----
+ instance O.HasOrvilleState Application where
+ askOrvilleState =
+ Application (Reader.asks applicationOrvilleState)
+
+ localOrvilleState f (Application reader) =
+ let
+ mkLocalContext :: ApplicationContext -> ApplicationContext
+ mkLocalContext ctx =
+ ctx
+ { applicationOrvilleState = f (applicationOrvilleState ctx)
+ }
+ in
+ Application (Reader.local mkLocalContext reader)
+
getGreeting :: Application String

View File

@ -0,0 +1,9 @@
*** Main.hs (Old)
--- Main.hs (New)
***************
*** 22,23 ****
--- 22,25 ----
, MIO.MonadIO
+ , O.MonadOrville
+ , O.MonadOrvilleControl
)

View File

@ -0,0 +1,33 @@
cabal-version: 2.2
name: adding-orville-existing-readert
version: 0.1.0.0
-- synopsis:
-- description:
homepage: https://github.com/flipstone/adding-orville-existing-readert#readme
license: BSD-3-Clause
author: Flipstone Technology Partners, Inc
maintainer: maintainers@flipstone.com
copyright:
category: sample
build-type: Simple
executable adding-orville-existing-readert
hs-source-dirs: src
main-is: Main.hs
default-language: Haskell2010
build-depends: base >= 4.7 && < 5,
mtl,
orville-postgresql,
text
ghc-options: -Wall
-Wcompat
-Widentities
-Wincomplete-record-updates
-Wincomplete-uni-patterns
-Wmissing-export-lists
-Wmissing-home-modules
-Wpartial-fields
-Wredundant-constraints

View File

@ -0,0 +1 @@
Hello Application

View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
DIFF_OPTS=(-C 1 --label 'Main.hs (Old)' --label 'Main.hs (New)')
diff "${DIFF_OPTS[@]}" snapshots/Main-1.hs snapshots/Main-2.hs > 1-add-orville-state.patch
diff "${DIFF_OPTS[@]}" snapshots/Main-2.hs snapshots/Main-3.hs > 2-update-runApplication.patch
diff "${DIFF_OPTS[@]}" snapshots/Main-3.hs snapshots/Main-4.hs > 3-add-HasOrvilleState.patch
diff "${DIFF_OPTS[@]}" snapshots/Main-4.hs snapshots/Main-5.hs > 4-add-remaining-typeclasses.patch

View File

@ -0,0 +1,22 @@
set -e
service postgresql start
patch --output=snapshots/Main-2.hs snapshots/Main-1.hs 1-add-orville-state.patch
patch --output=snapshots/Main-3.hs snapshots/Main-2.hs 2-update-runApplication.patch
patch --output=snapshots/Main-4.hs snapshots/Main-3.hs 3-add-HasOrvilleState.patch
patch --output=snapshots/Main-5.hs snapshots/Main-4.hs 4-add-remaining-typeclasses.patch
mkdir -p src
cp snapshots/Main-5.hs src/Main.hs
stack build
expected=$(cat expected-output.txt)
actual=$(stack exec adding-orville-existing-readert)
if [ "$expected" = "$actual" ]; then
echo "Output matches expected"
else
echo "Expected output to be: $expected"
echo "But it was actually : $actual"
exit 1
fi;

View File

@ -0,0 +1,44 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Main
( main
) where
import qualified Control.Monad.IO.Class as MIO
import qualified Control.Monad.Reader as Reader
data ApplicationContext =
ApplicationContext
{ applicationGreeting :: String
}
newtype Application a =
Application (Reader.ReaderT ApplicationContext IO a)
deriving
( Functor
, Applicative
, Monad
, MIO.MonadIO
)
getGreeting :: Application String
getGreeting =
Application (Reader.asks applicationGreeting)
runApplication :: String -> Application a -> IO a
runApplication greeting (Application io) =
let
context =
ApplicationContext
{ applicationGreeting = greeting
}
in
Reader.runReaderT io context
myApplication :: Application ()
myApplication = do
greeting <- getGreeting
MIO.liftIO . putStrLn $ greeting
main :: IO ()
main =
runApplication "Hello Application" myApplication

View File

@ -0,0 +1,46 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Main
( main
) where
import qualified Control.Monad.IO.Class as MIO
import qualified Control.Monad.Reader as Reader
import qualified Orville.PostgreSQL as O
data ApplicationContext =
ApplicationContext
{ applicationGreeting :: String
, applicationOrvilleState :: O.OrvilleState
}
newtype Application a =
Application (Reader.ReaderT ApplicationContext IO a)
deriving
( Functor
, Applicative
, Monad
, MIO.MonadIO
)
getGreeting :: Application String
getGreeting =
Application (Reader.asks applicationGreeting)
runApplication :: String -> Application a -> IO a
runApplication greeting (Application io) =
let
context =
ApplicationContext
{ applicationGreeting = greeting
}
in
Reader.runReaderT io context
myApplication :: Application ()
myApplication = do
greeting <- getGreeting
MIO.liftIO . putStrLn $ greeting
main :: IO ()
main =
runApplication "Hello Application" myApplication

View File

@ -0,0 +1,62 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Main
( main
) where
import qualified Control.Monad.IO.Class as MIO
import qualified Control.Monad.Reader as Reader
import qualified Orville.PostgreSQL as O
data ApplicationContext =
ApplicationContext
{ applicationGreeting :: String
, applicationOrvilleState :: O.OrvilleState
}
newtype Application a =
Application (Reader.ReaderT ApplicationContext IO a)
deriving
( Functor
, Applicative
, Monad
, MIO.MonadIO
)
getGreeting :: Application String
getGreeting =
Application (Reader.asks applicationGreeting)
runApplication :: O.ConnectionPool -> String -> Application a -> IO a
runApplication pool greeting (Application io) =
let
orvilleState =
O.newOrvilleState
O.defaultErrorDetailLevel
pool
context =
ApplicationContext
{ applicationGreeting = greeting
, applicationOrvilleState = orvilleState
}
in
Reader.runReaderT io context
myApplication :: Application ()
myApplication = do
greeting <- getGreeting
MIO.liftIO . putStrLn $ greeting
main :: IO ()
main = do
pool <-
O.createConnectionPool
O.ConnectionOptions
{ O.connectionString = "host=localhost user=postgres password=postgres"
, O.connectionNoticeReporting = O.DisableNoticeReporting
, O.connectionPoolStripes = O.OneStripePerCapability
, O.connectionPoolLingerTime = 10
, O.connectionPoolMaxConnections = O.MaxConnectionsPerStripe 1
}
runApplication pool "Hello Application" myApplication

View File

@ -0,0 +1,76 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Main
( main
) where
import qualified Control.Monad.IO.Class as MIO
import qualified Control.Monad.Reader as Reader
import qualified Orville.PostgreSQL as O
data ApplicationContext =
ApplicationContext
{ applicationGreeting :: String
, applicationOrvilleState :: O.OrvilleState
}
newtype Application a =
Application (Reader.ReaderT ApplicationContext IO a)
deriving
( Functor
, Applicative
, Monad
, MIO.MonadIO
)
instance O.HasOrvilleState Application where
askOrvilleState =
Application (Reader.asks applicationOrvilleState)
localOrvilleState f (Application reader) =
let
mkLocalContext :: ApplicationContext -> ApplicationContext
mkLocalContext ctx =
ctx
{ applicationOrvilleState = f (applicationOrvilleState ctx)
}
in
Application (Reader.local mkLocalContext reader)
getGreeting :: Application String
getGreeting =
Application (Reader.asks applicationGreeting)
runApplication :: O.ConnectionPool -> String -> Application a -> IO a
runApplication pool greeting (Application io) =
let
orvilleState =
O.newOrvilleState
O.defaultErrorDetailLevel
pool
context =
ApplicationContext
{ applicationGreeting = greeting
, applicationOrvilleState = orvilleState
}
in
Reader.runReaderT io context
myApplication :: Application ()
myApplication = do
greeting <- getGreeting
MIO.liftIO . putStrLn $ greeting
main :: IO ()
main = do
pool <-
O.createConnectionPool
O.ConnectionOptions
{ O.connectionString = "host=localhost user=postgres password=postgres"
, O.connectionNoticeReporting = O.DisableNoticeReporting
, O.connectionPoolStripes = O.OneStripePerCapability
, O.connectionPoolLingerTime = 10
, O.connectionPoolMaxConnections = O.MaxConnectionsPerStripe 1
}
runApplication pool "Hello Application" myApplication

View File

@ -0,0 +1,78 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Main
( main
) where
import qualified Control.Monad.IO.Class as MIO
import qualified Control.Monad.Reader as Reader
import qualified Orville.PostgreSQL as O
data ApplicationContext =
ApplicationContext
{ applicationGreeting :: String
, applicationOrvilleState :: O.OrvilleState
}
newtype Application a =
Application (Reader.ReaderT ApplicationContext IO a)
deriving
( Functor
, Applicative
, Monad
, MIO.MonadIO
, O.MonadOrville
, O.MonadOrvilleControl
)
instance O.HasOrvilleState Application where
askOrvilleState =
Application (Reader.asks applicationOrvilleState)
localOrvilleState f (Application reader) =
let
mkLocalContext :: ApplicationContext -> ApplicationContext
mkLocalContext ctx =
ctx
{ applicationOrvilleState = f (applicationOrvilleState ctx)
}
in
Application (Reader.local mkLocalContext reader)
getGreeting :: Application String
getGreeting =
Application (Reader.asks applicationGreeting)
runApplication :: O.ConnectionPool -> String -> Application a -> IO a
runApplication pool greeting (Application io) =
let
orvilleState =
O.newOrvilleState
O.defaultErrorDetailLevel
pool
context =
ApplicationContext
{ applicationGreeting = greeting
, applicationOrvilleState = orvilleState
}
in
Reader.runReaderT io context
myApplication :: Application ()
myApplication = do
greeting <- getGreeting
MIO.liftIO . putStrLn $ greeting
main :: IO ()
main = do
pool <-
O.createConnectionPool
O.ConnectionOptions
{ O.connectionString = "host=localhost user=postgres password=postgres"
, O.connectionNoticeReporting = O.DisableNoticeReporting
, O.connectionPoolStripes = O.OneStripePerCapability
, O.connectionPoolLingerTime = 10
, O.connectionPoolMaxConnections = O.MaxConnectionsPerStripe 1
}
runApplication pool "Hello Application" myApplication

View File

@ -0,0 +1,69 @@
# This file was automatically generated by 'stack init'
#
# Some commonly used options have been documented as comments in this file.
# For advanced use and comprehensive documentation of the format, please see:
# https://docs.haskellstack.org/en/stable/yaml_configuration/
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
# A snapshot resolver dictates the compiler version and the set of packages
# to be used for project dependencies. For example:
#
# resolver: lts-21.13
# resolver: nightly-2023-09-24
# resolver: ghc-9.6.2
#
# The location of a snapshot can be provided as a file or url. Stack assumes
# a snapshot provided as a file might change, whereas a url resource does not.
#
# resolver: ./custom-snapshot.yaml
# resolver: https://example.com/snapshots/2023-01-01.yaml
resolver: lts-21.19
system-ghc: true
install-ghc: false
# User packages to be built.
# Various formats can be used as shown in the example below.
#
# packages:
# - some-directory
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
# subdirs:
# - auto-update
# - wai
packages:
- .
# Dependency packages to be pulled from upstream that are not in the resolver.
# These entries can reference officially published versions as well as
# forks / in-progress versions pinned to a git hash. For example:
#
# extra-deps:
# - acme-missiles-0.3
# - git: https://github.com/commercialhaskell/stack.git
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
#
extra-deps:
- orville-postgresql-1.0.0.0
# Override default flag values for local packages and extra-deps
# flags: {}
# Extra package databases containing global packages
# extra-package-dbs: []
# Control whether we use the GHC we find on the path
# system-ghc: true
#
# Require a specific version of Stack, using version ranges
# require-stack-version: -any # Default
# require-stack-version: ">=2.13"
#
# Override the architecture used by Stack, especially useful on Windows
# arch: i386
# arch: x86_64
#
# Extra directories used by Stack for building
# extra-include-dirs: [/path/to/dir]
# extra-lib-dirs: [/path/to/dir]
#
# Allow a newer minor version of GHC than the snapshot specifies
# compiler-check: newer-minor

View File

@ -0,0 +1,19 @@
# This file was autogenerated by Stack.
# You should not edit this file by hand.
# For more information, please see the documentation at:
# https://docs.haskellstack.org/en/stable/lock_files
packages:
- completed:
hackage: orville-postgresql-1.0.0.0@sha256:35e9b9f8bc0bc1ee1847bcb5340fa39bed320f1573099ec16ca394726a50593a,9018
pantry-tree:
sha256: b8d324f2ad94f12ac419996cc2947ee0c69c5178b2caf13dc92135118602bbd8
size: 12020
original:
hackage: orville-postgresql-1.0.0.0
snapshots:
- completed:
sha256: fb482b8e2d5d061cdda4ba1da2957c012740c893a5ee1c1b99001adae7b1fbe7
size: 640046
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/21/19.yaml
original: lts-21.19

View File

@ -1,7 +1,6 @@
# SNIPPET: hidden
set -e
service postgresql start
# SNIPPET: hidden
patch --output=snapshots/Main-2.hs snapshots/Main-1.hs 1-add-readert.patch
patch --output=snapshots/Main-3.hs snapshots/Main-2.hs 2-add-orville-typeclasses.patch
patch --output=snapshots/Main-4.hs snapshots/Main-3.hs 3-update-runApplication.patch
@ -10,9 +9,9 @@ patch --output=snapshots/Main-6.hs snapshots/Main-5.hs 5-add-table.patch
patch --output=snapshots/Main-7.hs snapshots/Main-6.hs 6-add-migrations.patch
mkdir -p src
cp snapshots/Main-7.hs src/Main.hs
# SNIPPET: buildAndExecute
stack build
# SNIPPET: hidden
expected=$(cat expected-output.txt)
actual=$(stack exec adding-orville-new-readert)

View File

@ -1,6 +1,6 @@
---
title: How Add Custom Marshalling Validations (Upcoming)
navOrder: 3
navOrder: 4
---
Coming Soon

View File

@ -0,0 +1,63 @@
---
title: How To Add Orville to an Existing Reader Context
navOrder: 2
---
This guide will show you how to add Orville to a monad that is already using
`ReaderT` in its monad stack. It builds conceptually on top of [the previous
guide](how-to-add-orville-to-your-application-monad.html), which assumed there
was not already a `ReaderT` in the application monad stack. It's recommended
that you read that guide before this one.
The file listing below shows a simple application with its own `Application`
monad that already has a reader context. When there is already a reader context
in the application stack it's generally perferrable to incorporate Orville into
the existing reader context rather than adding a new `ReaderT` layer atop the
one that's already there.
$sample("adding-orville-existing-readert/snapshots/Main-1.hs", "filename=Main.hs (Before)")$
As in [the last guide](how-to-add-orville-to-your-application-monad.html), we
will first add an `OrvilleState` to our application monad. In this case we'll
add it as a new field to the existing `ApplicationContext`.
$sample("adding-orville-existing-readert/1-add-orville-state.patch", "filename=Main.hs")$
This requires that the new `applicationOrvilleState` field be populated in the
`runApplication` function using a `ConnectionPool`. The `ConnectionPool` is
created in the `main` function and passed in where `runApplication` is called.
$sample("adding-orville-existing-readert/2-update-runApplication.patch", "filename=Main.hs")$
Now we must declare an instance of `HasOrvilleState` to allow Orville access to
the `OrvilleState` state that is stored in our custom `ApplicationContext`
field. The `askOrvilleState` function is generally quite easy to implement.
It's the equivalent of the `ask` function from the `Reader` module. In this
example we use the `asks` function from the `Reader` module to access the
`applicationOrvilleState` field in the reader context.
The `localOrvilleState` function is the equivalent of the `local` function from
the `Reader` module. It's slightly more complicated to implemented because we
have adapt the function that Orville passes to `localOrvilleState` (which has type
`OrvilleState -> OrvilleState`) so that the function is applied within the
`ApplicationContext`. The adapted function is then passed `Reader.local` to
complete our implementation of `localOrvilleState`. We've included a type
signature for `mkLocalContext` in the example so you can clearly see the type
of function being passed to `Reader.local`, but this is not necessary for the
code to compile.
$sample("adding-orville-existing-readert/3-add-HasOrvilleState.patch", "filename=Main.hs")$
Once we have defined our instance of `HasOrvilleState` we can add
`MonadOrville` and `MonadOrvilleControl` to the list of derived instances for
`Application`.
$sample("adding-orville-existing-readert/4-add-remaining-typeclasses.patch", "filename=Main.hs")$
Now our `Application` monad is fully equipped with Orville capabilities! [The
previous guide](how-to-add-orville-to-your-application-monad.html) showed how
to add a first table and Orville operation as well. That part is exactly the
same from this point, so we won't include it again here. We'll conclude this
guide with the final listing of `Main.hs` with all our changes applied.
$sample("adding-orville-existing-readert/snapshots/Main-5.hs", "filename=Main.hs (After)")$

View File

@ -28,9 +28,9 @@ job. In order to use functions from the Orville package directly in your monad
it will need to provide instances for the three typeclasses that make up a
complete Orville monad - `MonadOrville`, `MonadOrvilleControl` and
`HasOrvilleState`. Luckily, it's a simple matter of adding these three
typeclasses the the deriving list for `Application`. If you're not using
`GHC2021` you'll need the `GeneralizedNewtypeDeriving` language extension, as
in the example in this guide.
typeclasses the deriving list for `Application`. If you're not using `GHC2021`
you'll need the `GeneralizedNewtypeDeriving` language extension, as in the
example in this guide.
$sample("adding-orville-new-readert/2-add-orville-typeclasses.patch", "filename=Main.hs")$

View File

@ -1,6 +1,6 @@
---
title: How To Execute Raw SQL (Upcoming)
navOrder: 6
navOrder: 7
---
Coming Soon

View File

@ -1,6 +1,6 @@
---
title: How To Marshall a Haskell Record (Upcoming)
navOrder: 2
navOrder: 3
---
Coming Soon

View File

@ -1,6 +1,6 @@
---
title: How To Marshall a Haskell Sum Type (Upcoming)
navOrder: 4
navOrder: 5
---
Coming Soon

View File

@ -1,6 +1,6 @@
---
title: How To Set Up An Auto-incrementing Id Column (Upcoming)
navOrder: 5
navOrder: 6
---
Coming Soon