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 > < -< / 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" > < -< / span > person, b < span class = "ot" > < -< / 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" > < -< / span > person; b < span class = "ot" > < -< / 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" > < -< / span > person; b < span class = "ot" > < -< / 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" > < -< / span > query person
b < span class = "ot" > < -< / 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" > > < < / 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" > < -< / span > query person
b < span class = "ot" > < -< / 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" > > < < / 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" > < -< / span > query person
b < span class = "ot" > < -< / 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" > > < < / 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" > < -< / span > query person
gFam < span class = "ot" > < -< / 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" > > < < / 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" > < -< / span > query person
b < span class = "ot" > < -< / 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" > .> =.< / span > value (fromGregorian < span class = "dv" > 1989< / span > < span class = "dv" > 1< / span > < span class = "dv" > 8< / span > )
gbd < span class = "ot" > < -< / 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" > .> .< / 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" > > < < / 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 > = < 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) > < 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" > < -< / span > query person
b < span class = "ot" > < -< / 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" > .> =.< / span > value (fromGregorian < span class = "dv" > 1989< / span > < span class = "dv" > 1< / span > < span class = "dv" > 8< / span > )
gbd < span class = "ot" > < -< / 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" > .> .< / span > value < span class = "dv" > 1< / span >
2016-09-17 09:05:13 +03:00
return < span class = "fu" > $< / span > gbd < span class = "fu" > > < < / 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" > < -< / span > query person
b < span class = "ot" > < -< / 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" > > < < / 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" > < -< / span > query personAndBirthday < span class = "co" > -- Re-use predefined< / span >
(ph, ()) < span class = "ot" > < -< / span > placeholder
(\ph' < span class = "ot" > -> < / 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" > < -< / 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" > > < < / span >
2016-09-17 09:05:13 +03:00
my < span class = "fu" > !< / span > family' < span class = "fu" > > < < / 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" > => < / span > < span class = "dt" > Relation< / span > () r
< span class = "ot" > -> < / 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" > => < / span > < span class = "dt" > Relation< / span > () r
< span class = "ot" > -> < / 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" > => < / span > < span class = "dt" > Projection< / span > < span class = "dt" > Flat< / span > (< span class = "dt" > Maybe< / span > < span class = "dt" > Bool< / span > ) < span class = "ot" > -> < / 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" > => < / 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" > -> < / 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" > -> < / 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" > => < / span > < span class = "dt" > Projection< / span > < span class = "dt" > Flat< / span > a < span class = "ot" > -> < / 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" > => < / span > < span class = "dt" > Projection< / span > c (< span class = "dt" > Maybe< / span > < span class = "dt" > Bool< / span > )
< span class = "ot" > -> < / span > m ()
< span class = "ot" > wheres ::< / span > < span class = "dt" > MonadRestrict< / span > < span class = "dt" > Flat< / span > m
< span class = "ot" > => < / 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" > -> < / 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" > => < / span > < span class = "dt" > Projection< / span > c (< span class = "dt" > Maybe< / span > < span class = "dt" > Bool< / span > )
< span class = "ot" > -> < / span > m ()
< span class = "ot" > having ::< / span > < span class = "dt" > MonadRestrict< / span > < span class = "dt" > Aggregated< / span > m
< span class = "ot" > => < / 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" > -> < / span > m ()< / code > < / pre > < / div >
2016-09-14 13:32:21 +03:00
< / div >
< / div >
< / body >
< / html >