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.85k stars 1.56k forks source link

[Introspection] Validation maybe does not return all errors all the time #1097

Open janpio opened 4 years ago

janpio commented 4 years ago

Ok, complicated issue incoming:

I have 2 database servers (A and B [note to myself: A = remote, B = local) with the same schema, but because of "I do not really know why" (versions blabla) the schemas are slightly different which leads to different models:

Server A:

Introspected Schema:

model cites {
  cited_paper_id  String? @default("NULL")
  citing_paper_id String? @default("NULL")

  @@index([cited_paper_id], name: "cited_paper_id")
  @@index([citing_paper_id], name: "citing_paper_id")
}

model content {
  class_label   String? @default("NULL")
  paper_id      paper?  @default("NULL")
  word_cited_id String? @default("NULL")
}

model paper {
  class_label String?   @default("NULL")
  paper_id    String    @id
  contents    content[] @relation(onDelete: CASCADE)
}

Server B:

Introspected Schema:

model cites {
  cited_paper_id  String?
  citing_paper_id String?

  @@index([cited_paper_id], name: "cited_paper_id")
  @@index([citing_paper_id], name: "citing_paper_id")
}

model content {
  class_label   String?
  paper_id      paper?
  word_cited_id String?
}

model paper {
  class_label String?
  paper_id    String    @id
  contents    content[] @relation(onDelete: CASCADE)
}

And a diff:

4,5c4,5
<   cited_paper_id  String? @default("NULL")
<   citing_paper_id String? @default("NULL")
---
>   cited_paper_id  String?
>   citing_paper_id String?
12,14c12,14
<   class_label   String? @default("NULL")
<   paper_id      paper?  @default("NULL")
<   word_cited_id String? @default("NULL")
---
>   class_label   String?
>   paper_id      paper?
>   word_cited_id String?
18c18
<   class_label String?   @default("NULL")
---
>   class_label String?

So the @default("NULL") is missing on Server B.

Both of these databases causes Introspection to trip up on the validation step:

Server A:


Introspection failed: Introspected schema can't be parsed.
Error: Schema parsing
error: Error parsing attribute "@default": Cannot set a default value on a relation field..
  -->  schema.prisma:11
   | 
10 |   class_label   String? @default("NULL")
11 |   paper_id      paper?  @default("NULL")
12 |   word_cited_id String? @default("NULL")
   | 
    at Object.<anonymous> (C:\ProgramData\nvm\v10.16.3\node_modules\prisma2\build\index.js:73435:23)
    at Generator.throw (<anonymous>)
    at rejected (C:\ProgramData\nvm\v10.16.3\node_modules\prisma2\build\index.js:73330:65)
    at process._tickCallback (internal/process/next_tick.js:68:7)

Server B:


Introspection failed: Introspected schema can't be parsed.
Error: Schema parsing
error: Error validating model "cites": Each model must have exactly one id criteria. Either mark a single field with `@id` or add a multi field id criterion with `@@id([])` to the model..
  -->  schema.prisma:1
   | 
   | 
 1 | model cites {
 2 |   cited_paper_id  String?
   | 
error: Error validating model "content": Each model must have exactly one id criteria. Either mark a single field with `@id` or add a multi field id criterion with `@@id([])` to the model..
  -->  schema.prisma:9
   | 
 8 | 
 9 | model content {
10 |   class_label   String?
   | 
    at Object.<anonymous> (C:\ProgramData\nvm\v10.16.3\node_modules\prisma2\build\index.js:73435:23)
    at Generator.throw (<anonymous>)
    at rejected (C:\ProgramData\nvm\v10.16.3\node_modules\prisma2\build\index.js:73330:65)
    at process._tickCallback (internal/process/next_tick.js:68:7)

And that now is curious: A has an additional "attribute" (correct name?) on the fields, which it complains about. But it does not complain about the other two things B complains about that are certainly also part of the model of A - so these are somehow swallowed by the presence of the other error.

Is this intended and wanted?

pantharshit00 commented 4 years ago

Can you please share the actual SQL schemas of the database? Also, pasting database versions of the two database server can also be helpful.

janpio commented 4 years ago

This has nothing to do with the database servers - the errors are generated after the models/schemas are successfully returned by the IE.

You can reproduce this 2 ways:

  1. Just paste the schemas posted above in a a.prisma and b.prisma and look at them in VS Code - it will validate and show the same errors.

  2. Create a new folder with prisma/schema.prisma and post the model you want to validate, then run prisma2 generate:

C:\Users\Jan\Documents\throwaway\1097
λ prisma2 generate
Error: Schema parsing
error: Error parsing attribute "@default": Cannot set a default value on a relation field..
  -->  schema.prisma:11
   |
10 |   class_label   String? @default("NULL")
11 |   paper_id      paper?  @default("NULL")
12 |   word_cited_id String? @default("NULL")
   |
C:\Users\Jan\Documents\throwaway\1097
λ prisma2 generate
Error: Schema parsing
error: Error validating model "cites": Each model must have exactly one id criteria. Either mark a single field with `@id` or add a multi field id criterion with `@@id([])` to the model..
  -->  schema.prisma:1
   |
   |
 1 | model cites {
 2 |   cited_paper_id  String?
   |
error: Error validating model "content": Each model must have exactly one id criteria. Either mark a single field with `@id` or add a multi field id criterion with `@@id([])` to the model..
  -->  schema.prisma:9
   |
 8 |
 9 | model content {
10 |   class_label   String?
   |

I repeat the problem this points to:

A has an additional "attribute" (correct name?) on the fields, which it complains about. But it does not complain about the other two things B complains about that are certainly also part of the model of A - so these are somehow swallowed by the presence of the other error.

janpio commented 4 years ago

Another example:

Server A:

Introspected Schema:

model activities {
  activity_comment        String?           @default("NULL")
  activity_id             Int               @id
  assay_id                assays?
  doc_id                  docs?
  molregno                compounds?
  published_activity_type String?           @default("NULL")
  published_units         String?           @default("NULL")
  published_value         Float?
  record_id               compound_records?
  relation                String?           @default("NULL")
  standard_flag           Int?
  standard_type           String?           @default("NULL")
  standard_units          String?           @default("NULL")
  standard_value          Float?
}

model assay2target {
  assay_id          assays
  assay_organism    String?            @default("NULL")
  assay_strain      String?            @default("NULL")
  assay_tax_id      Int?
  complex           Int?
  confidence        confidence_lookup?
  multi             Int?
  relationship_type String?            @default("NULL")
  tid               target_dictionary

  @@id([assay_id, tid])
}

model assays {
  assay_id      Int            @id
  assay_type    assay_type?    @default("NULL")
  description   String?        @default("NULL")
  doc_id        docs?
  activitieses  activities[]   @relation(onDelete: CASCADE)
  assay2targets assay2target[] @relation(onDelete: CASCADE)
}

model assay_type {
  assay_desc String?  @default("NULL")
  assay_type String   @id
  assayses   assays[] @relation(references: [assay_type], onDelete: CASCADE)
}

model compounds {
  canonical_smiles    String?             @default("NULL")
  inchi               String?             @default("NULL")
  inchi_key           String?             @default("NULL")
  molfile             String?             @default("NULL")
  molformula          String?             @default("NULL")
  molregno            Int                 @id
  molweight           Float?
  activitieses        activities[]        @relation(onDelete: CASCADE)
  compound_recordses  compound_records[]  @relation(onDelete: CASCADE)
  compound_synonymses compound_synonyms[] @relation(onDelete: CASCADE)
}

model compound_properties {
  alogp              Float?
  hba                Int?
  hbd                Int?
  med_chem_friendly  String? @default("NULL")
  molregno           Int     @id
  mol_id             Int?
  mw_freebase        Float?
  num_ro5_violations Int?
  psa                Float?
  ro3_pass           String? @default("NULL")
  rtb                Int?
}

model compound_records {
  compound_key  String?      @default("NULL")
  compound_name String?      @default("NULL")
  doc_id        docs?
  molregno      compounds?
  record_id     Int          @id
  activitieses  activities[] @relation(onDelete: CASCADE)
}

model compound_synonyms {
  molregno compounds
  synonyms String

  @@id([molregno, synonyms])
}

model confidence_lookup {
  confidence         Int            @id
  confidence_summary String?        @default("NULL")
  description        String?        @default("NULL")
  assay2targets      assay2target[] @relation(onDelete: CASCADE)
}

model docs {
  doc_id             Int                @id
  first_page         String?            @default("NULL")
  issue              String?            @default("NULL")
  journal            String?            @default("NULL")
  last_page          String?            @default("NULL")
  pubmed_id          Int?
  volume             String?            @default("NULL")
  year               String?            @default("NULL")
  activitieses       activities[]       @relation(onDelete: CASCADE)
  assayses           assays[]           @relation(onDelete: CASCADE)
  compound_recordses compound_records[] @relation(onDelete: CASCADE)
}

model relationship_type {
  relationship_desc String? @default("NULL")
  relationship_type String  @id
}

model target_class {
  l1                    String?            @default("NULL")
  l2                    String?            @default("NULL")
  l3                    String?            @default("NULL")
  l4                    String?            @default("NULL")
  l5                    String?            @default("NULL")
  l6                    String?            @default("NULL")
  l7                    String?            @default("NULL")
  l8                    String?            @default("NULL")
  target_classification String?            @default("NULL")
  tc_id                 Int                @id
  tid                   target_dictionary?
}

model target_dictionary {
  cell_line         String?        @default("NULL")
  db_source         String?        @default("NULL")
  db_version        String?        @default("NULL")
  description       String?        @default("NULL")
  ec_number         String?        @default("NULL")
  gene_names        String?        @default("NULL")
  in_drugstore      Boolean?
  in_starlite       Boolean?
  keywords          String?        @default("NULL")
  organism          String?        @default("NULL")
  pref_name         String?        @default("NULL")
  protein_accession String?        @default("NULL")
  protein_md5sum    String?        @default("NULL")
  protein_sequence  String?        @default("NULL")
  strain            String?        @default("NULL")
  synonyms          String?        @default("NULL")
  target_type       target_type?   @default("NULL")
  tax_id            Int?
  tid               Int            @id
  tissue            String?        @default("NULL")
  assay2targets     assay2target[] @relation(onDelete: CASCADE)
  target_classes    target_class[] @relation(onDelete: CASCADE)
}

model target_protein {
  assay_organism    String? @default("NULL")
  assay_type        String? @default("NULL")
  canonical_smiles  String? @default("NULL")
  organism          String? @default("NULL")
  protein_accession String? @default("NULL")
  relation          String? @default("NULL")
  relationship_type String? @default("NULL")
  standard_type     String? @default("NULL")
  standard_units    String? @default("NULL")
  standard_value    Float?
  target_type       String? @default("NULL")
}

model target_type {
  target_desc         String?             @default("NULL")
  target_type         String              @id
  target_dictionaries target_dictionary[] @relation(onDelete: CASCADE)
}

model version {
  comments      String?   @default("NULL")
  creation_date DateTime?
  name          String    @id
}

Server B:

Introspected Schema:

model activities {
  activity_comment        String?
  activity_id             Int               @id
  assay_id                assays?
  doc_id                  docs?
  molregno                compounds?
  published_activity_type String?
  published_units         String?
  published_value         Float?
  record_id               compound_records?
  relation                String?
  standard_flag           Int?
  standard_type           String?
  standard_units          String?
  standard_value          Float?
}

model assay2target {
  assay_id          assays
  assay_organism    String?
  assay_strain      String?
  assay_tax_id      Int?
  complex           Int?
  confidence        confidence_lookup?
  multi             Int?
  relationship_type String?
  tid               target_dictionary

  @@id([assay_id, tid])
}

model assays {
  assay_id      Int            @id
  assay_type    assay_type?
  description   String?
  doc_id        docs?
  activitieses  activities[]   @relation(onDelete: CASCADE)
  assay2targets assay2target[] @relation(onDelete: CASCADE)
}

model assay_type {
  assay_desc String?
  assay_type String   @id
  assayses   assays[] @relation(references: [assay_type], onDelete: CASCADE)
}

model compounds {
  canonical_smiles    String?
  inchi               String?
  inchi_key           String?
  molfile             String?
  molformula          String?
  molregno            Int                 @id
  molweight           Float?
  activitieses        activities[]        @relation(onDelete: CASCADE)
  compound_recordses  compound_records[]  @relation(onDelete: CASCADE)
  compound_synonymses compound_synonyms[] @relation(onDelete: CASCADE)
}

model compound_properties {
  alogp              Float?
  hba                Int?
  hbd                Int?
  med_chem_friendly  String?
  molregno           Int     @id
  mol_id             Int?
  mw_freebase        Float?
  num_ro5_violations Int?
  psa                Float?
  ro3_pass           String?
  rtb                Int?
}

model compound_records {
  compound_key  String?
  compound_name String?
  doc_id        docs?
  molregno      compounds?
  record_id     Int          @id
  activitieses  activities[] @relation(onDelete: CASCADE)
}

model compound_synonyms {
  molregno compounds
  synonyms String

  @@id([molregno, synonyms])
}

model confidence_lookup {
  confidence         Int            @id
  confidence_summary String?
  description        String?
  assay2targets      assay2target[] @relation(onDelete: CASCADE)
}

model docs {
  doc_id             Int                @id
  first_page         String?
  issue              String?
  journal            String?
  last_page          String?
  pubmed_id          Int?
  volume             String?
  year               String?
  activitieses       activities[]       @relation(onDelete: CASCADE)
  assayses           assays[]           @relation(onDelete: CASCADE)
  compound_recordses compound_records[] @relation(onDelete: CASCADE)
}

model relationship_type {
  relationship_desc String?
  relationship_type String  @id
}

model target_class {
  l1                    String?
  l2                    String?
  l3                    String?
  l4                    String?
  l5                    String?
  l6                    String?
  l7                    String?
  l8                    String?
  target_classification String?
  tc_id                 Int                @id
  tid                   target_dictionary?
}

model target_dictionary {
  cell_line         String?
  db_source         String?
  db_version        String?
  description       String?
  ec_number         String?
  gene_names        String?
  in_drugstore      Boolean?
  in_starlite       Boolean?
  keywords          String?
  organism          String?
  pref_name         String?
  protein_accession String?
  protein_md5sum    String?
  protein_sequence  String?
  strain            String?
  synonyms          String?
  target_type       target_type?
  tax_id            Int?
  tid               Int            @id
  tissue            String?
  assay2targets     assay2target[] @relation(onDelete: CASCADE)
  target_classes    target_class[] @relation(onDelete: CASCADE)
}

model target_protein {
  assay_organism    String?
  assay_type        String?
  canonical_smiles  String?
  organism          String?
  protein_accession String?
  relation          String?
  relationship_type String?
  standard_type     String?
  standard_units    String?
  standard_value    Float?
  target_type       String?
}

model target_type {
  target_desc         String?
  target_type         String              @id
  target_dictionaries target_dictionary[] @relation(onDelete: CASCADE)
}

model version {
  comments      String?
  creation_date DateTime?
  name          String    @id
}

Leads to errors from Server A:


Introspection failed: Introspected schema can't be parsed.
Error: Schema parsing
error: Error parsing attribute "@default": Cannot set a default value on a relation field..
  -->  schema.prisma:34
   | 
33 |   assay_id      Int            @id
34 |   assay_type    assay_type?    @default("NULL")
35 |   description   String?        @default("NULL")
   | 
error: Error parsing attribute "@default": Cannot set a default value on a relation field..
  -->  schema.prisma:147
   | 
146 |   synonyms          String?        @default("NULL")
147 |   target_type       target_type?   @default("NULL")
148 |   tax_id            Int?
   | 
    at Object.<anonymous> (C:\ProgramData\nvm\v10.16.3\node_modules\prisma2\build\index.js:73435:23)
    at Generator.throw (<anonymous>)
    at rejected (C:\ProgramData\nvm\v10.16.3\node_modules\prisma2\build\index.js:73330:65)
    at process._tickCallback (internal/process/next_tick.js:68:7)

And errors from server B:


Introspection failed: Introspected schema can't be parsed.
Error: Schema parsing
error: Error validating model "target_protein": Each model must have exactly one id criteria. Either mark a single field with `@id` or add a multi field id criterion with `@@id([])` to the model..
  -->  schema.prisma:155
   | 
154 | 
155 | model target_protein {
156 |   assay_organism    String?
   | 
    at Object.<anonymous> (/Users/divyendusingh/.nvm/versions/node/v10.16.3/lib/node_modules/prisma2/build/index.js:73435:23)
    at Generator.throw (<anonymous>)
    at rejected (/Users/divyendusingh/.nvm/versions/node/v10.16.3/lib/node_modules/prisma2/build/index.js:73330:65)
    at process._tickCallback (internal/process/next_tick.js:68:7)
Jolg42 commented 3 years ago

I would assume this works better now, we could try again to confirm.

pantharshit00 commented 3 years ago

It doesn't seem to be fixed in 2.25 to me. We should have another look here.