I'd like to use Persistent/Esqueleto to implement count estimates.
One approach recommended in this article is to define a function like this
CREATE FUNCTION count_estimate(query text) RETURNS integer AS $$
DECLARE
rec record;
rows integer;
BEGIN
FOR rec IN EXECUTE 'EXPLAIN ' || query LOOP
rows := substring(rec."QUERY PLAN" FROM ' rows=([[:digit:]]+)');
EXIT WHEN rows IS NOT NULL;
END LOOP;
RETURN rows;
END;
$$ LANGUAGE plpgsql VOLATILE STRICT;
and then use it like this
SELECT count_estimate('SELECT * FROM companies WHERE status = ''Active''');
In order to use the count_estimate
function, I'll need (I think?) to render the query that Peristent/Equeleto generates, however when I try rendering the query with renderQuerySelect
, I get something like this
SELECT "companies"."id", "companies"."name", "companies"."status"
FROM "companies"
WHERE "companies"."status" IN (?)
; [PersistText "Active"]
This of course can't be stuffed into the count_estimate
, because it will syntax error on the ?
placeholder. I also can't naïvely replace the ?
with "Active"
, because it will syntax error on that first double quote.
How do I render the query in a way that my count_estimate
function will accept?
I tried something like this, but it fails at runtime
getEstimate :: (Text, [PersistValue]) -> DB [Single Int]
getEstimate (query, params) = rawSql [st|
SELECT count_estimate('#{query}');
|] params