Skip to content

Add ability to do tag based refreshing (or dedicated queries for pagination/infinite results) #14522

@jjones315

Description

@jjones315

Describe the problem

When using remote queries with a result set of an unknown size it can be very difficult to properly refresh all of the queries.

For example a notifications area, its obviously unreasonable to load every notification a user has ever received, so our backend expects the id of the last notification queried on the next query in able to do offsets with.

(note: in playing with this i have changed the backend to use a more traditional page, pageSize system so my examples below use that, but i think the issue is similar with either method)

Say i have

// 3 commands/forms
markNotificationAsRead(notificationId:string);
markNotificationAsUnread(notificationId:string);
markAllNotificationAsRead();

// and 2 queried
getUnreadNotificationCount();
getNotification(data: { page: number });

When i call markNotificationAsRead i have no way of knowing which page that notification was actually on, therefor i don't know which page to refresh().

I can work around these fairly easily by passing that page the notification was on along with the id like. That will usually work as long as that notification is still on that page, if new notification have come in and pushed it to the n+1 page i am out of luck.

for markAllNotificationAsRead the solution is more difficult, i initially tried something like

async function refreshAllNotifications() {
    await getNotificationCounts().refresh();
    await getAllNotifications({}).refresh();
    const totalPages = getAllNotifications({ page: 1 }).current?.totalPages ?? 0;

    const promises: Promise<void>[] = [];
    for (let i = 1; i < totalPages; i++) {
        promises.push(getAllNotifications({ page: i + 1 }).refresh());
    }

    await Promise.all(promises);
}

but that will end up querying every notification a user has received even if the user is only on the first "page".

Describe the proposed solution

Allow Queries to be tagged. (preferably in a typed/referenceable way)

something like
const notificationTag = new ResourceTag("notifications");

export const getNotification= query(v.object({ page: v.optional(v.number(), 1) }), async input => {
     // some way to make usage of a tag
    notificationTag.reference();

    const event = getRequestEvent();
    await requireLogin();

    // get notifications()
});

export const getUnreadNotificationCounts = query(async () => {
    // some way to make usage of a tag
    notificationTag.reference();

    const event = getRequestEvent();
    await requireLogin();

    // get notification counts
});

export const markAllNotificationAsRead = command(async () => {
    const event = getRequestEvent();
    await requireRemoteLogin();

    // update notification

    // some way to make refresh those usages
    await notificationTag.refresh();
});

i also have a ws connection to push updates to clients that also refreshed the queries(counts) queries. That one i didnt even begin to tackle.

I understand the complexities of making this work in a single flight, but for my use cases i would rather have 2 request, than over/under query updates.

Alternatives considered

For this specific usage (pagination/infinite) queries you could create a specific query subtype to handle a lot of this.
See Tanstack Infinite Queries and Tanstack Paginated Queries for reference.

i still think some use cases are better served with tagging, but i am open to being convinced otherwise

Importance

would make my life easier

Additional Information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions