diff --git a/.changeset/shiny-panthers-nail.md b/.changeset/shiny-panthers-nail.md new file mode 100644 index 000000000000..2d0783854f28 --- /dev/null +++ b/.changeset/shiny-panthers-nail.md @@ -0,0 +1,8 @@ +--- +"@refinedev/supabase": patch +--- + +fix: handle multiple filters in Supabase liveProvider. +This update addresses the handling of multiple filters in the Supabase liveProvider. It ensures only the first filter is applied and introduces a configurable `meta.realtimeFilter` option for custom filter behavior. A warning is logged when multiple filters are detected. + +[Resolves #6360](https://github.com/refinedev/refine/issues/6360) diff --git a/packages/supabase/src/liveProvider/index.ts b/packages/supabase/src/liveProvider/index.ts index 19200da1de4c..a8a91906a284 100644 --- a/packages/supabase/src/liveProvider/index.ts +++ b/packages/supabase/src/liveProvider/index.ts @@ -6,6 +6,23 @@ import type { } from "@supabase/supabase-js"; import { liveTypes, supabaseTypes } from "../types"; import { mapOperator } from "../utils"; +import warnOnce from "warn-once"; + +const supportedOperators = [ + "eq", + "ne", + "nin", + "ina", + "nina", + "contains", + "ncontains", + "containss", + "ncontainss", + "between", + "nbetween", + "null", + "nnull", +]; export const liveProvider = ( supabaseClient: SupabaseClient, @@ -49,19 +66,37 @@ export const liveProvider = ( } }; - const mapFilter = (filters?: CrudFilters): string | undefined => { + const mapFilter = ( + filters?: CrudFilters, + meta?: any, + ): string | undefined => { if (!filters || filters?.length === 0) { return; } - return filters + if (filters.length > 1 && !meta?.realtimeFilter) { + warnOnce( + true, + `Warning: Multiple filters detected for resource "${resource}". Supabase Realtime currently supports only a single filter. The first filter will be applied. To customize this behavior, use the 'meta.realtimeFilter' property.`, + ); + } + + const effectiveFilter = meta?.realtimeFilter + ? [meta.realtimeFilter] + : [filters[0]]; + + return effectiveFilter .map((filter: CrudFilter): string | undefined => { if ("field" in filter) { - return `${filter.field}=${mapOperator(filter.operator)}.${ - filter.value - }`; + if (supportedOperators.includes(filter.operator)) { + return `${filter.field}=${mapOperator(filter.operator)}.${ + filter.value + }`; + } + warnOnce(true, `Unsupported filter operator: ${filter.operator}`); + return undefined; } - return; + return undefined; }) .filter(Boolean) .join(","); @@ -70,7 +105,7 @@ export const liveProvider = ( const events = types .map((x) => supabaseTypes[x]) .sort((a, b) => a.localeCompare(b)); - const filter = mapFilter(params?.filters); + const filter = mapFilter(params?.filters, meta); const ch = `${channel}:${events.join("|")}${filter ? `:${filter}` : ""}`; let client = supabaseClient.channel(ch);