feat: Drop support for pg 9.6
This commit is contained in:
committed by
Wolfgang Walther
parent
ec110720dc
commit
daa77d17aa
@@ -67,7 +67,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
pgVersion: ["9_6", 10, 11, 12, 13, 14, 15, 16]
|
||||
pgVersion: [10, 11, 12, 13, 14, 15, 16]
|
||||
name: PG ${{ matrix.pgVersion }}
|
||||
runs-on: ubuntu-22.04
|
||||
defaults:
|
||||
|
||||
@@ -5,6 +5,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Changed
|
||||
|
||||
- #2052, Dropped support for PostgreSQL 9.6 - @wolfgangwalther
|
||||
|
||||
## [12.2.0] - 2024-06-11
|
||||
|
||||
### Added
|
||||
|
||||
@@ -56,7 +56,6 @@ let
|
||||
{ name = "postgresql-12"; postgresql = pkgs.postgresql_12.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
|
||||
{ name = "postgresql-11"; postgresql = pkgs.postgresql_11.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
|
||||
{ name = "postgresql-10"; postgresql = pkgs.postgresql_10.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
|
||||
{ name = "postgresql-9_6"; postgresql = pkgs.postgresql_9_6.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
|
||||
];
|
||||
|
||||
# Dynamic derivation for PostgREST
|
||||
|
||||
@@ -16,14 +16,14 @@ Supported PostgreSQL versions
|
||||
=============================
|
||||
|
||||
=============== =================================
|
||||
**Supported** PostgreSQL >= 9.6
|
||||
**Supported** PostgreSQL >= 10
|
||||
=============== =================================
|
||||
|
||||
PostgREST works with all PostgreSQL versions starting from 9.6.
|
||||
PostgREST works with all PostgreSQL versions starting from 10.
|
||||
|
||||
.. note::
|
||||
|
||||
Support for PostgreSQL versions 9.6, 10 and 11 is deprecated. From this on version onwards, PostgREST will only support non-end-of-life PostgreSQL versions.
|
||||
Support for PostgreSQL versions 10 and 11 is deprecated. From this on version onwards, PostgREST will only support non-end-of-life PostgreSQL versions.
|
||||
|
||||
See https://www.postgresql.org/support/versioning/.
|
||||
|
||||
|
||||
+2
-2
@@ -79,7 +79,7 @@ postgrest-coverage postgrest-with-postgresql-10
|
||||
postgrest-lint postgrest-with-postgresql-11
|
||||
postgrest-run postgrest-with-postgresql-12
|
||||
postgrest-style postgrest-with-postgresql-13
|
||||
postgrest-style-check postgrest-with-postgresql-9.6
|
||||
postgrest-style-check postgrest-with-postgresql-14
|
||||
postgrest-test-io
|
||||
...
|
||||
|
||||
@@ -103,7 +103,7 @@ postgrest-coverage postgrest-with-postgresql-10
|
||||
postgrest-lint postgrest-with-postgresql-11
|
||||
postgrest-run postgrest-with-postgresql-12
|
||||
postgrest-style postgrest-with-postgresql-13
|
||||
postgrest-style-check postgrest-with-postgresql-9.6
|
||||
postgrest-style-check postgrest-with-postgresql-14
|
||||
postgrest-test-io
|
||||
postgrest-test-memory
|
||||
...
|
||||
|
||||
@@ -20,9 +20,4 @@ in
|
||||
postgis = prev.postgresql_10.pkgs.postgis.overrideAttrs (_: postgis_3_2_3);
|
||||
};
|
||||
};
|
||||
postgresql_9_6 = prev.postgresql_9_6.override { this = final.postgresql_11; } // {
|
||||
pkgs = prev.postgresql_9_6.pkgs // {
|
||||
postgis = prev.postgresql_9_6.pkgs.postgis.overrideAttrs (_: postgis_3_2_3);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,21 +2,6 @@ _: _:
|
||||
# Overlay that adds legacy versions of PostgreSQL that are supported by
|
||||
# PostgREST.
|
||||
{
|
||||
# PostgreSQL 9.6 was removed from Nixpkgs with
|
||||
# https://github.com/NixOS/nixpkgs/commit/757dd008b2f2926fc0f7688fa8189f930ea47521
|
||||
# We pin its parent commit to get the last version that was available.
|
||||
postgresql_9_6 =
|
||||
let
|
||||
rev = "571cbf3d1db477058303cef8754fb85a14e90eb7";
|
||||
tarballHash = "0q74wn418i1bn5sssacmw8ykpmqvzr0s93sj6pbs3rf6bf134fkz";
|
||||
pinnedPkgs =
|
||||
builtins.fetchTarball {
|
||||
url = "https://github.com/nixos/nixpkgs/archive/${rev}.tar.gz";
|
||||
sha256 = tarballHash;
|
||||
};
|
||||
in
|
||||
(import pinnedPkgs { }).pkgs.postgresql_9_6;
|
||||
|
||||
# PostgreSQL 10 was removed from Nixpkgs with
|
||||
# https://github.com/NixOS/nixpkgs/commit/aa1483114bb329fee7e1266100b8d8921ed4723f
|
||||
# We pin its parent commit to get the last version that was available.
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
module PostgREST.Config.PgVersion
|
||||
( PgVersion(..)
|
||||
, minimumPgVersion
|
||||
, pgVersion96
|
||||
, pgVersion100
|
||||
, pgVersion109
|
||||
, pgVersion110
|
||||
, pgVersion112
|
||||
@@ -33,10 +31,7 @@ instance Ord PgVersion where
|
||||
|
||||
-- | Tells the minimum PostgreSQL version required by this version of PostgREST
|
||||
minimumPgVersion :: PgVersion
|
||||
minimumPgVersion = pgVersion96
|
||||
|
||||
pgVersion96 :: PgVersion
|
||||
pgVersion96 = PgVersion 90600 "9.6" "9.6"
|
||||
minimumPgVersion = pgVersion100
|
||||
|
||||
pgVersion100 :: PgVersion
|
||||
pgVersion100 = PgVersion 100000 "10" "10"
|
||||
|
||||
@@ -178,7 +178,7 @@ actionQuery (DbCall plan@CallReadPlan{..}) conf@AppConfig{..} apiReq@ApiRequest{
|
||||
actionQuery (MaybeDb plan@InspectPlan{ipSchema=tSchema}) AppConfig{..} _ pgVer sCache =
|
||||
lift $ case configOpenApiMode of
|
||||
OAFollowPriv -> do
|
||||
tableAccess <- SQL.statement [tSchema] (SchemaCache.accessibleTables pgVer configDbPreparedStatements)
|
||||
tableAccess <- SQL.statement [tSchema] (SchemaCache.accessibleTables configDbPreparedStatements)
|
||||
MaybeDbResult plan . Just <$> ((,,)
|
||||
(HM.filterWithKey (\qi _ -> S.member qi tableAccess) $ SchemaCache.dbTables sCache)
|
||||
<$> SQL.statement (tSchema, configDbHoistedTxSettings) (SchemaCache.accessibleFuncs pgVer configDbPreparedStatements)
|
||||
|
||||
@@ -47,8 +47,7 @@ import PostgREST.Config (AppConfig (..))
|
||||
import PostgREST.Config.Database (TimezoneNames,
|
||||
pgVersionStatement,
|
||||
toIsolationLevel)
|
||||
import PostgREST.Config.PgVersion (PgVersion, pgVersion100,
|
||||
pgVersion110,
|
||||
import PostgREST.Config.PgVersion (PgVersion, pgVersion110,
|
||||
pgVersion120)
|
||||
import PostgREST.SchemaCache.Identifiers (AccessSet, FieldName,
|
||||
QualifiedIdentifier (..),
|
||||
@@ -477,8 +476,8 @@ schemaDescription =
|
||||
where
|
||||
n.nspname = $1 |]
|
||||
|
||||
accessibleTables :: PgVersion -> Bool -> SQL.Statement [Schema] AccessSet
|
||||
accessibleTables pgVer =
|
||||
accessibleTables :: Bool -> SQL.Statement [Schema] AccessSet
|
||||
accessibleTables =
|
||||
SQL.Statement sql (arrayParam HE.text) decodeAccessibleIdentifiers
|
||||
where
|
||||
sql = [q|
|
||||
@@ -494,10 +493,9 @@ accessibleTables pgVer =
|
||||
pg_has_role(c.relowner, 'USAGE')
|
||||
or has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER')
|
||||
or has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES')
|
||||
) |] <>
|
||||
relIsPartition <>
|
||||
"ORDER BY table_schema, table_name"
|
||||
relIsPartition = if pgVer >= pgVersion100 then " AND not c.relispartition " else mempty
|
||||
)
|
||||
AND not c.relispartition
|
||||
ORDER BY table_schema, table_name|]
|
||||
|
||||
{-
|
||||
Adds M2O and O2O relationships for views to tables, tables to views, and views to views. The example below is taken from the test fixtures, but the views names/colnames were modified.
|
||||
@@ -810,11 +808,10 @@ tablesSqlQuery pgVer =
|
||||
LEFT JOIN tbl_pk_cols tpks ON n.nspname = tpks.table_schema AND c.relname = tpks.table_name
|
||||
LEFT JOIN columns_agg cols_agg ON n.nspname = cols_agg.table_schema AND c.relname = cols_agg.table_name
|
||||
WHERE c.relkind IN ('v','r','m','f','p')
|
||||
AND n.nspname NOT IN ('pg_catalog', 'information_schema') |] <>
|
||||
relIsPartition <>
|
||||
"ORDER BY table_schema, table_name"
|
||||
AND n.nspname NOT IN ('pg_catalog', 'information_schema')
|
||||
AND not c.relispartition
|
||||
ORDER BY table_schema, table_name|]
|
||||
where
|
||||
relIsPartition = if pgVer >= pgVersion100 then " AND not c.relispartition " else mempty
|
||||
columnDefault -- typbasetype and typdefaultbin handles `CREATE DOMAIN .. DEFAULT val`, attidentity/attgenerated handles generated columns, pg_get_expr gets the default of a column
|
||||
| pgVer >= pgVersion120 = [q|
|
||||
CASE
|
||||
@@ -823,15 +820,10 @@ tablesSqlQuery pgVer =
|
||||
WHEN a.attgenerated = 's' THEN null
|
||||
ELSE pg_get_expr(ad.adbin, ad.adrelid)::text
|
||||
END|]
|
||||
| pgVer >= pgVersion100 = [q|
|
||||
CASE
|
||||
WHEN t.typbasetype != 0 THEN pg_get_expr(t.typdefaultbin, 0)
|
||||
WHEN a.attidentity = 'd' THEN format('nextval(%s)', quote_literal(seqsch.nspname || '.' || seqclass.relname))
|
||||
ELSE pg_get_expr(ad.adbin, ad.adrelid)::text
|
||||
END|]
|
||||
| otherwise = [q|
|
||||
CASE
|
||||
WHEN t.typbasetype != 0 THEN pg_get_expr(t.typdefaultbin, 0)
|
||||
WHEN a.attidentity = 'd' THEN format('nextval(%s)', quote_literal(seqsch.nspname || '.' || seqclass.relname))
|
||||
ELSE pg_get_expr(ad.adbin, ad.adrelid)::text
|
||||
END|]
|
||||
|
||||
|
||||
@@ -11,8 +11,7 @@ import Network.HTTP.Types
|
||||
import Test.Hspec hiding (pendingWith)
|
||||
import Test.Hspec.Wai
|
||||
|
||||
import PostgREST.Config.PgVersion (PgVersion, pgVersion100,
|
||||
pgVersion110)
|
||||
import PostgREST.Config.PgVersion (PgVersion, pgVersion110)
|
||||
|
||||
import PostgREST.Version (docsVersion)
|
||||
import Protolude hiding (get)
|
||||
@@ -269,7 +268,6 @@ spec actualPgVersion = describe "OpenAPI" $ do
|
||||
]
|
||||
|]
|
||||
|
||||
when (actualPgVersion >= pgVersion100) $ do
|
||||
describe "Partitioned table" $
|
||||
|
||||
it "includes partitioned table properties" $ do
|
||||
|
||||
@@ -7,8 +7,7 @@ import Network.HTTP.Types
|
||||
import Test.Hspec
|
||||
import Test.Hspec.Wai
|
||||
|
||||
import PostgREST.Config.PgVersion (PgVersion, pgVersion100,
|
||||
pgVersion110)
|
||||
import PostgREST.Config.PgVersion (PgVersion, pgVersion110)
|
||||
|
||||
import Protolude
|
||||
import SpecHelper
|
||||
@@ -25,7 +24,6 @@ spec actualPgVersion = describe "Allow header" $ do
|
||||
it "fails with 404 for an unknown table" $
|
||||
request methodOptions "/unknown" [] "" `shouldRespondWith` 404
|
||||
|
||||
when (actualPgVersion >= pgVersion100) $
|
||||
context "a partitioned table" $ do
|
||||
it "includes read/write methods for writeable partitioned tables" $ do
|
||||
r <- request methodOptions "/car_models" [] ""
|
||||
|
||||
@@ -11,10 +11,9 @@ import Test.Hspec.Wai
|
||||
import Test.Hspec.Wai.JSON
|
||||
import Text.Heredoc
|
||||
|
||||
import PostgREST.Config.PgVersion (PgVersion, pgVersion100,
|
||||
pgVersion110, pgVersion112,
|
||||
pgVersion120, pgVersion130,
|
||||
pgVersion140)
|
||||
import PostgREST.Config.PgVersion (PgVersion, pgVersion110,
|
||||
pgVersion112, pgVersion120,
|
||||
pgVersion130, pgVersion140)
|
||||
|
||||
import Protolude hiding (get)
|
||||
import SpecHelper
|
||||
@@ -494,8 +493,6 @@ spec actualPgVersion = do
|
||||
{"id": 205, "body": "zzz"}]|] `shouldRespondWith` 400
|
||||
|
||||
context "apply defaults on missing values" $ do
|
||||
-- inserting the array fails on pg 9.6, but the feature should work normally
|
||||
when (actualPgVersion >= pgVersion100) $
|
||||
it "inserts table default values(field-with_sep) when json keys are undefined" $
|
||||
request methodPost "/complex_items?columns=id,name,field-with_sep,arr_data" [("Prefer", "return=representation"), ("Prefer", "missing=default")]
|
||||
[json|[
|
||||
@@ -537,7 +534,6 @@ spec actualPgVersion = do
|
||||
, matchHeaders = ["Preference-Applied" <:> "missing=default, return=representation"]
|
||||
}
|
||||
|
||||
when (actualPgVersion >= pgVersion100) $
|
||||
it "inserts a default on a generated by default as identity column" $
|
||||
request methodPost "/channels?columns=id,data,slug&select=data,slug" [("Prefer", "return=representation"), ("Prefer", "missing=default")]
|
||||
[json| { "slug": "foo" } |]
|
||||
@@ -798,8 +794,6 @@ spec actualPgVersion = do
|
||||
}
|
||||
|
||||
|
||||
-- Data representations for payload parsing requires Postgres 10 or above.
|
||||
when (actualPgVersion >= pgVersion100) $ do
|
||||
describe "Data representations" $ do
|
||||
context "on regular table" $ do
|
||||
it "parses values in POST body" $
|
||||
|
||||
@@ -7,13 +7,11 @@ import Test.Hspec
|
||||
import Test.Hspec.Wai
|
||||
import Test.Hspec.Wai.JSON
|
||||
|
||||
import PostgREST.Config.PgVersion (PgVersion, pgVersion100)
|
||||
|
||||
import Protolude hiding (get)
|
||||
import SpecHelper
|
||||
|
||||
spec :: PgVersion -> SpecWith ((), Application)
|
||||
spec actualPgVersion = describe "PostGIS features" $
|
||||
spec :: SpecWith ((), Application)
|
||||
spec = describe "PostGIS features" $
|
||||
context "GeoJSON output" $ do
|
||||
it "works for a table that has a geometry column" $
|
||||
request methodGet "/shops"
|
||||
@@ -56,8 +54,7 @@ spec actualPgVersion = describe "PostGIS features" $
|
||||
it "works with resource embedding" $
|
||||
request methodGet "/shops?select=*,shop_bles(*)&id=eq.1"
|
||||
[("Accept", "application/geo+json")] "" `shouldRespondWith`
|
||||
(if actualPgVersion >= pgVersion100
|
||||
then [json| {
|
||||
[json| {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
@@ -83,32 +80,6 @@ spec actualPgVersion = describe "PostGIS features" $
|
||||
}
|
||||
]
|
||||
}|]
|
||||
else [json| {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": { "coordinates": [ -71.10044, 42.373695 ], "type": "Point" },
|
||||
"properties": {
|
||||
"address": "1369 Cambridge St", "id": 1,
|
||||
"shop_bles": [
|
||||
{ "id": 1, "name": "Beacon-1", "shop_id": 1 ,
|
||||
"coords": { "coordinates": [ -71.10044, 42.373695 ], "type": "Point" },
|
||||
"range_area": {
|
||||
"coordinates": [ [ [ -71.10045254230499, 42.37387083326593 ], [ -71.10048070549963, 42.37377126199953 ], [ -71.10039688646793, 42.37375838212269 ], [ -71.10037006437777, 42.37385844878863 ], [ -71.10045254230499, 42.37387083326593 ] ] ],
|
||||
"type": "Polygon" }
|
||||
},
|
||||
{ "coords": { "coordinates": [ -71.10044, 42.373695 ], "type": "Point" },
|
||||
"id": 2, "name": "Beacon-2", "shop_id": 1,
|
||||
"range_area": {
|
||||
"coordinates": [ [ [ -71.10034391283989, 42.37385299961788 ], [ -71.10036939382553, 42.373756895982865 ], [ -71.1002916097641, 42.373745997623224 ], [ -71.1002641171217, 42.37384408279195 ], [ -71.10034391283989, 42.37385299961788 ] ] ],
|
||||
"type": "Polygon" }
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}|])
|
||||
{ matchHeaders = ["Content-Type" <:> "application/geo+json; charset=utf-8"] }
|
||||
|
||||
it "works with RPC" $
|
||||
@@ -219,14 +190,8 @@ spec actualPgVersion = describe "PostGIS features" $
|
||||
|
||||
it "gets the geojson geometry object with the regular application/json output" $
|
||||
request methodGet "/shops?id=eq.1" [] "" `shouldRespondWith`
|
||||
(if actualPgVersion >= pgVersion100
|
||||
then [json|[{
|
||||
[json|[{
|
||||
"id":1,"address":"1369 Cambridge St",
|
||||
"shop_geom":{"type":"Point","crs":{"type":"name","properties":{"name":"EPSG:4326"}},"coordinates":[-71.10044,42.373695]}
|
||||
}]|]
|
||||
else [json|[{
|
||||
"address": "1369 Cambridge St",
|
||||
"id": 1,
|
||||
"shop_geom": { "coordinates": [ -71.10044, 42.373695 ], "type": "Point" }
|
||||
}]|])
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
@@ -11,9 +11,9 @@ import Test.Hspec.Wai
|
||||
import Test.Hspec.Wai.JSON
|
||||
import Text.Heredoc
|
||||
|
||||
import PostgREST.Config.PgVersion (PgVersion, pgVersion100,
|
||||
pgVersion109, pgVersion110,
|
||||
pgVersion112, pgVersion114)
|
||||
import PostgREST.Config.PgVersion (PgVersion, pgVersion109,
|
||||
pgVersion110, pgVersion112,
|
||||
pgVersion114)
|
||||
|
||||
import Protolude hiding (get)
|
||||
import SpecHelper
|
||||
@@ -530,38 +530,6 @@ spec actualPgVersion =
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
context "proc argument types" $ do
|
||||
-- different syntax for array needed for pg<10
|
||||
when (actualPgVersion < pgVersion100) $
|
||||
it "accepts a variety of arguments (Postgres < 10)" $
|
||||
post "/rpc/varied_arguments"
|
||||
[json| {
|
||||
"double": 3.1,
|
||||
"varchar": "hello",
|
||||
"boolean": true,
|
||||
"date": "20190101",
|
||||
"money": 0,
|
||||
"enum": "foo",
|
||||
"arr": "{a,b,c}",
|
||||
"integer": 43,
|
||||
"json": {"some key": "some value"},
|
||||
"jsonb": {"another key": [1, 2, "3"]}
|
||||
} |]
|
||||
`shouldRespondWith`
|
||||
[json| {
|
||||
"double": 3.1,
|
||||
"varchar": "hello",
|
||||
"boolean": true,
|
||||
"date": "2019-01-01",
|
||||
"money": "$0.00",
|
||||
"enum": "foo",
|
||||
"arr": ["a", "b", "c"],
|
||||
"integer": 43,
|
||||
"json": {"some key": "some value"},
|
||||
"jsonb": {"another key": [1, 2, "3"]}
|
||||
} |]
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
when (actualPgVersion >= pgVersion100) $
|
||||
it "accepts a variety of arguments (Postgres >= 10)" $
|
||||
post "/rpc/varied_arguments"
|
||||
[json| {
|
||||
@@ -635,14 +603,6 @@ spec actualPgVersion =
|
||||
[json|"object"|]
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
when (actualPgVersion < pgVersion100) $
|
||||
it "parses quoted JSON arguments as JSON (Postgres < 10)" $
|
||||
post "/rpc/json_argument"
|
||||
[json| { "arg": "{ \"key\": 3 }" } |]
|
||||
`shouldRespondWith`
|
||||
[json|"object"|]
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
when ((actualPgVersion >= pgVersion109 && actualPgVersion < pgVersion110)
|
||||
|| actualPgVersion >= pgVersion114) $
|
||||
it "parses quoted JSON arguments as JSON string (from Postgres 10.9, 11.4)" $
|
||||
@@ -765,14 +725,6 @@ spec actualPgVersion =
|
||||
[json|[{"a": "A", "b": "B"}]|]
|
||||
|
||||
context "procs with VARIADIC params" $ do
|
||||
when (actualPgVersion < pgVersion100) $
|
||||
it "works with POST (Postgres < 10)" $
|
||||
post "/rpc/variadic_param"
|
||||
[json| { "v": "{hi,hello,there}" } |]
|
||||
`shouldRespondWith`
|
||||
[json|["hi", "hello", "there"]|]
|
||||
|
||||
when (actualPgVersion >= pgVersion100) $ do
|
||||
it "works with POST (Postgres >= 10)" $
|
||||
post "/rpc/variadic_param"
|
||||
[json| { "v": ["hi", "hello", "there"] } |]
|
||||
@@ -822,7 +774,6 @@ spec actualPgVersion =
|
||||
`shouldRespondWith`
|
||||
[json|"Hello, world"|]
|
||||
|
||||
when (actualPgVersion >= pgVersion100) $
|
||||
it "returns last value for repeated non-variadic params in function with other VARIADIC arguments" $
|
||||
get "/rpc/sayhello_variadic?name=ignored&name=world&v=unused"
|
||||
`shouldRespondWith`
|
||||
|
||||
@@ -7,14 +7,11 @@ import Network.HTTP.Types
|
||||
import Test.Hspec.Wai
|
||||
import Test.Hspec.Wai.JSON
|
||||
|
||||
import PostgREST.Config.PgVersion (PgVersion, pgVersion100)
|
||||
|
||||
|
||||
import Protolude hiding (get)
|
||||
import SpecHelper
|
||||
|
||||
spec :: PgVersion -> SpecWith ((), Application)
|
||||
spec actualPgVersion = do
|
||||
spec :: SpecWith ((), Application)
|
||||
spec = do
|
||||
describe "Patching record" $ do
|
||||
context "to unknown uri" $
|
||||
it "indicates no table found by returning 404" $
|
||||
@@ -623,110 +620,7 @@ spec actualPgVersion = do
|
||||
}
|
||||
|
||||
-- Data representations for payload parsing requires Postgres 10 or above.
|
||||
when (actualPgVersion >= pgVersion100) $ do
|
||||
describe "Data representations" $ do
|
||||
context "for a single row" $ do
|
||||
it "parses values in payload" $
|
||||
request methodPatch "/datarep_todos?id=eq.2" [("Prefer", "return=headers-only")]
|
||||
[json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:00Z"} |]
|
||||
`shouldRespondWith`
|
||||
""
|
||||
{ matchStatus = 204
|
||||
, matchHeaders = [ matchHeaderAbsent hContentType
|
||||
, "Content-Range" <:> "0-0/*"]
|
||||
}
|
||||
|
||||
it "parses values in payload and formats individually selected values in return=representation" $
|
||||
request methodPatch "/datarep_todos?id=eq.2&select=id,label_color" [("Prefer", "return=representation")]
|
||||
[json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:00Z"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [{"id":2, "label_color": "#221100"}] |]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"
|
||||
, "Content-Range" <:> "0-0/*"
|
||||
, "Preference-Applied" <:> "return=representation"]
|
||||
}
|
||||
|
||||
it "parses values in payload and formats values in return=representation" $
|
||||
request methodPatch "/datarep_todos?id=eq.2" [("Prefer", "return=representation")]
|
||||
[json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:20Z", "icon_image": "3q2+7w"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [{"id":2,"name":"Essay","label_color":"#221100","due_at":"2019-01-03T11:00:20Z","icon_image":"3q2+7w==","created_at":1513213350,"budget":"100000000000000.13"}] |]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"
|
||||
, "Content-Range" <:> "0-0/*"
|
||||
, "Preference-Applied" <:> "return=representation"]
|
||||
}
|
||||
|
||||
it "parses values in payload and formats star mixed selected values in return=representation" $
|
||||
request methodPatch "/datarep_todos?id=eq.2&select=due_at,*" [("Prefer", "return=representation")]
|
||||
[json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:00Z", "created_at": 0} |]
|
||||
`shouldRespondWith`
|
||||
-- end up with due_at twice here but that's unrelated to data reps
|
||||
[json| [{"due_at":"2019-01-03T11:00:00Z","id":2,"name":"Essay","label_color":"#221100","due_at":"2019-01-03T11:00:00Z","icon_image":null,"created_at":0,"budget":"100000000000000.13"}] |]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"
|
||||
, "Content-Range" <:> "0-0/*"
|
||||
, "Preference-Applied" <:> "return=representation"]
|
||||
}
|
||||
context "for multiple rows" $ do
|
||||
it "parses values in payload and formats individually selected values in return=representation" $
|
||||
request methodPatch "/datarep_todos?id=lt.4&select=id,name,label_color" [("Prefer", "return=representation")]
|
||||
[json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:00Z"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [
|
||||
{"id":1, "name": "Report", "label_color": "#221100"},
|
||||
{"id":2, "name": "Essay", "label_color": "#221100"},
|
||||
{"id":3, "name": "Algebra", "label_color": "#221100"}
|
||||
] |]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"
|
||||
, "Content-Range" <:> "0-2/*"
|
||||
, "Preference-Applied" <:> "return=representation"]
|
||||
}
|
||||
|
||||
it "parses values in payload and formats values in return=representation" $
|
||||
request methodPatch "/datarep_todos?id=lt.4" [("Prefer", "return=representation")]
|
||||
[json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:00Z", "icon_image": "3q2+7w="} |]
|
||||
`shouldRespondWith`
|
||||
[json| [
|
||||
{"id":1,"name":"Report","label_color":"#221100","due_at":"2019-01-03T11:00:00Z","icon_image":"3q2+7w==","created_at":1513213350,"budget":"12.50"},
|
||||
{"id":2,"name":"Essay","label_color":"#221100","due_at":"2019-01-03T11:00:00Z","icon_image":"3q2+7w==","created_at":1513213350,"budget":"100000000000000.13"},
|
||||
{"id":3,"name":"Algebra","label_color":"#221100","due_at":"2019-01-03T11:00:00Z","icon_image":"3q2+7w==","created_at":1513213350,"budget":"0.00"}
|
||||
] |]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"
|
||||
, "Content-Range" <:> "0-2/*"
|
||||
, "Preference-Applied" <:> "return=representation"]
|
||||
}
|
||||
context "with ?columns parameter" $ do
|
||||
it "ignores json keys not included in ?columns; parses only the ones specified" $
|
||||
request methodPatch "/datarep_todos?id=eq.2&columns=due_at" [("Prefer", "return=representation")]
|
||||
[json| {"due_at": "2019-01-03T11:00:00Z", "smth": "here", "label_color": "invalid", "fake_id": 13} |]
|
||||
`shouldRespondWith`
|
||||
[json| [
|
||||
{"id":2,"name":"Essay","label_color":"#000100","due_at":"2019-01-03T11:00:00Z","icon_image":null,"created_at":1513213350,"budget":"100000000000000.13"}
|
||||
] |]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"
|
||||
, "Content-Range" <:> "0-0/*"
|
||||
, "Preference-Applied" <:> "return=representation"]
|
||||
}
|
||||
|
||||
it "fails if at least one specified column doesn't exist" $
|
||||
request methodPatch "/datarep_todos?id=eq.2&columns=label_color,helicopters" [("Prefer", "return=representation")]
|
||||
[json| {"due_at": "2019-01-03T11:00:00Z", "smth": "here", "label_color": "invalid", "fake_id": 13} |]
|
||||
`shouldRespondWith`
|
||||
[json| {"code":"PGRST204","details":null,"hint":null,"message":"Could not find the 'helicopters' column of 'datarep_todos' in the schema cache"} |]
|
||||
{ matchStatus = 400
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"]
|
||||
}
|
||||
|
||||
it "ignores json keys and gives 200 if no record updated" $
|
||||
request methodPatch "/datarep_todos?id=eq.2001&columns=label_color" [("Prefer", "return=representation")]
|
||||
[json| {"due_at": "2019-01-03T11:00:00Z", "smth": "here", "label_color": "invalid", "fake_id": 13} |]
|
||||
`shouldRespondWith` 200
|
||||
context "on a view" $ do
|
||||
context "for a single row" $ do
|
||||
it "parses values in payload" $
|
||||
request methodPatch "/datarep_todos_computed?id=eq.2" [("Prefer", "return=headers-only")]
|
||||
|
||||
+2
-2
@@ -162,7 +162,7 @@ main = do
|
||||
, ("Feature.Query.RpcSpec" , Feature.Query.RpcSpec.spec actualPgVersion)
|
||||
, ("Feature.Query.SingularSpec" , Feature.Query.SingularSpec.spec)
|
||||
, ("Feature.Query.SpreadQueriesSpec" , Feature.Query.SpreadQueriesSpec.spec)
|
||||
, ("Feature.Query.UpdateSpec" , Feature.Query.UpdateSpec.spec actualPgVersion)
|
||||
, ("Feature.Query.UpdateSpec" , Feature.Query.UpdateSpec.spec)
|
||||
, ("Feature.Query.UpsertSpec" , Feature.Query.UpsertSpec.spec actualPgVersion)
|
||||
]
|
||||
|
||||
@@ -228,7 +228,7 @@ main = do
|
||||
-- this test runs with an extra search path
|
||||
parallel $ before extraSearchPathApp $ do
|
||||
describe "Feature.ExtraSearchPathSpec" Feature.ExtraSearchPathSpec.spec
|
||||
describe "Feature.Query.PostGISSpec" $ Feature.Query.PostGISSpec.spec actualPgVersion
|
||||
describe "Feature.Query.PostGISSpec" Feature.Query.PostGISSpec.spec
|
||||
|
||||
-- this test runs with a root spec function override
|
||||
parallel $ before rootSpecApp $
|
||||
|
||||
Vendored
+1
-3
@@ -680,14 +680,12 @@ INSERT INTO private.films (id, title) VALUES (12,'douze commandements'), (2001,'
|
||||
TRUNCATE TABLE private.personnages CASCADE;
|
||||
INSERT INTO private.personnages (film_id, role_id, character) VALUES (12,1,'méchant'), (2001,2,'astronaute');
|
||||
|
||||
DO $do$BEGIN
|
||||
IF (SELECT current_setting('server_version_num')::INT >= 100000) THEN
|
||||
INSERT INTO test.car_models(name, year) VALUES ('DeLorean',1981);
|
||||
INSERT INTO test.car_models(name, year) VALUES ('F310-B',1997);
|
||||
INSERT INTO test.car_models(name, year) VALUES ('Veneno',2013);
|
||||
INSERT INTO test.car_models(name, year) VALUES ('Murcielago',2001);
|
||||
END IF;
|
||||
|
||||
DO $do$BEGIN
|
||||
IF (SELECT current_setting('server_version_num')::INT >= 110000) THEN
|
||||
INSERT INTO test.car_brands(name) VALUES ('DMC');
|
||||
INSERT INTO test.car_brands(name) VALUES ('Ferrari');
|
||||
|
||||
Vendored
-6
@@ -41,13 +41,7 @@ GRANT USAGE ON SEQUENCE
|
||||
, leak_id_seq
|
||||
TO postgrest_test_anonymous;
|
||||
|
||||
DO $do$
|
||||
BEGIN
|
||||
IF current_setting('server_version_num')::INT >= 100000 THEN
|
||||
GRANT USAGE ON SEQUENCE channels_id_seq TO postgrest_test_anonymous;
|
||||
END IF;
|
||||
END
|
||||
$do$;
|
||||
|
||||
-- Privileges for non anonymous users
|
||||
GRANT USAGE ON SCHEMA test TO postgrest_test_author;
|
||||
|
||||
Vendored
+1
-18
@@ -2289,10 +2289,6 @@ create table private.rollen (
|
||||
);
|
||||
|
||||
-- Tables used for testing embedding between partitioned tables
|
||||
|
||||
do $do$begin
|
||||
-- partitioned tables using the PARTITION syntax are supported from pg v10
|
||||
if (select current_setting('server_version_num')::int >= 100000) then
|
||||
create table test.car_models(
|
||||
name varchar(64) not null,
|
||||
year int not null
|
||||
@@ -2307,8 +2303,8 @@ A test for partitioned tables$$;
|
||||
for values in (2021);
|
||||
create table test.car_models_default partition of test.car_models
|
||||
for values in (1981,1997,2001,2013);
|
||||
end if;
|
||||
|
||||
do $do$begin
|
||||
-- primary keys for partitioned tables are supported from pg v11
|
||||
if (select current_setting('server_version_num')::int >= 110000) then
|
||||
create table test.car_brands (
|
||||
@@ -2492,10 +2488,6 @@ BEGIN
|
||||
END$$;
|
||||
|
||||
-- This view is not used in any requests but just parsed by the pfkSourceColumns query.
|
||||
-- XMLTABLE is only supported from PG 10 on
|
||||
DO $do$
|
||||
BEGIN
|
||||
IF current_setting('server_version_num')::INT >= 100000 THEN
|
||||
CREATE VIEW test.xml AS
|
||||
SELECT *
|
||||
FROM (SELECT ''::xml AS data) _,
|
||||
@@ -2505,9 +2497,6 @@ BEGIN
|
||||
COLUMNS id int PATH '@id',
|
||||
premier_name text PATH 'PREMIER_NAME' DEFAULT 'not specified'
|
||||
);
|
||||
END IF;
|
||||
END
|
||||
$do$;
|
||||
|
||||
-- https://github.com/PostgREST/postgrest/issues/1543
|
||||
CREATE TYPE complex AS (
|
||||
@@ -3277,17 +3266,11 @@ create table test.tbl_w_json(
|
||||
data json
|
||||
);
|
||||
|
||||
DO $do$
|
||||
BEGIN
|
||||
IF current_setting('server_version_num')::INT >= 100000 THEN
|
||||
CREATE TABLE test.channels (
|
||||
id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
data jsonb DEFAULT '{"foo": "bar"}',
|
||||
slug text
|
||||
);
|
||||
END IF;
|
||||
END
|
||||
$do$;
|
||||
|
||||
CREATE FUNCTION test.is_superuser() RETURNS boolean
|
||||
LANGUAGE sql
|
||||
|
||||
Reference in New Issue
Block a user