-- encode straeto API params into the query string by the graphql API. -- yes, javascript in the database: the lazy way. CREATE OR REPLACE FUNCTION encode_straeto_querystring(obj jsonb) RETURNS text LANGUAGE plv8 STRICT IMMUTABLE AS $$ return Object.keys(obj).map(function(variableName) { const variableValue = obj[variableName]; if (typeof variableValue == 'object') { return encodeURIComponent(variableName) + '=' + encodeURIComponent(JSON.stringify(variableValue)); } else { return encodeURIComponent(variableName) + '=' + encodeURIComponent(variableValue); } }).join('&'); $$; CREATE OR REPLACE FUNCTION create_straeto_parameters(bus_routes text[]) RETURNS jsonb LANGUAGE plpgsql AS $$ DECLARE query_params jsonb; BEGIN -- This is the unencoded GraphQL request payload. query_params := '{ "operationName": "BusLocationByRoute", "variables": { "trips":[], "routes": [] }, "extensions": { "persistedQuery": { "version": 1, "sha256Hash": "8f9ee84171961f8a3b9a9d1a7b2a7ac49e7e122e1ba1727e75cfe3a94ff3edb8" } } }'::jsonb; -- Add requested bus routes to the `routes` GraphQL variable. SELECT INTO query_params jsonb_set(query_params, '{variables, routes}', array_to_json(bus_routes)::jsonb); RETURN query_params; END $$; -- Builds the full request URL to download bus positions of the given -- route numbers. CREATE OR REPLACE FUNCTION build_api_url(bus_routes text[]) RETURNS text LANGUAGE sql AS $$ SELECT concat( 'https://straeto.is/graphql?', encode_straeto_querystring(create_straeto_parameters(bus_routes)) ); $$; -- Called by a scheduled job to request data on a timer. A trigger -- handles insertion of the response after record initially inserted. CREATE TABLE IF NOT EXISTS raw_bus_position_requests( request_id int, created TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() ); CREATE OR REPLACE FUNCTION gather_bus_data() RETURNS void LANGUAGE sql as $$ INSERT INTO raw_bus_position_requests (request_id) SELECT net.http_get( url := build_api_url(array['1', '2', '3']), headers := '{"Content-Type": "application/json"}'::jsonb ); $$;