git.iko.soy/rowtype-yoga/purescript-yoga-postgres
on main help sign in
Add PostgreSQL koans
commit421b53b264ddf36f8baccdbbb682765365da0a4b authorMark <mark.eibes@gmail.com> dateSun 12 Jul 2026, 10:43 (3 months ago) parent35e8250
1 file changed+106
KOANS.md+106
KOANS.mdnew file+106
@@ -0,0 +1,106 @@
1+# PostgreSQL Koans
2+
3+Small “will this compile?” puzzles from the typed query builder. Each prompt is short enough to adapt into a post; keep the answer for a follow-up.
4+
5+## Koan 1 — GROUP BY
6+
7+### Prompt
8+
9+PureScript knows both the table schema and selected columns. Should this compile?
10+
11+```purescript
12+from users
13+ # select @"name, email"
14+ # groupBy @"name"
15+```
16+
17+The inferred result row is:
18+
19+```purescript
20+(name :: String, email :: String)
21+```
22+
23+PostgreSQL koan: which column betrays us only at runtime?
24+
25+### Answer
26+
27+It currently compiles and renders:
28+
29+```sql
30+SELECT name, email FROM users GROUP BY name
31+```
32+
33+PostgreSQL rejects `email`: every selected, non-aggregated expression must participate in the grouping. The type-level parser validates column existence but does not yet relate the SELECT expressions to GROUP BY.
34+
35+## Koan 2 — Nothing to insert
36+
37+### Prompt
38+
39+Every column has a database-generated value:
40+
41+```purescript
42+type Config = Table "config"
43+ ( id :: Int # PrimaryKey # AutoIncrement
44+ , active :: Boolean # Default True
45+ , score :: Int # Default 0
46+ )
47+
48+from (Proxy :: Proxy Config) # insert {}
49+```
50+
51+The empty record is exactly the right input. What SQL should it produce?
52+
53+### Answer
54+
55+PostgreSQL expects:
56+
57+```sql
58+INSERT INTO config DEFAULT VALUES
59+```
60+
61+The builder currently emits invalid SQL:
62+
63+```sql
64+INSERT INTO config () VALUES ()
65+```
66+
67+The input type is correct; the zero-column rendering branch is not.
68+
69+## Koan 3 — One means how many?
70+
71+### Prompt
72+
73+What should `executeSqlOne` return when a query unexpectedly produces two rows?
74+
75+```purescript
76+executeSqlOne query params connection
77+ :: Aff (Either String (Maybe User))
78+```
79+
80+Choose one:
81+
82+1. `Left "expected at most one row"`
83+2. `Right (Just firstRow)`
84+3. `Right Nothing`
85+
86+### Answer
87+
88+Today it returns `Right Nothing`. The implementation maps both zero rows and multiple rows to `Nothing`, so “not found” and “cardinality bug” are indistinguishable. A one-row API should preserve that invariant in its result or error channel.
89+
90+## Koan 4 — Half a second
91+
92+### Prompt
93+
94+PostgreSQL returns this `TIME` value:
95+
96+```text
97+14:30:00.5
98+```
99+
100+How many milliseconds does the PureScript decoder put in `PGTime`?
101+
102+### Answer
103+
104+Today: `5`. Correct: `500`.
105+
106+The decoder parses the fractional digits directly as milliseconds. PostgreSQL fractions are decimal fractions of a second, so `.5`, `.50`, and `.500` must all decode to 500 milliseconds; longer fractions also need an explicit rounding or truncation rule.