olivierwilkinson / prisma-extension-nested-operations

Utils for creating Prisma client extensions with nested operations
Apache License 2.0
28 stars 4 forks source link

Typescript is slow after using the lib #5

Open manoelramos opened 5 months ago

manoelramos commented 5 months ago

First, congratulations on your work, it helped us a lot here in our project.

But we had a side effect when using this lib. Typescript suggestions were very slow. And this happened on every machine, from every developer. I recorded the screen, showing the difference between when we use the lib and when we don't.

Do you have any suggestions to avoid this side effect? Has anyone ever experienced this?

https://github.com/olivierwilkinson/prisma-extension-nested-operations/assets/12393428/8de6d406-fef1-4dd8-9a20-978a4867cc3f

olivierwilkinson commented 5 months ago

Hi there, thank you for the kind words and I'm happy the library has been helpful!

Very strange that it's choking up Typescipt, I'm not sure off the top of my head what could be causing this 🤔. Would you mind letting me know the version of Typescript, Prisma client and the extension code you are using so I can reproduce the problem locally?

One thing that's occured to me actually is that using nodemon to regenerate the Prisma client on save might cause things to be slow, are you doing that by any chance?

Thanks for raising the issue, it is very frustrating to have slow typescript suggestions for sure!

manoelramos commented 5 months ago

Of course, here's the information:

"@prisma/client": "^4.16.2", "prisma-extension-nested-operations": "^1.0.1", "prisma": "^4.16.2", "typescript": "4.9.5"

export function prismaAccessControlMiddleware(req: NextApiRequest) {
  const dateNow = dayjs().toDate();
  return prisma.$extends({
    query: {
      $allModels: {
        $allOperations: withNestedOperations({
          async $rootOperation(params) {
            const tenantId = await tenantIdLoggedUser(req);
            const userId = await userLogged(req);
            if (
              params.operation === 'findMany' ||
              params.operation === 'findFirst' ||
              params.operation === 'findFirstOrThrow'
            ) {
              return await params.query({
                ...params.args,
                where: {
                  ...params.args.where,
                  OR: [
                    {
                      TenantId: tenantId,
                    },
                    {
                      TenantId: 'system',
                    },
                  ],
                } as any,
              });
            }
            if (params.operation === 'create') {
              return await params.query({
                ...params.args,
                data: {
                  ...params.args.data,
                  // TenantId: tenantId,
                  Ativo: true,
                  AddedDate: dateNow,
                  CreatedBy: userId,
                },
              });
            }
            if (params.operation === 'update') {
              return await params.query({
                ...params.args,
                data: {
                  ...params.args.data,
                  // TenantId: tenantId,
                  ModifiedDate: dateNow,
                  UpdatedBy: userId,
                },
              });
            }
            if (params.operation === 'upsert') {
              params.query({
                ...params.args,
                create: {
                  ...params.args.create,
                  // TenantId: tenantId,
                  Ativo: true,
                  AddedDate: dateNow,
                  CreatedBy: userId,
                },
                update: {
                  ...params.args.update,
                  // TenantId: tenantId,
                  ModifiedDate: dateNow,
                  UpdatedBy: userId,
                },
              });
            }
            return await params.query(params.args);
          },
          async $allNestedOperations(params) {
            const tenantId = await tenantIdLoggedUser(req);
            const userId = await userLogged(req);
            if (params.operation === 'create') {
              params.query({
                ...params.args,
                // TenantId: tenantId,
                Ativo: true,
                AddedDate: dateNow,
                CreatedBy: userId,
              });
            }
            if (params.operation === 'createMany') {
              params.args.data.forEach((data: any) => {
                if (!data.Ativo) {
                  data.Ativo = true;
                }
                if (!data.AddedDate) {
                  data.AddedDate = dateNow;
                }
                if (!data.CreatedBy) {
                  data.CreatedBy = userId;
                }
              });
            }
            if (params.operation === 'connectOrCreate') {
              params.query({
                ...params.args,
                create: {
                  ...params.args.create,
                  // TenantId: tenantId,
                  Ativo: true,
                  AddedDate: dateNow,
                  CreatedBy: userId,
                },
              });
            }
            if (
              params.operation === 'update' ||
              params.operation === 'updateMany'
            ) {
              if (params.args.data) {
                params.query({
                  ...params.args,
                  data: {
                    // TenantId: tenantId,
                    ...params.args.data,
                    ModifiedDate: dateNow,
                    UpdatedBy: userId,
                  },
                });
              } else {
                params.query({
                  ...params.args,
                  // TenantId: tenantId,
                  ModifiedDate: dateNow,
                  UpdatedBy: userId,
                });
              }
            }
            if (params.operation === 'upsert') {
              params.query({
                ...params.args,
                create: {
                  ...params.args.create,
                  // TenantId: tenantId,
                  Ativo: true,
                  AddedDate: dateNow,
                  CreatedBy: userId,
                },
                update: {
                  ...params.args.update,
                  // TenantId: tenantId,
                  ModifiedDate: dateNow,
                  UpdatedBy: userId,
                },
              });
            }
            return await params.query(params.args);
          },
        }),
      },
    },
  });
}

This is the code we are using, but I have already excluded everything within the functions, leaving only the return, as shown in the doc.

return await params.query(params.args);

and the problem happens. If I remove the return from within the function, the slowness stops.

We are not using nodemon.

Thank you for the response and support.

navitpadan commented 4 months ago

+1: both on the compliments and +1 on observing the slowness side-effect

olivierwilkinson commented 4 months ago

Hi there,

I have not been able to reproduce this yet! I'm using the packages listed in a new NextJS project and the type of the client returned from the prismaAccessControlMiddleware function is as follows:

Screenshot 2024-03-02 at 10 47 40

I'm not finding any slowness, but it's not too surprising because the extension doesn't result in any changes to the client's types.

It could be that this library is not playing well with the types produced from other extensions. Is the prisma instance an extended client? Please can you let me know the type of the prisma instance so I can reproduce that as well?