Skip to content

Commit

Permalink
feat: Raise minimum supported pg version to 11.22
Browse files Browse the repository at this point in the history
PostgreSQL 11 is EOL already, so we only support the latest minor release.
  • Loading branch information
wolfgangwalther committed Feb 10, 2024
1 parent 1e66df6 commit f9cc345
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 143 deletions.
16 changes: 5 additions & 11 deletions src/PostgREST/Config/PgVersion.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
module PostgREST.Config.PgVersion
( PgVersion(..)
, minimumPgVersion
, pgVersion112
, pgVersion114
, pgVersion120
, pgVersion121
, pgVersion130
Expand All @@ -28,16 +26,12 @@ instance Ord PgVersion where

-- | Tells the minimum PostgreSQL version required by this version of PostgREST
minimumPgVersion :: PgVersion
minimumPgVersion = pgVersion110
minimumPgVersion = pgVersion11

pgVersion110 :: PgVersion
pgVersion110 = PgVersion 110000 "11.0"

pgVersion112 :: PgVersion
pgVersion112 = PgVersion 110002 "11.2"

pgVersion114 :: PgVersion
pgVersion114 = PgVersion 110004 "11.4"
-- PostgreSQL 11 is EOL already, so we only allow the last
-- minor release as the minimum version
pgVersion11 :: PgVersion
pgVersion11 = PgVersion 112200 "11.22"

pgVersion120 :: PgVersion
pgVersion120 = PgVersion 120000 "12.0"
Expand Down
46 changes: 14 additions & 32 deletions test/spec/Feature/Auth/AuthSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,51 +7,33 @@ import Test.Hspec
import Test.Hspec.Wai
import Test.Hspec.Wai.JSON

import PostgREST.Config.PgVersion (PgVersion, pgVersion112)

import Protolude hiding (get)
import SpecHelper

spec :: PgVersion -> SpecWith ((), Application)
spec actualPgVersion = describe "authorization" $ do
spec :: SpecWith ((), Application)
spec = describe "authorization" $ do
let single = ("Accept","application/vnd.pgrst.object+json")

it "denies access to tables that anonymous does not own" $
get "/authors_only" `shouldRespondWith` (
if actualPgVersion >= pgVersion112 then
[json| {
"hint":null,
"details":null,
"code":"42501",
"message":"permission denied for table authors_only"} |]
else
[json| {
"hint":null,
"details":null,
"code":"42501",
"message":"permission denied for relation authors_only"} |]
)
get "/authors_only" `shouldRespondWith`
[json| {
"hint":null,
"details":null,
"code":"42501",
"message":"permission denied for table authors_only"} |]
{ matchStatus = 401
, matchHeaders = ["WWW-Authenticate" <:> "Bearer"]
}

it "denies access to tables that postgrest_test_author does not own" $
let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIn0.Xod-F15qsGL0WhdOCr2j3DdKuTw9QJERVgoFD3vGaWA" in
request methodGet "/private_table" [auth] ""
`shouldRespondWith` (
if actualPgVersion >= pgVersion112 then
[json| {
"hint":null,
"details":null,
"code":"42501",
"message":"permission denied for table private_table"} |]
else
[json| {
"hint":null,
"details":null,
"code":"42501",
"message":"permission denied for relation private_table"} |]
)
`shouldRespondWith`
[json| {
"hint":null,
"details":null,
"code":"42501",
"message":"permission denied for table private_table"} |]
{ matchStatus = 403
, matchHeaders = []
}
Expand Down
27 changes: 12 additions & 15 deletions test/spec/Feature/Query/AndOrParamsSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,11 @@ import Test.Hspec
import Test.Hspec.Wai
import Test.Hspec.Wai.JSON

import PostgREST.Config.PgVersion (PgVersion, pgVersion112)

import Protolude hiding (get)
import SpecHelper

spec :: PgVersion -> SpecWith ((), Application)
spec actualPgVersion =
spec :: SpecWith ((), Application)
spec =
describe "and/or params used for complex boolean logic" $ do
context "used with GET" $ do
context "or param" $ do
Expand Down Expand Up @@ -96,17 +94,16 @@ spec actualPgVersion =
get "/entities?and=(id.gte.2,arr.isdistinct.{1,2})&select=id" `shouldRespondWith`
[json|[{ "id": 3 }, { "id": 4 }]|] { matchHeaders = [matchContentTypeJson] }

when (actualPgVersion >= pgVersion112) $
it "can handle wfts (websearch_to_tsquery)" $
get "/tsearch?or=(text_search_vector.plfts(german).Art,text_search_vector.plfts(french).amusant,text_search_vector.not.wfts(english).impossible)"
`shouldRespondWith`
[json|[
{"text_search_vector": "'also':2 'fun':3 'possibl':8" },
{"text_search_vector": "'ate':3 'cat':2 'fat':1 'rat':4" },
{"text_search_vector": "'amus':5 'fair':7 'impossibl':9 'peu':4" },
{"text_search_vector": "'art':4 'spass':5 'unmog':7" }
]|]
{ matchHeaders = [matchContentTypeJson] }
it "can handle wfts (websearch_to_tsquery)" $
get "/tsearch?or=(text_search_vector.plfts(german).Art,text_search_vector.plfts(french).amusant,text_search_vector.not.wfts(english).impossible)"
`shouldRespondWith`
[json|[
{"text_search_vector": "'also':2 'fun':3 'possibl':8" },
{"text_search_vector": "'ate':3 'cat':2 'fat':1 'rat':4" },
{"text_search_vector": "'amus':5 'fair':7 'impossibl':9 'peu':4" },
{"text_search_vector": "'art':4 'spass':5 'unmog':7" }
]|]
{ matchHeaders = [matchContentTypeJson] }

it "can handle cs and cd" $
get "/entities?or=(arr.cs.{1,2,3},arr.cd.{1})&select=id" `shouldRespondWith`
Expand Down
21 changes: 6 additions & 15 deletions test/spec/Feature/Query/InsertSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ import Test.Hspec.Wai
import Test.Hspec.Wai.JSON
import Text.Heredoc

import PostgREST.Config.PgVersion (PgVersion, pgVersion112,
pgVersion120, pgVersion130,
pgVersion140)
import PostgREST.Config.PgVersion (PgVersion, pgVersion120,
pgVersion130, pgVersion140)

import Protolude hiding (get)
import SpecHelper
Expand Down Expand Up @@ -694,24 +693,16 @@ spec actualPgVersion = do

it "fails inserting if more columns are selected" $
request methodPost "/limited_article_stars?select=article_id,user_id,created_at" [("Prefer", "return=representation")]
[json| {"article_id": 2, "user_id": 2} |] `shouldRespondWith` (
if actualPgVersion >= pgVersion112 then
[json|{"hint":null,"details":null,"code":"42501","message":"permission denied for view limited_article_stars"}|]
else
[json|{"hint":null,"details":null,"code":"42501","message":"permission denied for relation limited_article_stars"}|]
)
[json| {"article_id": 2, "user_id": 2} |] `shouldRespondWith`
[json|{"hint":null,"details":null,"code":"42501","message":"permission denied for view limited_article_stars"}|]
{ matchStatus = 401
, matchHeaders = []
}

it "fails inserting if select is not specified" $
request methodPost "/limited_article_stars" [("Prefer", "return=representation")]
[json| {"article_id": 3, "user_id": 1} |] `shouldRespondWith` (
if actualPgVersion >= pgVersion112 then
[json|{"hint":null,"details":null,"code":"42501","message":"permission denied for view limited_article_stars"}|]
else
[json|{"hint":null,"details":null,"code":"42501","message":"permission denied for relation limited_article_stars"}|]
)
[json| {"article_id": 3, "user_id": 1} |] `shouldRespondWith`
[json|{"hint":null,"details":null,"code":"42501","message":"permission denied for view limited_article_stars"}|]
{ matchStatus = 401
, matchHeaders = []
}
Expand Down
19 changes: 3 additions & 16 deletions test/spec/Feature/Query/JsonOperatorSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import Test.Hspec
import Test.Hspec.Wai
import Test.Hspec.Wai.JSON

import PostgREST.Config.PgVersion (PgVersion, pgVersion112,
pgVersion121)
import PostgREST.Config.PgVersion (PgVersion, pgVersion121)

import Protolude hiding (get)
import SpecHelper
Expand Down Expand Up @@ -75,28 +74,16 @@ spec actualPgVersion = describe "json and jsonb operators" $ do
-- this works fine for /rpc/unexistent requests, but for this case a 500 seems more appropriate
it "fails when a double arrow ->> is followed with a single arrow ->" $ do
get "/json_arr?select=data->>c->1"
`shouldRespondWith` (
if actualPgVersion >= pgVersion112 then
`shouldRespondWith`
[json|
{"hint":"No operator matches the given name and argument types. You might need to add explicit type casts.",
"details":null,"code":"42883","message":"operator does not exist: text -> integer"} |]
else
[json|
{"hint":"No operator matches the given name and argument type(s). You might need to add explicit type casts.",
"details":null,"code":"42883","message":"operator does not exist: text -> integer"} |]
)
{ matchStatus = 404 , matchHeaders = [] }
get "/json_arr?select=data->>c->b"
`shouldRespondWith` (
if actualPgVersion >= pgVersion112 then
`shouldRespondWith`
[json|
{"hint":"No operator matches the given name and argument types. You might need to add explicit type casts.",
"details":null,"code":"42883","message":"operator does not exist: text -> unknown"} |]
else
[json|
{"hint":"No operator matches the given name and argument type(s). You might need to add explicit type casts.",
"details":null,"code":"42883","message":"operator does not exist: text -> unknown"} |]
)
{ matchStatus = 404 , matchHeaders = [] }

context "with array index" $ do
Expand Down
66 changes: 31 additions & 35 deletions test/spec/Feature/Query/QuerySpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ import Test.Hspec hiding (pendingWith)
import Test.Hspec.Wai
import Test.Hspec.Wai.JSON

import PostgREST.Config.PgVersion (PgVersion, pgVersion112,
pgVersion121)
import PostgREST.Config.PgVersion (PgVersion, pgVersion121)
import Protolude hiding (get)
import SpecHelper

Expand Down Expand Up @@ -176,29 +175,28 @@ spec actualPgVersion = do
[json| [ {"text_search_vector": "'ate':3 'cat':2 'fat':1 'rat':4" }] |]
{ matchHeaders = [matchContentTypeJson] }

when (actualPgVersion >= pgVersion112) $ do
it "finds matches with websearch_to_tsquery" $
get "/tsearch?text_search_vector=wfts.The%20Fat%20Rats" `shouldRespondWith`
[json| [ {"text_search_vector": "'ate':3 'cat':2 'fat':1 'rat':4" }] |]
{ matchHeaders = [matchContentTypeJson] }

it "can use boolean operators(and, or, -) in websearch_to_tsquery" $ do
get "/tsearch?text_search_vector=wfts.fun%20and%20possible"
`shouldRespondWith`
[json| [ {"text_search_vector": "'also':2 'fun':3 'possibl':8"}] |]
{ matchHeaders = [matchContentTypeJson] }
get "/tsearch?text_search_vector=wfts.impossible%20or%20possible"
`shouldRespondWith`
[json| [
{"text_search_vector": "'fun':5 'imposs':9 'kind':3"},
{"text_search_vector": "'also':2 'fun':3 'possibl':8"}]
|]
{ matchHeaders = [matchContentTypeJson] }
get "/tsearch?text_search_vector=wfts.fun%20and%20-possible"
`shouldRespondWith`
[json| [ {"text_search_vector": "'fun':5 'imposs':9 'kind':3"}] |]
it "finds matches with websearch_to_tsquery" $
get "/tsearch?text_search_vector=wfts.The%20Fat%20Rats" `shouldRespondWith`
[json| [ {"text_search_vector": "'ate':3 'cat':2 'fat':1 'rat':4" }] |]
{ matchHeaders = [matchContentTypeJson] }

it "can use boolean operators(and, or, -) in websearch_to_tsquery" $ do
get "/tsearch?text_search_vector=wfts.fun%20and%20possible"
`shouldRespondWith`
[json| [ {"text_search_vector": "'also':2 'fun':3 'possibl':8"}] |]
{ matchHeaders = [matchContentTypeJson] }
get "/tsearch?text_search_vector=wfts.impossible%20or%20possible"
`shouldRespondWith`
[json| [
{"text_search_vector": "'fun':5 'imposs':9 'kind':3"},
{"text_search_vector": "'also':2 'fun':3 'possibl':8"}]
|]
{ matchHeaders = [matchContentTypeJson] }
get "/tsearch?text_search_vector=wfts.fun%20and%20-possible"
`shouldRespondWith`
[json| [ {"text_search_vector": "'fun':5 'imposs':9 'kind':3"}] |]
{ matchHeaders = [matchContentTypeJson] }

it "finds matches with different dictionaries" $ do
get "/tsearch?text_search_vector=fts(french).amusant" `shouldRespondWith`
[json| [{"text_search_vector": "'amus':5 'fair':7 'impossibl':9 'peu':4" }] |]
Expand All @@ -207,11 +205,10 @@ spec actualPgVersion = do
[json| [{"text_search_vector": "'amus':5 'fair':7 'impossibl':9 'peu':4" }] |]
{ matchHeaders = [matchContentTypeJson] }

when (actualPgVersion >= pgVersion112) $
get "/tsearch?text_search_vector=wfts(french).amusant%20impossible"
`shouldRespondWith`
[json| [{"text_search_vector": "'amus':5 'fair':7 'impossibl':9 'peu':4" }] |]
{ matchHeaders = [matchContentTypeJson] }
get "/tsearch?text_search_vector=wfts(french).amusant%20impossible"
`shouldRespondWith`
[json| [{"text_search_vector": "'amus':5 'fair':7 'impossibl':9 'peu':4" }] |]
{ matchHeaders = [matchContentTypeJson] }

it "can be negated with not operator" $ do
get "/tsearch?text_search_vector=not.fts.impossible%7Cfat%7Cfun" `shouldRespondWith`
Expand All @@ -231,13 +228,12 @@ spec actualPgVersion = do
{"text_search_vector": "'amus':5 'fair':7 'impossibl':9 'peu':4"},
{"text_search_vector": "'art':4 'spass':5 'unmog':7"}]|]
{ matchHeaders = [matchContentTypeJson] }
when (actualPgVersion >= pgVersion112) $
get "/tsearch?text_search_vector=not.wfts(english).impossible%20or%20fat%20or%20fun"
`shouldRespondWith`
[json| [
{"text_search_vector": "'amus':5 'fair':7 'impossibl':9 'peu':4"},
{"text_search_vector": "'art':4 'spass':5 'unmog':7"}]|]
{ matchHeaders = [matchContentTypeJson] }
get "/tsearch?text_search_vector=not.wfts(english).impossible%20or%20fat%20or%20fun"
`shouldRespondWith`
[json| [
{"text_search_vector": "'amus':5 'fair':7 'impossibl':9 'peu':4"},
{"text_search_vector": "'art':4 'spass':5 'unmog':7"}]|]
{ matchHeaders = [matchContentTypeJson] }

