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

Query subscriptions #221

Open
Soviut opened this issue Sep 11, 2022 · 13 comments
Open

Query subscriptions #221

Soviut opened this issue Sep 11, 2022 · 13 comments
Labels
enhancement New feature or request

Comments

@Soviut
Copy link

Soviut commented Sep 11, 2022

Feature request

Is your feature request related to a problem? Please describe.

Queries and subscriptions need to be mixed for most real-time applications. However, their implementations are very different and return different results, requiring the application manually mix the two sets of data to keep them in sync.

For example, you might have a chat app that does an initial query for the latest 50 messages in the current chat room.

const { data } = supabase
  .from('messages')
  .select('id, name, body, created_at')
  .match({ room_id: 'abc-123' })
  .limit(50)

messages.value = data

But in order to make the chat real-time, you need to set up a subscription that can only listen for inserts on the table. None of the querying operations can be used, only a rudimentary filter with different syntax. Likewise, the payload that is returned is simply the entire row with no control over which fields are sent.

supabase
  .channel('public:messages')
  .on(
    'postgres_changes',
    {
      event: 'INSERT',
      schema: 'public',
      table: 'messages',
      filter: 'room_id=eq.abc-123'
    },
    (payload) => {
      messages.value.push(payload.new)
    }
  )
  .subscribe()

This gets even more complicated if you want to allow messages to be edited, since that requires subscribing to the UPDATE event, then manually finding the message in the local chat history and updating it.

Describe the solution you'd like

Extend the query syntax to allow subscribing to a query.

supabase
  .from('messages')
  .select('id, name, body, created_at')
  .match({ room_id: 'abc-123' })
  .subscribe((payload) => {
    messages.value = payload.new
  }))

The idea being that unless a change to the table affects the query, don't send a payload.

It would be useful if both a full payload and a sparse payload could be chosen. Full payloads are good for things like real-time chat where you need old messages to be truncated, so replacing the entire immediate chat history can be beneficial. A sparse payload is useful for surgical changes to a local dataset, when the data is potentially too large to resend each time there is a change.

Describe alternatives you've considered

A clear and concise description of any alternative solutions or features you've considered.

Additional context

This feature request is similar to subscriptions in GraphQL which use the same syntax as normal queries. It would be really great if subscriptions could be added to the GraphQL API as well.

@Soviut Soviut added the enhancement New feature or request label Sep 11, 2022
@kiwicopple kiwicopple transferred this issue from supabase/supabase Jan 20, 2023
@sampl
Copy link

sampl commented Apr 8, 2023

+1. I'm surprised this request hasn't gotten more comments!

This gets even more complicated if you want to allow messages to be edited, since that requires subscribing to the UPDATE event, then manually finding the message in the local chat history and updating it.

This is so key--the current way I use realtime means a lot of manual data mgmt, when the original query was so simple.

I think subscriptions for queries it could unlock a crazy level of productivity for supabase users. I've used the Firebase equivalent in production for years and found the DX amazing.

It's how Firebase subscriptions work, too:

  • You create a query, and get the results by listening to the changes
  • React takes the new data and does the right thing with it
  • When you update a model somewhere in the app, subscriptions elsewhere get the update too (even w/o network, but that may be a whole other topic)

As a consequence,

  • Any data changes happen immediately
  • Developers can see whether a change happened locally or was persisted to the server
  • Developers can easily see the diff of a change

Example from Firebase docs:

import { doc, onSnapshot } from "firebase/firestore";

const unsub = onSnapshot(doc(db, "cities", "SF"), (doc) => {
    console.log("Current data: ", doc.data());
});

How I would want to use this in a React app:

import { supabase, useQuery } from "db/supabase";

export function Chat = () => {
  const messagesQuery = supabase.from('messages').select()
  const [messages, messagesLoading, messagesError] = useQuery(messagesQuery, { realtime: true } )

  if (messagesLoading || messagesError) return null
  return messages.map(m => <Message message={m} />)
}

Example use cases:

  1. You have a React context that has a one-line, realtime query for the user's Stripe subscription and provides it to the rest of the component tree. When a user subscribes on the upgrade page, the subscription context immediately knows and the entire app updates accordingly.
  2. You have an onboarding checklist, and one of the items is "publish a post". The box shows as checked or unchecked based on a one-line realtime subscription that queries "all published posts by this user". As a user publishes a post, the onboarding checklist box is immediately checked.

Etc etc. There are plenty of realtime use cases already, my point is that ideally realtime should be the default.

@user72356
Copy link

user72356 commented Jun 5, 2023

Interesting, I could also use that. Subscribe to a query instead of 1 or multiple tables with filters. The way I'm tackling this is by creating a special-purpose table and subscribing to changes on this table. My mutative queries modify this table in order to trigger the subscribed clients.

@pedrovivaldi
Copy link

I could use this feature as well

@accounts01
Copy link

+1

1 similar comment
@spriteshaper
Copy link

+1

@Christophershivers
Copy link

If this could be implemented it can be a game-changer.

@taromorimoto
Copy link

Any ideas on if this feature is on the roadmap? This is also available in AWS Amplify:
https://docs.amplify.aws/gen1/react/build-a-backend/graphqlapi/subscribe-data/

@TKasperczyk
Copy link

+1

1 similar comment
@alexruimy
Copy link

+1

@Soviut
Copy link
Author

Soviut commented Oct 13, 2024

Please stop typing "+1"! If you like the idea, use the reactions on the original post. Adding +1 posts just spam everyone's email who is following this thread.

It won't give the feature more attention, it won't bump the feature to the top of the backlog, it won't make the feature get done any faster. All it will do is encourage the thread to get closed.

Sorry in advance for contributing to the spam but we need this to stop.

@alexruimy
Copy link

+1

@Soviut
Copy link
Author

Soviut commented Oct 13, 2024

@alexruimy Not cool. I asked nicely for people to show some basic courtesy since not everyone knows about the spamming but you decided to troll. This is the wrong place for it and I'll happily close the this issue to avoid any more of that.

@alexruimy
Copy link

+1

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

No branches or pull requests

10 participants