Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

syncedSupabase Missing Relational Data & Ignoring Filters #476

Open
alpppine opened this issue Feb 19, 2025 · 1 comment
Open

syncedSupabase Missing Relational Data & Ignoring Filters #476

alpppine opened this issue Feb 19, 2025 · 1 comment

Comments

@alpppine
Copy link

We’ve encountered some issues using LegendState’s Supabase sync plugin in our React Native application. When inserting a new record into a table with related data, the realtime sync does not behave as expected.

When a new record is created, it does not include related fields such as user or comments, even though the select query explicitly requests them. The record only contains the primary table fields, and the relational fields return undefined. However, when manually fetching the same data from Supabase, the related fields are included as expected.

Another issue is that realtime updates do not respect the filters provided. For example, if we filter records by user_id, new inserts still appear in all user stores, rather than just the ones where user_id matches the filter.

Steps to Reproduce

Using syncedSupabase, a new observable is created for a list of posts. The setup includes a select query that requests the full post data, including the author and associated comments. The realtime option is enabled with a filter to listen only for posts by a specific user.

const posts$ = observable( syncedSupabase({ supabase, collection: "Posts", actions: ["read", "create", "update"], realtime: { filter: user_id=eq.${userId} }, select: (select) => select .select("*, author: Users!inner(*), comments: Comments(*)") .filter("user_id", "eq", userId), }) );

After creating a new post, the observable updates, but the author and comments fields are missing. Instead of containing the full user object, author is just an ID, and comments is an empty array. Furthermore, the new post appears in all user views, rather than only in the views where user_id matches the filter.

Expected Behavior

When a new post is created, the full data—including relational fields—should be available in the realtime update. The realtime filter should ensure that updates only appear where user_id matches the filter. Additionally, new posts should sync instantly across devices without requiring a manual refresh.

To work around these issues, we can manually re-fetch the full post data after creation using a direct Supabase query and set up a separate Supabase Realtime listener instead of relying on syncedSupabase to handle updates; however, this defeats the purpose of using syncedSupabase for automatic state synchronization.

@legendapp/state: 3.0.0-beta.23

@alpppine
Copy link
Author

We’ve investigated further and found that Supabase Realtime does not return joined (relational) data, which means that when using syncedSupabase, any select query with related fields (e.g., author: Users(), comments: Comments()) does not return the expected data in realtime updates.

To resolve this issue within syncedSupabase, could the subscribe function be updated to fetch full data after a realtime event instead of just applying the raw row update?

const subscribe = ({ node, value$, update }: SyncedSubscribeParams<TRemote[]>) => {
    const channel = client
        .channel(`LS_${node.key}`)
        .on(
            'postgres_changes',
            { event: '*', table: collection, schema: 'public', filter: filter || undefined },
            async (payload) => {
                const { data } = await client
                    .from(collection)
                    .select(props.select || "*") // Use the same select query
                    .eq("id", payload.new.id)
                    .single();

                if (data) {
                    update({ value: [data], mode: 'merge' });
                }
            }
        )
        .subscribe();

    return () => channel.unsubscribe();
};

cc @jmeistrich

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant