@@ -1,46 +1,8 @@
1−<!DOCTYPE html>
2−<html>
3−<head>
4− <title>Title</title>
5− <meta charset="utf-8">
6− <style>
7− @import url(https://fonts.googleapis.com/css?family=PT+Sans+Narrow);
8− @import url(https://fonts.googleapis.com/css?family=Montserrat:400,700,400italic);
9− @import url(https://fonts.googleapis.com/css?family=Ubuntu+Mono:400,700,400italic);
10−
11− body { font-family: 'Montserrat'; }
12− h1, h2, h3 {
13− font-family: 'PT Sans Narrow';
14− font-weight: normal;
15− }
16−
17− .note {
18− background-color: #ccc;
19− padding: 1rem;
20− border-radius: 4px;
21− }
22− .remark-code, .remark-inline-code { font-family: 'Ubuntu Mono'; }
23−
24− .signature {
25− position: absolute;
26− top: 1%;
27− right: 1%;
28− font-size:.6em;
29− opacity: .5;
30− }
31− </style>
32− </head>
33− <body>
34− <textarea id="source">
35−
36−class: center, middle
37−count: false
38−
391# Squeal
402
413_A bridge between SQL and Haskell_
424
43−.signature[2018/09/12 - by @Raveline]
5+by [@Raveline](https://github.com/raveline)
446
457---
468
@@ -62,9 +24,6 @@ Using `postgresql-simple` you have a typical "Trial, error, despair" workflow:
6224
6325---
6426
65−class: center, middle
66−count: false
67−
6827
6928
7029---
@@ -85,9 +44,6 @@ However, it's not an ORM. There's no caching, lazy loading - you retain control
8544
8645---
8746
88−class: center, middle
89−count: false
90−
9147# Part I. Schema & migration
9248
9349---
@@ -107,16 +63,13 @@ type Schema = '[ "mp" ::: 'Table MemberOfParliament
10763 , "groupp" ::: 'Table ParliamentGroup ]
10864```
10965
110−--
66+---
11167
112−.note[*
113−We need the `DataKinds` extension to be able to express heterogenous lists containing
114−specific types like this one.
68+> _note_ We need the `DataKinds` extension to be able to express heterogenous lists containing
69+> specific types like this one.
11570
116−*
117−You can perfectly call your table "group" and not "groupp" even though it is a
118−keyword in SQL - Squeal queries will be properly escaped.
119−]
71+> You can perfectly call your table "group" and not "groupp" even though it is a
72+> keyword in SQL - Squeal queries will be properly escaped.
12073
12174---
12275
@@ -139,17 +92,13 @@ type ParliamentaryGroup =
13992
14093- Let's split constraints and column to study the syntax a bit more.
14194
142−--
95+---
14396
144−.note[*
145−We are using `:::` and `:=>` to quickly express associations when writing
146−our schema. We need the `TypeOperators` extension.]
97+> _note_ We are using `:::` and `:=>` to quickly express associations when writing
98+> our schema. We need the `TypeOperators` extension.]
14799
148100---
149101
150−class: center, middle
151−count: false
152−
153102
154103
155104---
@@ -195,10 +144,10 @@ type MpCols =
195144
196145 * the type (obviously).
197146
198−--
147+---
199148
200−.note[*
201−GHC is already helping. If I named the "mp_id" column differently, GHC would yell because I promised a primary key constraint on a column named `mp_id`, so there must be one.]
149+> _note_ GHC is already helping. If I named the "mp_id" column differently,
150+> GHC would yell because I promised a primary key constraint on a column named `mp_id`, so there must be one.]
202151
203152---
204153
@@ -208,7 +157,7 @@ GHC is already helping. If I named the "mp_id" column differently, GHC would yel
208157
209158- But before we play with this schema, we need to implement it.
210159
211−--
160+---
212161
213162```haskell
214163setup :: Definition '[] Schema
@@ -240,15 +189,14 @@ setup =
240189
241190- You use `>>>` to compose table creation.
242191
243−- Note that the compiler will catch any mistype between Schema and
244−definition; wrong nullability, wrong type, wrong name, etc.
192+> _note_ The compiler will catch any mistype between Schema and
193+> definition; wrong nullability, wrong type, wrong name, etc.
245194
246−--
195+---
247196
248−.note[*
249−You'll also need `OverloadedLabels`, for naming stuff.
250−This is mostly to avoid having to write manual proxies all
251−the time and for convenience.]
197+> _note_ You'll also need `OverloadedLabels`, for naming stuff.
198+> This is mostly to avoid having to write manual proxies all
199+> the time and for convenience.
252200
253201---
254202
@@ -283,8 +231,8 @@ tearDown :: Definition Schema '[]
283231tearDown = dropTable #mp >>> dropTable #groupp
284232```
285233
286−- Note that GHC will also detect the _proper_ order of what you typed in
287− downgrade and upgrade should there be any conflict (with foreign keys).
234+> _note_ GHC will also detect the _proper_ order of what you typed in
235+> downgrade and upgrade should there be any conflict (with foreign keys).
288236
289237```haskell
290238initDB :: Migration IO '[] Schema
@@ -314,16 +262,10 @@ main = do
314262
315263---
316264
317−class: center, middle
318−count: false
319−
320265
321266
322267---
323268
324−class: center, middle
325−count: false
326−
327269# Part II. Insertions
328270
329271---
@@ -369,9 +311,8 @@ data MemberOfParliament =
369311 , lastName :: Text }
370312```
371313
372−- You'll note that we didn't use anything from Squeal.
373−
374−- The model can be entirely separated from the persistence layer.
314+> _note_ We didn't use anything from Squeal.
315+> The model can be entirely separated from the persistence layer.
375316
376317---
377318
@@ -386,7 +327,7 @@ type GroupInsertionParams = '[ 'NotNull 'PGuuid
386327
387328- Params are not named, but they are indexed. You just need nullability and type.
388329
389−--
330+---
390331
391332```haskell
392333groupInsertion :: Manipulation Schema GroupInsertionParams '[]
@@ -395,7 +336,7 @@ groupInsertion =
395336 :* Set (param @2) `as` #name )
396337```
397338
398−--
339+---
399340
400341- `TypeApplication` lets us use the index of parameters (counting from 1).
401342
@@ -410,19 +351,19 @@ _Inserting a Member of Parliament_
410351
411352- We could create a naive query that takes MP uuid, first name, last name and group uuid...
412353
413−--
354+---
414355
415356- But that's boring. So let's use the `INSERT INTO ... SELECT`.
416357
417−--
358+---
418359
419360- We will build a query that will return as constants our MP's uuid, first name and last name...
420361
421−--
362+---
422363
423364- ... and fetch the uuid of a group given the name of the group.
424365
425−--
366+---
426367
427368- There's a `insertQuery` utility function for that. All we have to do is write the `select` !
428369
@@ -572,16 +513,11 @@ insertParliament = traverse_ insertGroup
572513
573514---
574515
575−class: center, middle
576−count: false
577−
578516
579517
580518
581519---
582520
583−class: center, middle
584−
585521# Part III. Selects
586522
587523---
@@ -653,7 +589,7 @@ type BaseParliamentSelection =
653589 , "m" ::: TableToRow MpCols ]
654590```
655591
656−- Note that we've also put everything with table aliases: "g" and "m".
592+> _note_ We've also put everything with table aliases: "g" and "m".
657593
658594---
659595
@@ -831,16 +767,10 @@ getGroupMembers =
831767
832768---
833769
834−class: center, middle
835−count: false
836−
837770
838771
839772---
840773
841−class: center, middle
842−count: false
843−
844774# Conclusion
845775
846776---
@@ -860,17 +790,5 @@ count: false
860790- Typesafe. 'nuff said.
861791
862792---
863−class: center, middle
864−count: false
865793
866794# Thank you !
867−
868−
869− </textarea>
870− <script src="https://remarkjs.com/downloads/remark-latest.min.js">
871− </script>
872− <script>
873− var slideshow = remark.create({countIncrementalSlides: false});
874− </script>
875− </body>
876−</html>