Skip to content

Conditions hoisted from nested read overwrites toplevel where conditions #634

@ymc9

Description

@ymc9

Version
1.0.0-Beta.18

Schema

model User {
    id String @id @default(uuid())
    email String @unique
    password String? @password @omit
    name String?
    orgs Organization[]
    posts Post[]
    groups Group[]
    comments Comment[]
    // can be created by anyone, even not logged in
    @@allow('create', true)
    // can be read by users in the same organization
    @@allow('read', orgs?[members?[auth() == this]])
    // full access by oneself
    @@allow('all', auth() == this)
}

model Organization {
    id String @id @default(uuid())
    name String
    members User[]
    post Post[]
    groups Group[]
    comments Comment[]

    // everyone can create a organization
    @@allow('create', true)
    // any user in the organization can read the organization
    @@allow('read', members?[auth() == this])
}

abstract model organizationBaseEntity {
    id String @id @default(uuid())
    createdAt DateTime @default(now())
    updatedAt DateTime @updatedAt
    isDeleted Boolean @default(false) @omit
    isPublic Boolean @default(false)
    owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade)
    ownerId String
    org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
    orgId String
    groups Group[]

    // when create, owner must be set to current user, and user must be in the organization
    @@allow('create', owner == auth() && org.members?[this == auth()])
    // only the owner can update it and is not allowed to change the owner
    @@allow('update', owner == auth() && org.members?[this == auth()] && future().owner == owner)
    // allow owner to read
    @@allow('read', owner == auth())
    // allow shared group members to read it
    @@allow('read', groups?[users?[this == auth()]])
    // allow organization to access if public
    @@allow('read', isPublic && org.members?[this == auth()])
    // can not be read if deleted
    @@deny('all', isDeleted == true)
}

model Post extends organizationBaseEntity {
    title String
    content String
    comments Comment[]
}

model Comment extends organizationBaseEntity {
    content String
    post Post @relation(fields: [postId], references: [id])
    postId String
}

model Group {
    id String @id @default(uuid())
    name String
    users User[]
    posts Post[]
    comments Comment[]
    org Organization @relation(fields: [orgId], references: [id])
    orgId String

    // group is shared by organization
    @@allow('all', org.members?[auth() == this])
}

Query

const result = await client.comment.findMany({
    where: {
      owner: {
        name: "Bryan",
      },
    },
    select: {
      id: true,
      content: true,
      owner: {
        select: {
          id: true,
          name: true,
        },
      },
    },
  });

The query selects nested owner, causing owner's read condition to be hoisted to top-level (because owner is a non-nullable to-one relation). It conflicts with the original owner: {...} clause in the top-level where and caused it to be overwritten.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions