supabase / postgrest-js

Isomorphic JavaScript client for PostgREST.

Home Page:https://supabase.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Cannot use filter or modifiers on rpc call

N00nDay opened this issue · comments

Bug report

Describe the bug

When chaining filters or modifiers to an rpc function as documented here the filter and modifiers are ignored and all records are returned.

To Reproduce

Steps to reproduce the behavior, please provide code snippets or a repository:

  1. Create a table options with 50 records [id, value]
  2. Create a function fetch_options that fetches all records in the options table
  3. Call the function with await supabase.rpc('fetch_options').ilike('%' + 'some partial value' + '%').limit(25);

Expected behavior

Only records matching the filter and modifier are returned instead of all records.

System information

  • OS: macOS
  • Browser: chrome
  • Version of supabase-js: 2.1.0
  • Version of Node.js: 16.15.0

After doing a few more tests I have found the following filters and modifiers do not work chaining on to rpc as documented:

  • eq (filter)
  • like (filter)
  • ilike (filter) but interestingly enough it loses case insensitivity
  • limit (modifier)

Can you show your function?
eq,ilike,limit all work for me on an rpc call with returns setof mytable as

From PostgREST docs: A function that returns a table type response can be shaped using the same filters as the ones used for tables and views:

@GaryAustin1 here is the function. If I am doing something incorrectly any information would be appreciated.

CREATE OR REPLACE FUNCTION fetch_customers()
RETURNS TABLE ( id bigint, value text, subtext text) AS 
$BODY$
  BEGIN
      RETURN QUERY EXECUTE format(
        'SELECT id, full_name, address FROM customers ORDER BY full_name ASC;');
  END;
$BODY$
LANGUAGE plpgsql;

Tried SETOF Record with the following and it is still not working:

create or replace function fetch_customers()
RETURNS SETOF Record
language sql
security definer
set search_path = public
stable
as $$
    SELECT id, full_name as value, address as subtext FROM customers ORDER BY full_name ASC;
$$;
 RETURNS SETOF messages AS
 $$
     select * from messages;
 $$ LANGUAGE sql;
let {data:data1,error:error1,count} = await supabase1
        .rpc('get_records')
        .select('*')
        .ilike('message','Hi there')
        .limit(5)
{id: 39, created_at1: '2022-07-28T23:42:17.130425+00:00', message: 'hi there', message2: null, tags: null, …}
{id: 40, created_at1: '2022-07-28T23:43:34.705675+00:00', message: 'hi there', message2: null, tags: null, …}
{id: 41, created_at1: '2022-07-29T15:21:30.432956+00:00', message: 'hi there', message2: null, tags: null, …}
{id: 42, created_at1: '2022-07-29T15:21:40.915049+00:00', message: 'hi there', message2: null, tags: null, …}
{id: 43, created_at1: '2022-07-30T00:09:33.404916+00:00', message: 'hi there', message2: null, tags: null, …}

Supabase-js 2.1.0
There is not easy way to know which server PostgREST version is running and it was supposed to move from 9.x to 10.x over past month.

I did not think SETOF RECORD or TABLE should impact it, but I only tested with SETOF tablename...

I have a feeling it has to do with me coercing the data. My columns are id, full_name, address but I am returning them as id, value, subtext as this is what all options are read as in my front-end. That's the only difference I can see between what you are doing and what I am doing.

It is possible. Hopefully narrowed it down enough a dev will know. I'm dropping out. Luck.

Tried creating a view with:

CREATE OR REPLACE VIEW fetch_customers as
SELECT id, full_name as value, address as subtext FROM customers ORDER BY full_name ASC

And a function with:

CREATE OR REPLACE FUNCTION fetch_customers()
RETURNS SETOF fetch_customers as
$$
    SELECT id, value, subtext FROM fetch_customers;
$$ LANGUAGE SQL;

Which is having the same effect as everything I have tried above.

Currently, I have a workaround, albeit unpleasant, it is working. I am just encapsulating the entire function including the chaining, not ideal but it works.

@N00nDay Could you provide a reproducible example? Table with sample data, the function plus a JS snippet would be great.

Note: RPC filters are tested to work.

@N00nDay Could you provide a reproducible example? Table with sample data, the function plus a JS snippet would be great.

Note: RPC filters are tested to work.

2 things I noticed when looking at the tested function in the link you provided - 'get_username_and_status':

  1. The function is expressly set as immutable.
  2. The table columns being returned matches the table columns being queried.

Could either of these be the cause? I will work on a reproduction but I am curious if either of those jump out as a possible issue/difference that may be causing this.

Could either of these be the cause?

  1. The function is expressly set as immutable.

Not really, there tests done at the REST level here with a function that's not immutable.

The table columns being returned matches the table columns being queried.

That's strange.

CREATE OR REPLACE FUNCTION fetch_customers()
RETURNS TABLE ( id bigint, value text, subtext text) AS
$BODY$
BEGIN
RETURN QUERY EXECUTE format(
'SELECT id, full_name, address FROM customers ORDER BY full_name ASC;');
END;
$BODY$
LANGUAGE plpgsql;

Why do you need to change the SELECT columns inside the function if supabase-js can do it? Usually users use dynamic sql for things like GROUP BY which cannot be done directly with supabase-js.

That could be the issue, we could confirm with a reproducible example.

Could either of these be the cause?

  1. The function is expressly set as immutable.

Not really, there tests done at the REST level here with a function that's not immutable.

The table columns being returned matches the table columns being queried.

That's strange.

CREATE OR REPLACE FUNCTION fetch_customers()
RETURNS TABLE ( id bigint, value text, subtext text) AS
BODY
BEGIN
RETURN QUERY EXECUTE format(
'SELECT id, full_name, address FROM customers ORDER BY full_name ASC;');
END;
BODY
LANGUAGE plpgsql;

Why do you need to change the SELECT columns inside the function if supabase-js can do it? Usually users use dynamic sql for things like GROUP BY which cannot be done directly with supabase-js.

That could be the issue, we could confirm with a reproducible example.

I don't know why I never thought of this and you are completely right which I love because I would prefer to avoid rpc as much as possible to keep all my database calls in one place. You sir are a genius.