feat: add optional nulls=stripped parameter for mediatypes applicatio… (#2894)
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
module Feature.Query.NullsStrip where
|
||||
|
||||
import Network.Wai (Application)
|
||||
|
||||
import Network.HTTP.Types
|
||||
import Test.Hspec
|
||||
import Test.Hspec.Wai
|
||||
import Test.Hspec.Wai.JSON
|
||||
|
||||
import Protolude hiding (get)
|
||||
import SpecHelper
|
||||
|
||||
spec :: SpecWith ((), Application)
|
||||
spec =
|
||||
describe "Stripping null values from JSON response" $ do
|
||||
let arrayStrip = ("Accept", "application/vnd.pgrst.array+json;nulls=stripped")
|
||||
let singularStrip = ("Accept", "application/vnd.pgrst.object+json;nulls=stripped")
|
||||
|
||||
context "strip nulls from response" $ do
|
||||
it "strips nulls when Accept: application/vnd.pgrst.array+json;nulls=stripped" $ do
|
||||
request methodGet "/organizations?select=*"
|
||||
[arrayStrip]
|
||||
""
|
||||
`shouldRespondWith`
|
||||
[json|[{"id":1,"name":"Referee Org","manager_id":1},{"id":2,"name":"Auditor Org","manager_id":2},{"id":3,"name":"Acme","referee":1,"auditor":2,"manager_id":3},{"id":4,"name":"Umbrella","referee":1,"auditor":2,"manager_id":4},{"id":5,"name":"Cyberdyne","referee":3,"auditor":4,"manager_id":5},{"id":6,"name":"Oscorp","referee":3,"auditor":4,"manager_id":6}]|]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = [matchCTArrayStrip]
|
||||
}
|
||||
|
||||
request methodPost "/organizations?select=*"
|
||||
[arrayStrip,("Prefer","return=representation")]
|
||||
[json|{"id":7,"name":"John","referee":null,"auditor":null,"manager_id":6}|]
|
||||
`shouldRespondWith`
|
||||
[json|[{"id":7,"name":"John","manager_id":6}]|]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = [matchCTArrayStrip]
|
||||
}
|
||||
|
||||
request methodPatch "/organizations?id=eq.3&select=*"
|
||||
[arrayStrip, ("Prefer","return=representation")]
|
||||
[json|{"name":"John","referee":null}|]
|
||||
`shouldRespondWith`
|
||||
[json|[{"id":3,"name":"John","auditor":2,"manager_id":3}]|]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = [matchCTArrayStrip]
|
||||
}
|
||||
|
||||
it "strips nulls when Accept: application/vnd.pgrst.object+json;nulls=stripped" $
|
||||
request methodGet "/organizations?limit=1"
|
||||
[singularStrip]
|
||||
""
|
||||
`shouldRespondWith`
|
||||
[json|{"id":1,"name":"Referee Org","manager_id":1}|]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = [matchCTSingularStrip]
|
||||
}
|
||||
|
||||
it "throws error when Accept: application/vnd.pgrst.object+json;nulls=stripped and result not singular" $
|
||||
request methodGet "/organizations?select=*"
|
||||
[singularStrip]
|
||||
""
|
||||
`shouldRespondWith`
|
||||
[json|{"details":"The result contains 6 rows","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST116","hint":null}|]
|
||||
{ matchStatus = 406
|
||||
, matchHeaders = [matchContentTypeSingular]
|
||||
}
|
||||
|
||||
context "strip nulls from response even if explicitly selected" $ do
|
||||
it "strips nulls when Accept: application/vnd.pgrst.array+json;nulls=stripped" $ do
|
||||
request methodGet "/organizations?select=id,referee,auditor"
|
||||
[arrayStrip]
|
||||
""
|
||||
`shouldRespondWith`
|
||||
[json|[{"id":1},{"id":2},{"id":3,"referee":1,"auditor":2},{"id":4,"referee":1,"auditor":2},{"id":5,"referee":3,"auditor":4},{"id":6,"referee":3,"auditor":4}]|]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = [matchCTArrayStrip]
|
||||
}
|
||||
|
||||
request methodPost "/organizations?select=id,referee,auditor"
|
||||
[arrayStrip,("Prefer","return=representation")]
|
||||
[json|{"id":7,"name":"John","referee":null,"auditor":null,"manager_id":6}|]
|
||||
`shouldRespondWith`
|
||||
[json|[{"id":7}]|]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = [matchCTArrayStrip]
|
||||
}
|
||||
|
||||
request methodPatch "/organizations?id=eq.3&select=id,name,referee,auditor"
|
||||
[arrayStrip, ("Prefer","return=representation")]
|
||||
[json|{"name":"John","referee":null}|]
|
||||
`shouldRespondWith`
|
||||
[json|[{"id":3,"name":"John","auditor":2}]|]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = [matchCTArrayStrip]
|
||||
}
|
||||
|
||||
it "strips nulls when Accept: application/vnd.pgrst.object+json;nulls=stripped" $
|
||||
request methodGet "/organizations?select=id,referee,auditor&limit=1"
|
||||
[singularStrip]
|
||||
""
|
||||
`shouldRespondWith`
|
||||
[json|{"id":1}|]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = [matchCTSingularStrip]
|
||||
}
|
||||
|
||||
context "doesn't strip nulls" $ do
|
||||
it "doesn't strips nulls when Accept: application/vnd.pgrst.array+json" $
|
||||
request methodGet "/organizations?select=id,referee,auditor"
|
||||
[("Accept", "application/vnd.pgrst.array+json")]
|
||||
""
|
||||
`shouldRespondWith`
|
||||
[json|[{"id":1,"referee":null,"auditor":null},{"id":2,"referee":null,"auditor":null},{"id":3,"referee":1,"auditor":2},{"id":4,"referee":1,"auditor":2},{"id":5,"referee":3,"auditor":4},{"id":6,"referee":3,"auditor":4}]|]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = [matchContentTypeJson]
|
||||
}
|
||||
@@ -45,6 +45,7 @@ import qualified Feature.Query.HtmlRawOutputSpec
|
||||
import qualified Feature.Query.InsertSpec
|
||||
import qualified Feature.Query.JsonOperatorSpec
|
||||
import qualified Feature.Query.MultipleSchemaSpec
|
||||
import qualified Feature.Query.NullsStrip
|
||||
import qualified Feature.Query.PgSafeUpdateSpec
|
||||
import qualified Feature.Query.PlanSpec
|
||||
import qualified Feature.Query.PostGISSpec
|
||||
@@ -139,6 +140,7 @@ main = do
|
||||
, ("Feature.Query.RawOutputTypesSpec" , Feature.Query.RawOutputTypesSpec.spec)
|
||||
, ("Feature.Query.RpcSpec" , Feature.Query.RpcSpec.spec actualPgVersion)
|
||||
, ("Feature.Query.SingularSpec" , Feature.Query.SingularSpec.spec)
|
||||
, ("Feature.Query.NullsStrip" , Feature.Query.NullsStrip.spec)
|
||||
, ("Feature.Query.UpdateSpec" , Feature.Query.UpdateSpec.spec actualPgVersion)
|
||||
, ("Feature.Query.UpsertSpec" , Feature.Query.UpsertSpec.spec actualPgVersion)
|
||||
, ("Feature.Query.ComputedRelsSpec" , Feature.Query.ComputedRelsSpec.spec)
|
||||
|
||||
@@ -40,6 +40,12 @@ matchContentTypeJson = "Content-Type" <:> "application/json; charset=utf-8"
|
||||
matchContentTypeSingular :: MatchHeader
|
||||
matchContentTypeSingular = "Content-Type" <:> "application/vnd.pgrst.object+json; charset=utf-8"
|
||||
|
||||
matchCTArrayStrip :: MatchHeader
|
||||
matchCTArrayStrip = "Content-Type" <:> "application/vnd.pgrst.array+json;nulls=stripped; charset=utf-8"
|
||||
|
||||
matchCTSingularStrip :: MatchHeader
|
||||
matchCTSingularStrip = "Content-Type" <:> "application/vnd.pgrst.object+json;nulls=stripped; charset=utf-8"
|
||||
|
||||
matchHeaderAbsent :: HeaderName -> MatchHeader
|
||||
matchHeaderAbsent name = MatchHeader $ \headers _body ->
|
||||
case lookup name headers of
|
||||
|
||||
Reference in New Issue
Block a user