context "Use of the phraseto_tsquery function" $ do
it "finds matches" $
Expand Down
27 changes: 11 additions & 16 deletions test/spec/Feature/Query/RpcSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,11 @@ import Test.Hspec.Wai
import Test.Hspec.Wai.JSON
import Text.Heredoc

import PostgREST.Config.PgVersion (PgVersion, pgVersion112,
pgVersion114)

import Protolude hiding (get)
import SpecHelper

spec :: PgVersion -> SpecWith ((), Application)
spec actualPgVersion =
spec :: SpecWith ((), Application)
spec =
describe "remote procedure call" $ do
context "a proc that returns a set" $ do
context "returns paginated results" $ do
Expand Down Expand Up @@ -599,13 +596,12 @@ spec actualPgVersion =
[json|"object"|]
{ matchHeaders = [matchContentTypeJson] }

when (actualPgVersion >= pgVersion114) $
it "parses quoted JSON arguments as JSON string (from Postgres 10.9, 11.4)" $
post "/rpc/json_argument"
[json| { "arg": "{ \"key\": 3 }" } |]
`shouldRespondWith`
[json|"string"|]
{ matchHeaders = [matchContentTypeJson] }
it "parses quoted JSON arguments as JSON string (from Postgres 10.9, 11.4)" $
post "/rpc/json_argument"
[json| { "arg": "{ \"key\": 3 }" } |]
`shouldRespondWith`
[json|"string"|]
{ matchHeaders = [matchContentTypeJson] }

