git.iko.soy/rowtype-yoga/purescript-yoga-postgres
on main help sign in
commit18200e67b70d1bb5a7b966090d69146c3b88b248 authorMark <mark.eibes@gmail.com> dateSun 15 Feb 2026, 14:04 (8 months ago) parentdc6cf88
1 file changed+85−5
src/Yoga/Postgres/Schema.purs+85−5
src/Yoga/Postgres/Schema.purs+85−5
@@ -1251,7 +1251,7 @@ data NoType
12511251class ParseWhere :: Symbol -> Row (Row Type) -> Row Type -> Constraint
12521252class ParseWhere sym tables params | sym tables -> params
12531253
1254−instance ParseWhere "" tables ()
1254+instance Fail (Text "Empty WHERE clause") => ParseWhere "" tables params
12551255else instance
12561256 ( Symbol.Cons h t sym
12571257 , ParseWhereGo h t "" NoType tables RL.Nil outRL
@@ -1671,11 +1671,16 @@ else instance
16711671class ValidateOrderByGo :: Symbol -> Symbol -> Symbol -> Row (Row Type) -> Constraint
16721672class ValidateOrderByGo head tail acc tables
16731673
1674−-- Comma: flush column, continue
1674+-- Leading/double comma: no column before comma
16751675instance
1676+ Fail (Text "Unexpected comma in ORDER BY clause (missing column name)") =>
1677+ ValidateOrderByGo "," tail "" tables
1678+
1679+-- Comma: flush column, continue (non-empty acc)
1680+else instance
16761681 ( FlushOrderByWord acc tables
16771682 , SkipSpaces tail rest
1678− , ValidateOrderBy rest tables
1683+ , ValidateOrderByContinueNonEmpty rest tables
16791684 ) =>
16801685 ValidateOrderByGo "," tail acc tables
16811686
@@ -1689,7 +1694,7 @@ else instance
16891694-- End of string: flush final column
16901695else instance
16911696 ( Symbol.Append acc h acc'
1692− , FlushOrderByWord acc' tables
1697+ , FlushOrderByFinalWord acc' tables
16931698 ) =>
16941699 ValidateOrderByGo h "" acc tables
16951700
@@ -1701,6 +1706,31 @@ else instance
17011706 ) =>
17021707 ValidateOrderByGo h tail acc tables
17031708
1709+-- After comma: reject empty (trailing comma)
1710+class ValidateOrderByContinueNonEmpty :: Symbol -> Row (Row Type) -> Constraint
1711+class ValidateOrderByContinueNonEmpty sym tables
1712+
1713+instance Fail (Text "Trailing comma in ORDER BY clause") => ValidateOrderByContinueNonEmpty "" tables
1714+else instance
1715+ ( Symbol.Cons h t sym
1716+ , ValidateOrderByGo h t "" tables
1717+ ) =>
1718+ ValidateOrderByContinueNonEmpty sym tables
1719+
1720+-- End of string: reject bare modifiers (ASC/DESC without column)
1721+class FlushOrderByFinalWord :: Symbol -> Row (Row Type) -> Constraint
1722+class FlushOrderByFinalWord word tables
1723+
1724+instance Fail (Text "ORDER BY requires at least one column") => FlushOrderByFinalWord "" tables
1725+else instance Fail (Text "ORDER BY requires a column name before ASC/DESC") => FlushOrderByFinalWord "ASC" tables
1726+else instance Fail (Text "ORDER BY requires a column name before ASC/DESC") => FlushOrderByFinalWord "asc" tables
1727+else instance Fail (Text "ORDER BY requires a column name before ASC/DESC") => FlushOrderByFinalWord "DESC" tables
1728+else instance Fail (Text "ORDER BY requires a column name before ASC/DESC") => FlushOrderByFinalWord "desc" tables
1729+else instance Fail (Text "ORDER BY requires a column name before ASC/DESC") => FlushOrderByFinalWord "NULLS" tables
1730+else instance Fail (Text "ORDER BY requires a column name before ASC/DESC") => FlushOrderByFinalWord "FIRST" tables
1731+else instance Fail (Text "ORDER BY requires a column name before ASC/DESC") => FlushOrderByFinalWord "LAST" tables
1732+else instance ResolveColumn word tables typ => FlushOrderByFinalWord word tables
1733+
17041734class FlushOrderByWord :: Symbol -> Row (Row Type) -> Constraint
17051735class FlushOrderByWord word tables
17061736
@@ -2570,16 +2600,66 @@ instance
25702600
25712601instance ParseLimitOffsetParams False name params params
25722602
2603+-- Validate that a Symbol is a non-negative integer (all digits, non-empty)
2604+class ValidateNumericLiteral :: Symbol -> Constraint
2605+class ValidateNumericLiteral sym
2606+
2607+instance
2608+ ( Symbol.Cons h t sym
2609+ , ValidateAllDigits h t
2610+ ) =>
2611+ ValidateNumericLiteral sym
2612+
2613+class ValidateAllDigits :: Symbol -> Symbol -> Constraint
2614+class ValidateAllDigits head tail
2615+
2616+instance ValidateAllDigits "0" ""
2617+else instance ValidateAllDigits "1" ""
2618+else instance ValidateAllDigits "2" ""
2619+else instance ValidateAllDigits "3" ""
2620+else instance ValidateAllDigits "4" ""
2621+else instance ValidateAllDigits "5" ""
2622+else instance ValidateAllDigits "6" ""
2623+else instance ValidateAllDigits "7" ""
2624+else instance ValidateAllDigits "8" ""
2625+else instance ValidateAllDigits "9" ""
2626+else instance (Symbol.Cons h2 t2 tail, ValidateAllDigits h2 t2) => ValidateAllDigits "0" tail
2627+else instance (Symbol.Cons h2 t2 tail, ValidateAllDigits h2 t2) => ValidateAllDigits "1" tail
2628+else instance (Symbol.Cons h2 t2 tail, ValidateAllDigits h2 t2) => ValidateAllDigits "2" tail
2629+else instance (Symbol.Cons h2 t2 tail, ValidateAllDigits h2 t2) => ValidateAllDigits "3" tail
2630+else instance (Symbol.Cons h2 t2 tail, ValidateAllDigits h2 t2) => ValidateAllDigits "4" tail
2631+else instance (Symbol.Cons h2 t2 tail, ValidateAllDigits h2 t2) => ValidateAllDigits "5" tail
2632+else instance (Symbol.Cons h2 t2 tail, ValidateAllDigits h2 t2) => ValidateAllDigits "6" tail
2633+else instance (Symbol.Cons h2 t2 tail, ValidateAllDigits h2 t2) => ValidateAllDigits "7" tail
2634+else instance (Symbol.Cons h2 t2 tail, ValidateAllDigits h2 t2) => ValidateAllDigits "8" tail
2635+else instance (Symbol.Cons h2 t2 tail, ValidateAllDigits h2 t2) => ValidateAllDigits "9" tail
2636+else instance
2637+ Fail (Beside (Text "LIMIT/OFFSET must be a non-negative integer or $parameter, got: ") (Quote sym)) =>
2638+ ValidateAllDigits head tail
2639+
25732640class ParseLimitOffset :: Symbol -> Row Type -> Row Type -> Constraint
25742641class ParseLimitOffset sym params params' | sym params -> params'
25752642
25762643instance
25772644 ( Symbol.Cons head tail sym
25782645 , IsLimitParam head tail isParam
2579− , ParseLimitOffsetParams isParam tail params params'
2646+ , ParseLimitOffsetBranch isParam sym tail params params'
25802647 ) =>
25812648 ParseLimitOffset sym params params'
25822649
2650+class ParseLimitOffsetBranch :: Boolean -> Symbol -> Symbol -> Row Type -> Row Type -> Constraint
2651+class ParseLimitOffsetBranch isParam sym paramName params params' | isParam sym paramName params -> params'
2652+
2653+instance
2654+ ( Row.Lacks paramName params
2655+ , Row.Cons paramName Int params params'
2656+ ) =>
2657+ ParseLimitOffsetBranch True sym paramName params params'
2658+
2659+instance
2660+ ValidateNumericLiteral sym =>
2661+ ParseLimitOffsetBranch False sym paramName params params
2662+
25832663limit
25842664 :: forall @sym tables result params params' stage stage'
25852665 . ParseLimitOffset sym params params'