grammyjs / storages

Storage adapters for grammY sessions.
48 stars 23 forks source link

fix(prisma): silence the "Record to delete does not exist" error #186

Closed leonekmi closed 10 months ago

leonekmi commented 11 months ago

Prisma error P2025 is thrown when a record to delete is not found. This error should not propagate further into the grammy stack.

Ref: https://www.prisma.io/docs/reference/api-reference/error-reference#p2025

The issue I was trying to solve

I want to isolate the conversations storage in its own session (to have a different session key strategy, basically) using multi sessions and the Prisma adapter.

bot.use(
  session({
    type: "multi",
    favorites: {
      getSessionKey(ctx) {
        return `user/favorites/${ctx.from?.id}`;
      },
      initial: () => ({
        favoriteStations: [],
      }),
      storage: new PrismaAdapter(prisma.grammYSession),
    },
    conversation: {
      getSessionKey(ctx) {
        if (!ctx.chat?.id) return undefined;
        return `chat/conversation/${ctx.chat?.id}`;
      },
      storage: new PrismaAdapter(prisma.grammYSession),
    },
  })
);

Using this configuration, Prisma will throw an error indicating that "Record to delete does not exist".

    err: {
      "type": "PrismaClientKnownRequestError",
      "message": "\nInvalid `this.sessionDelegate.delete()` invocation in\n/home/leonekmi/MaxPing/node_modules/@grammyjs/storage-prisma/dist/index.js:36:42\n\n  33     });\n  34 }\n  35 async delete(key) {\n→ 36     await this.sessionDelegate.delete(\nAn operation failed because it depends on one or more records that were required but not found. Record to delete does not exist.",
      "stack":
          Error: 
          Invalid `this.sessionDelegate.delete()` invocation in
          /home/leonekmi/MaxPing/node_modules/@grammyjs/storage-prisma/dist/index.js:36:42

            33     });
            34 }
            35 async delete(key) {
          → 36     await this.sessionDelegate.delete(
          An operation failed because it depends on one or more records that were required but not found. Record to delete does not exist.
              at Pn.handleRequestError (/home/leonekmi/MaxPing/node_modules/@prisma/client/runtime/library.js:171:6929)
              at Pn.handleAndLogRequestError (/home/leonekmi/MaxPing/node_modules/@prisma/client/runtime/library.js:171:6358)
              at Pn.request (/home/leonekmi/MaxPing/node_modules/@prisma/client/runtime/library.js:171:6237)
              at async PrismaAdapter.delete (/home/leonekmi/MaxPing/node_modules/@grammyjs/storage-prisma/dist/index.js:36:9)
              at async PropertySession.finish (/home/leonekmi/MaxPing/node_modules/grammy/out/convenience/session.js:231:21)
              at async Promise.all (index 1)
              at async /home/leonekmi/MaxPing/node_modules/grammy/out/convenience/session.js:86:9
              at async /home/leonekmi/MaxPing/node_modules/grammy/out/composer.js:61:13
              at async /home/leonekmi/MaxPing/node_modules/grammy/out/composer.js:56:9
              at async /home/leonekmi/MaxPing/node_modules/grammy/out/composer.js:56:9
      "code": "P2025",
      "clientVersion": "4.14.0",
      "meta": {
        "cause": "Record to delete does not exist."
      }
    }

I found that the cause is the conversations plugin setting session.convesation to undefined when no conversations are running, to delete the session entry.

This will mark the storage prop wrote, thus triggering a delete. But the Prisma adapter will throw when trying to delete a record that was not yet written to database.

To fix that, we ignore the Prisma P2025 error and return instead.