supabase / postgrest-js

Isomorphic JavaScript client for PostgREST.
https://supabase.com
MIT License
967 stars 130 forks source link

Upsert on conflict with more than one row returns undefined with 2.0.0-rc.10 #343

Closed mansueli closed 1 year ago

mansueli commented 1 year ago

Bug report

Describe the bug

A clear and concise description of what the bug is.

To Reproduce

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

Minimum Verified Reproducible Example:

                                     Table "public.projects"
   Column   |           Type           | Collation | Nullable |             Default              
------------+--------------------------+-----------+----------+----------------------------------
 id         | bigint                   |           | not null | generated by default as identity
 created_at | timestamp with time zone |           |          | now()
 name       | text                     |           |          | 
Indexes:
    "projects_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "interactive_experiences" CONSTRAINT "fk_projects" FOREIGN KEY (project_id) REFERENCES projects(id)

                               Table "public.interactive_experiences"
   Column   |  Type   | Collation | Nullable |                       Default                        
------------+---------+-----------+----------+------------------------------------------------------
 idd        | integer |           | not null | nextval('interactive_experiences_idd_seq'::regclass)
 project_id | bigint  |           | not null | 
 message    | text    |           |          | 
Indexes:
    "pk_interactive_experiences" PRIMARY KEY, btree (project_id, idd)
Foreign-key constraints:
    "fk_projects" FOREIGN KEY (project_id) REFERENCES projects(id)

Create a row in projects e.g INSERT INTO projects (id, name) VALUES (3,'Foo')

Then create a row in interactive_experiences:

INSERT INTO projects (idd, project_id, message) VALUES (1,3, 'message')

Then, you run the client:

let { data: data, error } = await supabase
  .from("interactive_experiences")
  .upsert([
    { idd: 1, project_id: 3, message: 'updated msg 2' }],{ onConflict: 'idd,project_id'});

Expected behavior

The client response should inform that the upsert was successful.

System information

Additional context

Add any other context about the problem here.

soedirgo commented 1 year ago

Thanks! .upsert() doesn't return rows by default, so you need to do it like:

let { data: data, error } = await supabase
  .from("interactive_experiences")
  .upsert([
    { idd: 1, project_id: 3, message: 'updated msg 2' }],{ onConflict: 'idd,project_id'})
  .select();
steve-chavez commented 1 year ago

The client response should inform that the upsert was successful.

Also even without select() the error key should contain a message if the upsert wasn't successful.

eikonomega commented 1 year ago

@mansueli and @soedirgo Thank you for looking into this issue for me.

I'm still having difficulty however getting the permissions correct. My tables are setup essentially as you have described above (except the id fields are uuid type).

When I attempt to do an upsert I get an error unless I have given the READ permission to the anon user.

const updateStart = async (dateTime) => {      
            const { data, error } = await analyticsConnection
              .from("ie_experiences")
              .upsert(
                {
                  started: dateTime.toISO(),
                  project: projectID,
                  id: analyticsExperienceID,
                },
                { onConflict: "id,project" }
              )
        };

I'm trying to allow an anon user to insert/update entries in the table, but not be able to read all the entries. Here is the error message if read permission is not granted. Is read permission required to do an upsert if you aren't calling select afterwards?

{
  code: "42501",
  details: null,
  hint: null,
  message:
    'new row violates row-level security policy for table "ie_experiences"',
};