morintd / prismock

A mock for PrismaClient, dedicated to unit testing.
https://www.npmjs.com/package/prismock
MIT License
189 stars 20 forks source link

Nested updates not enforcing AND clause #1057

Open JoeRoddy opened 1 month ago

JoeRoddy commented 1 month ago

Again, great work on this library! It is massively valuable!

We're running into an issue with prismock not enforcing an AND clause in nested updates. (It might also have something to do with nesting some's and OR's inside of it)

Imagine a schema with user groups, and groupRoles for permissions. Psuedocode, but I think you'll get the idea

model User {}

model Group {
  users User[]
  groupRoles GroupRole[]
}

model GroupRole {
  // Owner or Member
  role String 
  userId String
  user User
  groupId String
  group Group
}

We run the following code:

  // create a group with an owner (admin) and a member
  const group = await db.group.create({
    data: {
      groupRoles: {
        create: [
          {
            role: 'Owner',
            userId: user1.id,
          },
          {
            role: 'Member',
            userId: user2.id,
          },
        ],
      },
    },
  });

  const user2Role = await db.groupRole.findFirst(...)  

  const userMakingQuery = user2;

   // update a group role, should only work if the user performing the query is the grp owner
   await db.group.update({
    where: { id: group.id },
    data: {
      groupRoles: {
        update: {
          data: { role: 'Owner' },
          where: {
            id: user2Role.id,
            // the following enforces that only group owners may manage group roles
            // if the user is not the group owner, this query should fail
            AND: [
              {
                group: {
                  groupRoles: {
                    some: {
                      OR: [{ role: 'Owner', userId: userMakingQuery.id }],
                    },
                  },
                },
              },
            ],
          },
        },
      },
    },
  });

The AND clause in question may look odd (nesting AND, OR, some, etc), but changing it is not really an option. The query is dynamically build by our Authorization library Casl

When we run the above code with Prisma, we get an error (desired behavior):

Invalid `prisma.group.update()` invocation:

An operation failed because it depends on one or more records that were required but not found. No 'GroupRole' record was found for a nested update on relation 'GroupToGroupRole'.

When we run it with Prismock, there is no error, and we're able to validate that the update persisted. (undesired, inconsistent wiht Prisma)

morintd commented 3 weeks ago

Hello @JoeRoddy , I'm not surprised this is happening, we don't throw error yet in Prismock (including foreign key, duplicate, etc.). While Prismock is now in a state where we could add those errors, I don't plan to implement it short-term.

On another hand, this does not completely look like it's only about supporting errors, the nested where clauses should return no data, hence no update should occur.... I'll still have a look