zenstack icon indicating copy to clipboard operation
zenstack copied to clipboard

[BUG] Missing relation attributes from createMany and createManyAndReturn

Open Tsimopak opened this issue 1 year ago • 9 comments

createMany and createManyAndReturn misses relation attributes, although they can be used. An example,

If I have the following schema:

model House {
  id Int @id @default(autoincrement())
  doorTypeId Int
  door Door @relation(fields: [doorTypeId], references: [id])
  windows Window[]
  type String
  @@delegate(type)

}

model PrivateHouse extends House {
  card Int

}
model Skyscraper extends House {
  ticket Int

}

model Door {
  id Int @id @default(autoincrement())
  color String
  houses House[]
  type String
  @@delegate(type)

}


model IronDoor extends Door {
  strength Int

}

model WoodenDoor extends Door {
  texture String

}

model Window {
  id Int @id @default(autoincrement())
  houses House[]
}

And let's say I try to add a new houses using the createMany or createManyAndReturn api, see what options it gives me: image

^ No windows option, even though it is possible to make multiple connect, as i mentioned if i ignore this typing error it still works, it's just the typing that is messed up.

Another example, if I want to connect a door: image

I can only use doorTypeId, but from some reason it's not showing me the option to do that as safely by:

data: {
  door: {
     connect: id
  }
}

Versions:

  "devDependencies": {
    "prisma": "^5.19.1",
    "typescript": "^5.6.2",
    "zenstack": "2.5.1"
  },
  "dependencies": {
    "@prisma/client": "^5.19.1",
    "@zenstackhq/runtime": "2.5.1"
  }
}

Tsimopak avatar Sep 18 '24 11:09 Tsimopak

Hi @Tsimopak , as far as I understand, Prisma only supports scalar field in createMany and createManyAndReturn. Have you tried if it's the case with plain prisma, without zenstack?

E.g.:

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  posts Post[]
}

model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
  author    User?   @relation(fields: [authorId], references: [id])
  authorId  Int?
}

If you call prisma.user.createMany, you can't assign posts.

ymc9 avatar Sep 20 '24 03:09 ymc9

You are actually right :\ I'm not sure how it worked for me

Tsimopak avatar Sep 20 '24 10:09 Tsimopak

@ymc9 why does it work with zenstack then? for example:

  const w  = await db.window.create({ data: {} })
  const q = await db.privateHouse.createMany({
    data: {
      card: 1,
      windows: {
        connect: [{ id: w.id }]
      }
    } as any
  })

  ^ Works

models:

model House {
  id Int @id @default(autoincrement())
  doorTypeId Int?
  door Door? @relation(fields: [doorTypeId], references: [id])
  windows Window[]
  type String
  @@delegate(type)

}

model PrivateHouse extends House {
  card Int

}
model Skyscraper extends House {
  ticket Int

}

model Door {
  id Int @id @default(autoincrement())
  color String
  houses House[]
  type String
  @@delegate(type)

}


model IronDoor extends Door {
  strength Int

}

model WoodenDoor extends Door {
  texture String

}

model Window {
  id Int @id @default(autoincrement())
  houses House[]
}

Tsimopak avatar Sep 20 '24 13:09 Tsimopak

@ymc9 why does it work with zenstack then? for example:

  const w  = await db.window.create({ data: {} })
  const q = await db.privateHouse.createMany({
    data: {
      card: 1,
      windows: {
        connect: [{ id: w.id }]
      }
    } as any
  })

  ^ Works

models:

model House {
  id Int @id @default(autoincrement())
  doorTypeId Int?
  door Door? @relation(fields: [doorTypeId], references: [id])
  windows Window[]
  type String
  @@delegate(type)

}

model PrivateHouse extends House {
  card Int

}
model Skyscraper extends House {
  ticket Int

}

model Door {
  id Int @id @default(autoincrement())
  color String
  houses House[]
  type String
  @@delegate(type)

}


model IronDoor extends Door {
  strength Int

}

model WoodenDoor extends Door {
  texture String

}

model Window {
  id Int @id @default(autoincrement())
  houses House[]
}

I need to debug to confirm, but I believe it's because ZenStack translates createMany to create internally to enforce access policies. That part doesn't have strict input check, so the connect payload is passed through to create. It shouldn't be considered a feature though 😅. We should add some check and stay consistent with Prisma.

ymc9 avatar Sep 20 '24 16:09 ymc9

: ( I liked the connect in many to many

Tsimopak avatar Sep 20 '24 16:09 Tsimopak

@ymc9 So if we don't use createMany under the hood but create, does it mean we don't enjoy Batching when creating many polymorphic data?

https://www.prisma.io/docs/orm/prisma-client/queries/query-optimization-performance#using-bulk-queries

Tsimopak avatar Sep 20 '24 17:09 Tsimopak

@ymc9 So if we don't use createMany under the hood but create, does it mean we don't enjoy Batching when creating many polymorphic data?

https://www.prisma.io/docs/orm/prisma-client/queries/query-optimization-performance#using-bulk-queries

Yes, since creating a polymorphic entity involves nested write, it's always translated to plain create.

ymc9 avatar Sep 20 '24 18:09 ymc9

Thanks, closing this one.

Tsimopak avatar Sep 21 '24 10:09 Tsimopak

I reopen because I just noticed that you may want to take an action from this one about aligning the convention with prisma

Tsimopak avatar Sep 21 '24 10:09 Tsimopak