context "improper input" $ do
it "rejects unknown content type even if payload is good" $ do
Expand Down Expand Up @@ -1019,10 +1015,9 @@ spec actualPgVersion =
get "/rpc/get_tsearch?text_search_vector=not.fts(english).fun%7Crat" `shouldRespondWith`
[json|[{"text_search_vector":"'amus':5 'fair':7 'impossibl':9 'peu':4"},{"text_search_vector":"'art':4 'spass':5 'unmog':7"}]|]
{ matchHeaders = [matchContentTypeJson] }
when (actualPgVersion >= pgVersion112) $
get "/rpc/get_tsearch?text_search_vector=wfts.impossible" `shouldRespondWith`
[json|[{"text_search_vector":"'fun':5 'imposs':9 'kind':3"}]|]
{ matchHeaders = [matchContentTypeJson] }
get "/rpc/get_tsearch?text_search_vector=wfts.impossible" `shouldRespondWith`
[json|[{"text_search_vector":"'fun':5 'imposs':9 'kind':3"}]|]
{ matchHeaders = [matchContentTypeJson] }

it "should work with the phraseto_tsquery function" $
get "/rpc/get_tsearch?text_search_vector=phfts(english).impossible" `shouldRespondWith`
Expand Down
6 changes: 3 additions & 3 deletions test/spec/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ main = do
analyzeTable "child_entities"

