haskell-relational-record/doc/slide/Haskell-Day-201609/HRR.html

342 lines
245 KiB
HTML
Raw Normal View History

2016-09-14 13:32:21 +03:00
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta name="generator" content="pandoc" />
2016-09-17 09:05:13 +03:00
<meta name="version" content="S5 1.1" />
2016-09-14 13:32:21 +03:00
<meta name="author" content="Kei Hibino" />
<meta name="date" content="2016-09-17" />
2016-09-16 14:55:10 +03:00
<title>Haskell Relational Record Composable, Typesafe SQL building</title>
2016-09-14 13:32:21 +03:00
<style type="text/css">code{white-space: pre;}</style>
<!-- configuration parameters -->
<meta name="defaultView" content="slideshow" />
<meta name="controlVis" content="hidden" />
<style type="text/css">
2016-09-17 09:05:13 +03:00
div.sourceCode { overflow-x: auto; }
2016-09-14 13:32:21 +03:00
table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
margin: 0; padding: 0; vertical-align: baseline; border: none; }
table.sourceCode { width: 100%; line-height: 100%; }
td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
td.sourceCode { padding-left: 5px; }
2016-09-17 09:05:13 +03:00
code > span.kw { color: #007020; font-weight: bold; } /* Keyword */
code > span.dt { color: #902000; } /* DataType */
code > span.dv { color: #40a070; } /* DecVal */
code > span.bn { color: #40a070; } /* BaseN */
code > span.fl { color: #40a070; } /* Float */
code > span.ch { color: #4070a0; } /* Char */
code > span.st { color: #4070a0; } /* String */
code > span.co { color: #60a0b0; font-style: italic; } /* Comment */
code > span.ot { color: #007020; } /* Other */
code > span.al { color: #ff0000; font-weight: bold; } /* Alert */
code > span.fu { color: #06287e; } /* Function */
code > span.er { color: #ff0000; font-weight: bold; } /* Error */
code > span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
code > span.cn { color: #880000; } /* Constant */
code > span.sc { color: #4070a0; } /* SpecialChar */
code > span.vs { color: #4070a0; } /* VerbatimString */
code > span.ss { color: #bb6688; } /* SpecialString */
code > span.im { } /* Import */
code > span.va { color: #19177c; } /* Variable */
code > span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code > span.op { color: #666666; } /* Operator */
code > span.bu { } /* BuiltIn */
code > span.ex { } /* Extension */
code > span.pp { color: #bc7a00; } /* Preprocessor */
code > span.at { color: #7d9029; } /* Attribute */
code > span.do { color: #ba2121; font-style: italic; } /* Documentation */
code > span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code > span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
2016-09-14 13:32:21 +03:00
</style>
<!-- style sheet links -->
2016-09-17 09:05:13 +03:00
<link href="data:text/css;charset=utf-8,%40import%20url%28data%3Atext%2Fcss%3Bcharset%3Dutf%2D8%2C%250Adiv%2523header%252C%2520div%2523footer%252C%2520div%2523controls%252C%2520%252Eslide%2520%257Bposition%253A%2520absolute%253B%257D%250Ahtml%253Ebody%2520div%2523header%252C%2520html%253Ebody%2520div%2523footer%252C%2520html%253Ebody%2520div%2523controls%252C%2520html%253Ebody%2520%252Eslide%2520%257Bposition%253A%2520fixed%253B%257D%250A%252Ehandout%2520%257Bdisplay%253A%2520none%253B%257D%250A%252Elayout%2520%257Bdisplay%253A%2520block%253B%257D%250A%252Eslide%252C%2520%252Ehideme%252C%2520%252Eincremental%2520%257Bvisibility%253A%2520hidden%253B%257D%250A%2523slide0%2520%257Bvisibility%253A%2520visible%253B%257D%250A%29%3B%20%0A%40import%20url%28data%3Atext%2Fcss%3Bcharset%3Dutf%2D8%2C%250A%250Adiv%2523header%252C%2520div%2523footer%252C%2520%252Eslide%2520%257Bwidth%253A%2520100%2525%253B%2520top%253A%25200%253B%2520left%253A%25200%253B%257D%250Adiv%2523header%2520%257Btop%253A%25200%253B%2520height%253A%25203em%253B%2520z%252Dindex%253A%25201%253B%257D%250Adiv%2523footer%2520%257Btop%253A%2520auto%253B%2520bottom%253A%25200%253B%2520height%253A%25202%252E5em%253B%2520z%252Dindex%253A%25205%253B%257D%250A%252Eslide%2520%257Btop%253A%25200%253B%2520width%253A%252092%2525%253B%2520padding%253A%25203%252E5em%25204%2525%25204%2525%253B%2520z%252Dindex%253A%25202%253B%2520list%252Dstyle%253A%2520none%253B%257D%250Adiv%2523controls%2520%257Bleft%253A%252050%2525%253B%2520bottom%253A%25200%253B%2520width%253A%252050%2525%253B%2520z%252Dindex%253A%2520100%253B%257D%250Adiv%2523controls%2520form%2520%257Bposition%253A%2520absolute%253B%2520bottom%253A%25200%253B%2520right%253A%25200%253B%2520width%253A%2520100%2525%253B%250Amargin%253A%25200%253B%257D%250A%2523currentSlide%2520%257Bposition%253A%2520absolute%253B%2520width%253A%252010%2525%253B%2520left%253A%252045%2525%253B%2520bottom%253A%25201em%253B%2520z%252Dindex%253A%252010%253B%257D%250Ahtml%253Ebody%2520%2523currentSlide%2520%257Bposition%253A%2520fixed%253B%257D%250A%250A%29%3B%20%0A%40import%20url%28data%3Atext%2Fcss%3Bcharset%3Dutf%2D8%2C%250Abody%2520%257Bbackground%253A%2520%2523FFF%2520url%2528data%253Aimage%252Fgif%253Bbase64%252CR0lGODlh5gBOAcT%252FAMDAwLW1tb29vcbGxs7OztbW1t7e3ufn5%252B%252Fv7%252Ff39%252Bfv7%252B%252F39%252Ff%252F%252F8bOzs7W1tbe3t7n57W9vb3Gxuf3987e3tbn597v78bW1r3Ozs7n5wAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAADmAE4BAAX%252F4CEez3UZ1PNAjppCpALM9GxNgLXUfD8pC6BC1mMoLApGb7nUMRaWBLOmwAGOREVlqK38LNNwbQIWm2fH2aLScJzf8NqI1Lg8Cqq6w9EoOAwPZT0KFBkIcVhkSwlQh3E8EDhrOmELFEQ5VTMJRwwQDTtXFRlbj2hRWwkZhZhMDBVINQsZMrMUgqa5PHMiDw0qdg8igIAOUjxrVo9YEE0VFaG6sZ5Imj2zuFxFFBQ1Smm5UAATzeJhnkEV1%252BqWF8268DO8JA8GbcIjD3%252FvsrQIuGegKFkyJJ4NIhAoUULGb8aEZwQlDER2a0o0WdDeLYCQACCNIwsflqKxZpyECx4N%252F77hpW9ePgcirkEwF2cjE3DxfhxUB43HK48bdRyjQeFCD1W3KjSkUW3JxlcAStZgFATLUACMMvBQFVVCCpWm5rR02Qvmga3qdEnt10pt2iGcgPBQOhHjz2gVKAx8liEDBHUJ0m5FogxZ2sAAGCRQTMpCLCaq%252BAVe%252FAlDW7Bi5hgwS3ZzTBpQ4a3dJNggggqcyhjxhrru1JmMLCB4CMrCsyiLEWMtDfqyKwqjZrYCqSChT1I0WkPIIME35iUjDFwgOwLC9LPJXT9ayyBDynC3tTbhaOYZrISELDhYsEA31kK8VfJGwi3D1RoV9krh1kD78x7DcEadZ9h5cl84YECEWf9oNvUQyYFidHPFBSWh9p8YF7EHIVEcWlAIAReGIYJ11FV33SbiGcTAAwBIiJmEDLhYw0JiDMRIdx%252FpYGGIUyxlRoqUfNJAfDwCIMJ1JR5gjwgyhKaSVk6qeBhA2pgR2BNKVSWDBRDMVCQcxk2R31470NKAjzwegGSSJOwhXooGvfkiDXAG8RgTyCGn1HvoVXPRl2JM8GcPD9g3g3AWMLfhfwc0wKZYhc4gIzx5SQpWik4GxQRfacGJpSDOASpfKN0oIEEGDYhq5JqPHiAhnNIsNgOsuZQmISOlcWnbM7JqFxiRPQCrKhw9FWQmi4Ce0Ooc4nVkkIy0miKjOq%252Bw8wP%252FF%252By1N0WUNQ777KwA%252FDMBKIAasGw%252BjrQYD43qxlOaVpOxp2uoc0XrrUH5NYFDQYRkIACg546QKp3xwCrsGxnUxeszaIZh773uApDfjjQ8IEUa3jnwHVgBHzmRe9LykDA85M11sJiLQkzpZPmSiYYCCBQSQcrxdNzoVVeacsNcNIeRL37%252BldezyivPsIURBUlcLapBG9SxCj3otcxlFJvSU3JDB5s10e7GVRUq7S3nwMm6dIyHdlULjQavEm89YytXI5LBoFyHGAs5SUABxWKFSEC30x1TCEncZ%252FSExGLQEP7GnYf%252BPQXj3u6NhuMqgXPtEAlx8pfUjHa83oxBUS6L%252FwVI19Cl6INsGQ27ZiT95ROu6coIBRcRgjocR0ihJRSOISHAxmUHfMd9OnCJ%252BlMAQNCWh7c7BAbMCtHbhPS5ODbQaVIg7Vhi1isw9xUT%252FKAYaG4jI5sSenPyTBANUB%252BH58iqkZcMkZixMwJJzKg85Ew0WI0MrgsI8OCgk48AJ38vs8ommAJAMMxiC%252FLawRPCkZBQaKIjGZgANzq
<link href="data:text/css;charset=utf-8,%0A%2Elayout%20div%2C%20%23footer%20%2A%2C%20%23controlForm%20%2A%20%7Bdisplay%3A%20none%3B%7D%0A%23footer%2C%20%23controls%2C%20%23controlForm%2C%20%23navLinks%2C%20%23toggle%20%7B%0Adisplay%3A%20block%3B%20visibility%3A%20visible%3B%20margin%3A%200%3B%20padding%3A%200%3B%7D%0A%23toggle%20%7Bfloat%3A%20right%3B%20padding%3A%200%2E5em%3B%7D%0Ahtml%3Ebody%20%23toggle%20%7Bposition%3A%20fixed%3B%20top%3A%200%3B%20right%3A%200%3B%7D%0A%0A%23slide0%20h1%2C%20%23slide0%20h2%2C%20%23slide0%20h3%2C%20%23slide0%20h4%20%7Bborder%3A%20none%3B%20margin%3A%200%3B%7D%0A%23slide0%20h1%20%7Bpadding%2Dtop%3A%201%2E5em%3B%7D%0A%2Eslide%20h1%20%7Bmargin%3A%201%2E5em%200%200%3B%20padding%2Dtop%3A%200%2E25em%3B%0Aborder%2Dtop%3A%201px%20solid%20%23888%3B%20border%2Dbottom%3A%201px%20solid%20%23AAA%3B%7D%0A%23toggle%20%7Bborder%3A%201px%20solid%3B%20border%2Dwidth%3A%200%200%201px%201px%3B%20background%3A%20%23FFF%3B%7D%0A" rel="stylesheet" type="text/css" media="screen" id="outlineStyle" />
<link href="data:text/css;charset=utf-8,%0A%2Eslide%2C%20ul%20%7Bpage%2Dbreak%2Dinside%3A%20avoid%3B%20visibility%3A%20visible%20%21important%3B%7D%0Ah1%20%7Bpage%2Dbreak%2Dafter%3A%20avoid%3B%7D%0Abody%20%7Bfont%2Dsize%3A%2012pt%3B%20background%3A%20white%3B%7D%0A%2A%20%7Bcolor%3A%20black%3B%7D%0A%23slide0%20h1%20%7Bfont%2Dsize%3A%20200%25%3B%20border%3A%20none%3B%20margin%3A%200%2E5em%200%200%2E25em%3B%7D%0A%23slide0%20h3%20%7Bmargin%3A%200%3B%20padding%3A%200%3B%7D%0A%23slide0%20h4%20%7Bmargin%3A%200%200%200%2E5em%3B%20padding%3A%200%3B%7D%0A%23slide0%20%7Bmargin%2Dbottom%3A%203em%3B%7D%0Ah1%20%7Bborder%2Dtop%3A%202pt%20solid%20gray%3B%20border%2Dbottom%3A%201px%20dotted%20silver%3B%7D%0A%2Eextra%20%7Bbackground%3A%20transparent%20%21important%3B%7D%0Adiv%2Eextra%2C%20pre%2Eextra%2C%20%2Eexample%20%7Bfont%2Dsize%3A%2010pt%3B%20color%3A%20%23333%3B%7D%0Aul%2Eextra%20a%20%7Bfont%2Dweight%3A%20bold%3B%7D%0Ap%2Eexample%20%7Bdisplay%3A%20none%3B%7D%0A%23header%20%7Bdisplay%3A%20none%3B%7D%0A%23footer%20h1%20%7Bmargin%3A%200%3B%20border%2Dbottom%3A%201px%20solid%3B%20color%3A%20gray%3B%20font%2Dstyle%3A%20italic%3B%7D%0A%23footer%20h2%2C%20%23controls%20%7Bdisplay%3A%20none%3B%7D%0A%0A%2Elayout%2C%20%2Elayout%20%2A%20%7Bdisplay%3A%20none%20%21important%3B%7D" rel="stylesheet" type="text/css" media="print" id="slidePrint" />
<link href="data:text/css;charset=utf-8,%0A%2Eslide%20%7B%0Avisibility%3A%20visible%20%21important%3B%0Aposition%3A%20static%20%21important%3B%0Apage%2Dbreak%2Dbefore%3A%20always%3B%0A%7D%0A%23slide0%20%7Bpage%2Dbreak%2Dbefore%3A%20avoid%3B%7D%0A" rel="stylesheet" type="text/css" media="projection" id="operaFix" />
2016-09-14 13:32:21 +03:00
<!-- S5 JS -->
2016-09-17 09:05:13 +03:00
<script src="data:application/x-javascript;base64,Ly8gUzUgdjEuMSBzbGlkZXMuanMgLS0gcmVsZWFzZWQgaW50byB0aGUgUHVibGljIERvbWFpbgovLwovLyBQbGVhc2Ugc2VlIGh0dHA6Ly93d3cubWV5ZXJ3ZWIuY29tL2VyaWMvdG9vbHMvczUvY3JlZGl0cy5odG1sIGZvciBpbmZvcm1hdGlvbiAKLy8gYWJvdXQgYWxsIHRoZSB3b25kZXJmdWwgYW5kIHRhbGVudGVkIGNvbnRyaWJ1dG9ycyB0byB0aGlzIGNvZGUhCgp2YXIgdW5kZWY7CnZhciBzbGlkZUNTUyA9ICcnOwp2YXIgc251bSA9IDA7CnZhciBzbWF4ID0gMTsKdmFyIGluY3BvcyA9IDA7CnZhciBudW1iZXIgPSB1bmRlZjsKdmFyIHM1bW9kZSA9IHRydWU7CnZhciBkZWZhdWx0VmlldyA9ICdzbGlkZXNob3cnOwp2YXIgY29udHJvbFZpcyA9ICd2aXNpYmxlJzsKCnZhciBpc0lFID0gbmF2aWdhdG9yLmFwcE5hbWUgPT0gJ01pY3Jvc29mdCBJbnRlcm5ldCBFeHBsb3JlcicgPyAxIDogMDsKdmFyIGlzT3AgPSBuYXZpZ2F0b3IudXNlckFnZW50LmluZGV4T2YoJ09wZXJhJykgPiAtMSA/IDEgOiAwOwp2YXIgaXNHZSA9IG5hdmlnYXRvci51c2VyQWdlbnQuaW5kZXhPZignR2Vja28nKSA+IC0xICYmIG5hdmlnYXRvci51c2VyQWdlbnQuaW5kZXhPZignU2FmYXJpJykgPCAxID8gMSA6IDA7CgpmdW5jdGlvbiBoYXNDbGFzcyhvYmplY3QsIGNsYXNzTmFtZSkgewoJaWYgKCFvYmplY3QuY2xhc3NOYW1lKSByZXR1cm4gZmFsc2U7CglyZXR1cm4gKG9iamVjdC5jbGFzc05hbWUuc2VhcmNoKCcoXnxcXHMpJyArIGNsYXNzTmFtZSArICcoXFxzfCQpJykgIT0gLTEpOwp9CgpmdW5jdGlvbiBoYXNWYWx1ZShvYmplY3QsIHZhbHVlKSB7CglpZiAoIW9iamVjdCkgcmV0dXJuIGZhbHNlOwoJcmV0dXJuIChvYmplY3Quc2VhcmNoKCcoXnxcXHMpJyArIHZhbHVlICsgJyhcXHN8JCknKSAhPSAtMSk7Cn0KCmZ1bmN0aW9uIHJlbW92ZUNsYXNzKG9iamVjdCxjbGFzc05hbWUpIHsKCWlmICghb2JqZWN0KSByZXR1cm47CglvYmplY3QuY2xhc3NOYW1lID0gb2JqZWN0LmNsYXNzTmFtZS5yZXBsYWNlKG5ldyBSZWdFeHAoJyhefFxccyknK2NsYXNzTmFtZSsnKFxcc3wkKScpLCBSZWdFeHAuJDErUmVnRXhwLiQyKTsKfQoKZnVuY3Rpb24gYWRkQ2xhc3Mob2JqZWN0LGNsYXNzTmFtZSkgewoJaWYgKCFvYmplY3QgfHwgaGFzQ2xhc3Mob2JqZWN0LCBjbGFzc05hbWUpKSByZXR1cm47CglpZiAob2JqZWN0LmNsYXNzTmFtZSkgewoJCW9iamVjdC5jbGFzc05hbWUgKz0gJyAnK2NsYXNzTmFtZTsKCX0gZWxzZSB7CgkJb2JqZWN0LmNsYXNzTmFtZSA9IGNsYXNzTmFtZTsKCX0KfQoKZnVuY3Rpb24gR2V0RWxlbWVudHNXaXRoQ2xhc3NOYW1lKGVsZW1lbnROYW1lLGNsYXNzTmFtZSkgewoJdmFyIGFsbEVsZW1lbnRzID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoZWxlbWVudE5hbWUpOwoJdmFyIGVsZW1Db2xsID0gbmV3IEFycmF5KCk7Cglmb3IgKHZhciBpID0gMDsgaTwgYWxsRWxlbWVudHMubGVuZ3RoOyBpKyspIHsKCQlpZiAoaGFzQ2xhc3MoYWxsRWxlbWVudHNbaV0sIGNsYXNzTmFtZSkpIHsKCQkJZWxlbUNvbGxbZWxlbUNvbGwubGVuZ3RoXSA9IGFsbEVsZW1lbnRzW2ldOwoJCX0KCX0KCXJldHVybiBlbGVtQ29sbDsKfQoKZnVuY3Rpb24gaXNQYXJlbnRPclNlbGYoZWxlbWVudCwgaWQpIHsKCWlmIChlbGVtZW50ID09IG51bGwgfHwgZWxlbWVudC5ub2RlTmFtZT09J0JPRFknKSByZXR1cm4gZmFsc2U7CgllbHNlIGlmIChlbGVtZW50LmlkID09IGlkKSByZXR1cm4gdHJ1ZTsKCWVsc2UgcmV0dXJuIGlzUGFyZW50T3JTZWxmKGVsZW1lbnQucGFyZW50Tm9kZSwgaWQpOwp9CgpmdW5jdGlvbiBub2RlVmFsdWUobm9kZSkgewoJdmFyIHJlc3VsdCA9ICIiOwoJaWYgKG5vZGUubm9kZVR5cGUgPT0gMSkgewoJCXZhciBjaGlsZHJlbiA9IG5vZGUuY2hpbGROb2RlczsKCQlmb3IgKHZhciBpID0gMDsgaSA8IGNoaWxkcmVuLmxlbmd0aDsgKytpKSB7CgkJCXJlc3VsdCArPSBub2RlVmFsdWUoY2hpbGRyZW5baV0pOwoJCX0JCQoJfQoJZWxzZSBpZiAobm9kZS5ub2RlVHlwZSA9PSAzKSB7CgkJcmVzdWx0ID0gbm9kZS5ub2RlVmFsdWU7Cgl9CglyZXR1cm4ocmVzdWx0KTsKfQoKZnVuY3Rpb24gc2xpZGVMYWJlbCgpIHsKCXZhciBzbGlkZUNvbGwgPSBHZXRFbGVtZW50c1dpdGhDbGFzc05hbWUoJyonLCdzbGlkZScpOwoJdmFyIGxpc3QgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnanVtcGxpc3QnKTsKCXNtYXggPSBzbGlkZUNvbGwubGVuZ3RoOwoJZm9yICh2YXIgbiA9IDA7IG4gPCBzbWF4OyBuKyspIHsKCQl2YXIgb2JqID0gc2xpZGVDb2xsW25dOwoKCQl2YXIgZGlkID0gJ3NsaWRlJyArIG4udG9TdHJpbmcoKTsKCQlvYmouc2V0QXR0cmlidXRlKCdpZCcsZGlkKTsKCQlpZiAoaXNPcCkgY29udGludWU7CgoJCXZhciBvdGV4dCA9ICcnOwoJCXZhciBtZW51ID0gb2JqLmZpcnN0Q2hpbGQ7CgkJaWYgKCFtZW51KSBjb250aW51ZTsgLy8gdG8gY29wZSB3aXRoIGVtcHR5IHNsaWRlcwoJCXdoaWxlIChtZW51ICYmIG1lbnUubm9kZVR5cGUgPT0gMykgewoJCQltZW51ID0gbWVudS5uZXh0U2libGluZzsKCQl9CgkgCWlmICghbWVudSkgY29udGludWU7IC8vIHRvIGNvcGUgd2l0aCBzbGlkZXMgd2l0aCBvbmx5IHRleHQgbm9kZXMKCgkJdmFyIG1lbnVub2RlcyA9IG1lbnUuY2hpbGROb2RlczsKCQlmb3IgKHZhciBvID0gMDsgbyA8IG1lbnVub2Rlcy5sZW5ndGg7IG8rKykgewoJCQlvdGV4dCArPSBub2RlVmFsdWUobWVudW5vZGVzW29dKTsKCQl9CgkJbGlzdC5vcHRpb25zW2xpc3QubGVuZ3RoXSA9IG5ldyBPcHRpb24obiArICcgOiAnICArIG90ZXh0LCBuKTsKCX0KfQoKZnVuY3Rpb24gY3VycmVudFNsaWRlKCkgewoJdmFyIGNzOwoJaWYgKGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKSB7CgkJY3MgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnY3VycmVudFNsaWRlJyk7Cgl9IGVsc2UgewoJCWNzID0gZG9jdW1lbnQuY3VycmVudFNsaWRlOwoJfQoJY3MuaW5uZXJIVE1MID0gJzxzcGFuIGlkPSJjc0hlcmUiPicgKyBzbnVtICsgJzxcL3NwYW4
<script src="data:application/x-javascript;base64,LyoNCkxhVGVYTWF0aE1MLmpzDQo9PT09PT09PT09PT09PQ0KDQpUaGlzIGZpbGUsIGluIHRoaXMgZm9ybSwgaXMgZHVlIHRvIERvdWdsYXMgV29vZGFsbCwgSnVuZSAyMDA2Lg0KSXQgY29udGFpbnMgSmF2YVNjcmlwdCBmdW5jdGlvbnMgdG8gY29udmVydCAobW9zdCBzaW1wbGUpIExhVGVYDQptYXRoIG5vdGF0aW9uIHRvIFByZXNlbnRhdGlvbiBNYXRoTUwuICBJdCB3YXMgb2J0YWluZWQgYnkNCmRvd25sb2FkaW5nIHRoZSBmaWxlIEFTQ0lJTWF0aE1MLmpzIGZyb20NCglodHRwOi8vd3d3MS5jaGFwbWFuLmVkdS9+amlwc2VuL21hdGhtbC9hc2NpaW1hdGhkb3dubG9hZC8NCmFuZCBtb2RpZnlpbmcgaXQgc28gdGhhdCBpdCBjYXJyaWVzIG91dCBPTkxZIHRob3NlIGNvbnZlcnNpb25zDQp0aGF0IHdvdWxkIGJlIGNhcnJpZWQgb3V0IGluIExhVGVYLiAgQSBkZXNjcmlwdGlvbiBvZiB0aGUgb3JpZ2luYWwNCmZpbGUsIHdpdGggZXhhbXBsZXMsIGNhbiBiZSBmb3VuZCBhdA0KCXd3dzEuY2hhcG1hbi5lZHUvfmppcHNlbi9tYXRobWwvYXNjaWltYXRoLmh0bWwNCglBU0NJSU1hdGhNTDogTWF0aCBvbiB0aGUgd2ViIGZvciBldmVyeW9uZQ0KDQpIZXJlIGlzIHRoZSBoZWFkZXIgbm90aWNlIGZyb20gdGhlIG9yaWdpbmFsIGZpbGU6DQoNCkFTQ0lJTWF0aE1MLmpzDQo9PT09PT09PT09PT09PQ0KVGhpcyBmaWxlIGNvbnRhaW5zIEphdmFTY3JpcHQgZnVuY3Rpb25zIHRvIGNvbnZlcnQgQVNDSUkgbWF0aCBub3RhdGlvbg0KdG8gUHJlc2VudGF0aW9uIE1hdGhNTC4gVGhlIGNvbnZlcnNpb24gaXMgZG9uZSB3aGlsZSB0aGUgKFgpSFRNTCBwYWdlDQpsb2FkcywgYW5kIHNob3VsZCB3b3JrIHdpdGggRmlyZWZveC9Nb3ppbGxhL05ldHNjYXBlIDcrIGFuZCBJbnRlcm5ldA0KRXhwbG9yZXIgNitNYXRoUGxheWVyIChodHRwOi8vd3d3LmRlc3NjaS5jb20vZW4vcHJvZHVjdHMvbWF0aHBsYXllci8pLg0KSnVzdCBhZGQgdGhlIG5leHQgbGluZSB0byB5b3VyIChYKUhUTUwgcGFnZSB3aXRoIHRoaXMgZmlsZSBpbiB0aGUgc2FtZSBmb2xkZXI6DQo8c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCIgc3JjPSJBU0NJSU1hdGhNTC5qcyI+PC9zY3JpcHQ+DQpUaGlzIGlzIGEgY29udmVuaWVudCBhbmQgaW5leHBlbnNpdmUgc29sdXRpb24gZm9yIGF1dGhvcmluZyBNYXRoTUwuDQoNClZlcnNpb24gMS40LjcgRGVjIDE1LCAyMDA1LCAoYykgUGV0ZXIgSmlwc2VuIGh0dHA6Ly93d3cuY2hhcG1hbi5lZHUvfmppcHNlbg0KTGF0ZXN0IHZlcnNpb24gYXQgaHR0cDovL3d3dy5jaGFwbWFuLmVkdS9+amlwc2VuL21hdGhtbC9BU0NJSU1hdGhNTC5qcw0KRm9yIGNoYW5nZXMgc2VlIGh0dHA6Ly93d3cuY2hhcG1hbi5lZHUvfmppcHNlbi9tYXRobWwvYXNjaWltYXRoY2hhbmdlcy50eHQNCklmIHlvdSB1c2UgaXQgb24gYSB3ZWJwYWdlLCBwbGVhc2Ugc2VuZCB0aGUgVVJMIHRvIGppcHNlbkBjaGFwbWFuLmVkdQ0KDQpUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeQ0KaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkNCnRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlciB2ZXJzaW9uIDIgb2YgdGhlIExpY2Vuc2UsIG9yIChhdA0KeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLg0KDQpUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwNCmJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mDQpNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VDQpHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIChhdCBodHRwOi8vd3d3LmdudS5vcmcvY29weWxlZnQvZ3BsLmh0bWwpDQpmb3IgbW9yZSBkZXRhaWxzLg0KDQpMYVRlWE1hdGhNTC5qcyAoY3RkKQ0KPT09PT09PT09PT09PT0NCg0KVGhlIGluc3RydWN0aW9ucyBmb3IgdXNlIGFyZSB0aGUgc2FtZSBhcyBmb3IgdGhlIG9yaWdpbmFsDQpBU0NJSU1hdGhNTC5qcywgZXhjZXB0IHRoYXQgb2YgY291cnNlIHRoZSBsaW5lIHlvdSBhZGQgdG8geW91cg0KZmlsZSBzaG91bGQgYmUNCjxzY3JpcHQgdHlwZT0idGV4dC9qYXZhc2NyaXB0IiBzcmM9IkxhVGVYTWF0aE1MLmpzIj48L3NjcmlwdD4NCk9yIHVzZSBhYnNvbHV0ZSBwYXRoIG5hbWVzIGlmIHRoZSBmaWxlIGlzIG5vdCBpbiB0aGUgc2FtZSBmb2xkZXINCmFzIHlvdXIgKFgpSFRNTCBwYWdlLg0KKi8NCg0KdmFyIGNoZWNrRm9yTWF0aE1MID0gdHJ1ZTsgICAvLyBjaGVjayBpZiBicm93c2VyIGNhbiBkaXNwbGF5IE1hdGhNTA0KdmFyIG5vdGlmeUlmTm9NYXRoTUwgPSB0cnVlOyAvLyBkaXNwbGF5IG5vdGUgaWYgbm8gTWF0aE1MIGNhcGFiaWxpdHkNCnZhciBhbGVydElmTm9NYXRoTUwgPSBmYWxzZTsgIC8vIHNob3cgYWxlcnQgYm94IGlmIG5vIE1hdGhNTCBjYXBhYmlsaXR5DQovLyB3YXMgInJlZCI6DQp2YXIgbWF0aGNvbG9yID0gIiI7CSAgICAgLy8gY2hhbmdlIGl0IHRvICIiICh0byBpbmhlcml0KSBvciBhbnkgb3RoZXIgY29sb3INCi8vIHdhcyAic2VyaWYiOg0KdmFyIG1hdGhmb250ZmFtaWx5ID0gIiI7ICAgICAgLy8gY2hhbmdlIHRvICIiIHRvIGluaGVyaXQgKHdvcmtzIGluIElFKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gb3IgYW5vdGhlciBmYW1pbHkgKGUuZy4gImFyaWFsIikNCnZhciBzaG93YXNjaWlmb3JtdWxhb25ob3ZlciA9IHRydWU7IC8vIGhlbHBzIHN0dWRlbnRzIGxlYXJuIEFTQ0lJTWF0aA0KLyoNCi8vIENvbW1lbnRlZCBvdXQgYnkgRFJXIC0tIG5vdCBub3cgdXNlZCAtLSBzZWUgREVMSU1JVEVSUyAodHdpY2UpIG5lYXIgdGhlIGVuZA0KdmFyIGRpc3BsYXlzdHlsZSA9IGZhbHNlOyAgICAgLy8gcHV0cyBsaW1pdHMgYWJvdmUgYW5kIGJlbG93IGxhcmdlIG9wZXJhdG9ycw0
2016-09-14 13:32:21 +03:00
</head>
<body>
<div class="layout">
<div id="controls"></div>
<div id="currentSlide"></div>
<div id="header"></div>
<div id="footer">
<h1>2016-09-17</h1>
2016-09-16 14:55:10 +03:00
<h2>Haskell Relational Record Composable, Typesafe SQL building</h2>
2016-09-14 13:32:21 +03:00
</div>
</div>
<div class="presentation">
<div class="titleslide slide">
2016-09-17 09:05:13 +03:00
<h1 class="title">Haskell Relational Record Composable, Typesafe SQL building</h1>
<h3 class="author">Kei Hibino</h3>
<h4 class="date">2016-09-17</h4>
2016-09-14 13:32:21 +03:00
</div>
<div id="concepts" class="slide section level2">
<h1>Concepts</h1>
<ul>
<li>SQL building DSL using Haskell
<ul>
2016-10-05 14:58:22 +03:00
<li>http://khibino.github.io/haskell-relational-record/</li>
2016-09-14 13:32:21 +03:00
</ul></li>
2016-09-16 14:55:10 +03:00
<li>Composability and Type-Safety
<ul>
<li>Want to find errors of SQL at compile time</li>
</ul></li>
2023-04-02 17:24:36 +03:00
<li>Compile time schema loading and generating type information</li>
2016-09-14 13:32:21 +03:00
</ul>
</div>
<div id="intro" class="titleslide slide section level1"><h1>Intro</h1></div><div id="intro-join---set" class="slide section level2">
<h1>Intro / Join - Set</h1>
<p>When building joined query:</p>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode sql"><code class="sourceCode sql"><span class="kw">SELECT</span> <span class="kw">ALL</span> T0.name <span class="kw">AS</span> f0, T0.age <span class="kw">AS</span> f1, T0.family <span class="kw">AS</span> f2,
2016-09-14 13:32:21 +03:00
T1.name <span class="kw">AS</span> f3, T1.day <span class="kw">AS</span> f4
<span class="kw">FROM</span> EXAMPLE.person T0 <span class="kw">INNER</span> <span class="kw">JOIN</span> EXAMPLE.birthday T1
2016-09-17 09:05:13 +03:00
<span class="kw">ON</span> (T0.name = T1.name)</code></pre></div>
2016-09-14 13:32:21 +03:00
<p>Like the following set operation:</p>
<p><span class="LaTeX">$$\{ (p, b) | p \in P, b \in B, \pi_{P.name}(p) = \pi_{B.name}(b) \}$$</span></p>
</div><div id="intro-set-operation-and-haskell" class="slide section level2">
<h1>Intro / Set operation and Haskell</h1>
<p><span class="LaTeX">$$\{ (p, b) | p \in P, b \in B, \pi_{P.name}(p) = \pi_{B.name}(b) \}$$</span></p>
<ul>
<li><code>&lt;-</code> is analogy of <span class="LaTeX">$\in$</span></li>
</ul>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"> [ (p, b)
2016-09-14 13:32:21 +03:00
<span class="fu">|</span> p <span class="ot">&lt;-</span> person, b <span class="ot">&lt;-</span> birthday , P.name p <span class="fu">==</span> B.name b ]
<span class="co">-- List Comprehension</span>
2016-09-17 09:05:13 +03:00
<span class="kw">do</span> { p <span class="ot">&lt;-</span> person; b <span class="ot">&lt;-</span> birthday; guard (P.name p <span class="fu">==</span> B.name b)
; return (p, b) } <span class="co">-- List Monad</span></code></pre></div>
2016-09-14 13:32:21 +03:00
<p>The same meanings</p>
</div><div id="intro-dsl-using-haskell" class="slide section level2">
<h1>Intro / DSL using Haskell!</h1>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"> <span class="kw">do</span> { p <span class="ot">&lt;-</span> person; b <span class="ot">&lt;-</span> birthday; guard (P.name p <span class="fu">==</span> B.name b)
; return (p, b) } <span class="co">-- List Monad</span></code></pre></div>
2016-09-14 13:32:21 +03:00
<p>Building a joined query like list monad:</p>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">personAndBirthday ::</span> <span class="dt">Relation</span> () (<span class="dt">Person</span>, <span class="dt">Birthday</span>)
2016-09-14 13:32:21 +03:00
personAndBirthday <span class="fu">=</span> relation <span class="fu">$</span> <span class="kw">do</span>
p <span class="ot">&lt;-</span> query person
b <span class="ot">&lt;-</span> query birthday <span class="co">-- Join product accumulated</span>
on <span class="fu">$</span> p <span class="fu">!</span> Person.name' <span class="fu">.=.</span> b <span class="fu">!</span> Birthday.name'
2016-09-17 09:05:13 +03:00
return <span class="fu">$</span> p <span class="fu">&gt;&lt;</span> b</code></pre></div>
2016-09-14 13:32:21 +03:00
</div><div id="intro-built-joined-query" class="slide section level2">
<h1>Intro / Built joined query</h1>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">personAndBirthday ::</span> <span class="dt">Relation</span> () (<span class="dt">Person</span>, <span class="dt">Birthday</span>)
2016-09-14 13:32:21 +03:00
personAndBirthday <span class="fu">=</span> relation <span class="fu">$</span> <span class="kw">do</span>
p <span class="ot">&lt;-</span> query person
b <span class="ot">&lt;-</span> query birthday <span class="co">-- Join product accumulated</span>
on <span class="fu">$</span> p <span class="fu">!</span> Person.name' <span class="fu">.=.</span> b <span class="fu">!</span> Birthday.name'
2016-09-17 09:05:13 +03:00
return <span class="fu">$</span> p <span class="fu">&gt;&lt;</span> b</code></pre></div>
<div class="sourceCode"><pre class="sourceCode sql"><code class="sourceCode sql"><span class="kw">SELECT</span> <span class="kw">ALL</span> T0.name <span class="kw">AS</span> f0, T0.age <span class="kw">AS</span> f1, T0.family <span class="kw">AS</span> f2,
2016-09-14 13:32:21 +03:00
T1.name <span class="kw">AS</span> f3, T1.day <span class="kw">AS</span> f4
<span class="kw">FROM</span> EXAMPLE.person T0 <span class="kw">INNER</span> <span class="kw">JOIN</span> EXAMPLE.birthday T1
2016-09-17 09:05:13 +03:00
<span class="kw">ON</span> (T0.name = T1.name)</code></pre></div>
2016-09-14 13:32:21 +03:00
</div>
<div id="by-examples" class="titleslide slide section level1"><h1>By examples</h1></div><div id="by-examples-left-outer-join" class="slide section level2">
<h1>By examples / Left outer join</h1>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">personAndBirthdayL ::</span> <span class="dt">Relation</span> () (<span class="dt">Person</span>, <span class="dt">Maybe</span> <span class="dt">Birthday</span>)
2016-09-14 13:32:21 +03:00
personAndBirthdayL <span class="fu">=</span> relation <span class="fu">$</span> <span class="kw">do</span>
p <span class="ot">&lt;-</span> query person
b <span class="ot">&lt;-</span> queryMaybe birthday
on <span class="fu">$</span> just (p <span class="fu">!</span> Person.name') <span class="fu">.=.</span> b <span class="fu">?!</span> Birthday.name'
2016-09-17 09:05:13 +03:00
return <span class="fu">$</span> p <span class="fu">&gt;&lt;</span> b</code></pre></div>
2016-09-14 13:32:21 +03:00
<p>generates left-joined SQL:</p>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode sql"><code class="sourceCode sql"><span class="kw">SELECT</span> <span class="kw">ALL</span> T0.name <span class="kw">AS</span> f0, T0.age <span class="kw">AS</span> f1, T0.family <span class="kw">AS</span> f2,
2016-09-14 13:32:21 +03:00
T1.name <span class="kw">AS</span> f3, T1.day <span class="kw">AS</span> f4
<span class="kw">FROM</span> EXAMPLE.person T0 <span class="kw">LEFT</span> <span class="kw">JOIN</span> EXAMPLE.birthday T1
2016-09-17 09:05:13 +03:00
<span class="kw">ON</span> (T0.name = T1.name)</code></pre></div>
2016-09-14 13:32:21 +03:00
</div><div id="by-examples-aggregation" class="slide section level2">
<h1>By examples / Aggregation</h1>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">agesOfFamilies ::</span> <span class="dt">Relation</span> () (<span class="dt">String</span>, <span class="dt">Maybe</span> <span class="dt">Int32</span>)
2016-09-14 13:32:21 +03:00
agesOfFamilies <span class="fu">=</span> aggregateRelation <span class="fu">$</span> <span class="kw">do</span>
p <span class="ot">&lt;-</span> query person
gFam <span class="ot">&lt;-</span> groupBy <span class="fu">$</span> p <span class="fu">!</span> Person.family' <span class="co">-- Specify grouping key</span>
2016-09-17 09:05:13 +03:00
return <span class="fu">$</span> gFam <span class="fu">&gt;&lt;</span> sum' (p <span class="fu">!</span> Person.age') <span class="co">-- Aggregated results</span></code></pre></div>
2016-09-14 13:32:21 +03:00
<p>sums ages per family.</p>
<p>Generated SQL:</p>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode sql"><code class="sourceCode sql"><span class="kw">SELECT</span> <span class="kw">ALL</span> T0.family <span class="kw">AS</span> f0, <span class="fu">SUM</span>(T0.age) <span class="kw">AS</span> f1
2016-09-14 13:32:21 +03:00
<span class="kw">FROM</span> EXAMPLE.person T0
2016-09-17 09:05:13 +03:00
<span class="kw">GROUP</span> <span class="kw">BY</span> T0.family</code></pre></div>
2016-09-14 13:32:21 +03:00
</div><div id="by-examples-restriction" class="slide section level2">
<h1>By examples / Restriction</h1>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">sameBirthdayHeisei' ::</span> <span class="dt">Relation</span> () (<span class="dt">Day</span>, <span class="dt">Int64</span>)
2016-09-14 13:32:21 +03:00
sameBirthdayHeisei' <span class="fu">=</span> aggregateRelation <span class="fu">$</span> <span class="kw">do</span>
p <span class="ot">&lt;-</span> query person
b <span class="ot">&lt;-</span> query birthday
on <span class="fu">$</span> p <span class="fu">!</span> Person.name' <span class="fu">.=.</span> b <span class="fu">!</span> Birthday.name'
wheres <span class="fu">$</span>
b <span class="fu">!</span> Birthday.day' <span class="fu">.&gt;=.</span> value (fromGregorian <span class="dv">1989</span> <span class="dv">1</span> <span class="dv">8</span>)
gbd <span class="ot">&lt;-</span> groupBy <span class="fu">$</span> b <span class="fu">!</span> Birthday.day'
having <span class="fu">$</span> count (p <span class="fu">!</span> Person.name') <span class="fu">.&gt;.</span> value (<span class="dv">1</span><span class="ot"> ::</span> <span class="dt">Int64</span>)
2016-09-17 09:05:13 +03:00
return <span class="fu">$</span> gbd <span class="fu">&gt;&lt;</span> count (p <span class="fu">!</span> Person.name')</code></pre></div>
2016-09-14 13:32:21 +03:00
<p>counts people with the same birthday, who were born in the Heisei period.</p>
<p>Generated SQL:</p>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode sql"><code class="sourceCode sql"><span class="kw">SELECT</span> <span class="kw">ALL</span> T1.day <span class="kw">AS</span> f0, <span class="fu">COUNT</span>(T0.name) <span class="kw">AS</span> f1
2016-09-14 13:32:21 +03:00
<span class="kw">FROM</span> EXAMPLE.person T0 <span class="kw">INNER</span> <span class="kw">JOIN</span> EXAMPLE.birthday T1
<span class="kw">ON</span> (T0.name = T1.name)
<span class="kw">WHERE</span> (T1.day &gt;= <span class="dt">DATE</span> <span class="st">'1989-01-08'</span>)
<span class="kw">GROUP</span> <span class="kw">BY</span> T1.day
2016-09-17 09:05:13 +03:00
<span class="kw">HAVING</span> (<span class="fu">COUNT</span>(T0.name) &gt; <span class="dv">1</span>)</code></pre></div>
2016-09-14 13:32:21 +03:00
</div><div id="by-examples-restriction---let" class="slide section level2">
<h1>By examples / Restriction - let</h1>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">sameBirthdayHeisei ::</span> <span class="dt">Relation</span> () (<span class="dt">Day</span>, <span class="dt">Int64</span>)
2016-09-14 13:32:21 +03:00
sameBirthdayHeisei <span class="fu">=</span> aggregateRelation <span class="fu">$</span> <span class="kw">do</span>
p <span class="ot">&lt;-</span> query person
b <span class="ot">&lt;-</span> query birthday
on <span class="fu">$</span> p <span class="fu">!</span> Person.name' <span class="fu">.=.</span> b <span class="fu">!</span> Birthday.name'
<span class="kw">let</span> birthDay <span class="fu">=</span> b <span class="fu">!</span> Birthday.day'
wheres <span class="fu">$</span> birthDay <span class="fu">.&gt;=.</span> value (fromGregorian <span class="dv">1989</span> <span class="dv">1</span> <span class="dv">8</span>)
gbd <span class="ot">&lt;-</span> groupBy birthDay
<span class="kw">let</span> personCount <span class="fu">=</span> count <span class="fu">$</span> p <span class="fu">!</span> Person.name'
having <span class="fu">$</span> personCount <span class="fu">.&gt;.</span> value <span class="dv">1</span>
2016-09-17 09:05:13 +03:00
return <span class="fu">$</span> gbd <span class="fu">&gt;&lt;</span> personCount</code></pre></div>
2016-09-14 13:32:21 +03:00
</div><div id="by-examples-ordering" class="slide section level2">
<h1>By examples / Ordering</h1>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">personAndBirthdayO ::</span> <span class="dt">Relation</span> () (<span class="dt">Person</span>, <span class="dt">Birthday</span>)
2016-09-14 13:32:21 +03:00
personAndBirthdayO <span class="fu">=</span> relation <span class="fu">$</span> <span class="kw">do</span>
p <span class="ot">&lt;-</span> query person
b <span class="ot">&lt;-</span> query birthday
on <span class="fu">$</span> p <span class="fu">!</span> Person.name' <span class="fu">.=.</span> b <span class="fu">!</span> Birthday.name'
orderBy (b <span class="fu">!</span> Birthday.day') <span class="dt">Asc</span> <span class="co">-- Specify ordering key</span>
orderBy (p <span class="fu">!</span> Person.name') <span class="dt">Asc</span>
2016-09-17 09:05:13 +03:00
return <span class="fu">$</span> p <span class="fu">&gt;&lt;</span> b</code></pre></div>
2016-09-14 13:32:21 +03:00
<p>orders by birthday and then name:</p>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode sql"><code class="sourceCode sql"><span class="kw">SELECT</span> <span class="kw">ALL</span> T0.name <span class="kw">AS</span> f0, T0.age <span class="kw">AS</span> f1, T0.family <span class="kw">AS</span> f2,
2016-09-14 13:32:21 +03:00
T1.name <span class="kw">AS</span> f3, T1.day <span class="kw">AS</span> f4
<span class="kw">FROM</span> EXAMPLE.person T0 <span class="kw">INNER</span> <span class="kw">JOIN</span> EXAMPLE.birthday T1
<span class="kw">ON</span> (T0.name = T1.name)
2016-09-17 09:05:13 +03:00
<span class="kw">ORDER</span> <span class="kw">BY</span> T1.day <span class="kw">ASC</span>, T0.name <span class="kw">ASC</span></code></pre></div>
2016-09-14 13:32:21 +03:00
</div><div id="by-examples-placeholders" class="slide section level2">
<h1>By examples / Placeholders</h1>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">specifyPerson ::</span> <span class="dt">Relation</span> <span class="dt">String</span> (<span class="dt">Person</span>, <span class="dt">Birthday</span>)
2016-09-14 13:32:21 +03:00
specifyPerson <span class="fu">=</span> relation' <span class="fu">$</span> <span class="kw">do</span>
pb <span class="ot">&lt;-</span> query personAndBirthday <span class="co">-- Re-use predefined</span>
(ph, ()) <span class="ot">&lt;-</span> placeholder
(\ph' <span class="ot">-&gt;</span> wheres <span class="fu">$</span> pb <span class="fu">!</span> fst' <span class="fu">!</span> Person.name' <span class="fu">.=.</span> ph')
2016-09-17 09:05:13 +03:00
return (ph, pb)</code></pre></div>
2016-09-14 13:32:21 +03:00
<p>specifies a person name using a placeholder:</p>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode sql"><code class="sourceCode sql"><span class="kw">SELECT</span> <span class="kw">ALL</span> T2.f0 <span class="kw">AS</span> f0, T2.f1 <span class="kw">AS</span> f1, T2.f2 <span class="kw">AS</span> f2,
2016-09-14 13:32:21 +03:00
T2.f3 <span class="kw">AS</span> f3, T2.f4 <span class="kw">AS</span> f4
<span class="kw">FROM</span> (<span class="kw">SELECT</span> <span class="kw">ALL</span> T0.name <span class="kw">AS</span> f0, T0.age <span class="kw">AS</span> f1, T0.family <span class="kw">AS</span> f2,
T1.name <span class="kw">AS</span> f3, T1.day <span class="kw">AS</span> f4
<span class="kw">FROM</span> EXAMPLE.person T0 <span class="kw">INNER</span> <span class="kw">JOIN</span>
EXAMPLE.birthday T1
<span class="kw">ON</span> (T0.name = T1.name)) T2
2016-09-17 09:05:13 +03:00
<span class="kw">WHERE</span> (T2.f0 = ?)</code></pre></div>
2016-09-14 13:32:21 +03:00
</div><div id="by-examples-window-function" class="slide section level2">
<h1>By examples / Window function</h1>
<p>Building windows:</p>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">ageRankOfFamilies ::</span> <span class="dt">Relation</span> () ((<span class="dt">Int64</span>, <span class="dt">String</span>), <span class="dt">Int32</span>)
2016-09-14 13:32:21 +03:00
ageRankOfFamilies <span class="fu">=</span> relation <span class="fu">$</span> <span class="kw">do</span>
my <span class="ot">&lt;-</span> query myTable
return <span class="fu">$</span>
rank <span class="ot">`over`</span> <span class="kw">do</span>
partitionBy <span class="fu">$</span> my <span class="fu">!</span> family' <span class="co">-- Monad to build window</span>
orderBy (my <span class="fu">!</span> age') <span class="dt">Desc</span>
<span class="fu">&gt;&lt;</span>
2016-09-17 09:05:13 +03:00
my <span class="fu">!</span> family' <span class="fu">&gt;&lt;</span> my <span class="fu">!</span> age'</code></pre></div>
2016-09-14 13:32:21 +03:00
<p>age ranking per family:</p>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode sql"><code class="sourceCode sql"><span class="kw">SELECT</span> <span class="kw">ALL</span>
2016-09-14 13:32:21 +03:00
<span class="fu">RANK</span>() <span class="kw">OVER</span> (<span class="kw">PARTITION</span> <span class="kw">BY</span> T0.family
<span class="kw">ORDER</span> <span class="kw">BY</span> T0.age <span class="kw">DESC</span>) <span class="kw">AS</span> f0,
T0.family <span class="kw">AS</span> f1, T0.age <span class="kw">AS</span> f2
2016-09-17 09:05:13 +03:00
<span class="kw">FROM</span> PUBLIC.my_table T0</code></pre></div>
2016-09-16 15:10:55 +03:00
</div><div id="demo" class="slide section level2">
<h1>Demo</h1>
2016-09-16 15:22:28 +03:00
<ul>
<li><p>expansion of Template Haskell</p></li>
<li><p>aggregation type check</p></li>
</ul>
2016-09-16 15:10:55 +03:00
</div><div id="conclusion" class="slide section level2">
<h1>Conclusion</h1>
<ul>
<li>Composable
<ul>
<li>Haskell expressions in HRR DSL bound to variables are reusable.</li>
</ul></li>
<li>Type Safety
<ul>
<li>Statically type checking makes composition of small expressions safer.</li>
</ul></li>
</ul>
</div><div id="question" class="slide section level2">
<h1>Question</h1>
2016-09-14 13:32:21 +03:00
</div>
<div id="structure" class="titleslide slide section level1"><h1>Structure</h1></div><div id="structure-concepts" class="slide section level2">
<h1>Structure / Concepts</h1>
<p>A simple and useful method:</p>
<ul>
<li>Untype and accumulate from typeful DSL terms into a state monad context</li>
<li>Typeful result (Phantom context and Phantom result type)</li>
</ul>
</div><div id="structure-monad-stack" class="slide section level2">
<h1>Structure / Monad Stack</h1>
<p>Relational Record's query-building DSL accumulates various context in a state or writer monad context stack.</p>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode sql"><code class="sourceCode sql"> <span class="kw">SELECT</span> ...
2016-09-14 13:32:21 +03:00
<span class="kw">FROM</span> ... <span class="co">-- State , join product tree</span>
<span class="kw">WHERE</span> ... <span class="co">-- Writer, restrictions terms monoid</span>
<span class="kw">GROUP</span> <span class="kw">BY</span> ... <span class="co">-- Writer, aggregate terms monoid</span>
<span class="kw">HAVING</span> ... <span class="co">-- Writer, restrictions terms monoid</span>
2016-09-17 09:05:13 +03:00
<span class="kw">ORDER</span> <span class="kw">BY</span> ... <span class="co">-- Writer, ordering key and spec monoid</span></code></pre></div>
2016-09-14 13:32:21 +03:00
</div><div id="structure-join-product" class="slide section level2">
<h1>Structure / Join Product</h1>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">query ::</span> (<span class="dt">MonadQualify</span> <span class="dt">ConfigureQuery</span> m, <span class="dt">MonadQuery</span> m)
2016-09-14 13:32:21 +03:00
<span class="ot">=&gt;</span> <span class="dt">Relation</span> () r
<span class="ot">-&gt;</span> m (<span class="dt">Projection</span> <span class="dt">Flat</span> r)
<span class="co">-- Used for outer join</span>
<span class="ot">queryMaybe ::</span> (<span class="dt">MonadQualify</span> <span class="dt">ConfigureQuery</span> m, <span class="dt">MonadQuery</span> m)
<span class="ot">=&gt;</span> <span class="dt">Relation</span> () r
<span class="ot">-&gt;</span> m (<span class="dt">Projection</span> <span class="dt">Flat</span> (<span class="dt">Maybe</span> r))
2016-09-17 09:05:13 +03:00
<span class="ot">on ::</span> <span class="dt">MonadQuery</span> m <span class="ot">=&gt;</span> <span class="dt">Projection</span> <span class="dt">Flat</span> (<span class="dt">Maybe</span> <span class="dt">Bool</span>) <span class="ot">-&gt;</span> m ()</code></pre></div>
2016-09-14 13:32:21 +03:00
<p>'query' and 'queryMaybe' return a record Projection result corresponding table forms.</p>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode sql"><code class="sourceCode sql"><span class="kw">SELECT</span> .. <span class="kw">FROM</span> ...
2016-09-14 13:32:21 +03:00
<span class="co">-- Accumulating uniquely qualified</span>
<span class="co">-- ( like 'as T0', 'as T1' ... )</span>
2016-09-17 09:05:13 +03:00
<span class="co">-- table forms of SQL FROM clause</span></code></pre></div>
2016-09-14 13:32:21 +03:00
</div><div id="structure-aggregation" class="slide section level2">
<h1>Structure / Aggregation</h1>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">groupBy ::</span> <span class="dt">MonadAggregate</span> m
2016-09-14 13:32:21 +03:00
<span class="ot">=&gt;</span> <span class="dt">Projection</span> <span class="dt">Flat</span> r
<span class="co">-- ^ Projection to add into group by</span>
<span class="ot">-&gt;</span> m (<span class="dt">Projection</span> <span class="dt">Aggregated</span> r)
<span class="co">-- ^ Result context and aggregated projection</span>
<span class="ot">count ::</span> <span class="dt">Projection</span> <span class="dt">Flat</span> a <span class="ot">-&gt;</span> <span class="dt">Projection</span> <span class="dt">Aggregated</span> <span class="dt">Int64</span>
<span class="ot">max' ::</span> <span class="dt">Ord</span> a
2016-09-17 09:05:13 +03:00
<span class="ot">=&gt;</span> <span class="dt">Projection</span> <span class="dt">Flat</span> a <span class="ot">-&gt;</span> <span class="dt">Projection</span> <span class="dt">Aggregated</span> (<span class="dt">Maybe</span> a)</code></pre></div>
2016-09-14 13:32:21 +03:00
<p>'groupBy' can be used under only 'MonadAggregate' monad constraint, stronger than 'MonadQuery'.</p>
<p>'groupBy' returns a Projection value with an Aggregated context type:</p>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode sql"><code class="sourceCode sql"><span class="kw">SELECT</span> .. <span class="kw">GROUP</span> <span class="kw">BY</span> ...
2016-09-14 13:32:21 +03:00
<span class="co">-- Accumulating keys</span>
2016-09-17 09:05:13 +03:00
<span class="co">-- of SQL GROUP BY clause</span></code></pre></div>
2016-09-14 13:32:21 +03:00
</div><div id="structure-restriction-where" class="slide section level2">
<h1>Structure / Restriction / WHERE</h1>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">restrict ::</span> <span class="dt">MonadRestrict</span> c m
2016-09-14 13:32:21 +03:00
<span class="ot">=&gt;</span> <span class="dt">Projection</span> c (<span class="dt">Maybe</span> <span class="dt">Bool</span>)
<span class="ot">-&gt;</span> m ()
<span class="ot">wheres ::</span> <span class="dt">MonadRestrict</span> <span class="dt">Flat</span> m
<span class="ot">=&gt;</span> <span class="dt">Projection</span> <span class="dt">Flat</span> (<span class="dt">Maybe</span> <span class="dt">Bool</span>)
2016-09-17 09:05:13 +03:00
<span class="ot">-&gt;</span> m ()</code></pre></div>
2016-09-14 13:32:21 +03:00
<p>adds a WHERE clause restriction:</p>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode sql"><code class="sourceCode sql"><span class="kw">SELECT</span> .. <span class="kw">WHERE</span> x <span class="kw">AND</span> y <span class="kw">AND</span> ...
2016-09-14 13:32:21 +03:00
<span class="co">-- Accumulating AND predicates</span>
2016-09-17 09:05:13 +03:00
<span class="co">-- of SQL WHERE clause</span></code></pre></div>
2016-09-14 13:32:21 +03:00
</div><div id="structure-restriction-having" class="slide section level2">
<h1>Structure / Restriction / HAVING</h1>
2016-09-17 09:05:13 +03:00
<div class="sourceCode"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">restrict ::</span> <span class="dt">MonadRestrict</span> c m
2016-09-14 13:32:21 +03:00
<span class="ot">=&gt;</span> <span class="dt">Projection</span> c (<span class="dt">Maybe</span> <span class="dt">Bool</span>)
<span class="ot">-&gt;</span> m ()
<span class="ot">having ::</span> <span class="dt">MonadRestrict</span> <span class="dt">Aggregated</span> m
<span class="ot">=&gt;</span> <span class="dt">Projection</span> <span class="dt">Aggregated</span> (<span class="dt">Maybe</span> <span class="dt">Bool</span>)
2016-09-17 09:05:13 +03:00
<span class="ot">-&gt;</span> m ()</code></pre></div>
2016-09-14 13:32:21 +03:00
</div>
</div>
</body>
</html>