From 49dc2fbb1b5b08ed86e21a86c4d1fd78e918fffc Mon Sep 17 00:00:00 2001 From: tr00d Date: Thu, 6 Aug 2026 14:32:07 +0200 Subject: [PATCH] fix: omit null table from postgres_changes join payload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A schema-wide listener has no table, so Table is null — but it serialized as "table": null in the join config.postgres_changes payload, whereas the server expects the key to be absent. Add NullValueHandling.Ignore so a null table is dropped, matching realtime-js. --- .../PostgresChanges/PostgresChangesOptions.cs | 6 ++-- .../PostgresChangesOptionsTests.cs | 29 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 RealtimeTests/Serialization/PostgresChangesOptionsTests.cs diff --git a/Realtime/PostgresChanges/PostgresChangesOptions.cs b/Realtime/PostgresChanges/PostgresChangesOptions.cs index 6f4a2e9..3b3d65c 100644 --- a/Realtime/PostgresChanges/PostgresChangesOptions.cs +++ b/Realtime/PostgresChanges/PostgresChangesOptions.cs @@ -57,9 +57,11 @@ public enum ListenType public string Schema { get; set; } /// - /// The table for this listener, can be: `*` matching all tables in schema. + /// The table for this listener, can be: `*` matching all tables in schema. When null + /// (a schema-wide listener), the table key is omitted from the join payload rather than + /// sent as null. /// - [JsonProperty("table")] + [JsonProperty("table", NullValueHandling = NullValueHandling.Ignore)] public string? Table { get; set; } /// diff --git a/RealtimeTests/Serialization/PostgresChangesOptionsTests.cs b/RealtimeTests/Serialization/PostgresChangesOptionsTests.cs new file mode 100644 index 0000000..a98c9f8 --- /dev/null +++ b/RealtimeTests/Serialization/PostgresChangesOptionsTests.cs @@ -0,0 +1,29 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Supabase.Realtime.PostgresChanges; + +namespace RealtimeTests; + +/// +/// Wire-shape of as it is serialized into a channel's +/// join config.postgres_changes payload. +/// +[TestClass] +public class PostgresChangesOptionsTests +{ + [TestMethod] + public void Table_ShouldBeOmittedFromJson_WhenNull() + { + // A schema-wide listener has no table; the server expects the key absent, not `"table": null`. + var json = JsonConvert.SerializeObject(new PostgresChangesOptions("public")); + Assert.IsFalse(JObject.Parse(json).ContainsKey("table")); + } + + [TestMethod] + public void Table_ShouldBeSerialized_WhenProvided() + { + var json = JsonConvert.SerializeObject(new PostgresChangesOptions("public", "todos")); + Assert.AreEqual("todos", JObject.Parse(json)["table"]?.Value()); + } +}