Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks amazing! It seems like this PR is still in Draft mode, but is it completed?
Also, maybe you plan to do this already, but if you could write how the public API is going to change (example code on how you can pass types to from
), that would be amazing!
I converted it to draft to adapt the tests to the new system. |
Looking forward to this one! I really like the new API! final data = await client
.from<List<Map<String, dynamic>>>('countries')
.select()
.withConverter<List<Country>>(
(data) => data.map(Country.fromJson).toList()); |
It gets even better by adding typedefs for common return types. |
Okay turns out this is much more complex than I thought, because you can't cast a |
@dshukertjr Should be working now. You can only use the specific typedefs, because we have to manually cast the data to the type. I think we should explain under which circumstances they can expect which type. Where should we add this? As well, under |
The case of insert/update/delete without Another proposalWe could make it void though, but I don't know if this is a breaking change. We could make final data = await postgrest.from('users').insert({'username': 'bar'});
//data is void final data = await postgrest.from('users').insert({'username': 'bar'}).select<PostgrestList>();
//data is of type PostgrestList |
I love this. Let's do it. I don't think it's a breaking change. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can only use the specific typedefs, because we have to manually cast the data to the type. I think we should explain under which circumstances they can expect which type. Where should we add this? As well, under from?
Frankly, I'm not sure if I'm a huge fan of introducing several new typedefs in a public API. I think it could cause more confusions than solving it. Could we just do something like this:
final data = await supabase.from<List<Map<String, dynamic>>>('table').select();
Edit
I had a misunderstanding on how typedef works, and noticed that above code is valid with the current codebase!
Great, will push the new proposal later today. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So it looks like the final api we have is like this?
final data = await supabase.from('table').select<List<Map<String, dynamic>>>();
At first, I thought this might be a crazy idea, but I wonder if this would be a better solution for this issue that we are trying to solve.
We could define two more classes PostgrestListResponse
and PostgrestMapResponse
that implements List and Map respectively.
class PostgrestListResponse extends PostgrestResponse implements List<Map<String, dynamic>> {
...
}
class PostgrestMapResponse extends PostgrestResponse implements Map<String, dynamic> {
...
}
With this, we could
final data = await supabase.from('table').select(); // data here has `PostgrestListResponse`
final firstRow = data.first; // This is valid since `PostgrestListResponse` implements List<Map<String, dynamic>>
@dshukertjr You are right, this may work. I would still keep insert/... as |
How should we handle |
@Vinzent03 It might be faster to discuss what to do with this PR. I have sent you a message on Discord. If you have time, let's discuss over a voice chat it there! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After further thinking about it, I don't have any good idea on how we might be able to handle maybeSingle
without a breaking change. I am happy to merge this one if you are! Thanks for the amazing work!
@Vinzent03 Wanted to get one last approval to double check. I'm good with merging this one, but would it be okay on your end as well? |
@dshukertjr I've written a comment here. #94 (comment) I think we should change the doc more to demonstrate the "danger" of using the wrong type and that it's optional. |
We could probably provide some example code for each return type with some description. Something like this maybe? /// - [List<Map<String, dynamic>>] is returned from query without `.single()` or `maybeSingle()` and does not contain `count` option.
/// ```dart
/// final data = await supabase.from('table').select();
/// ```
/// - [Map<String, dynamic>] is returned from query with `.single()` and does not contain `count` option.
/// ```dart
/// final data = await supabase.from('table').select().single();
/// ```
... etc |
Co-authored-by: Tyler <18113850+dshukertjr@users.noreply.github.com>
@dshukertjr I think the types are now properly documented on both |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Love the docs! Let's merge this one in! Thanks for the amazing update!
The idea is to pass a type to
from
select
, which sets the response type. I had to add another generic toPostgrestBuilder
to properly type the converter. The type fromfrom
is used as parameter type forconverter
. This doesn't infer the type depending onsingle
orcount
, but makes it easier to type if you know what you get.insert
/update
/upsert
/delete
now returnvoid
and need aselect
to change the type.close supabase/supabase-flutter#252