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

[prisma] Using extensions to remove the need for subject helper with prisma #783

Open
Faithfinder opened this issue Jul 4, 2023 · 5 comments

Comments

@Faithfinder
Copy link

Is your feature request related to a problem? Please describe.
Currently, you need the subject helper to use CASL with Prisma. With client extensions being stable now, we can do better.

Describe the solution you'd like
Provide a pre-packaged extension in CASL, that will add the model name to a field in prisma client (maybe use a symbol for the field?). Make the default detectSubjectType know how to read that field.

Describe alternatives you've considered
This is fairly easily solvable in user-land, just thought it might be a good idea if the prisma package made the process streamlined.

@stalniy
Copy link
Owner

stalniy commented Jul 4, 2023

Makes sense. Im glad to accept PR.

@PavlMais
Copy link

PavlMais commented Sep 7, 2023

Why not go further and write an extension that will add additional query functions that will accept the ability,
Under the hood, it might look like this:

Prisma.defineExtension({
  model: {
    $allModels: {
      async tryFindMany<T, A extends Prisma.Args<T, 'findMany'>>(
        this: T,
        { ability, ...args }: A & { ability: AppAbility },
      ): Promise<Prisma.Result<T, A, 'findMany'>> {
        const context = Prisma.getExtensionContext(this) as { name: Prisma.ModelName };
        const where = {
          AND: [accessibleBy(args.ability, 'read')[context.name], args.where],
        };

        return (context as any).findMany({ ...args, where });
      },
      // ... other methods
    },
  },
});

@stalniy
Copy link
Owner

stalniy commented Sep 7, 2023

Adding methods is a bit more opinionated, also I don’t know how to adjust prisma types in this case. I have experience adding methods to mongoose models, it made initial setup complicated and eventually I deprecated that and implemented accessibleBy helper, similar to Prisma’s one

so, there is no much difference what to use

model.find(accessibleBy().Post) or model.accessibleBy() in both cases you need to know that you need to use specific method/helper. It’s also doesn’t have much value from encapsulation point of view.

However boilerplate reduction can be reduced with methods but it’s very little reduction.

If you see this differently, please share your thoughts

@PavlMais
Copy link

PavlMais commented Sep 7, 2023

@stalniy what do you mean by to adjust prisma types?

@jrmyio
Copy link

jrmyio commented Nov 14, 2023

Maybe this could be handy:
https://www.prisma.io/docs/concepts/components/prisma-client/client-extensions/query

According to their docs:
For example, in a row-level security (RLS) scenario, you can keep each user in an entirely separate client. With middlewares, all users are active in the same client.

This means you could get a user /ability scoped prisma client that works on all models and operations and adds to nessecary checks as defined in your ability.

const prisma = new PrismaClient().$extends({
  query: {
    $allOperations({ model, operation, args, query }) {
      /* some  logic here that modifies the args / query depending on the ability */
      return query(args)
    },
  },
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants