prisma / prisma

Next-generation ORM for Node.js & TypeScript | PostgreSQL, MySQL, MariaDB, SQL Server, SQLite, MongoDB and CockroachDB
https://www.prisma.io
Apache License 2.0
39.73k stars 1.55k forks source link

`prisma introspect` with invalid schema leads to error #2599

Closed janpio closed 3 years ago

janpio commented 4 years ago

Problem

Right now if when you run prisma introspect and your schema has a syntax error, it errors out. This is kind of unnecessary overhead, since the schema will be overridden anyway. It appears like we validate the existing schema before overriding it.

How to Reproduce

Schema when running prisma introspect:

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "mysql"
  url      = "mysql://root:root@localhost:3316/_upgradeTest"
}

model Address {
  additionalAddress String?
  addressType       String        @default("PRIVATE")
  country           String
  id                String        @id
  place             String?
  street            String?
  zipcode           String?
  Customer          Customer?
  Organisation      Organisation?
  UserProfile       UserProfile?
}

model AnalyticsConfiguration {
  customSettings Json?
  enabled        Boolean  @de
  fault(true)
  id             String   @id
  product        String?
  productionOnly Boolean  @default(false)
  provider       String
  trackingCode   String
  Product        Product? @relation(fields: [product], references: [id])

  @@index([product], name: "product")
}

model AuthConfiguration {
  appClientId                    String
  enableFacebook                 Boolean                          @default(false)
  enableGoogle                   Boolean                          @default(false)
  id                             String                           @id
  identityPoolId                 String?
  userPoolId                     String
  AuthConfiguration_redirectUrls AuthConfiguration_redirectUrls[]
  Site                           Site?
}

model AuthConfiguration_redirectUrls {
  nodeId            String
  position          Int
  value             String
  AuthConfiguration AuthConfiguration @relation(fields: [nodeId], references: [id])

  @@id([nodeId, position])
  @@index([value], name: "value")
}

model BillingAddress {
  additionalAddress String?
  country           String
  id                String    @id
  name              String
  place             String
  street            String
  zipcode           String
  Customer          Customer?
  Issue             Issue?
}

model CDBreakpoints {
  id                                                                String            @id
  lg                                                                String
  md                                                                String
  sm                                                                String
  xl                                                                String
  xs                                                                String
  CorporateDesign_CDBreakpointsToCorporateDesign_containerMaxWidths CorporateDesign[] @relation("CDBreakpointsToCorporateDesign_containerMaxWidths")
  CorporateDesign_CDBreakpointsToCorporateDesign_gridBreakpoints    CorporateDesign[] @relation("CDBreakpointsToCorporateDesign_gridBreakpoints")
}

model CDColors {
  danger                                                         String
  default                                                        String
  id                                                             String            @id
  info                                                           String
  muted                                                          String
  primary                                                        String
  secondary                                                      String
  success                                                        String
  warning                                                        String
  CorporateDesign_CDColorsToCorporateDesign_backgroundTextColors CorporateDesign[] @relation("CDColorsToCorporateDesign_backgroundTextColors")
  CorporateDesign_CDColorsToCorporateDesign_backgrounds          CorporateDesign[] @relation("CDColorsToCorporateDesign_backgrounds")
  CorporateDesign_CDColorsToCorporateDesign_colors               CorporateDesign[] @relation("CDColorsToCorporateDesign_colors")
}

model CDFont {
  className       String
  id              String            @id
  name            String
  src             String
  type            String
  weight          String
  CorporateDesign CorporateDesign[] @relation("CDCustomFonts", references: [id])
}

model CDLogos {
  default         String?
  id              String           @id
  monochrome      String?
  small           String?
  CorporateDesign CorporateDesign?
}

model CorporateDesign {
  backgrounds                                                     String?
  backgroundTextColors                                            String?
  borderRadius                                                    String?
  colors                                                          String?
  containerMaxWidths                                              String?
  customScss                                                      String?
  designId                                                        String
  favicon                                                         String?
  gridBreakpoints                                                 String?
  id                                                              String         @id
  label                                                           String
  logos                                                           String?        @unique
  CDColors_CDColorsToCorporateDesign_backgroundTextColors         CDColors?      @relation("CDColorsToCorporateDesign_backgroundTextColors", fields: [backgroundTextColors], references: [id])
  CDColors_CDColorsToCorporateDesign_backgrounds                  CDColors?      @relation("CDColorsToCorporateDesign_backgrounds", fields: [backgrounds], references: [id])
  CDColors_CDColorsToCorporateDesign_colors                       CDColors?      @relation("CDColorsToCorporateDesign_colors", fields: [colors], references: [id])
  CDBreakpoints_CDBreakpointsToCorporateDesign_containerMaxWidths CDBreakpoints? @relation("CDBreakpointsToCorporateDesign_containerMaxWidths", fields: [containerMaxWidths], references: [id])
  CDBreakpoints_CDBreakpointsToCorporateDesign_gridBreakpoints    CDBreakpoints? @relation("CDBreakpointsToCorporateDesign_gridBreakpoints", fields: [gridBreakpoints], references: [id])
  CDLogos                                                         CDLogos?       @relation(fields: [logos], references: [id])
  CDFont                                                          CDFont[]       @relation("CDCustomFonts", references: [id])
  Site                                                            Site[]         @relation(references: [id])

  @@index([backgroundTextColors], name: "backgroundTextColors")
  @@index([backgrounds], name: "backgrounds")
  @@index([colors], name: "colors")
  @@index([containerMaxWidths], name: "containerMaxWidths")
  @@index([gridBreakpoints], name: "gridBreakpoints")
  @@index([logos], name: "logos")
}

model Customer {
  address           String?         @unique
  billingAddress    String?         @unique
  contactPreference String          @default("EMAIL")
  faxNumber         String?
  files             String?
  homePhone         String?
  id                String          @id
  interest          String?
  mobilePhone       String?
  siteLink          String?         @unique
  workPhone         String?
  Address           Address?        @relation(fields: [address], references: [id])
  BillingAddress    BillingAddress? @relation(fields: [billingAddress], references: [id])
  SiteLink          SiteLink?       @relation(fields: [siteLink], references: [id])
  Issue             Issue[]
  OptIn             OptIn[]
  User              User?

  @@index([address], name: "address")
  @@index([billingAddress], name: "billingAddress")
  @@index([siteLink], name: "siteLink")
}

model Issue {
  billingAddress        String?         @unique
  currentOfferDocument  String?
  currentPrice          String?
  currentProcessStateId String
  customer              String?
  deliveryAddress       Json?
  deliveryTrackingUrl   String?
  factoryRequestId      Int?            @unique
  gcOfferId             String?
  id                    String          @id
  installationDate      DateTime?
  objectAddress         Json?
  orderDate             DateTime?
  process               String?
  title                 String
  BillingAddress        BillingAddress? @relation(fields: [billingAddress], references: [id])
  Customer              Customer?       @relation(fields: [customer], references: [id])
  Process               Process?        @relation(fields: [process], references: [id])

  @@index([billingAddress], name: "billingAddress")
  @@index([customer], name: "customer")
  @@index([process], name: "process")
}

model JsonSchema {
  id         String       @id
  jsonSchema Json?
  label      String
  siteId     String
  MailConfig MailConfig[]
}

model Layout {
  id         String    @id
  label      String
  layoutHtml String
  layoutText String
  siteId     String
  Receiver   Receiver?
}

model MailAddress {
  bccReceiver                                          String?
  ccReceiver                                           String?
  email                                                String
  id                                                   String       @id
  name                                                 String
  replyToMailConfig                                    String?
  toReceiver                                           String?
  Receiver_MailAddress_bccReceiverToReceiver           Receiver?    @relation("MailAddress_bccReceiverToReceiver", fields: [bccReceiver], references: [id])
  Receiver_MailAddress_ccReceiverToReceiver            Receiver?    @relation("MailAddress_ccReceiverToReceiver", fields: [ccReceiver], references: [id])
  MailConfig_MailAddress_replyToMailConfigToMailConfig MailConfig?  @relation("MailAddress_replyToMailConfigToMailConfig", fields: [replyToMailConfig], references: [id])
  Receiver_MailAddress_toReceiverToReceiver            Receiver?    @relation("MailAddress_toReceiverToReceiver", fields: [toReceiver], references: [id])
  MailConfig_MailAddressToMailConfig_from              MailConfig[] @relation("MailAddressToMailConfig_from")

  @@index([bccReceiver], name: "bccReceiver")
  @@index([ccReceiver], name: "ccReceiver")
  @@index([replyToMailConfig], name: "replyToMailConfig")
  @@index([toReceiver], name: "toReceiver")
}

model MailAttachment {
  asEmbedded Boolean   @default(false)
  cid        String?
  filename   String
  id         String    @id
  mimeType   String
  name       String
  receiver   String?
  s3Bucket   String
  s3Key      String
  Receiver   Receiver? @relation(fields: [receiver], references: [id])

  @@index([receiver], name: "receiver")
}

model MailConfig {
  apiKey                                                String?
  canOverwriteFrom                                      Boolean       @default(true)
  createdAt                                             DateTime      @default(now())
  from                                                  String?
  id                                                    String        @id
  jsonSchema                                            String?
  label                                                 String
  siteId                                                String
  slug                                                  String
  updatedAt                                             DateTime      @default(now())
  MailAddress_MailAddressToMailConfig_from              MailAddress?  @relation("MailAddressToMailConfig_from", fields: [from], references: [id])
  JsonSchema                                            JsonSchema?   @relation(fields: [jsonSchema], references: [id])
  MailAddress_MailAddress_replyToMailConfigToMailConfig MailAddress[] @relation("MailAddress_replyToMailConfigToMailConfig")
  Receiver                                              Receiver[]

  @@index([from], name: "from")
  @@index([jsonSchema], name: "jsonSchema")
}

model MediaObject {
  bucket             String
  createdAt          DateTime             @default(now())
  id                 String               @id
  key                String
  siteId             String
  type               String
  updatedAt          DateTime             @default(now())
  url                String
  visibility         String               @default("PROTECTED")
  MediaObject_owners MediaObject_owners[]
}

model MediaObject_owners {
  nodeId      String
  position    Int
  value       String
  MediaObject MediaObject @relation(fields: [nodeId], references: [id])

  @@id([nodeId, position])
  @@index([value], name: "value")
}

model OptIn {
  customer      String?
  id            String    @id
  privacyPolicy DateTime
  product       String?
  terms         DateTime
  Customer      Customer? @relation(fields: [customer], references: [id])
  Product       Product?  @relation(fields: [product], references: [id])

  @@index([customer], name: "customer")
  @@index([product], name: "product")
}

model Organisation {
  address       String?  @unique
  createdAt     DateTime @default(now())
  employeeCount Int?
  id            String   @id
  name          String   @unique
  updatedAt     DateTime @default(now())
  Address       Address? @relation(fields: [address], references: [id])
  User          User[]   @relation(references: [id])

  @@index([address], name: "address")
}

model Process {
  id           String         @id
  processId    String         @unique
  Issue        Issue[]
  ProcessState ProcessState[]
}

model ProcessState {
  id             String   @id
  info           String
  process        String?
  processStateId String
  state          String
  step           String
  Process        Process? @relation(fields: [process], references: [id])

  @@index([process], name: "process")
}

model Product {
  canonicalUrl           String?
  createdAt              DateTime                 @default(now())
  favicon                String?
  id                     String                   @id
  label                  String
  logo                   String?
  name                   String
  site                   String?
  updatedAt              DateTime                 @default(now())
  Site                   Site?                    @relation(fields: [site], references: [id])
  AnalyticsConfiguration AnalyticsConfiguration[]
  OptIn                  OptIn[]

  @@index([site], name: "site")
}

model Receiver {
  canAttachFiles                                Boolean          @default(true)
  canOverwriteSubject                           Boolean          @default(true)
  canOverwriteTo                                Boolean          @default(true)
  id                                            String           @id
  label                                         String
  layout                                        String?          @unique
  mailConfig                                    String?
  siteId                                        String
  subject                                       String
  template                                      String?          @unique
  Layout                                        Layout?          @relation(fields: [layout], references: [id])
  MailConfig                                    MailConfig?      @relation(fields: [mailConfig], references: [id])
  Template                                      Template?        @relation(fields: [template], references: [id])
  MailAddress_MailAddress_bccReceiverToReceiver MailAddress[]    @relation("MailAddress_bccReceiverToReceiver")
  MailAddress_MailAddress_ccReceiverToReceiver  MailAddress[]    @relation("MailAddress_ccReceiverToReceiver")
  MailAddress_MailAddress_toReceiverToReceiver  MailAddress[]    @relation("MailAddress_toReceiverToReceiver")
  MailAttachment                                MailAttachment[]

  @@index([layout], name: "layout")
  @@index([mailConfig], name: "mailConfig")
  @@index([template], name: "template")
}

