supabase / supabase-flutter

Flutter integration for Supabase. This package makes it simple for developers to build secure and scalable products.
https://supabase.com/
MIT License
741 stars 183 forks source link

Postgrest giving stacktrace of only postgrest code #899

Open Jonny1987 opened 7 months ago

Jonny1987 commented 7 months ago

Describe the bug Whenever I use database function on the supabase client (supabase.rpc or supabase.from) and these throw an error then the stack trace is limited to postgrest code only and non of my app lines (other supabase functions do give a full stacktrace like calling supabase.signInWithPassword with an invalid email so I don't think it's my logging setup.

For example:

I/flutter ( 4414): PostgrestException(message: Could not find the function public.nearby_venues1(current_lat, current_long, limit_param, utc_offset_minutes_param) in the schema cache, code: PGRST202, details: Searched for the function public.nearby_venues1 with parameters current_lat, current_long, limit_param, utc_offset_minutes_param or with a single unnamed json/jsonb parameter, but no matches were found in the schema cache., hint: Perhaps you meant to call the function public.nearby_venues), #0 PostgrestBuilder._parseResponse (package:postgrest/src/postgrest_builder.dart:283:7)
I/flutter ( 4414): #1 PostgrestBuilder._execute (package:postgrest/src/postgrest_builder.dart:164:14)
I/flutter ( 4414): <asynchronous suspension>
I/flutter ( 4414): #2 PostgrestBuilder.then (package:postgrest/src/postgrest_builder.dart:372:24)
I/flutter ( 4414): <asynchronous suspension>

To Reproduce Call a supabase function which will give an error like await supabase.rpc('invalid_function')

Expected behavior The stacktrace should should lines in my app code which led up to the error.

dshukertjr commented 7 months ago

This is fair. Will look into it.

Jonny1987 commented 6 months ago

Any update on this? I will need to find a workaround if not which will probably involve rethrowing a custom error in every place that I use superbase database functions which will be annoying (simply logging isn't enough since like many people, I am using sentry to record errors). Or if you have any ideas about the cause I can try to fix and open a PR

Jonny1987 commented 6 months ago

I've spent hours looking at the SupabaseClient and PostgrestBuilder code an I can't see a way to do it other than just doing the following where the supabase function is called:

await supabase.rpc('my_function').catchError((error) => throw error);

This added some lines from my app to the postgrest stacktrace which is very useful, but annoying to do at every database related call I make.

I dont have a lot of dart experience but it seems that the problem is due to the PostgrestException thrown inside PostgrestBuilder causing the stacktrace to be limited to PostgrestBuilder (I think this is simply an inherent thing with throwing an exception inside a Future since it can't see the code which created the Future), and it needs to be rethrown outside that scope for the stacktrace to get lines from outside of the PostgrestBuilder code.

The rpc() method in SupabaseClient returns a PostgrestFilterBuilder, so the catchError method cannot be used here since this returns a Future. So the only way I can currently see to do this is in the app code as I mentioned above.

I feel like there must be another way to do this inside supabase/postgrest code which then doesn't require changing my app code but I don't know enough about dart to figure it out.

Jonny1987 commented 6 months ago

Actually, maybe the following method can be added to PostgrestFilterBuilder and PostgrestQueryBuilder?

  Future<T> end() {
    return this.catchError((error) => throw error);
  }

Then in the app code, the developer just needs to append .end() to ensure the stacktrace will include local lines (I've tried it and it works):

await supabase.rpc('my_function').end();
await supabase.from('profiles').select().eq('id', userId).single().end();

The stack trace of the same error as I gave in my first post is now:

I/flutter ( 7601): │ PostgrestException(message: Could not find the function public.nearby_venues1(current_lat, current_long, limit_param, utc_offset_minutes_param) in the schema cache, code: PGRST202, details: Searched for the function public.nearby_venues1 with parameters current_lat, current_long, limit_param, utc_offset_minutes_param or with a single unnamed json/jsonb parameter, but no matches were found in the schema cache., hint: Perhaps you meant to call the function public.nearby_venues), #0      PostgrestBuilder._parseResponse (package:postgrest/src/postgrest_builder.dart:282:7)
I/flutter ( 7601): │ #1      PostgrestBuilder._execute (package:postgrest/src/postgrest_builder.dart:164:14)
I/flutter ( 7601): │ <asynchronous suspension>
I/flutter ( 7601): │ #2      PostgrestBuilder.then (package:postgrest/src/postgrest_builder.dart:371:24)
I/flutter ( 7601): │ <asynchronous suspension>
I/flutter ( 7601): │ #3      VenuesRepository.fetchVenues (package:workwith/src/features/venues/data/venues_repository.dart:14:32)
I/flutter ( 7601): │ <asynchronous suspension>
I/flutter ( 7601): │ #4      VenueDisplayPageController.getVenues (package:workwith/src/features/venues/presentation/venue_display_page/venue_display_page_controller.dart:27:22)
I/flutter ( 7601): │ <asynchronous suspension>

@dshukertjr, what are your thoughts?

Jonny1987 commented 6 months ago

My solution is to create the following file in my own code and import that into files where I do supabase db operations and then append .end() to them as above:

import 'package:supabase_flutter/supabase_flutter.dart';

extension AddEndMethod on PostgrestBuilder {
  Future end() {
    return catchError((error) => throw error);
  }
}
dshukertjr commented 6 months ago

Adding .end() is a solution that we would like to avoid implementing as it adds a redundant code after every call.

I took a quick stab at this issue, but couldn't come up with a solution that includes the desired stack trace.

Although it's not ideal, this issue does have a workaround and is not a critical issue, the priority will be lower than some other issues that we have. With that being said, I will try to see if I can do something about it time to time.