Skip to content

Feature Request: Hook/callback for internal findMany calls #48

@tsegreto

Description

@tsegreto

Feature Request: Hook/callback for internal findMany calls

Problem

When using prisma-extension-pagination alongside extensions that add custom args to queries (e.g. prisma-extension-redis's cache option), there's no way to differentiate between the multiple internal findMany calls the pagination library makes.

For cursor-based pagination, paginateWithCursor runs 2 concurrent findMany calls via Promise.all:

  1. The main results query (take: limit + 1)
  2. A boundary check query (take: -1 or take: 1)

Since both calls receive the same spread of ...query, any custom args (like a cache key) are identical for both. This causes issues like cache key collisions where the boundary check overwrites the main results in cache.

Current workaround

We currently have to strip custom args in paginate() and use a Proxy around the model to re-inject them with a unique suffix per internal findMany call. This works but adds complexity that shouldn't be necessary.

Proposed solution

Expose a onFindMany (or wrapFindMany) callback that receives the args for each internal findMany call along with context about which call it is:

const [users, meta] = await prisma.user
  .paginate({
    where: { status: 'active' },
    orderBy: { id: 'asc' },
  })
  .withCursor({
    limit: 10,
    after: cursor,
    onFindMany: (args, context) => {
      // context.type: 'results' | 'boundaryCheck' | 'count'
      // context.index: 0, 1, 2...
      return {
        ...args,
        cache: {
          key: `my:cache:key:${context.type}`,
        },
      };
    },
  });

Alternative: strip unknown args

A simpler (but less flexible) approach would be to strip any non-Prisma args before passing them into internal findMany calls, and instead accept extension-specific config as a separate top-level option:

.paginate({
  where: { status: 'active' },
}, {
  // Separate bag for extension args, not spread into findMany
  extensions: { cache: { key: 'my:key' } }
})

Context

This is specifically painful when combining with prisma-extension-redis, but would affect any Prisma extension that adds custom args to findMany. Related discussion: the pagination library currently spreads the full query object into every internal call without filtering, which leaks consumer-provided custom args into calls they weren't intended for.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions