From 59e0b006a533b03a50e888f092141247268f0fae Mon Sep 17 00:00:00 2001 From: laurenceisla Date: Fri, 18 Jun 2021 18:09:19 -0500 Subject: [PATCH] fix: Location header with a null PK on a view (#1875) Regression after #1475 --- src/PostgREST/Query/SqlFragment.hs | 2 +- test/Feature/InsertSpec.hs | 12 +++++++++++- test/fixtures/privileges.sql | 1 + test/fixtures/schema.sql | 22 ++++++++++++++++++++++ 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/PostgREST/Query/SqlFragment.hs b/src/PostgREST/Query/SqlFragment.hs index 63dd2a709..e7eac1c3a 100644 --- a/src/PostgREST/Query/SqlFragment.hs +++ b/src/PostgREST/Query/SqlFragment.hs @@ -172,7 +172,7 @@ asBinaryF fieldName = "coalesce(string_agg(_postgrest_t." <> pgFmtIdent fieldNam locationF :: [Text] -> SqlFragment locationF pKeys = [qc|( WITH data AS (SELECT row_to_json(_) AS row FROM {sourceCTEName} AS _ LIMIT 1) - SELECT array_agg(json_data.key || '=eq.' || json_data.value) + SELECT array_agg(json_data.key || '=' || coalesce('eq.' || json_data.value, 'is.null')) FROM data CROSS JOIN json_each_text(data.row) AS json_data WHERE json_data.key IN ('{fmtPKeys}') )|] diff --git a/test/Feature/InsertSpec.hs b/test/Feature/InsertSpec.hs index bdf75172e..04985606e 100644 --- a/test/Feature/InsertSpec.hs +++ b/test/Feature/InsertSpec.hs @@ -527,7 +527,7 @@ spec actualPgVersion = do , matchHeaders = [ matchHeaderAbsent hLocation ] } - context "requesting header only representation" $ + context "requesting header only representation" $ do it "returns a location header" $ request methodPost "/compound_pk_view" [("Prefer", "return=headers-only")] [json|{"k1":1,"k2":"test","extra":2}|] @@ -537,3 +537,13 @@ spec actualPgVersion = do , matchHeaders = [ "Location" <:> "/compound_pk_view?k1=eq.1&k2=eq.test" , "Content-Range" <:> "*/*" ] } + + it "should not throw and return location header when a PK is null" $ + request methodPost "/test_null_pk_competitors_sponsors" [("Prefer", "return=headers-only")] + [json|{"id":1}|] + `shouldRespondWith` + "" + { matchStatus = 201 + , matchHeaders = [ "Location" <:> "/test_null_pk_competitors_sponsors?id=eq.1&sponsor_id=is.null" + , "Content-Range" <:> "*/*" ] + } diff --git a/test/fixtures/privileges.sql b/test/fixtures/privileges.sql index c9c40e94a..377e3c682 100644 --- a/test/fixtures/privileges.sql +++ b/test/fixtures/privileges.sql @@ -37,6 +37,7 @@ GRANT ALL ON TABLE , projects , projects_view , projects_view_alt + , test_null_pk_competitors_sponsors , simple_pk , simple_pk2 , tasks diff --git a/test/fixtures/schema.sql b/test/fixtures/schema.sql index d2b36ab5a..ed6bd53ba 100644 --- a/test/fixtures/schema.sql +++ b/test/fixtures/schema.sql @@ -670,6 +670,28 @@ CREATE VIEW projects_view_alt AS projects.client_id as t_client_id FROM projects; +CREATE TABLE sponsors ( + id integer primary key, + name varchar(20) not null +); + +CREATE TABLE competitors ( + id integer primary key, + sponsor_id integer references sponsors(id), + full_name varchar(40) not null +); + +CREATE VIEW test_null_pk_competitors_sponsors AS +SELECT c.id, s.id as sponsor_id +FROM competitors c + LEFT JOIN sponsors s on c.sponsor_id = s.id; + +CREATE RULE test_null_pk_competitors_sponsors AS + ON INSERT TO test_null_pk_competitors_sponsors DO INSTEAD + INSERT INTO competitors(id, full_name, sponsor_id) + VALUES (new.id, 'Competitor without sponsor', new.sponsor_id) + RETURNING id, sponsor_id; + -- -- Name: simple_pk; Type: TABLE; Schema: test; Owner: - --