From 07c79366602005c84a69f4fddbd95c7f05bb3717 Mon Sep 17 00:00:00 2001 From: Tyler <18113850+dshukertjr@users.noreply.github.com> Date: Thu, 7 Dec 2023 12:36:17 +0900 Subject: [PATCH] guide: adds Dart code sample to realtime giudes (#19323) * adds Dart code sample to broadcast docs * adds Dart code sample to presence guide * add Dart code sample to realtime postgres change guide * run prettier * add Dart code sample on client side throttling * add dart code sample to realtime overview * run prettier * update presence methods --- apps/docs/pages/guides/realtime.mdx | 49 ++- apps/docs/pages/guides/realtime/broadcast.mdx | 112 ++++++- .../guides/client-side-throttling.mdx | 32 ++ .../guides/realtime/postgres-changes.mdx | 300 ++++++++++++++++++ apps/docs/pages/guides/realtime/presence.mdx | 79 ++++- 5 files changed, 565 insertions(+), 7 deletions(-) diff --git a/apps/docs/pages/guides/realtime.mdx b/apps/docs/pages/guides/realtime.mdx index ba3a79314d4..ba44847800a 100644 --- a/apps/docs/pages/guides/realtime.mdx +++ b/apps/docs/pages/guides/realtime.mdx @@ -53,7 +53,16 @@ alter From the client, we can listen to any new data that is inserted into the `todos` table: -```javascript + + + +```js // Initialize the JS client import { createClient } from '@supabase/supabase-js' const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY) @@ -70,6 +79,44 @@ supabase .subscribe() ``` + + + +```dart +import 'package:supabase_flutter/supabase_flutter.dart'; + +void main() async { + // Initialize the Flutter client + Supabase.initialize( + url: 'https://.supabase.co', + anonKey: '', + realtimeClientOptions: const RealtimeClientOptions( + eventsPerSecond: 2, + ), + ); + runApp(const MyApp()); +} + +final supabase = Supabase.instance.client; + +void handleInserts(payload) { + print('Change received! $payload'); +} + +// Listen to inserts +supabase + .channel('todos') + .onPostgresChanges( + event: PostgresChangeEvent.insert, + schema: 'public', + table: 'todos', + callback: handleInserts) + .subscribe(); +``` + + + + Use [subscribe()](/docs/reference/javascript/subscribe) to listen to database changes. The Realtime API works through PostgreSQL's replication functionality. Postgres sends database changes to a [publication](/docs/guides/database/replication#publications) called `supabase_realtime`, and by managing this publication you can control which data is broadcast. diff --git a/apps/docs/pages/guides/realtime/broadcast.mdx b/apps/docs/pages/guides/realtime/broadcast.mdx index 177ced85477..f1707ad7249 100644 --- a/apps/docs/pages/guides/realtime/broadcast.mdx +++ b/apps/docs/pages/guides/realtime/broadcast.mdx @@ -35,6 +35,23 @@ const SUPABASE_KEY = '' const client = createClient(SUPABASE_URL, SUPABASE_KEY) ``` + + + +```dart +import 'package:supabase_flutter/supabase_flutter.dart'; + +void main() async { + Supabase.initialize( + url: 'https://.supabase.co', + anonKey: '', + ); + runApp(MyApp()); +} + +final supabase = Supabase.instance.client; +``` + @@ -82,6 +99,22 @@ channelA .subscribe() ``` + + + +```dart +// Simple function to log any messages we receive +void messageReceived(payload) { + print(payload); +} + +// Subscribe to the Channel +channelA + .onBroadcast( + event: 'test', callback: (payload) => messageReceived(payload)) + .subscribe(); +``` + @@ -135,6 +168,27 @@ channelB.subscribe((status) => { }) ``` + + + +```dart +// Join a room/topic. Can be anything except for 'realtime'. +final channelB = supabase.channel('room-1'); + +channelB.subscribe((status, error) { + // Wait for successful connection + if (status != RealtimeSubscribeStatus.subscribed) { + return; + } + + // Send a message once the client is subscribed + channelB.sendBroadcastMessage( + event: 'test', + payload: {'message': 'hello, world'}, + ); +}); +``` + @@ -199,6 +253,32 @@ myChannel.subscribe((status) => { }) ``` + + + +```dart +final myChannel = supabase.channel( + 'room-2', + opts: const RealtimeChannelConfig( + self: true, + ), +); + +myChannel.onBroadcast( + event: 'test-my-messages', + callback: (payload) => print(payload), +); + +myChannel.subscribe((status, error) { + if (status != RealtimeSubscribeStatus.subscribed) return; + // channelC.send({ + myChannel.sendBroadcastMessage( + event: 'test-my-messages', + payload: {'message': 'talking to myself'}, + ); +}); +``` + @@ -265,6 +345,29 @@ myChannel.subscribe(async (status) => { }) ``` + + + +```dart +final myChannel = supabase.channel('room-3',opts: const RealtimeChannelConfig( + ack: true, +), + +); + +myChannel.subscribe( (status, error) async { + if (status != RealtimeSubscribeStatus.subscribed) return; + + final serverResponse = await myChannel.sendBroadcastMessage( + + event: 'acknowledge', + payload: {}, + ); + + print('serverResponse: $serverResponse'); +}); +``` + @@ -330,15 +433,14 @@ client.removeChannel(channel) ```dart // No need to subscribe to channel -channel = client.channel('test-channel'); -final resp = await channel.send( - type: RealtimeListenTypes.broadcast, +final channel = supabase.channel('test-channel'); +final res = await channel.sendBroadcastMessage( + event: "test", payload: { 'message': 'Hi', }, - event: "test" ); -print(resp); +print(res); ```` diff --git a/apps/docs/pages/guides/realtime/guides/client-side-throttling.mdx b/apps/docs/pages/guides/realtime/guides/client-side-throttling.mdx index 55ff58726de..cc718c23a03 100644 --- a/apps/docs/pages/guides/realtime/guides/client-side-throttling.mdx +++ b/apps/docs/pages/guides/realtime/guides/client-side-throttling.mdx @@ -13,6 +13,15 @@ The Supabase clients include functionality for throttling messages. You can customize the client-side throttling when creating the client: + + + ```js import { createClient } from '@supabase/supabase-js' @@ -28,6 +37,29 @@ const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, { }) ``` + + + +```dart +import 'package:supabase_flutter/supabase_flutter.dart'; + +void main() async { + Supabase.initialize( + url: 'https://.supabase.co', + anonKey: '', + realtimeClientOptions: const RealtimeClientOptions( + eventsPerSecond: 2, + ), + ); + runApp(const MyApp()); +} + +final supabase = Supabase.instance.client; +``` + + + + ## Default client throttling By default the Supabase clients throttles messages to 10 messages per-second (1 message every 100 milliseconds). This is a soft-limit provided as a safe-guard when you're getting started. You'll rarely need to send more messages than this. diff --git a/apps/docs/pages/guides/realtime/postgres-changes.mdx b/apps/docs/pages/guides/realtime/postgres-changes.mdx index 681f5a0df8d..8d4d11e0dab 100644 --- a/apps/docs/pages/guides/realtime/postgres-changes.mdx +++ b/apps/docs/pages/guides/realtime/postgres-changes.mdx @@ -226,6 +226,20 @@ const changes = client .subscribe() ``` + + + +```dart +supabase + .channel('schema-db-changes') + .onPostgresChanges( + schema: 'public', // Subscribes to the "public" schema in Postgres + event: PostgresChangeEvent.all, // Listen to all changes + + callback: (payload) => print(payload)) + .subscribe(); +``` + @@ -280,6 +294,19 @@ const changes = client .subscribe() ``` + + + +```dart +final changes = supabase + .channel('schema-db-changes') + .onPostgresChanges( + event: PostgresChangeEvent.insert, + schema: 'public', + callback: (payload) => print(payload)) + .subscribe(); +``` + @@ -332,6 +359,19 @@ const changes = client .subscribe() ``` + + + +```dart +supabase + .channel('schema-db-changes') + .onPostgresChanges( + event: PostgresChangeEvent.update, // Listen only to UPDATEs + schema: 'public', + callback: (payload) => print(payload)) + .subscribe(); +``` + @@ -384,6 +424,19 @@ const changes = client .subscribe() ``` + + + +```dart +supabase + .channel('schema-db-changes') + .onPostgresChanges( + event: PostgresChangeEvent.delete, // Listen only to DELETEs + schema: 'public', + callback: (payload) => print(payload)) + .subscribe(); +``` + @@ -437,6 +490,20 @@ const changes = client .subscribe() ``` + + + +```dart +supabase + .channel('table-db-changes') + .onPostgresChanges( + event: PostgresChangeEvent.all, + schema: 'public', + table: 'todos', + callback: (payload) => print(payload)) + .subscribe(); +``` + @@ -499,6 +566,25 @@ const channel = supabase .subscribe() ``` + + + +```dart +supabase + .channel('db-changes') + .onPostgresChanges( + event: PostgresChangeEvent.all, + schema: 'public', + table: 'messages', + callback: (payload) => print(payload)) + .onPostgresChanges( + event: PostgresChangeEvent.insert, + schema: 'public', + table: 'users', + callback: (payload) => print(payload)) + .subscribe(); +``` + @@ -546,6 +632,25 @@ const changes = client .subscribe() ``` + + + +```dart + supabase + .channel('table-filter-changes') + .onPostgresChanges( + event: PostgresChangeEvent.insert, + schema: 'public', + table: 'todos', + filter: PostgresChangeFilter( + type: PostgresChangeFilterType.eq, + column: 'id', + value: 1, + ), + callback: (payload) => print(payload)) + .subscribe(); +``` + @@ -603,6 +708,25 @@ const channel = supabase .subscribe() ``` + + + +```dart +supabase + .channel('changes') + .onPostgresChanges( + event: PostgresChangeEvent.update, + schema: 'public', + table: 'messages', + filter: PostgresChangeFilter( + type: PostgresChangeFilterType.eq, + column: 'body', + value: 'hey', + ), + callback: (payload) => print(payload)) + .subscribe(); +``` + @@ -633,6 +757,15 @@ This filter uses Postgres's `=` filter. To listen to changes when a column's value in a table does not equal a client-specified value: + + + ```js const channel = supabase .channel('changes') @@ -649,6 +782,49 @@ const channel = supabase .subscribe() ``` + + + +```dart +supabase + .channel('changes') + .onPostgresChanges( + event: PostgresChangeEvent.insert, + schema: 'public', + table: 'messages', + filter: PostgresChangeFilter( + type: PostgresChangeFilterType.neq, + column: 'body', + value: 'bye', + ), + callback: (payload) => print(payload)) + .subscribe(); +``` + + + + +```kotlin +val myChannel = supabase.realtime.createChannel("db-changes") + +val changes = myChannel.postgresChangeFlow(schema = "public") { + table = "messages" + filter = "body=neq.bye" +} + +changes + .onEach { + println(it.record) + } + .launchIn(yourCoroutineScope) + +supabase.realtime.connect() +myChannel.join() +``` + + + + This filter uses Postgres's `!=` filter. ### Less than (lt) @@ -680,6 +856,25 @@ const channel = supabase .subscribe() ``` + + + +```dart +supabase + .channel('changes') + .onPostgresChanges( + event: PostgresChangeEvent.insert, + schema: 'public', + table: 'profiles', + filter: PostgresChangeFilter( + type: PostgresChangeFilterType.lt, + column: 'age', + value: 65, + ), + callback: (payload) => print(payload)) + .subscribe(); +``` + @@ -735,6 +930,25 @@ const channel = supabase .subscribe() ``` + + + +```dart +supabase + .channel('changes') + .onPostgresChanges( + event: PostgresChangeEvent.insert, + schema: 'public', + table: 'profiles', + filter: PostgresChangeFilter( + type: PostgresChangeFilterType.lte, + column: 'age', + value: 65, + ), + callback: (payload) => print(payload)) + .subscribe(); +``` + @@ -790,6 +1004,25 @@ const channel = supabase .subscribe() ``` + + + +```dart +supabase + .channel('changes') + .onPostgresChanges( + event: PostgresChangeEvent.insert, + schema: 'public', + table: 'products', + filter: PostgresChangeFilter( + type: PostgresChangeFilterType.gt, + column: 'quantity', + value: 10, + ), + callback: (payload) => print(payload)) + .subscribe(); +``` + @@ -845,6 +1078,25 @@ const channel = supabase .subscribe() ``` + + + +```dart +supabase + .channel('changes') + .onPostgresChanges( + event: PostgresChangeEvent.insert, + schema: 'public', + table: 'products', + filter: PostgresChangeFilter( + type: PostgresChangeFilterType.gte, + column: 'quantity', + value: 10, + ), + callback: (payload) => print(payload)) + .subscribe(); +``` + @@ -900,6 +1152,25 @@ const channel = supabase .subscribe() ``` + + + +```dart +supabase + .channel('changes') + .onPostgresChanges( + event: PostgresChangeEvent.insert, + schema: 'public', + table: 'colors', + filter: PostgresChangeFilter( + type: PostgresChangeFilterType.lte, + column: 'name', + value: ['red', 'blue', 'yellow'], + ), + callback: (payload) => print(payload)) + .subscribe(); +``` + @@ -1001,6 +1272,28 @@ const channel = supabase .subscribe() ``` + + + +```dart +supabase.realtime.setAuth('your-custom-jwt'); + +supabase + .channel('db-changes') + .onPostgresChanges( + event: PostgresChangeEvent.all, + schema: 'public', + table: 'messages', + filter: PostgresChangeFilter( + type: PostgresChangeFilterType.eq, + column: 'body', + value: 'bye', + ), + callback: (payload) => print(payload), + ) + .subscribe(); +``` + @@ -1051,6 +1344,13 @@ For example, if you're using the `supabase-js` `v2` client then you can pass you supabase.realtime.setAuth('fresh-token') ``` + + + +```dart +supabase.realtime.setAuth('fresh-token'); +``` + diff --git a/apps/docs/pages/guides/realtime/presence.mdx b/apps/docs/pages/guides/realtime/presence.mdx index 8d25c48ec6b..dbf8751a0dc 100644 --- a/apps/docs/pages/guides/realtime/presence.mdx +++ b/apps/docs/pages/guides/realtime/presence.mdx @@ -33,7 +33,23 @@ import { createClient } from '@supabase/supabase-js' const SUPABASE_URL = 'https://.supabase.co' const SUPABASE_KEY = '' -const client = createClient(SUPABASE_URL, SUPABASE_KEY) +const supabase = createClient(SUPABASE_URL, SUPABASE_KEY) +``` + + + + +```dart +void main() { + Supabase.initialize( + url: 'https://.supabase.co', + anonKey: '', + ); + + runApp(MyApp()); +} + +final supabase = Supabase.instance.client; ``` @@ -80,6 +96,24 @@ roomOne .subscribe() ``` + + + +```dart +final supabase = Supabase.instance.client; + +final roomOne = supabase.channel('room_01'); + +roomOne.onPresenceSync((_) { + final newState = roomOne.presenceState(); + print('sync: $newState'); +}).onPresenceJoin((payload) { + print('join: $payload'); +}).onPresenceLeave((payload) { + print('leave: $payload'); +}).subscribe(); +``` + @@ -131,6 +165,25 @@ roomOne.subscribe(async (status) => { }) ``` + + + +```dart +final roomOne = supabase.channel('room_01'); + +final userStatus = { + 'user': 'user-1', + 'online_at': DateTime.now().toIso8601String(), +}; + +roomOne.subscribe((status, error) async { + if (status != RealtimeSubscribeStatus.subscribed) return; + + final presenceTrackStatus = await roomOne.track(userStatus); + print(presenceTrackStatus); +}); +``` + @@ -175,6 +228,20 @@ const untrackPresence = async () => { untrackPresence() ``` + + + +```dart +final roomOne = supabase.channel('room_01'); + +untrackPresence() async { + final presenceUntrackStatus = await roomOne.untrack(); + print(presenceUntrackStatus); +} + +untrackPresence(); +``` + @@ -218,6 +285,16 @@ const channelC = supabase.channel('test', { }) ``` + + + +```dart +final channelC = supabase.channel( + 'test', + opts: const RealtimeChannelConfig(key: 'userId-123'), +); +``` +