Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions frameworks/Haskell/postgrest/README.md
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* [DB](src/db.sql)
* [QUERY](src/query.sql)
* [CACHED QUERY] Not Implemented
* [UPDATE] Not Implemented
* [UPDATE](src/update.sql)
* [FORTUNES](src/fortunes.sql)

## Important Libraries
Expand All @@ -17,7 +17,7 @@ The tests were run with:
## Test URLs
### JSON

http://localhost:3000/rpc/json
http://localhost:3000/rpc/jsonser

### PLAINTEXT

Expand All @@ -31,13 +31,20 @@ http://localhost:3000/rpc/db

http://localhost:3000/rpc/query?queries=

### CACHED QUERY Not Implemented
### CACHED QUERY - Not Implemented

http://localhost:8080/cached_query?queries=

### UPDATE Not Implemented
### UPDATE - Not Working

http://localhost:3000/rpc/update?queries=
http://localhost:3000/rpc/updates?queries=

Technically, this is implemented (maybe not correctly though).
However, the benchmark issues this as a GET request.
PostgREST sets the transaction to READ ONLY for GET requests,
as they are supposed to be idempotent.
Hence this results in an error. Calling the endpoint with POST
works though.

### FORTUNES

Expand Down
4 changes: 2 additions & 2 deletions frameworks/Haskell/postgrest/benchmark_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
"tests": [
{
"default": {
"json_url": "/rpc/json",
"json_url": "/rpc/jsonser",
"plaintext_url": "/rpc/plaintext",
"db_url": "/rpc/db",
"query_url": "/rpc/queries?queries=",
"fortunes_url": "/rpc/fortunes.html",
"fortune_url": "/rpc/fortunes",
"port": 3000,
"approach": "Realistic",
"classification": "Micro",
Expand Down
1 change: 1 addition & 0 deletions frameworks/Haskell/postgrest/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ urls.plaintext = "/rpc/plaintext"
urls.json = "/rpc/json"
urls.db = "/rpc/db"
urls.query = "/rpc/queries?queries="
urls.fortune = "/rpc/fortunes"
approach = "Realistic"
classification = "Micro"
database = "postgres"
Expand Down
5 changes: 3 additions & 2 deletions frameworks/Haskell/postgrest/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
version: '3'
services:
tfb-database:
build:
Expand All @@ -13,4 +12,6 @@ services:
dockerfile: postgrest.dockerfile
context: .
ports:
- 3030:3000
- 3030:3000
depends_on:
- tfb-database
1 change: 0 additions & 1 deletion frameworks/Haskell/postgrest/postgrest.conf
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,3 @@ role-claim-key = "$(PGRST_ROLE_CLAIM_KEY)"
max-rows = "$(PGRST_MAX_ROWS)"
pre-request = "$(PGRST_PRE_REQUEST)"
root-spec = "$(PGRST_ROOT_SPEC)"
raw-media-types = "$(PGRST_RAW_MEDIA_TYPES)"
4 changes: 1 addition & 3 deletions frameworks/Haskell/postgrest/postgrest.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,10 @@ ENV PGRST_MAX_ROWS=
ENV PGRST_PRE_REQUEST=
ENV PGRST_ROLE_CLAIM_KEY=.role
ENV PGRST_ROOT_SPEC=
ENV PGRST_RAW_MEDIA_TYPES=

ENV PGRST_DB_URI=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world
ENV PGRST_DB_SCHEMA=public
ENV PGRST_DB_ANON_ROLE=benchmarkdbuser
ENV PGRST_RAW_MEDIA_TYPES="text/html, text/plain"
ENV PGRST_DB_POOL=64
RUN mkdir /app
COPY src /app
Expand All @@ -37,4 +35,4 @@ WORKDIR /app

EXPOSE 3000

ENTRYPOINT [ "/app/entrypoint.sh" ]
ENTRYPOINT [ "/app/entrypoint.sh" ]
49 changes: 17 additions & 32 deletions frameworks/Haskell/postgrest/src/fortunes.sql
Original file line number Diff line number Diff line change
@@ -1,35 +1,20 @@
CREATE TYPE fortune_t AS (id int, message text);
create domain "text/html" as text;

create or replace function fortune_template(f fortune_t) returns text as $$
SELECT format('<tr><td>%s</td><td>%s</td></tr>', $1.id, regexp_replace($1.message, '<', '&lt;','g'));
$$ language sql volatile;
create or replace function sanitize_html(text) returns text as $$
select replace(replace(replace(replace(replace($1, '&', '&amp;'), '"', '&quot;'),'>', '&gt;'),'<', '&lt;'), '''', '&apos;')
$$ language sql immutable;

create or replace function fortunes_template(fortunes fortune_t[]) returns text as $$
WITH header AS (
SELECT 0 as id,'<!DOCTYPE html>
<html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>' as html
), footer AS (
SELECT 2,'</table></body></html>' as html
), fortunes AS (
SELECT unnest as fortune from unnest($1)
), additional AS (
SELECT (-1, 'Additional fortune added at request time.')::fortune_t as f
), all_fortunes AS (
SELECT * from (SELECT * FROM fortunes UNION ALL SELECT * from additional) p ORDER BY (fortune).message
), fortunes_html AS (
SELECT 1,string_agg(fortune_template(fortune), '') from all_fortunes
), html AS (
SELECT * FROM header UNION SELECT * FROM fortunes_html UNION SELECT * from footer ORDER BY id
)
SELECT string_agg(html,'') from html;
$$ language sql volatile;
create or replace function fortune_template("Fortune") returns text as $$
SELECT format('<tr><td>%s</td><td>%s</td></tr>', $1.id, sanitize_html($1.message));
$$ language sql immutable;

create or replace function "fortunes.html"() returns bytea as $$
DECLARE
fortunes fortune_t[];
BEGIN
SET LOCAL "response.headers" = '[{"Content-Type": "text/html"}]';
SELECT array_agg(CAST((id,message) AS fortune_t)) FROM "Fortunes" INTO fortunes;
RETURN convert_to(fortunes_template(fortunes), 'UTF8');
END
$$ language plpgsql volatile;
create or replace function fortunes() returns "text/html" as $$
-- This is only necessary bc. of the benchmark: The domain gives us content-type: text/html,
-- but the benchmark explicitly tests for the charset in the content-type.
select set_config('response.headers', '[{"Content-Type": "text/html; charset=utf-8"}]', true);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @cptwunderlich,

This line shouldn't be necessary. PostgREST will automatically set the content type to the "text/html" domain.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, this adds the type "text/html", but the benchmark harness expects an explicit value of "text/html; charset=UTF-8".
If you remove it, the test fails with:

   FAIL for http://tfb-server:3000/rpc/fortunes
     Invalid Content-Type header, found "text/html", did not match "^text/html; ?charset=(UTF|utf)-8$".

I can add a comment to clarify.

There are some oddities in this benchmark. E.g., the "updates" benchmark will never work for postgREST, bc. they use a "GET" request for that and you just get a read-only transaction for that in postgrest....

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, this adds the type "text/html", but the benchmark harness expects an explicit value of "text/html; charset=UTF-8".

Got it, thanks for clarifying.

the "updates" benchmark will never work for postgREST, bc. they use a "GET" request for that and you just get a read-only transaction for that in postgrest....

Yeah, that is weird on how they landed on GET for this. There are no escape hatches on PostgREST for doing a write in a GET.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the update benchmark should just be omitted

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is, it's not in the config.

select '<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>'
|| string_agg(fortune_template(f), NULL order by f.message collate unicode asc)
|| '</table></body></html>'
from (select * from "Fortune" union all select 0, 'Additional fortune added at request time.') f;
$$ language sql volatile;
4 changes: 2 additions & 2 deletions frameworks/Haskell/postgrest/src/json.sql
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
create function json() returns json as $$
create function jsonser() returns json as $$
SELECT json_build_object('message', 'Hello, World!');
$$ language sql volatile;
$$ language sql immutable;
6 changes: 4 additions & 2 deletions frameworks/Haskell/postgrest/src/plaintext.sql
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
create function plaintext() returns text as $$
create domain "text/plain" as text;

create function plaintext() returns "text/plain" as $$
SELECT 'Hello, World!';
$$ language sql volatile;
$$ language sql immutable;
7 changes: 3 additions & 4 deletions frameworks/Haskell/postgrest/src/update.sql
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
create or replace function update(queries text default '') returns jsonb as $$
create or replace function updates(queries text default '') returns jsonb as $$
DECLARE
r "World"%ROWTYPE;
j jsonb := jsonb_build_array();
new_rnd int;
rnd_id int;
count int;
BEGIN
SET TRANSACTION READ WRITE;
IF queries ~ '^[1-9]\d{0,2}$' THEN
count := CAST(queries as int);
ELSE
count := 1;
ELSE
count := 1;
END IF;
IF count > 500 THEN
count := 500;
Expand Down
Loading