From b2266815a8a528741312a5ffdd56b26329f673d4 Mon Sep 17 00:00:00 2001 From: Vinzent Date: Sat, 8 Jan 2022 20:10:03 +0100 Subject: [PATCH 1/3] fix!: stream replaces the correct row --- example/main.dart | 2 +- lib/src/supabase_query_builder.dart | 13 ++++++++----- lib/src/supabase_realtime_payload.dart | 9 ++++++++- lib/src/supabase_stream_builder.dart | 21 ++++++++++----------- test/mock_test.dart | 14 ++++++-------- 5 files changed, 33 insertions(+), 26 deletions(-) diff --git a/example/main.dart b/example/main.dart index fe28798..fbfe4dc 100644 --- a/example/main.dart +++ b/example/main.dart @@ -64,7 +64,7 @@ Future main() async { // stream final streamSubscription = client .from('countries') - .stream() + .stream('id') .order('name') .limit(10) .execute() diff --git a/lib/src/supabase_query_builder.dart b/lib/src/supabase_query_builder.dart index ee81a9b..a31794c 100644 --- a/lib/src/supabase_query_builder.dart +++ b/lib/src/supabase_query_builder.dart @@ -43,16 +43,19 @@ class SupabaseQueryBuilder extends PostgrestQueryBuilder { /// Notifies of data at the queried table /// /// ```dart - /// supabase.from('chats').stream().execute().listen(_onChatsReceived); + /// supabase.from('chats').stream('my_primary_key').execute().listen(_onChatsReceived); /// ``` /// /// `eq`, `orderBy`, `limit` filter are available to limit the data being queried. /// /// ```dart - /// supabase.from('chats:room_id=eq.123').orderBy('created_at').limit(20).stream().listen(_onChatsReceived); + /// supabase.from('chats:room_id=eq.123').stream('my_primary_key').order('created_at').limit(20).execute().listen(_onChatsReceived); /// ``` - /// - SupabaseStreamBuilder stream() { - return SupabaseStreamBuilder(this, streamFilter: _streamFilter); + SupabaseStreamBuilder stream(String primaryKey) { + return SupabaseStreamBuilder( + this, + streamFilter: _streamFilter, + primaryKey: primaryKey, + ); } } diff --git a/lib/src/supabase_realtime_payload.dart b/lib/src/supabase_realtime_payload.dart index 3430013..8d9b0bd 100644 --- a/lib/src/supabase_realtime_payload.dart +++ b/lib/src/supabase_realtime_payload.dart @@ -15,6 +15,9 @@ class SupabaseRealtimePayload { final Map? oldRecord; /// List of columns that are set as primary key + @Deprecated( + "The new RLS real-time server no longer sends the required data", + ) final List primaryKeys; SupabaseRealtimePayload({ @@ -24,7 +27,10 @@ class SupabaseRealtimePayload { required this.table, required this.newRecord, required this.oldRecord, - required this.primaryKeys, + @Deprecated( + "The new RLS real-time server no longer sends the required data", + ) + required this.primaryKeys, }); factory SupabaseRealtimePayload.fromJson(Map json) { @@ -55,6 +61,7 @@ class SupabaseRealtimePayload { eventType: eventType, newRecord: newRecord, oldRecord: oldRecord, + // ignore: deprecated_member_use_from_same_package primaryKeys: primaryKeys, ); } diff --git a/lib/src/supabase_stream_builder.dart b/lib/src/supabase_stream_builder.dart index d8398e1..5815712 100644 --- a/lib/src/supabase_stream_builder.dart +++ b/lib/src/supabase_stream_builder.dart @@ -41,11 +41,16 @@ class SupabaseStreamBuilder { /// `eq` filter used for both postgrest and realtime late final StreamPostgrestFilter? _streamFilter; + /// Used to identify which row has changed + final String _primaryKey; + SupabaseStreamBuilder( SupabaseQueryBuilder queryBuilder, { required StreamPostgrestFilter? streamFilter, + required String primaryKey, }) : _queryBuilder = queryBuilder, - _streamFilter = streamFilter; + _streamFilter = streamFilter, + _primaryKey = primaryKey; /// Which column to order by and whether it's ascending _Order? _orderBy; @@ -58,7 +63,7 @@ class SupabaseStreamBuilder { /// When `ascending` value is true, the result will be in ascending order. /// /// ```dart - /// supabase.from('users').stream().order('username', ascending: false); + /// supabase.from('users').stream('id).order('username', ascending: false); /// ``` SupabaseStreamBuilder order(String column, {bool ascending = false}) { _orderBy = _Order(column: column, ascending: ascending); @@ -68,7 +73,7 @@ class SupabaseStreamBuilder { /// Limits the result with the specified `count`. /// /// ```dart - /// supabase.from('users').stream().limit(10); + /// supabase.from('users').stream('id).limit(10); /// ``` SupabaseStreamBuilder limit(int count) { _limit = count; @@ -146,7 +151,7 @@ class SupabaseStreamBuilder { _addStream(); } - static bool _isTargetRecord({ + bool _isTargetRecord({ required Map record, required SupabaseRealtimePayload payload, }) { @@ -157,13 +162,7 @@ class SupabaseStreamBuilder { targetRecord = payload.oldRecord!; } - bool isTarget = true; - for (final primaryKey in payload.primaryKeys) { - if (record[primaryKey] != targetRecord[primaryKey]) { - isTarget = false; - } - } - return isTarget; + return record[_primaryKey] == targetRecord[_primaryKey]; } void _sortData() { diff --git a/test/mock_test.dart b/test/mock_test.dart index 3570bef..ec94ddd 100644 --- a/test/mock_test.dart +++ b/test/mock_test.dart @@ -84,19 +84,16 @@ void main() { 'type': 'INSERT', 'columns': [ { - 'flags': ['key'], 'name': 'id', 'type': 'int4', - 'type_modifier': 4294967295 + 'type_modifier': 4294967295, }, { - 'flags': [], 'name': 'task', 'type': 'text', 'type_modifier': 4294967295 }, { - 'flags': [], 'name': 'status', 'type': 'bool', 'type_modifier': 4294967295 @@ -139,7 +136,7 @@ void main() { }); test('stream() emits data', () { - final stream = client.from('todos').stream().execute(); + final stream = client.from('todos').stream('id').execute(); expect( stream, emitsInOrder([ @@ -157,7 +154,7 @@ void main() { }); test('Can filter stream results with eq', () { - final stream = client.from('todos:status=eq.true').stream().execute(); + final stream = client.from('todos:status=eq.true').stream('id').execute(); expect( stream, emitsInOrder([ @@ -173,7 +170,7 @@ void main() { }); test('stream() with order', () { - final stream = client.from('todos').stream().order('id').execute(); + final stream = client.from('todos').stream('id').order('id').execute(); expect( stream, emitsInOrder([ @@ -191,7 +188,8 @@ void main() { }); test('stream() with limit', () { - final stream = client.from('todos').stream().order('id').limit(2).execute(); + final stream = + client.from('todos').stream('id').order('id').limit(2).execute(); expect( stream, emitsInOrder([ From 2ebe18ad3247092b4999739167aa254f570a9fdb Mon Sep 17 00:00:00 2001 From: Vinzent Date: Sat, 8 Jan 2022 23:55:11 +0100 Subject: [PATCH 2/3] refactor: use list of unique columns --- example/main.dart | 6 +++--- lib/src/supabase_query_builder.dart | 6 ++++-- lib/src/supabase_stream_builder.dart | 12 ++++++------ test/mock_test.dart | 8 ++++---- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/example/main.dart b/example/main.dart index fbfe4dc..59a63a2 100644 --- a/example/main.dart +++ b/example/main.dart @@ -64,13 +64,13 @@ Future main() async { // stream final streamSubscription = client .from('countries') - .stream('id') + .stream(['id']) .order('name') .limit(10) .execute() .listen((snapshot) { - print('snapshot: $snapshot'); - }); + print('snapshot: $snapshot'); + }); // remember to remove subscription streamSubscription.cancel(); diff --git a/lib/src/supabase_query_builder.dart b/lib/src/supabase_query_builder.dart index 4e9a725..1254935 100644 --- a/lib/src/supabase_query_builder.dart +++ b/lib/src/supabase_query_builder.dart @@ -41,6 +41,8 @@ class SupabaseQueryBuilder extends PostgrestQueryBuilder { /// Notifies of data at the queried table /// + /// [uniqueColumns] can be either the primary key or a combination of unique columns. + /// /// ```dart /// supabase.from('chats').stream('my_primary_key').execute().listen(_onChatsReceived); /// ``` @@ -50,11 +52,11 @@ class SupabaseQueryBuilder extends PostgrestQueryBuilder { /// ```dart /// supabase.from('chats:room_id=eq.123').stream('my_primary_key').order('created_at').limit(20).execute().listen(_onChatsReceived); /// ``` - SupabaseStreamBuilder stream(String primaryKey) { + SupabaseStreamBuilder stream(List uniqueColumns) { return SupabaseStreamBuilder( this, streamFilter: _streamFilter, - primaryKey: primaryKey, + uniqueColumns: uniqueColumns, ); } } diff --git a/lib/src/supabase_stream_builder.dart b/lib/src/supabase_stream_builder.dart index 86c0b92..741d0b3 100644 --- a/lib/src/supabase_stream_builder.dart +++ b/lib/src/supabase_stream_builder.dart @@ -41,15 +41,15 @@ class SupabaseStreamBuilder { late final StreamPostgrestFilter? _streamFilter; /// Used to identify which row has changed - final String _primaryKey; + final List _uniqueColumns; SupabaseStreamBuilder( SupabaseQueryBuilder queryBuilder, { required StreamPostgrestFilter? streamFilter, - required String primaryKey, + required List uniqueColumns, }) : _queryBuilder = queryBuilder, _streamFilter = streamFilter, - _primaryKey = primaryKey; + _uniqueColumns = uniqueColumns; /// Which column to order by and whether it's ascending _Order? _orderBy; @@ -72,7 +72,7 @@ class SupabaseStreamBuilder { /// Limits the result with the specified `count`. /// /// ```dart - /// supabase.from('users').stream('id).limit(10); + /// supabase.from('users').stream('id').limit(10); /// ``` SupabaseStreamBuilder limit(int count) { _limit = count; @@ -160,8 +160,8 @@ class SupabaseStreamBuilder { } else if (payload.eventType == 'DELETE') { targetRecord = payload.oldRecord!; } - - return record[_primaryKey] == targetRecord[_primaryKey]; + return _uniqueColumns + .every((column) => record[column] == targetRecord[column]); } void _sortData() { diff --git a/test/mock_test.dart b/test/mock_test.dart index df67a55..975fba1 100644 --- a/test/mock_test.dart +++ b/test/mock_test.dart @@ -136,7 +136,7 @@ void main() { }); test('stream() emits data', () { - final stream = client.from('todos').stream('id').execute(); + final stream = client.from('todos').stream(['id']).execute(); expect( stream, emitsInOrder([ @@ -154,7 +154,7 @@ void main() { }); test('Can filter stream results with eq', () { - final stream = client.from('todos:status=eq.true').stream('id').execute(); + final stream = client.from('todos:status=eq.true').stream(['id']).execute(); expect( stream, emitsInOrder([ @@ -170,7 +170,7 @@ void main() { }); test('stream() with order', () { - final stream = client.from('todos').stream('id').order('id').execute(); + final stream = client.from('todos').stream(['id']).order('id').execute(); expect( stream, emitsInOrder([ @@ -189,7 +189,7 @@ void main() { test('stream() with limit', () { final stream = - client.from('todos').stream('id').order('id').limit(2).execute(); + client.from('todos').stream(['id']).order('id').limit(2).execute(); expect( stream, emitsInOrder([ From 3cb6bf8af46b60d9965a9c9ece7a5a3cf0452d23 Mon Sep 17 00:00:00 2001 From: Vinzent Date: Sun, 9 Jan 2022 01:14:28 +0100 Subject: [PATCH 3/3] docs: use lists for stream docs Co-authored-by: Tyler <18113850+dshukertjr@users.noreply.github.com> --- lib/src/supabase_query_builder.dart | 4 ++-- lib/src/supabase_stream_builder.dart | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/src/supabase_query_builder.dart b/lib/src/supabase_query_builder.dart index 1254935..6a7550c 100644 --- a/lib/src/supabase_query_builder.dart +++ b/lib/src/supabase_query_builder.dart @@ -44,13 +44,13 @@ class SupabaseQueryBuilder extends PostgrestQueryBuilder { /// [uniqueColumns] can be either the primary key or a combination of unique columns. /// /// ```dart - /// supabase.from('chats').stream('my_primary_key').execute().listen(_onChatsReceived); + /// supabase.from('chats').stream(['my_primary_key']).execute().listen(_onChatsReceived); /// ``` /// /// `eq`, `order`, `limit` filter are available to limit the data being queried. /// /// ```dart - /// supabase.from('chats:room_id=eq.123').stream('my_primary_key').order('created_at').limit(20).execute().listen(_onChatsReceived); + /// supabase.from('chats:room_id=eq.123').stream(['my_primary_key']).order('created_at').limit(20).execute().listen(_onChatsReceived); /// ``` SupabaseStreamBuilder stream(List uniqueColumns) { return SupabaseStreamBuilder( diff --git a/lib/src/supabase_stream_builder.dart b/lib/src/supabase_stream_builder.dart index 741d0b3..456e7db 100644 --- a/lib/src/supabase_stream_builder.dart +++ b/lib/src/supabase_stream_builder.dart @@ -62,7 +62,7 @@ class SupabaseStreamBuilder { /// When `ascending` value is true, the result will be in ascending order. /// /// ```dart - /// supabase.from('users').stream('id').order('username', ascending: false); + /// supabase.from('users').stream(['id']).order('username', ascending: false); /// ``` SupabaseStreamBuilder order(String column, {bool ascending = false}) { _orderBy = _Order(column: column, ascending: ascending); @@ -72,7 +72,7 @@ class SupabaseStreamBuilder { /// Limits the result with the specified `count`. /// /// ```dart - /// supabase.from('users').stream('id').limit(10); + /// supabase.from('users').stream(['id']).limit(10); /// ``` SupabaseStreamBuilder limit(int count) { _limit = count;