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

Can't retrieve data through RealtimeChannel.OnUpdate #22

Closed Shenrak closed 1 year ago

Shenrak commented 1 year ago

Bug report

Describe the bug

RealtimeChannel's response isn't parsed correctly. Both RealtimeChannel.Model<T>() and PostgresChangesEventArgs.Response.Payload.Data.Record.Record are defaults values.

To Reproduce

Subscribe to a table with RealtimeChannel.OnUpdate

Expected behavior

Getting correct data that's been updated

Screenshots

Table maintenance image

    [Table("maintenance")]
    public class SchemaMaintenance : BaseModel
    {
        [PrimaryKey("forced_version", false)] public string ForcedVersion { get; set; }
        [Column("is_on_maintenance")] public bool IsOnMaintenance { get; set; }
    }
    public static void StartConnectedDeviceWatcher()
    {
        var channel = SupabaseManager.app.Realtime.Channel("realtime", "public", "maintenance");

        channel.OnUpdate += (object sender, PostgresChangesEventArgs a) =>
        {
            var m = a.Response.Model<SchemaMaintenance>();
            Console.WriteLine("Item updated: " + a.Response.Payload.Data.Record.Record);
        };
        channel.Subscribe().ContinueWith(HandleErrors);
    }

The following screenshot showcases what's happening in RealtimeChannel.Model() image

The raw content of Json : image

System information

Additional context

I'd like to add that it was not clear to me as what to put in databasefield of Channel() : image As my table was in the postgres database, i had a though time to figure it out :p

Guillaume

Shenrak commented 1 year ago

columns and commit_timestamp a correctly populated

Shenrak commented 1 year ago

Managed to get it working by adding :

[JsonProperty("forced_version")]
[JsonProperty("is_on_maintenance")]

as so :

    [Table("maintenance")]
    public class SchemaMaintenance : BaseModel
    {
        [JsonProperty("forced_version")][PrimaryKey("forced_version", false)] public string ForcedVersion { get; set; }
        [JsonProperty("is_on_maintenance")][Column("is_on_maintenance")] public bool IsOnMaintenance { get; set; }
    }

Might be a good idea to embed it in [Column] and [PrimaryKey] ??

However, seems like old_record is always missing the boolean property is_on_maintenance, has it something to do with it begin a boolean ? It is missing in all cases, with it being the modified value or not : image

acupofjose commented 1 year ago

@Shenrak such a thorough issue! I love when so much data is provided.

I think this is a regression from updating the Newtonsoft.Json dependency - I'll get it pushed out in an update this evening! Thanks so much for digging into it!

acupofjose commented 1 year ago

Available in realtime-csharp@5.0.1 / supabase-csharp@0.8.2!

Shenrak commented 1 year ago

Hi,

Made the update, works like a charm ! However, i'm still running into this issue : image

old_payload is always lacking data, and OnUpdate is always called, even if the UPDATE didn't change anything Do you have an idea on the matter ?

acupofjose commented 1 year ago

Have you tried using OldModel<T>()? Like so:

var m = a.Response.OldModel<SchemaMaintenance>();
acupofjose commented 1 year ago

And to be clear... you're having OnUpdate being called on inserts and deletes?

Shenrak commented 1 year ago

I'm using OnUpdate only with updates, i'v not try it with Inserts and Deletes I might not have been really clear, i'll try to :

        void OnChannelUpdate(object sender, PostgresChangesEventArgs a)
        {
            var oldModel = a.Response.OldModel<SupabaseModel>();
            var model = a.Response.Model<SupabaseModel>();
            if (JsonConvert.SerializeObject(oldModel) != JsonConvert.SerializeObject(model))
            {
                OnRemotelyUpdated?.Invoke(model);
            }
        }

Pretty much what I'm trying to do is to call OnRemotelyUpdated only if the row has effectively been updated. It happens that a row has been updated but no data changed, because i'm doing bluk upserts of lists with some elements that havn't changed.

The issue here is that OldModel is missing some data, as i linked in my preview message

acupofjose commented 1 year ago

Gotcha! If you want to receive the "previous" data for updates and deletes, you will need to set REPLICA IDENTITY to FULL, like this: ALTER TABLE your_table REPLICA IDENTITY FULL - you can set that in your supabase console using the SQL editor. (That documentation is here - but I'll add it to the docs in the code as well!)

As for the updates with no changed data being sent - you are calling with an insert, even if there isn't actually a change. So the client is working as expected - you'll need to do the filtering on your side.

Shenrak commented 1 year ago

Yup, that's pretty much what I ended up doing, also i don't update the DB if there's been no change anymore Thanks for your help !