supabase-community / realtime-csharp

A C# client library for supabase/realtime.
https://supabase-community.github.io/realtime-csharp/api/Supabase.Realtime.Client.html
MIT License
70 stars 12 forks source link

Supabase realtime not work for delete events in row level filters #49

Open hernanjls opened 1 month ago

hernanjls commented 1 month ago

Bug report

events not fired in suscription for channel with row level filters

Describe the bug

Row level filtering in the channel, not allow detect events for delete operations

To Reproduce

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

Here this example is using suoabase realtime events suscriptions.

using RealtimeExample.Models; using Supabase.Realtime; using System; using System.Diagnostics; using System.Threading.Tasks; using Supabase.Realtime.Interfaces; using Supabase.Realtime.PostgresChanges; using Supabase.Realtime.Socket; using static Supabase.Realtime.Constants; using static Supabase.Realtime.PostgresChanges.PostgresChangesOptions;

namespace RealtimeExample { class Program {

    private const string ApiKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Imxpb2d2YmhsZXFwa2xrdGprc25zIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTkwMTA2OTMsImV4cCI6MjAzNDU4NjY5M30.Nbns8OlJQHmOOojjm2LmcfFTaYH9H93IlCtPxLnyNTg";

    private const string SocketEndpoint = "wss://xxxxxxxxxxx.supabase.co/realtime/v1";

    static async Task Main(string[] args)
    {

        var realtimeClient = new Client(SocketEndpoint, new ClientOptions
        {
            Parameters = new SocketOptionsParameters
            {
                ApiKey = ApiKey
            }
        });

        if (realtimeClient != null)
        {
            realtimeClient.AddDebugHandler((sender, message, exception) => Console.WriteLine(message));
            realtimeClient.AddStateChangedHandler(SocketEventHandler);
            await realtimeClient.ConnectAsync();
        }

        //var channelTodos = realtimeClient.Channel("public:producto");
        //channelTodos.Register(new PostgresChangesOptions("public", "producto", ListenType.All));

        var idTienda = 1;
        var channelTodos = realtimeClient.Channel($"public:producto:idtienda=eq.{idTienda}");
        channelTodos.Register(new PostgresChangesOptions("public", "producto", ListenType.All, $"idtienda=eq.{idTienda}"));

        channelTodos.AddPostgresChangeHandler(ListenType.Inserts, PostgresInsertedHandler);
        channelTodos.AddPostgresChangeHandler(ListenType.Updates, PostgresUpdatedHandler);
        channelTodos.AddPostgresChangeHandler(ListenType.Deletes, PostgresDeletedHandler);

        // Suscribirse a los cambios en el canal
        await channelTodos.Subscribe();

        Console.ReadKey();
    }

    // Here fire always without filltering but with filtered row level channel not fire
    private static void PostgresDeletedHandler(IRealtimeChannel _, PostgresChangesResponse change)
    {
        Console.WriteLine("Item Deleted");
    }

    private static void PostgresUpdatedHandler(IRealtimeChannel _, PostgresChangesResponse change)
    {
        Console.WriteLine($"Item Updated: {change.Model<Producto>()}");
    }

    private static void PostgresInsertedHandler(IRealtimeChannel _, PostgresChangesResponse change)
    {
        Console.WriteLine($"New item inserted: {change.Model<Producto>()}");
    }

    // Manejador para eventos de estado del WebSocket
    private static void SocketEventHandler(IRealtimeClient<RealtimeSocket, RealtimeChannel> sender,
        SocketState state)
    {
        Debug.WriteLine($"Socket is {state.ToString()}");
    }
}

}

epjecha commented 3 weeks ago

Hey guys! We looked into this a bit further, and it looks like if the column the filter references is not one of the primary keys for the table, the delete will be lost. This seems to be because the delete record only contains primary keys, not the rest of the data that was contained in the row. We "fixed" it by including that column as a primary key for the table. Definitely not ideal in all contexts, but hey, at least it works. Hope this helps!