on dev help sign in
Merge pull request #76 from morphismtech/dev-patch-presentation
7ff3dbeEitan Chatav
squeal-presentation-2018-09-12.html → squeal-presentation-2018-09-12.mdrenamed+30−112
@@ -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−
39# Squeal
1# Squeal
40
2
41_A bridge between SQL and Haskell_
3_A bridge between SQL and Haskell_
42
4
43−.signature[2018/09/12 - by @Raveline]
5+by [@Raveline](https://github.com/raveline)
44
6
45---
7---
46
8
@@ -62,9 +24,6 @@ Using `postgresql-simple` you have a typical "Trial, error, despair" workflow:
62
24
63---
25---
64
26
65−class: center, middle
66−count: false
67−
68![Can't take this anymore](http://gif.eraveline.eu/static/img/0x16e.gif)
27![Can't take this anymore](http://gif.eraveline.eu/static/img/0x16e.gif)
69
28
70---
29---
@@ -85,9 +44,6 @@ However, it's not an ORM. There's no caching, lazy loading - you retain control
85
44
86---
45---
87
46
88−class: center, middle
89−count: false
90−
91# Part I. Schema & migration
47# Part I. Schema & migration
92
48
93---
49---
@@ -107,16 +63,13 @@ type Schema = '[ "mp" ::: 'Table MemberOfParliament
107 , "groupp" ::: 'Table ParliamentGroup ]
63 , "groupp" ::: 'Table ParliamentGroup ]
108```
64```
109
65
110−--
66+---
111
67
112−.note[*
113−We need the `DataKinds` extension to be able to express heterogenous lists containing
68+> _note_ We need the `DataKinds` extension to be able to express heterogenous lists containing
114−specific types like this one.
69+> specific types like this one.
115
70
116−*
117−You can perfectly call your table "group" and not "groupp" even though it is a
71+> 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.
72+> keyword in SQL - Squeal queries will be properly escaped.
119−]
120
73
121---
74---
122
75
@@ -139,17 +92,13 @@ type ParliamentaryGroup =
139
92
140- Let's split constraints and column to study the syntax a bit more.
93- Let's split constraints and column to study the syntax a bit more.
141
94
142−--
95+---
143
96
144−.note[*
145−We are using `:::` and `:=>` to quickly express associations when writing
97+> _note_ We are using `:::` and `:=>` to quickly express associations when writing
146−our schema. We need the `TypeOperators` extension.]
98+> our schema. We need the `TypeOperators` extension.]
147
99
148---
100---
149
101
150−class: center, middle
151−count: false
152−
153![What does this means ?!](http://gif.eraveline.eu/static/img/0x27e.gif)
102![What does this means ?!](http://gif.eraveline.eu/static/img/0x27e.gif)
154
103
155---
104---
@@ -195,10 +144,10 @@ type MpCols =
195
144
196 * the type (obviously).
145 * the type (obviously).
197
146
198−--
147+---
199
148
200−.note[*
149+> _note_ GHC is already helping. If I named the "mp_id" column differently,
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.]
150+> GHC would yell because I promised a primary key constraint on a column named `mp_id`, so there must be one.]
202
151
203---
152---
204
153
@@ -208,7 +157,7 @@ GHC is already helping. If I named the "mp_id" column differently, GHC would yel
208
157
209- But before we play with this schema, we need to implement it.
158- But before we play with this schema, we need to implement it.
210
159
211−--
160+---
212
161
213```haskell
162```haskell
214setup :: Definition '[] Schema
163setup :: Definition '[] Schema
@@ -240,15 +189,14 @@ setup =
240
189
241- You use `>>>` to compose table creation.
190- You use `>>>` to compose table creation.
242
191
243−- Note that the compiler will catch any mistype between Schema and
192+> _note_ The compiler will catch any mistype between Schema and
244−definition; wrong nullability, wrong type, wrong name, etc.
193+> definition; wrong nullability, wrong type, wrong name, etc.
245
194
246−--
195+---
247
196
248−.note[*
249−You'll also need `OverloadedLabels`, for naming stuff.
197+> _note_ You'll also need `OverloadedLabels`, for naming stuff.
250−This is mostly to avoid having to write manual proxies all
198+> This is mostly to avoid having to write manual proxies all
251−the time and for convenience.]
199+> the time and for convenience.
252
200
253---
201---
254
202
@@ -283,8 +231,8 @@ tearDown :: Definition Schema '[]
283tearDown = dropTable #mp >>> dropTable #groupp
231tearDown = dropTable #mp >>> dropTable #groupp
284```
232```
285
233
286−- Note that GHC will also detect the _proper_ order of what you typed in
234+> _note_ GHC will also detect the _proper_ order of what you typed in
287− downgrade and upgrade should there be any conflict (with foreign keys).
235+> downgrade and upgrade should there be any conflict (with foreign keys).
288
236
289```haskell
237```haskell
290initDB :: Migration IO '[] Schema
238initDB :: Migration IO '[] Schema
@@ -314,16 +262,10 @@ main = do
314
262
315---
263---
316
264
317−class: center, middle
318−count: false
319−
320![That was easy](http://gif.eraveline.eu/static/img/0x47f.gif)
265![That was easy](http://gif.eraveline.eu/static/img/0x47f.gif)
321
266
322---
267---
323
268
324−class: center, middle
325−count: false
326−
327# Part II. Insertions
269# Part II. Insertions
328
270
329---
271---
@@ -369,9 +311,8 @@ data MemberOfParliament =
369 , lastName :: Text }
311 , lastName :: Text }
370```
312```
371
313
372−- You'll note that we didn't use anything from Squeal.
314+> _note_ We didn't use anything from Squeal.
373−
374−- The model can be entirely separated from the persistence layer.
315+> The model can be entirely separated from the persistence layer.
375
316
376---
317---
377
318
@@ -386,7 +327,7 @@ type GroupInsertionParams = '[ 'NotNull 'PGuuid
386
327
387- Params are not named, but they are indexed. You just need nullability and type.
328- Params are not named, but they are indexed. You just need nullability and type.
388
329
389−--
330+---
390
331
391```haskell
332```haskell
392groupInsertion :: Manipulation Schema GroupInsertionParams '[]
333groupInsertion :: Manipulation Schema GroupInsertionParams '[]
@@ -395,7 +336,7 @@ groupInsertion =
395 :* Set (param @2) `as` #name )
336 :* Set (param @2) `as` #name )
396```
337```
397
338
398−--
339+---
399
340
400- `TypeApplication` lets us use the index of parameters (counting from 1).
341- `TypeApplication` lets us use the index of parameters (counting from 1).
401
342
@@ -410,19 +351,19 @@ _Inserting a Member of Parliament_
410
351
411- We could create a naive query that takes MP uuid, first name, last name and group uuid...
352- We could create a naive query that takes MP uuid, first name, last name and group uuid...
412
353
413−--
354+---
414
355
415- But that's boring. So let's use the `INSERT INTO ... SELECT`.
356- But that's boring. So let's use the `INSERT INTO ... SELECT`.
416
357
417−--
358+---
418
359
419- We will build a query that will return as constants our MP's uuid, first name and last name...
360- We will build a query that will return as constants our MP's uuid, first name and last name...
420
361
421−--
362+---
422
363
423- ... and fetch the uuid of a group given the name of the group.
364- ... and fetch the uuid of a group given the name of the group.
424
365
425−--
366+---
426
367
427- There's a `insertQuery` utility function for that. All we have to do is write the `select` !
368- There's a `insertQuery` utility function for that. All we have to do is write the `select` !
428
369
@@ -572,16 +513,11 @@ insertParliament = traverse_ insertGroup
572
513
573---
514---
574
515
575−class: center, middle
576−count: false
577−
578![Very simple](https://media1.tenor.com/images/0188c63209aced59f1583e1ca94e509e/tenor.gif?itemid=3550689)
516![Very simple](https://media1.tenor.com/images/0188c63209aced59f1583e1ca94e509e/tenor.gif?itemid=3550689)
579
517
580
518
581---
519---
582
520
583−class: center, middle
584−
585# Part III. Selects
521# Part III. Selects
586
522
587---
523---
@@ -653,7 +589,7 @@ type BaseParliamentSelection =
653 , "m" ::: TableToRow MpCols ]
589 , "m" ::: TableToRow MpCols ]
654```
590```
655
591
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".
657
593
658---
594---
659
595
@@ -831,16 +767,10 @@ getGroupMembers =
831
767
832---
768---
833
769
834−class: center, middle
835−count: false
836−
837![Eazy](https://media.tenor.com/images/8fc7c4077efe11b4a3a3b9ae4e643e87/tenor.gif)
770![Eazy](https://media.tenor.com/images/8fc7c4077efe11b4a3a3b9ae4e643e87/tenor.gif)
838
771
839---
772---
840
773
841−class: center, middle
842−count: false
843−
844# Conclusion
774# Conclusion
845
775
846---
776---
@@ -860,17 +790,5 @@ count: false
860- Typesafe. 'nuff said.
790- Typesafe. 'nuff said.
861
791
862---
792---
863−class: center, middle
864−count: false
865
793
866# Thank you !
794# 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>