feat: custom SQL handler for the "*/*" media type
This commit is contained in:
committed by
Steve Chavez
parent
7640de34e2
commit
9fe11249f9
@@ -222,3 +222,81 @@ spec = describe "custom media types" $ do
|
||||
simpleBody r `shouldBe` readFixtureFile "lines.csv"
|
||||
simpleHeaders r `shouldContain` [("Content-Type", "text/csv; charset=utf-8")]
|
||||
simpleHeaders r `shouldContain` [("Content-Disposition", "attachment; filename=\"lines.csv\"")]
|
||||
|
||||
context "any media type" $ do
|
||||
context "on functions" $ do
|
||||
-- TODO not correct, it should return the generic "application/octet-stream"
|
||||
it "returns application/json for */* if not explicitly set" $ do
|
||||
request methodGet "/rpc/ret_any_mt" (acceptHdrs "*/*") ""
|
||||
`shouldRespondWith` "any"
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = [matchContentTypeJson]
|
||||
}
|
||||
|
||||
it "accepts any media type and sets it as a header" $ do
|
||||
request methodGet "/rpc/ret_any_mt" (acceptHdrs "app/bingo") ""
|
||||
`shouldRespondWith` "any"
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "app/bingo"]
|
||||
}
|
||||
|
||||
request methodGet "/rpc/ret_any_mt" (acceptHdrs "text/bango") ""
|
||||
`shouldRespondWith` "any"
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "text/bango"]
|
||||
}
|
||||
|
||||
request methodGet "/rpc/ret_any_mt" (acceptHdrs "image/boingo") ""
|
||||
`shouldRespondWith` "any"
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "image/boingo"]
|
||||
}
|
||||
|
||||
it "returns custom media type for */* if explicitly set" $ do
|
||||
request methodGet "/rpc/ret_some_mt" (acceptHdrs "*/*") ""
|
||||
`shouldRespondWith` "groucho"
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "app/groucho"]
|
||||
}
|
||||
|
||||
it "accepts some media types if there's conditional logic" $ do
|
||||
request methodGet "/rpc/ret_some_mt" (acceptHdrs "app/chico") ""
|
||||
`shouldRespondWith` "chico"
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "app/chico"]
|
||||
}
|
||||
|
||||
request methodGet "/rpc/ret_some_mt" (acceptHdrs "app/harpo") ""
|
||||
`shouldRespondWith` "harpo"
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "app/harpo"]
|
||||
}
|
||||
|
||||
request methodGet "/rpc/ret_some_mt" (acceptHdrs "text/csv") ""
|
||||
`shouldRespondWith` 415
|
||||
|
||||
context "on tables" $ do
|
||||
-- TODO not correct, it should return the generic "application/octet-stream"
|
||||
it "returns application/json for */* if not explicitly set" $ do
|
||||
request methodGet "/some_numbers?val=eq.1" (acceptHdrs "*/*") ""
|
||||
`shouldRespondWith` "anything\n1"
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = [matchContentTypeJson]
|
||||
}
|
||||
|
||||
it "accepts any media type and sets it as a header" $ do
|
||||
request methodGet "/some_numbers?val=eq.2" (acceptHdrs "magic/number") ""
|
||||
`shouldRespondWith` "magic\n2"
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "magic/number"]
|
||||
}
|
||||
request methodGet "/some_numbers?val=eq.3" (acceptHdrs "crazy/bingo") ""
|
||||
`shouldRespondWith` "crazy\n3"
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "crazy/bingo"]
|
||||
}
|
||||
request methodGet "/some_numbers?val=eq.4" (acceptHdrs "unknown/unknown") ""
|
||||
`shouldRespondWith` "anything\n4"
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "unknown/unknown"]
|
||||
}
|
||||
|
||||
Vendored
+56
-1
@@ -130,6 +130,7 @@ create domain "application/json" as json;
|
||||
create domain "application/vnd.pgrst.object" as json;
|
||||
create domain "text/tab-separated-values" as text;
|
||||
create domain "text/csv" as text;
|
||||
create domain "*/*" as bytea;
|
||||
|
||||
CREATE TABLE items (
|
||||
id bigserial primary key
|
||||
@@ -3593,7 +3594,6 @@ $$ language sql;
|
||||
|
||||
create or replace function test.tsv_final (data "text/tab-separated-values")
|
||||
returns "text/tab-separated-values" as $$
|
||||
select set_config('response.headers', '[{"Cache-Control": "public"}, {"Cache-Control": "max-age=259200"}]', true);
|
||||
select (E'id\tname\tclient_id\n' || data)::"text/tab-separated-values";
|
||||
$$ language sql;
|
||||
|
||||
@@ -3650,3 +3650,58 @@ create table budget_expenses (
|
||||
, expense_amount numeric
|
||||
, budget_category_id integer references budget_categories(id)
|
||||
);
|
||||
|
||||
create or replace function ret_any_mt ()
|
||||
returns "*/*" as $$
|
||||
select 'any'::"*/*";
|
||||
$$ language sql;
|
||||
|
||||
create or replace function ret_some_mt ()
|
||||
returns "*/*" as $$
|
||||
declare
|
||||
req_accept text := current_setting('request.headers', true)::json->>'accept';
|
||||
resp bytea;
|
||||
begin
|
||||
case req_accept
|
||||
when 'app/chico' then resp := 'chico';
|
||||
when 'app/harpo' then resp := 'harpo';
|
||||
when '*/*' then
|
||||
perform set_config('response.headers', '[{"Content-Type": "app/groucho"}]', true);
|
||||
resp := 'groucho';
|
||||
else
|
||||
raise sqlstate 'PT415' using message = 'Unsupported Media Type';
|
||||
end case;
|
||||
return resp;
|
||||
end; $$ language plpgsql;
|
||||
|
||||
create table some_numbers as select x::int as val from generate_series(1,10) x;
|
||||
|
||||
create or replace function some_trans (state "*/*", next some_numbers)
|
||||
returns "*/*" as $$
|
||||
select (state || E'\n' || next.val::text::bytea)::"*/*";
|
||||
$$ language sql;
|
||||
|
||||
create or replace function some_final (data "*/*")
|
||||
returns "*/*" as $$
|
||||
declare
|
||||
req_accept text := current_setting('request.headers', true)::json->>'accept';
|
||||
prefix bytea;
|
||||
begin
|
||||
case req_accept
|
||||
when 'magic/number' then
|
||||
prefix := 'magic';
|
||||
when 'crazy/bingo' then
|
||||
prefix := 'crazy';
|
||||
else
|
||||
prefix := 'anything';
|
||||
end case;
|
||||
return (prefix || data)::"*/*";
|
||||
end; $$ language plpgsql;
|
||||
|
||||
drop aggregate if exists some_agg (some_numbers);
|
||||
create aggregate test.some_agg (some_numbers) (
|
||||
initcond = ''
|
||||
, stype = "*/*"
|
||||
, sfunc = some_trans
|
||||
, finalfunc = some_final
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user