Mercurial > urweb
comparison doc/manual.tex @ 786:fc3db9e0f0f6
Revised query types
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Tue, 05 May 2009 13:21:26 -0400 |
parents | fe63a08cbb91 |
children | c9c76aeaae64 |
comparison
equal
deleted
inserted
replaced
785:fe63a08cbb91 | 786:fc3db9e0f0f6 |
---|---|
1195 | 1195 |
1196 \subsection{HTTP} | 1196 \subsection{HTTP} |
1197 | 1197 |
1198 There are transactions for reading an HTTP header by name and for getting and setting strongly-typed cookies. Cookies may only be created by the $\mt{cookie}$ declaration form, ensuring that they be named consistently based on module structure. | 1198 There are transactions for reading an HTTP header by name and for getting and setting strongly-typed cookies. Cookies may only be created by the $\mt{cookie}$ declaration form, ensuring that they be named consistently based on module structure. |
1199 $$\begin{array}{l} | 1199 $$\begin{array}{l} |
1200 \mt{val} \; \mt{requestHeader} : \mt{string} \to \mt{transaction} \; (\mt{option} \; \mt{string}) \\ | 1200 \mt{val} \; \mt{requestHeader} : \mt{string} \to \mt{transaction} \; (\mt{option} \; \mt{string}) \\ |
1201 \\ | 1201 \\ |
1202 \mt{con} \; \mt{http\_cookie} :: \mt{Type} \to \mt{Type} \\ | 1202 \mt{con} \; \mt{http\_cookie} :: \mt{Type} \to \mt{Type} \\ |
1203 \mt{val} \; \mt{getCookie} : \mt{t} ::: \mt{Type} \to \mt{http\_cookie} \; \mt{t} \to \mt{transaction} \; (\mt{option} \; \mt{t}) \\ | 1203 \mt{val} \; \mt{getCookie} : \mt{t} ::: \mt{Type} \to \mt{http\_cookie} \; \mt{t} \to \mt{transaction} \; (\mt{option} \; \mt{t}) \\ |
1204 \mt{val} \; \mt{setCookie} : \mt{t} ::: \mt{Type} \to \mt{http\_cookie} \; \mt{t} \to \mt{t} \to \mt{transaction} \; \mt{unit} | 1204 \mt{val} \; \mt{setCookie} : \mt{t} ::: \mt{Type} \to \mt{http\_cookie} \; \mt{t} \to \mt{t} \to \mt{transaction} \; \mt{unit} |
1205 \end{array}$$ | |
1206 | |
1207 There are also an abstract $\mt{url}$ type and functions for converting to it, based on the policy defined by \texttt{[allow|deny] url} directives in the project file. | |
1208 $$\begin{array}{l} | |
1209 \mt{type} \; \mt{url} \\ | |
1210 \mt{val} \; \mt{bless} : \mt{string} \to \mt{url} \\ | |
1211 \mt{val} \; \mt{checkUrl} : \mt{string} \to \mt{option} \; \mt{url} | |
1212 \end{array}$$ | |
1213 $\mt{bless}$ raises a runtime error if the string passed to it fails the URL policy. | |
1214 | |
1215 It's possible for pages to return files of arbitrary MIME types. A file can be input from the user using this data type, along with the $\mt{upload}$ form tag. | |
1216 $$\begin{array}{l} | |
1217 \mt{type} \; \mt{file} \\ | |
1218 \mt{val} \; \mt{fileName} : \mt{file} \to \mt{option} \; \mt{string} \\ | |
1219 \mt{val} \; \mt{fileMimeType} : \mt{file} \to \mt{string} \\ | |
1220 \mt{val} \; \mt{fileData} : \mt{file} \to \mt{blob} | |
1221 \end{array}$$ | |
1222 | |
1223 A blob can be extracted from a file and returned as the page result. There are bless and check functions for MIME types analogous to those for URLs. | |
1224 $$\begin{array}{l} | |
1225 \mt{type} \; \mt{mimeType} \\ | |
1226 \mt{val} \; \mt{blessMime} : \mt{string} \to \mt{mimeType} \\ | |
1227 \mt{val} \; \mt{checkMime} : \mt{string} \to \mt{option} \; \mt{mimeType} \\ | |
1228 \mt{val} \; \mt{returnBlob} : \mt{t} ::: \mt{Type} \to \mt{blob} \to \mt{mimeType} \to \mt{transaction} \; \mt{t} | |
1205 \end{array}$$ | 1229 \end{array}$$ |
1206 | 1230 |
1207 \subsection{SQL} | 1231 \subsection{SQL} |
1208 | 1232 |
1209 The fundamental unit of interest in the embedding of SQL is tables, described by a type family and creatable only via the $\mt{table}$ declaration form. | 1233 The fundamental unit of interest in the embedding of SQL is tables, described by a type family and creatable only via the $\mt{table}$ declaration form. |
1356 $$\begin{array}{l} | 1380 $$\begin{array}{l} |
1357 \mt{val} \; \mt{sql\_query1} : \mt{tables} ::: \{\{\mt{Type}\}\} \\ | 1381 \mt{val} \; \mt{sql\_query1} : \mt{tables} ::: \{\{\mt{Type}\}\} \\ |
1358 \hspace{.1in} \to \mt{grouped} ::: \{\{\mt{Type}\}\} \\ | 1382 \hspace{.1in} \to \mt{grouped} ::: \{\{\mt{Type}\}\} \\ |
1359 \hspace{.1in} \to \mt{selectedFields} ::: \{\{\mt{Type}\}\} \\ | 1383 \hspace{.1in} \to \mt{selectedFields} ::: \{\{\mt{Type}\}\} \\ |
1360 \hspace{.1in} \to \mt{selectedExps} ::: \{\mt{Type}\} \\ | 1384 \hspace{.1in} \to \mt{selectedExps} ::: \{\mt{Type}\} \\ |
1361 \hspace{.1in} \to \{\mt{From} : \$(\mt{map} \; \mt{sql\_table} \; \mt{tables}), \\ | 1385 \hspace{.1in} \to \{\mt{From} : \mt{sql\_from\_items} \; \mt{tables}, \\ |
1362 \hspace{.2in} \mt{Where} : \mt{sql\_exp} \; \mt{tables} \; [] \; [] \; \mt{bool}, \\ | 1386 \hspace{.2in} \mt{Where} : \mt{sql\_exp} \; \mt{tables} \; [] \; [] \; \mt{bool}, \\ |
1363 \hspace{.2in} \mt{GroupBy} : \mt{sql\_subset} \; \mt{tables} \; \mt{grouped}, \\ | 1387 \hspace{.2in} \mt{GroupBy} : \mt{sql\_subset} \; \mt{tables} \; \mt{grouped}, \\ |
1364 \hspace{.2in} \mt{Having} : \mt{sql\_exp} \; \mt{grouped} \; \mt{tables} \; [] \; \mt{bool}, \\ | 1388 \hspace{.2in} \mt{Having} : \mt{sql\_exp} \; \mt{grouped} \; \mt{tables} \; [] \; \mt{bool}, \\ |
1365 \hspace{.2in} \mt{SelectFields} : \mt{sql\_subset} \; \mt{grouped} \; \mt{selectedFields}, \\ | 1389 \hspace{.2in} \mt{SelectFields} : \mt{sql\_subset} \; \mt{grouped} \; \mt{selectedFields}, \\ |
1366 \hspace{.2in} \mt {SelectExps} : \$(\mt{map} \; (\mt{sql\_exp} \; \mt{grouped} \; \mt{tables} \; []) \; \mt{selectedExps}) \} \\ | 1390 \hspace{.2in} \mt {SelectExps} : \$(\mt{map} \; (\mt{sql\_exp} \; \mt{grouped} \; \mt{tables} \; []) \; \mt{selectedExps}) \} \\ |
1397 \hspace{.1in} \to \mt{sql\_exp} \; \mt{tabs} \; \mt{agg} \; ([\mt{nm} = \mt{t}] \rc \mt{rest}) \; \mt{t} | 1421 \hspace{.1in} \to \mt{sql\_exp} \; \mt{tabs} \; \mt{agg} \; ([\mt{nm} = \mt{t}] \rc \mt{rest}) \; \mt{t} |
1398 \end{array}$$ | 1422 \end{array}$$ |
1399 | 1423 |
1400 Ur values of appropriate types may be injected into SQL expressions. | 1424 Ur values of appropriate types may be injected into SQL expressions. |
1401 $$\begin{array}{l} | 1425 $$\begin{array}{l} |
1426 \mt{class} \; \mt{sql\_injectable\_prim} \\ | |
1427 \mt{val} \; \mt{sql\_bool} : \mt{sql\_injectable\_prim} \; \mt{bool} \\ | |
1428 \mt{val} \; \mt{sql\_int} : \mt{sql\_injectable\_prim} \; \mt{int} \\ | |
1429 \mt{val} \; \mt{sql\_float} : \mt{sql\_injectable\_prim} \; \mt{float} \\ | |
1430 \mt{val} \; \mt{sql\_string} : \mt{sql\_injectable\_prim} \; \mt{string} \\ | |
1431 \mt{val} \; \mt{sql\_time} : \mt{sql\_injectable\_prim} \; \mt{time} \\ | |
1432 \mt{val} \; \mt{sql\_blob} : \mt{sql\_injectable\_prim} \; \mt{blob} \\ | |
1433 \mt{val} \; \mt{sql\_channel} : \mt{t} ::: \mt{Type} \to \mt{sql\_injectable\_prim} \; (\mt{channel} \; \mt{t}) \\ | |
1434 \mt{val} \; \mt{sql\_client} : \mt{sql\_injectable\_prim} \; \mt{client} \\ | |
1435 \\ | |
1402 \mt{class} \; \mt{sql\_injectable} \\ | 1436 \mt{class} \; \mt{sql\_injectable} \\ |
1403 \mt{val} \; \mt{sql\_bool} : \mt{sql\_injectable} \; \mt{bool} \\ | 1437 \mt{val} \; \mt{sql\_prim} : \mt{t} ::: \mt{Type} \to \mt{sql\_injectable\_prim} \; \mt{t} \to \mt{sql\_injectable} \; \mt{t} \\ |
1404 \mt{val} \; \mt{sql\_int} : \mt{sql\_injectable} \; \mt{int} \\ | 1438 \mt{val} \; \mt{sql\_option\_prim} : \mt{t} ::: \mt{Type} \to \mt{sql\_injectable\_prim} \; \mt{t} \to \mt{sql\_injectable} \; (\mt{option} \; \mt{t}) \\ |
1405 \mt{val} \; \mt{sql\_float} : \mt{sql\_injectable} \; \mt{float} \\ | 1439 \\ |
1406 \mt{val} \; \mt{sql\_string} : \mt{sql\_injectable} \; \mt{string} \\ | |
1407 \mt{val} \; \mt{sql\_time} : \mt{sql\_injectable} \; \mt{time} \\ | |
1408 \mt{val} \; \mt{sql\_option\_bool} : \mt{sql\_injectable} \; (\mt{option} \; \mt{bool}) \\ | |
1409 \mt{val} \; \mt{sql\_option\_int} : \mt{sql\_injectable} \; (\mt{option} \; \mt{int}) \\ | |
1410 \mt{val} \; \mt{sql\_option\_float} : \mt{sql\_injectable} \; (\mt{option} \; \mt{float}) \\ | |
1411 \mt{val} \; \mt{sql\_option\_string} : \mt{sql\_injectable} \; (\mt{option} \; \mt{string}) \\ | |
1412 \mt{val} \; \mt{sql\_option\_time} : \mt{sql\_injectable} \; (\mt{option} \; \mt{time}) \\ | |
1413 \mt{val} \; \mt{sql\_inject} : \mt{tables} ::: \{\{\mt{Type}\}\} \to \mt{agg} ::: \{\{\mt{Type}\}\} \to \mt{exps} ::: \{\mt{Type}\} \to \mt{t} ::: \mt{Type} \to \mt{sql\_injectable} \; \mt{t} \\ | 1440 \mt{val} \; \mt{sql\_inject} : \mt{tables} ::: \{\{\mt{Type}\}\} \to \mt{agg} ::: \{\{\mt{Type}\}\} \to \mt{exps} ::: \{\mt{Type}\} \to \mt{t} ::: \mt{Type} \to \mt{sql\_injectable} \; \mt{t} \\ |
1414 \hspace{.1in} \to \mt{t} \to \mt{sql\_exp} \; \mt{tables} \; \mt{agg} \; \mt{exps} \; \mt{t} | 1441 \hspace{.1in} \to \mt{t} \to \mt{sql\_exp} \; \mt{tables} \; \mt{agg} \; \mt{exps} \; \mt{t} |
1415 \end{array}$$ | 1442 \end{array}$$ |
1416 | 1443 |
1417 We have the SQL nullness test, which is necessary because of the strange SQL semantics of equality in the presence of null values. | 1444 We have the SQL nullness test, which is necessary because of the strange SQL semantics of equality in the presence of null values. |
1453 \mt{val} \; \mt{sql\_div} : \mt{t} ::: \mt{Type} \to \mt{sql\_arith} \; \mt{t} \to \mt{sql\_binary} \; \mt{t} \; \mt{t} \; \mt{t} \\ | 1480 \mt{val} \; \mt{sql\_div} : \mt{t} ::: \mt{Type} \to \mt{sql\_arith} \; \mt{t} \to \mt{sql\_binary} \; \mt{t} \; \mt{t} \; \mt{t} \\ |
1454 \mt{val} \; \mt{sql\_mod} : \mt{sql\_binary} \; \mt{int} \; \mt{int} \; \mt{int} | 1481 \mt{val} \; \mt{sql\_mod} : \mt{sql\_binary} \; \mt{int} \; \mt{int} \; \mt{int} |
1455 \end{array}$$ | 1482 \end{array}$$ |
1456 | 1483 |
1457 Finally, we have aggregate functions. The $\mt{COUNT(\ast)}$ syntax is handled specially, since it takes no real argument. The other aggregate functions are placed into a general type family, using constructor classes to restrict usage to properly-typed arguments. The key aspect of the $\mt{sql\_aggregate}$ function's type is the shift of aggregate-function-only fields into unrestricted fields. | 1484 Finally, we have aggregate functions. The $\mt{COUNT(\ast)}$ syntax is handled specially, since it takes no real argument. The other aggregate functions are placed into a general type family, using constructor classes to restrict usage to properly-typed arguments. The key aspect of the $\mt{sql\_aggregate}$ function's type is the shift of aggregate-function-only fields into unrestricted fields. |
1458 | |
1459 $$\begin{array}{l} | 1485 $$\begin{array}{l} |
1460 \mt{val} \; \mt{sql\_count} : \mt{tables} ::: \{\{\mt{Type}\}\} \to \mt{agg} ::: \{\{\mt{Type}\}\} \to \mt{exps} ::: \{\mt{Type}\} \to \mt{sql\_exp} \; \mt{tables} \; \mt{agg} \; \mt{exps} \; \mt{int} | 1486 \mt{val} \; \mt{sql\_count} : \mt{tables} ::: \{\{\mt{Type}\}\} \to \mt{agg} ::: \{\{\mt{Type}\}\} \to \mt{exps} ::: \{\mt{Type}\} \to \mt{sql\_exp} \; \mt{tables} \; \mt{agg} \; \mt{exps} \; \mt{int} |
1461 \end{array}$$ | 1487 \end{array}$$ |
1462 | 1488 |
1463 $$\begin{array}{l} | 1489 $$\begin{array}{l} |
1482 \mt{val} \; \mt{sql\_maxable\_time} : \mt{sql\_maxable} \; \mt{time} \\ | 1508 \mt{val} \; \mt{sql\_maxable\_time} : \mt{sql\_maxable} \; \mt{time} \\ |
1483 \mt{val} \; \mt{sql\_max} : \mt{t} ::: \mt{Type} \to \mt{sql\_maxable} \; \mt{t} \to \mt{sql\_aggregate} \; \mt{t} \\ | 1509 \mt{val} \; \mt{sql\_max} : \mt{t} ::: \mt{Type} \to \mt{sql\_maxable} \; \mt{t} \to \mt{sql\_aggregate} \; \mt{t} \\ |
1484 \mt{val} \; \mt{sql\_min} : \mt{t} ::: \mt{Type} \to \mt{sql\_maxable} \; \mt{t} \to \mt{sql\_aggregate} \; \mt{t} | 1510 \mt{val} \; \mt{sql\_min} : \mt{t} ::: \mt{Type} \to \mt{sql\_maxable} \; \mt{t} \to \mt{sql\_aggregate} \; \mt{t} |
1485 \end{array}$$ | 1511 \end{array}$$ |
1486 | 1512 |
1513 \texttt{FROM} clauses are specified using a type family. | |
1514 $$\begin{array}{l} | |
1515 \mt{con} \; \mt{sql\_from\_items} :: \{\{\mt{Type}\}\} \to \mt{Type} \\ | |
1516 \mt{val} \; \mt{sql\_from\_table} : \mt{t} ::: \mt{Type} \to \mt{fs} ::: \{\mt{Type}\} \to \mt{fieldsOf} \; \mt{t} \; \mt{fs} \to \mt{name} :: \mt{Name} \to \mt{t} \to \mt{sql\_from\_items} \; [\mt{name} = \mt{fs}] \\ | |
1517 \mt{val} \; \mt{sql\_from\_comma} : \mt{tabs1} ::: \{\{\mt{Type}\}\} \to \mt{tabs2} ::: \{\{\mt{Type}\}\} \to [\mt{tabs1} \sim \mt{tabs2}] \\ | |
1518 \hspace{.1in} \Rightarrow \mt{sql\_from\_items} \; \mt{tabs1} \to \mt{sql\_from\_items} \; \mt{tabs2} \\ | |
1519 \hspace{.1in} \to \mt{sql\_from\_items} \; (\mt{tabs1} \rc \mt{tabs2}) \\ | |
1520 \mt{val} \; \mt{sql\_inner\_join} : \mt{tabs1} ::: \{\{\mt{Type}\}\} \to \mt{tabs2} ::: \{\{\mt{Type}\}\} \to [\mt{tabs1} \sim \mt{tabs2}] \\ | |
1521 \hspace{.1in} \Rightarrow \mt{sql\_from\_items} \; \mt{tabs1} \to \mt{sql\_from\_items} \; \mt{tabs2} \\ | |
1522 \hspace{.1in} \to \mt{sql\_exp} \; (\mt{tabs1} \rc \mt{tabs2}) \; [] \; [] \; \mt{bool} \\ | |
1523 \hspace{.1in} \to \mt{sql\_from\_items} \; (\mt{tabs1} \rc \mt{tabs2}) | |
1524 \end{array}$$ | |
1525 | |
1526 Besides these basic cases, outer joins are supported, which requires a type class for turning non-$\mt{option}$ columns into $\mt{option}$ columns. | |
1527 $$\begin{array}{l} | |
1528 \mt{class} \; \mt{nullify} :: \mt{Type} \to \mt{Type} \to \mt{Type} \\ | |
1529 \mt{val} \; \mt{nullify\_option} : \mt{t} ::: \mt{Type} \to \mt{nullify} \; (\mt{option} \; \mt{t}) \; (\mt{option} \; \mt{t}) \\ | |
1530 \mt{val} \; \mt{nullify\_prim} : \mt{t} ::: \mt{Type} \to \mt{sql\_injectable\_prim} \; \mt{t} \to \mt{nullify} \; \mt{t} \; (\mt{option} \; \mt{t}) | |
1531 \end{array}$$ | |
1532 | |
1533 Left, right, and full outer joins can now be expressed using functions that accept records of $\mt{nullify}$ instances. Here, we give only the type for a left join as an example. | |
1534 | |
1535 $$\begin{array}{l} | |
1536 \mt{val} \; \mt{sql\_left\_join} : \mt{tabs1} ::: \{\{\mt{Type}\}\} \to \mt{tabs2} ::: \{\{(\mt{Type} \times \mt{Type})\}\} \to [\mt{tabs1} \sim \mt{tabs2}] \\ | |
1537 \hspace{.1in} \Rightarrow \$(\mt{map} \; (\lambda \mt{r} \Rightarrow \$(\mt{map} \; (\lambda \mt{p} :: (\mt{Type} \times \mt{Type}) \Rightarrow \mt{nullify} \; \mt{p}.1 \; \mt{p}.2) \; \mt{r})) \; \mt{tabs2}) \\ | |
1538 \hspace{.1in} \to \mt{sql\_from\_items} \; \mt{tabs1} \to \mt{sql\_from\_items} \; (\mt{map} \; (\mt{map} \; (\lambda \mt{p} :: (\mt{Type} \times \mt{Type}) \Rightarrow \mt{p}.1)) \; \mt{tabs2}) \\ | |
1539 \hspace{.1in} \to \mt{sql\_exp} \; (\mt{tabs1} \rc \mt{map} \; (\mt{map} \; (\lambda \mt{p} :: (\mt{Type} \times \mt{Type}) \Rightarrow \mt{p}.1)) \; \mt{tabs2}) \; [] \; [] \; \mt{bool} \\ | |
1540 \hspace{.1in} \to \mt{sql\_from\_items} \; (\mt{tabs1} \rc \mt{map} \; (\mt{map} \; (\lambda \mt{p} :: (\mt{Type} \times \mt{Type}) \Rightarrow \mt{p}.2)) \; \mt{tabs2}) | |
1541 \end{array}$$ | |
1542 | |
1487 We wrap up the definition of query syntax with the types used in representing $\mt{ORDER} \; \mt{BY}$, $\mt{LIMIT}$, and $\mt{OFFSET}$ clauses. | 1543 We wrap up the definition of query syntax with the types used in representing $\mt{ORDER} \; \mt{BY}$, $\mt{LIMIT}$, and $\mt{OFFSET}$ clauses. |
1488 $$\begin{array}{l} | 1544 $$\begin{array}{l} |
1489 \mt{type} \; \mt{sql\_direction} \\ | 1545 \mt{type} \; \mt{sql\_direction} \\ |
1490 \mt{val} \; \mt{sql\_asc} : \mt{sql\_direction} \\ | 1546 \mt{val} \; \mt{sql\_asc} : \mt{sql\_direction} \\ |
1491 \mt{val} \; \mt{sql\_desc} : \mt{sql\_direction} \\ | 1547 \mt{val} \; \mt{sql\_desc} : \mt{sql\_direction} \\ |
1666 \section{Ur/Web Syntax Extensions} | 1722 \section{Ur/Web Syntax Extensions} |
1667 | 1723 |
1668 Ur/Web features some syntactic shorthands for building values using the functions from the last section. This section sketches the grammar of those extensions. We write spans of syntax inside brackets to indicate that they are optional. | 1724 Ur/Web features some syntactic shorthands for building values using the functions from the last section. This section sketches the grammar of those extensions. We write spans of syntax inside brackets to indicate that they are optional. |
1669 | 1725 |
1670 \subsection{SQL} | 1726 \subsection{SQL} |
1727 | |
1728 \subsubsection{\label{tables}Table Declarations} | |
1671 | 1729 |
1672 \subsubsection{Queries} | 1730 \subsubsection{Queries} |
1673 | 1731 |
1674 Queries $Q$ are added to the rules for expressions $e$. | 1732 Queries $Q$ are added to the rules for expressions $e$. |
1675 | 1733 |