specs = uncurry describe <$> [
("Feature.Query.AndOrParamsSpec" , Feature.Query.AndOrParamsSpec.spec actualPgVersion)
, ("Feature.Auth.AuthSpec" , Feature.Auth.AuthSpec.spec actualPgVersion)
("Feature.Query.AndOrParamsSpec" , Feature.Query.AndOrParamsSpec.spec)
, ("Feature.Auth.AuthSpec" , Feature.Auth.AuthSpec.spec)
, ("Feature.ConcurrentSpec" , Feature.ConcurrentSpec.spec)
, ("Feature.CorsSpec" , Feature.CorsSpec.spec)
, ("Feature.CustomMediaSpec" , Feature.Query.CustomMediaSpec.spec)
Expand All @@ -143,7 +143,7 @@ main = do
, ("Feature.Query.PreferencesSpec" , Feature.Query.PreferencesSpec.spec)
, ("Feature.Query.QuerySpec" , Feature.Query.QuerySpec.spec actualPgVersion)
, ("Feature.Query.RawOutputTypesSpec" , Feature.Query.RawOutputTypesSpec.spec)
, ("Feature.Query.RpcSpec" , Feature.Query.RpcSpec.spec actualPgVersion)
, ("Feature.Query.RpcSpec" , Feature.Query.RpcSpec.spec)
, ("Feature.Query.SingularSpec" , Feature.Query.SingularSpec.spec)
, ("Feature.Query.NullsStripSpec" , Feature.Query.NullsStripSpec.spec)
, ("Feature.Query.UpdateSpec" , Feature.Query.UpdateSpec.spec)
Expand Down

0 comments on commit f9cc345

Please sign in to comment.