diff --git a/CHANGELOG.md b/CHANGELOG.md index 1788c3a2b..ed9c6f07c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - #2020, Execute deferred constraint triggers when using `Prefer: tx=rollback` - @wolfgangwalther + - #2058, Return 204 No Content without Content-Type for PUT - @wolfgangwalther + - #2077, Fix `is` not working with upper or mixed case values like `NULL, TrUe, FaLsE` - @steve-chavez ## [9.0.0] - 2021-11-25 diff --git a/src/PostgREST/Request/Parsers.hs b/src/PostgREST/Request/Parsers.hs index 4a8db797f..fb2707fbc 100644 --- a/src/PostgREST/Request/Parsers.hs +++ b/src/PostgREST/Request/Parsers.hs @@ -199,10 +199,10 @@ pOpExpr pSVal = try ( string "not" *> pDelimiter *> (OpExpr True <$> pOperation) <|> pFts "operator (eq, gt, ...)" - pTriVal = try (string "null" $> TriNull) - <|> try (string "unknown" $> TriUnknown) - <|> try (string "true" $> TriTrue) - <|> try (string "false" $> TriFalse) + pTriVal = try (ciString "null" $> TriNull) + <|> try (ciString "unknown" $> TriUnknown) + <|> try (ciString "true" $> TriTrue) + <|> try (ciString "false" $> TriFalse) "null or trilean value (unknown, true, false)" pFts = do @@ -213,6 +213,12 @@ pOpExpr pSVal = try ( string "not" *> pDelimiter *> (OpExpr True <$> pOperation) ops = M.filterWithKey (const . flip notElem ("in":"is":ftsOps)) operators ftsOps = M.keys ftsOperators + -- case insensitive char and string + ciChar :: Char -> GenParser Char state Char + ciChar c = char c <|> char (toUpper c) + ciString :: [Char] -> GenParser Char state [Char] + ciString = traverse ciChar + pSingleVal :: Parser SingleVal pSingleVal = toS <$> many anyChar diff --git a/test/Feature/QuerySpec.hs b/test/Feature/QuerySpec.hs index 722deea40..23e077f66 100644 --- a/test/Feature/QuerySpec.hs +++ b/test/Feature/QuerySpec.hs @@ -85,6 +85,23 @@ spec actualPgVersion = do [json| [{"id": 3, "name": "wash the dishes", "done": null }] |] { matchHeaders = [matchContentTypeJson] } + it "matches with trilean values in upper or mixed case" $ do + get "/chores?done=is.NULL" `shouldRespondWith` + [json| [{"id": 3, "name": "wash the dishes", "done": null }] |] + { matchHeaders = [matchContentTypeJson] } + + get "/chores?done=is.TRUE" `shouldRespondWith` + [json| [{"id": 1, "name": "take out the garbage", "done": true }] |] + { matchHeaders = [matchContentTypeJson] } + + get "/chores?done=is.FAlSe" `shouldRespondWith` + [json| [{"id": 2, "name": "do the laundry", "done": false }] |] + { matchHeaders = [matchContentTypeJson] } + + get "/chores?done=is.UnKnOwN" `shouldRespondWith` + [json| [{"id": 3, "name": "wash the dishes", "done": null }] |] + { matchHeaders = [matchContentTypeJson] } + it "fails if 'is' used and there's no null or trilean value" $ do get "/chores?done=is.nil" `shouldRespondWith` 400 get "/chores?done=is.ok" `shouldRespondWith` 400