diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index eba263ebe..e2f59edf7 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -67,7 +67,7 @@ jobs: strategy: fail-fast: false matrix: - pgVersion: [12, 13, 14, 15, 16] + pgVersion: [12, 13, 14, 15, 16, 17] name: PG ${{ matrix.pgVersion }} runs-on: ubuntu-22.04 defaults: diff --git a/default.nix b/default.nix index 4b87b49dd..af73cce9a 100644 --- a/default.nix +++ b/default.nix @@ -36,7 +36,6 @@ let allOverlays.checked-shell-script allOverlays.gitignore allOverlays.postgresql-libpq - allOverlays.postgresql-future (allOverlays.haskell-packages { inherit compiler; }) allOverlays.slocat ]; @@ -47,6 +46,7 @@ let postgresqlVersions = [ + { name = "postgresql-17"; postgresql = pkgs.postgresql_17.withPackages (p: [ p.postgis p.pg_safeupdate ]); } { name = "postgresql-16"; postgresql = pkgs.postgresql_16.withPackages (p: [ p.postgis p.pg_safeupdate ]); } { name = "postgresql-15"; postgresql = pkgs.postgresql_15.withPackages (p: [ p.postgis p.pg_safeupdate ]); } { name = "postgresql-14"; postgresql = pkgs.postgresql_14.withPackages (p: [ p.postgis p.pg_safeupdate ]); } diff --git a/nix/README.md b/nix/README.md index e88984b1c..601fa4f55 100644 --- a/nix/README.md +++ b/nix/README.md @@ -80,7 +80,7 @@ postgrest-lint postgrest-with-postgresql-13 postgrest-run postgrest-with-postgresql-14 postgrest-style postgrest-with-postgresql-15 postgrest-style-check postgrest-with-postgresql-16 -postgrest-test-io +postgrest-test-io postgrest-with-postgresql-17 ... [nix-shell]$ @@ -104,7 +104,7 @@ postgrest-lint postgrest-with-postgresql-13 postgrest-run postgrest-with-postgresql-14 postgrest-style postgrest-with-postgresql-15 postgrest-style-check postgrest-with-postgresql-16 -postgrest-test-io +postgrest-test-io postgrest-with-postgresql-17 postgrest-test-memory ... diff --git a/nix/overlays/default.nix b/nix/overlays/default.nix index 32e03c741..18900f0a1 100644 --- a/nix/overlays/default.nix +++ b/nix/overlays/default.nix @@ -4,6 +4,5 @@ gitignore = import ./gitignore.nix; haskell-packages = import ./haskell-packages.nix; postgresql-libpq = import ./postgresql-libpq.nix; - postgresql-future = import ./postgresql-future.nix; slocat = import ./slocat.nix; } diff --git a/nix/overlays/postgresql-future.nix b/nix/overlays/postgresql-future.nix deleted file mode 100644 index 5ef8a42d8..000000000 --- a/nix/overlays/postgresql-future.nix +++ /dev/null @@ -1,19 +0,0 @@ -_: _: -# Overlay that adds future versions of PostgreSQL that are supported by -# PostgREST. -{ - ## Example for including a postgresql version from a specific nixpks commit: - ## - # postgresql_16 = - # let - # rev = "5148520bfab61f99fd25fb9ff7bfbb50dad3c9db"; - # tarballHash = "1dfjmz65h8z4lk845724vypzmf3dbgsdndjpj8ydlhx6c7rpcq3p"; - # - # pinnedPkgs = - # builtins.fetchTarball { - # url = "https://github.com/nixos/nixpkgs/archive/${rev}.tar.gz"; - # sha256 = tarballHash; - # }; - # in - # (import pinnedPkgs { }).pkgs.postgresql_16; -} diff --git a/src/PostgREST/Config/PgVersion.hs b/src/PostgREST/Config/PgVersion.hs index e1387b8f3..273d62941 100644 --- a/src/PostgREST/Config/PgVersion.hs +++ b/src/PostgREST/Config/PgVersion.hs @@ -6,6 +6,7 @@ module PostgREST.Config.PgVersion , pgVersion130 , pgVersion140 , pgVersion150 + , pgVersion170 ) where import qualified Data.Aeson as JSON @@ -38,3 +39,6 @@ pgVersion140 = PgVersion 140000 "14.0" "14.0" pgVersion150 :: PgVersion pgVersion150 = PgVersion 150000 "15.0" "15.0" + +pgVersion170 :: PgVersion +pgVersion170 = PgVersion 170000 "17.0" "17.0" diff --git a/test/spec/Feature/Query/PlanSpec.hs b/test/spec/Feature/Query/PlanSpec.hs index f1e27b117..837332b21 100644 --- a/test/spec/Feature/Query/PlanSpec.hs +++ b/test/spec/Feature/Query/PlanSpec.hs @@ -15,7 +15,8 @@ import Test.Hspec hiding (pendingWith) import Test.Hspec.Wai import Test.Hspec.Wai.JSON -import PostgREST.Config.PgVersion (PgVersion, pgVersion130) +import PostgREST.Config.PgVersion (PgVersion, pgVersion130, + pgVersion170) import Protolude hiding (get) import SpecHelper @@ -33,7 +34,7 @@ spec actualPgVersion = do liftIO $ do resHeaders `shouldSatisfy` elem ("Content-Type", "application/vnd.pgrst.plan+json; for=\"application/json\"; charset=utf-8") resStatus `shouldBe` Status { statusCode = 200, statusMessage="OK" } - totalCost `shouldBe` 15.63 + totalCost `shouldBe` (if actualPgVersion >= pgVersion170 then 11.32 else 15.63) it "outputs the total cost for a single filter on a view" $ do r <- request methodGet "/projects_view?id=gt.2" @@ -166,7 +167,7 @@ spec actualPgVersion = do liftIO $ do resHeaders `shouldSatisfy` elem ("Content-Type", "application/vnd.pgrst.plan+json; for=\"application/json\"; charset=utf-8") resStatus `shouldBe` Status { statusCode = 200, statusMessage="OK" } - totalCost `shouldBe` 15.68 + totalCost `shouldBe` (if actualPgVersion >= pgVersion170 then 11.37 else 15.68) it "outputs the total cost for a single upsert" $ do r <- request methodPut "/tiobe_pls?name=eq.Go" diff --git a/test/spec/fixtures/schema.sql b/test/spec/fixtures/schema.sql index a3b6edda1..a19261c69 100644 --- a/test/spec/fixtures/schema.sql +++ b/test/spec/fixtures/schema.sql @@ -257,7 +257,7 @@ CREATE FUNCTION varied_arguments( enum enum_menagerie_type, arr text[], "integer" integer default 42, - json json default '{}', + "json" json default '{}', jsonb jsonb default '{}' ) RETURNS json LANGUAGE sql @@ -299,7 +299,7 @@ CREATE FUNCTION varied_arguments_openapi( json_arr json[], jsonb_arr jsonb[], "integer" integer default 42, - json json default '{}', + "json" json default '{}', jsonb jsonb default '{}' ) RETURNS json LANGUAGE sql @@ -2770,11 +2770,11 @@ END; $$ LANGUAGE plpgsql SECURITY DEFINER; DROP DOMAIN IF EXISTS public.titlecasetext CASCADE; CREATE DOMAIN public.titlecasetext AS text; -CREATE OR REPLACE FUNCTION json(public.titlecasetext) RETURNS json AS $$ +CREATE OR REPLACE FUNCTION "json"(public.titlecasetext) RETURNS json AS $$ SELECT to_json(INITCAP($1::text)); $$ LANGUAGE SQL IMMUTABLE; -CREATE CAST (public.titlecasetext AS json) WITH FUNCTION json(public.titlecasetext) AS IMPLICIT; +CREATE CAST (public.titlecasetext AS json) WITH FUNCTION "json"(public.titlecasetext) AS IMPLICIT; -- End of data representations specific stuff except for where the domain is used in the table. CREATE TABLE designers ( @@ -3106,14 +3106,14 @@ CREATE OR REPLACE FUNCTION color(text) RETURNS public.color AS $$ SELECT (('x' || lpad((CASE WHEN SUBSTRING($1::text, 1, 1) = '#' THEN SUBSTRING($1::text, 2) ELSE $1::text END), 8, '0'))::bit(32)::int)::public.color; $$ LANGUAGE SQL IMMUTABLE; -CREATE OR REPLACE FUNCTION json(public.color) RETURNS json AS $$ +CREATE OR REPLACE FUNCTION "json"(public.color) RETURNS json AS $$ SELECT CASE WHEN $1 IS NULL THEN to_json(''::text) ELSE to_json('#' || lpad(upper(to_hex($1)), 6, '0')) END; $$ LANGUAGE SQL IMMUTABLE; -CREATE CAST (public.color AS json) WITH FUNCTION json(public.color) AS IMPLICIT; +CREATE CAST (public.color AS json) WITH FUNCTION "json"(public.color) AS IMPLICIT; CREATE CAST (json AS public.color) WITH FUNCTION color(json) AS IMPLICIT; CREATE CAST (text AS public.color) WITH FUNCTION color(text) AS IMPLICIT; @@ -3128,11 +3128,11 @@ CREATE OR REPLACE FUNCTION isodate(text) RETURNS public.isodate AS $$ SELECT (replace($1, 'Z', '+00:00')::timestamp with time zone)::public.isodate; $$ LANGUAGE SQL IMMUTABLE; -CREATE OR REPLACE FUNCTION json(public.isodate) RETURNS json AS $$ +CREATE OR REPLACE FUNCTION "json"(public.isodate) RETURNS json AS $$ SELECT to_json(replace(to_json($1)#>>'{}', '+00:00', 'Z')); $$ LANGUAGE SQL IMMUTABLE; -CREATE CAST (public.isodate AS json) WITH FUNCTION json(public.isodate) AS IMPLICIT; +CREATE CAST (public.isodate AS json) WITH FUNCTION "json"(public.isodate) AS IMPLICIT; CREATE CAST (json AS public.isodate) WITH FUNCTION isodate(json) AS IMPLICIT; -- We intentionally don't have this in order to test query string parsing doesn't try to fall back on JSON parsing. -- CREATE CAST (text AS public.isodate) WITH FUNCTION isodate(text) AS IMPLICIT; @@ -3150,11 +3150,11 @@ CREATE OR REPLACE FUNCTION bytea_b64(text) RETURNS public.bytea_b64 AS $$ SELECT decode($1 || repeat('=', 4 - (length($1) % 4)), 'base64')::public.bytea_b64; $$ LANGUAGE SQL IMMUTABLE; -CREATE OR REPLACE FUNCTION json(public.bytea_b64) RETURNS json AS $$ +CREATE OR REPLACE FUNCTION "json"(public.bytea_b64) RETURNS json AS $$ SELECT to_json(translate(encode($1, 'base64'), E'\n', '')); $$ LANGUAGE SQL IMMUTABLE; -CREATE CAST (public.bytea_b64 AS json) WITH FUNCTION json(public.bytea_b64) AS IMPLICIT; +CREATE CAST (public.bytea_b64 AS json) WITH FUNCTION "json"(public.bytea_b64) AS IMPLICIT; CREATE CAST (json AS public.bytea_b64) WITH FUNCTION bytea_b64(json) AS IMPLICIT; CREATE CAST (text AS public.bytea_b64) WITH FUNCTION bytea_b64(text) AS IMPLICIT; @@ -3170,12 +3170,12 @@ CREATE OR REPLACE FUNCTION unixtz(text) RETURNS public.unixtz AS $$ SELECT (to_timestamp($1::numeric)::public.unixtz); $$ LANGUAGE SQL IMMUTABLE; -CREATE OR REPLACE FUNCTION json(public.unixtz) RETURNS json AS $$ +CREATE OR REPLACE FUNCTION "json"(public.unixtz) RETURNS json AS $$ SELECT to_json(extract(epoch from $1)::bigint); $$ LANGUAGE SQL IMMUTABLE; -CREATE CAST (public.unixtz AS json) WITH FUNCTION json(public.unixtz) AS IMPLICIT; +CREATE CAST (public.unixtz AS json) WITH FUNCTION "json"(public.unixtz) AS IMPLICIT; CREATE CAST (json AS public.unixtz) WITH FUNCTION unixtz(json) AS IMPLICIT; CREATE CAST (text AS public.unixtz) WITH FUNCTION unixtz(text) AS IMPLICIT; @@ -3190,11 +3190,11 @@ CREATE OR REPLACE FUNCTION monetary(text) RETURNS public.monetary AS $$ SELECT ($1::numeric)::public.monetary; $$ LANGUAGE SQL IMMUTABLE; -CREATE OR REPLACE FUNCTION json(public.monetary) RETURNS json AS $$ +CREATE OR REPLACE FUNCTION "json"(public.monetary) RETURNS json AS $$ SELECT to_json($1::text); $$ LANGUAGE SQL IMMUTABLE; -CREATE CAST (public.monetary AS json) WITH FUNCTION json(public.monetary) AS IMPLICIT; +CREATE CAST (public.monetary AS json) WITH FUNCTION "json"(public.monetary) AS IMPLICIT; CREATE CAST (json AS public.monetary) WITH FUNCTION monetary(json) AS IMPLICIT; CREATE CAST (text AS public.monetary) WITH FUNCTION monetary(text) AS IMPLICIT;