model Role {
  customSettings Json?
  id             String  @id
  label          String?
  roleId         String  @unique
  User           User[]  @relation(references: [id])
}

model Site {
  authConfiguration String?            @unique
  createdAt         DateTime           @default(now())
  customSettings    Json?
  id                String             @id
  name              String
  owner             String?
  siteId            String             @unique
  updatedAt         DateTime           @default(now())
  AuthConfiguration AuthConfiguration? @relation(fields: [authConfiguration], references: [id])
  Product           Product[]
  User              User[]
  CorporateDesign   CorporateDesign[]  @relation(references: [id])

  @@index([authConfiguration], name: "authConfiguration")
}

model SiteLink {
  customerNumber String?
  factoryUserId  String?
  id             String    @id
  Customer       Customer?
}

model Template {
  id           String    @id
  label        String
  siteId       String
  templateHtml String
  templateText String
  Receiver     Receiver?
}

model User {
  createdAt          DateTime       @default(now())
  customer           String?        @unique
  email              String
  emailVerified      Boolean        @default(false)
  firstName          String?
  id                 String         @id
  identityId         String?        @unique
  lastName           String?
  passwordResetToken String?        @unique
  profile            String?        @unique
  salutation         String?
  settings           String?        @unique
  site               String?
  sub                String?
  title              String?
  updatedAt          DateTime       @default(now())
  Customer           Customer?      @relation(fields: [customer], references: [id])
  UserProfile        UserProfile?   @relation(fields: [profile], references: [id])
  UserSettings       UserSettings?  @relation(fields: [settings], references: [id])
  Site               Site?          @relation(fields: [site], references: [id])
  Organisation       Organisation[] @relation(references: [id])
  Role               Role[]         @relation(references: [id])

  @@index([customer], name: "customer")
  @@index([profile], name: "profile")
  @@index([settings], name: "settings")
  @@index([site], name: "site")
}

model UserProfile {
  address       String?   @unique
  birthdate     DateTime?
  id            String    @id
  picture       String
  preferredName String?
  Address       Address?  @relation(fields: [address], references: [id])
  User          User?

  @@index([address], name: "address")
}

model UserSettings {
  customSettings  Json?
  id              String  @id
  newsletterSub   Boolean @default(false)
  trackingConsent Boolean @default(false)
  User            User?
}

Leads to error:

C:\Users\Jan\Documents\throwaway\upgradeTest>prisma introspect
Environment variables loaded from ./prisma/.env

Introspecting based on datasource defined in prisma\schema.prisma …
Error: Error in datamodel: ErrorCollection { errors: [ValidationError { message: "This line is not a valid field or directive definition.", span: Span { start: 588, end: 600 } }] }
pantharshit00 commented 4 years ago

I am assuming this issue is regarding improvement of the error message and I am marking it as a improvement.

janpio commented 4 years ago

No, this was about the questions why Introspection should fail based on existing content in your schema that would be overwritten. Why do I have to fix that first to overwrite it anyway?

(The error message deserves an additional issue as well though - probably happens on prisma generate with that schema as well)

janpio commented 4 years ago

@do4gr says this should now work fine. Please reconfirm @pantharshit00

pantharshit00 commented 4 years ago

I am still able to reproduce this in 2.7.0

image

do4gr commented 4 years ago

This is intended behavior. There is the --force flag to ignore the schema. If that is not provided we want to return the errors we find. Please confirm again @pantharshit00 and re-open in case that does not work.

pantharshit00 commented 4 years ago

@do4gr Can we improve the error message here?

I mean even it was tough for me guess what is going on here so I wouldn't expect a user to get around.

janpio commented 4 years ago

As far as I am aware the error message should indeed point you towards --force instead of just dumping a raw error message like the one you showed above @pantharshit00.

pantharshit00 commented 3 years ago

This is no longer reproducible in latest version 2.21.2

pantharshit00 commented 3 years ago

image

This is how it looks like now