From 0940b2dccf06e0ca269c03b6715f1140b80241bf Mon Sep 17 00:00:00 2001 From: Christopher League Date: Sun, 22 May 2016 14:56:58 -0400 Subject: [PATCH] Simplify serialization of location header Possible after bug fix in a Hasql that we picked up with the new dependency bounds in #606. Also includes test to ensure location header is omitted on bulk insert. --- src/PostgREST/App.hs | 9 +++++---- src/PostgREST/QueryBuilder.hs | 10 ++++------ test/Feature/InsertSpec.hs | 10 ++++++++++ 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/PostgREST/App.hs b/src/PostgREST/App.hs index c526389ab..acf65cc54 100644 --- a/src/PostgREST/App.hs +++ b/src/PostgREST/App.hs @@ -130,9 +130,10 @@ app dbStructure conf apiRequest = let pKeys = map pkName $ filter (filterPk schema table) allPrKeys -- would it be ok to move primary key detection in the query itself? let stm = createWriteStatement qi sq mq isSingle (iPreferRepresentation apiRequest) pKeys (contentType == TextCSV) payload row <- H.query uniform stm - let (_, _, locationFieldsOpt, body) = extractQueryResult row - mkHeader fs = [(hLocation, "/" <> cs table <> renderLocationFields fs)] - header = maybe [] mkHeader locationFieldsOpt + let (_, _, fs, body) = extractQueryResult row + header = + if null fs then [] + else [(hLocation, "/" <> cs table <> renderLocationFields fs)] return $ if iPreferRepresentation apiRequest == Full then responseLBS status201 (contentTypeH : header) (cs body) @@ -391,4 +392,4 @@ instance ToJSON TableOptions where extractQueryResult :: Maybe ResultsWithCount -> ResultsWithCount -extractQueryResult = fromMaybe (Nothing, 0, Nothing, "") +extractQueryResult = fromMaybe (Nothing, 0, [], "") diff --git a/src/PostgREST/QueryBuilder.hs b/src/PostgREST/QueryBuilder.hs index 5227d9775..10ed4b88d 100644 --- a/src/PostgREST/QueryBuilder.hs +++ b/src/PostgREST/QueryBuilder.hs @@ -63,20 +63,18 @@ import PostgREST.ApiRequest (PreferRepresentation (..)) {-| The generic query result format used by API responses. The location header is represented as a list of strings containing variable bindings like - @"k1=eq.42"@. If unused, it's null/Nothing rather than the empty list - because 'PostgreSQL.Binary.Decoder.arrayDimension' cannot decode an empty - array! + @"k1=eq.42"@, or the empty list if there is no location header. -} -type ResultsWithCount = (Maybe Int64, Int64, Maybe [BS.ByteString], BS.ByteString) +type ResultsWithCount = (Maybe Int64, Int64, [BS.ByteString], BS.ByteString) standardRow :: HD.Row ResultsWithCount standardRow = (,,,) <$> HD.nullableValue HD.int8 <*> HD.value HD.int8 - <*> HD.nullableValue header <*> HD.value HD.bytea + <*> HD.value header <*> HD.value HD.bytea where header = HD.array $ HD.arrayDimension replicateM $ HD.arrayValue HD.bytea noLocationF :: Text -noLocationF = "NULL::text[]" +noLocationF = "array[]::text[]" {-| Read and Write api requests use a similar response format which includes various record counts and possible location header. This is the decoder diff --git a/test/Feature/InsertSpec.hs b/test/Feature/InsertSpec.hs index c176c54d4..3be0233d4 100644 --- a/test/Feature/InsertSpec.hs +++ b/test/Feature/InsertSpec.hs @@ -138,6 +138,16 @@ spec = do JSON.decode (simpleBody r) `shouldBe` Just [expectedObj] simpleStatus r `shouldBe` ok200 + context "with bulk insert" $ + it "returns 201 but no location header" $ do + let bulkData = [json| [ {"k1":21, "k2":"hello world"} + , {"k1":22, "k2":"bye for now"}] + |] + p <- request methodPost "/compound_pk" [] bulkData + liftIO $ do + simpleStatus p `shouldBe` created201 + lookup hLocation (simpleHeaders p) `shouldBe` Nothing + context "with invalid json payload" $ it "fails with 400 and error" $ post "/simple_pk" "}{ x = 2" `shouldRespondWith` 400