Prisma1: [RFC] Datamodel v1.1 - Field Behaviour

Created on 1 Nov 2018  ·  13Comments  ·  Source: prisma/prisma1

This part of the spec describes directives that are used to attach special behaviour to fields in the data model. See the issue #3408 to learn about the other parts of the spec.

The id directive

  • valid locations: on scalar non list fields of type ID, Int and UUID
  • behaviour: The field becomes the primary identifier of the type. It implies that this field is unique.
  • optional: No

    • This implies that it must be also explicitly specified for the id field.

  • arguments:

    • strategy: Enum



      • NONE: The id does not get auto generated. The id field is then required in the create input type.


      • AUTO: Based upon the type of the field an id will be generated automatically.





        • Int → An Identity column is used to in the underlying database. For each database a matching implementation is selected, e.g. a column of type SERIAL for Postgres.



        • UUID, ID → Prisma will generate a random value for the type when a node is created.





      • SEQUENCE: A sequence in the underlying database will be created to create ids for nodes of this type. When this strategy is used the directive sequence has to be specified as well.


      • optional: yes. Defaults to AUTO.



  • validations:

    • This directive must be specified at most once per type.

    • This directive must not be specified on embedded types.



      • The combination of strategy and id type must be supported, e.g. Mongo does not support the AUTO strategy for id fields of type Int.



Examples

An id field for which the AUTO strategy is used. Since this is the default it could be also omitted.

type Blog {
  id: UUID! @id(strategy: AUTO)
  name: String!
}

An id field for which the NONE strategy is used. The id does not get auto generated. It has to be provided in create mutations.

type Blog {
  id: ID! @id(strategy: NONE)
  name: String!
}

An id field for which the SEQUENCE strategy is used.

type Blog {
  id: Int! @id(strategy: SEQUENCE) @sequence(name: "MY_SEQUENCE" initialValue:1 allocationSize:100)
  name: String!
}

The sequence directive

  • valid locations: on fields that are marked with the id directive
  • behaviour: Configures the sequence to be used for ids for nodes of this type.
  • optional: No if the field uses the strategy SEQUENCE.
  • arguments:

    • name: String!



      • The name of the database sequence.


      • Optional: no.



    • initialValue: Int!



      • The initial value for the database sequence.


      • Optional: no.



    • allocationSize: Int!



      • The allocation size of the database sequence.


      • Optional: no.



  • validations:

    • This directive must be specified at most once per type.

    • This directive must not be specified on embedded types.

Examples

An id field for which the SEQUENCE strategy is used.

type Blog {
  id: Int! @id(strategy: SEQUENCE) @sequence(name: "MY_SEQUENCE" initialValue:1 allocationSize:100)
  name: String!
}

The default directive

  • valid locations: scalar non list fields

    • future: this should be possible for scalar list fields as well

  • optional: yes. Defaults to no default value.
  • arguments:

    • value:



      • Specifies the default value.


      • optional: no



Examples

A field omitting the directive and therefore having no default value. This means that viewCount has to be specified in a create mutation.

type Blog {
  id: ID! @id
  viewCount: Int!
}

A field specifying a default for the viewCount field. This means that no value has to be specified for this field in a create mutation.

type Blog {
  id: ID! @id
  viewCount: Int! @default(value: 0)
}

The createdAt directive

  • valid locations: on scalar non list fields of type DateTime!
  • behaviour: The field becomes readonly. Prisma will set the current time when a node for that type gets created if the query did not provide the argument yet.
  • optional:

    • yes if the user does not want to use this feature.

    • no if the user wants to use this feature (no automagic).

  • arguments: none

Examples

A field called createdAt and the right type that does not specify the directive. Therefore this field will be treated as any other field. It will not be handled as createdAt field.

type Blog {
  id: ID! @id
  createdAt: DateTime!
}

A field called createdAt and the right type that does specify the directive. Therefore this field be treated as a createdAt field.

type Blog {
  id: ID! @id
  createdAt: DateTime! @createdAt
}

A field called myCreatedAt and the right type that does specify the directive. Therefore this field be treated as a createdAt field.

type Blog {
  id: ID! @id
  myCreatedAt: DateTime! @createdAt
}

The updatedAt directive

  • valid locations: on scalar non list fields of type DateTime!
  • behaviour: The field becomes readonly. Prisma will set the current time when a node for that type gets updated if the query did not provide the argument yet.
  • optional:

    • yes if the user does not want to use this feature.

    • no if the user wants to use this feature (no automagic).

  • arguments: none

Examples

A field called updatedAt and the right type that does not specify the directive. Therefore this field will be treated as any other field. It will not be treated as an updatedAt field.

type Blog {
  id: ID! @id
  updatedAt: DateTime!
}

A field called updatedAt and the right type that does specify the directive. Therefore this field be treated as a updatedAt field.

type Blog {
  id: ID! @id
  updatedAt: DateTime! @updatedAt
}

A field called myCreatedAt and the right type that does specify the directive. Therefore this field be treated as a updatedAt field.

type Blog {
  id: ID! @id
  myUpdatedAt: DateTime! @updatedAt
}

The scalarList directive

  • valid locations: scalar list fields
  • behaviour: Configures the implementation strategy for a scalar list.
  • optional: yes
  • arguments:

    • strategy: Enum



      • Specifies the strategy to be used.


      • valid values:





        • EMBEDDED: The values are stored within the parent type.



        • RELATION: Values in that list are realised through a relation under the hood. ⚠️





      • optional: yes. Defaults to EMBEDDED



  • validation:

    • The current connector must support the chosen strategy.

Examples

Omitting the directive to use default strategy.

type Blog {
  id: ID! @id
  tags: [String]
} 

Configuring a scalar list field to use the RELATION strategy.

type Blog {
  id: ID! @id
  tags: [String] @scalarList(strategy:RELATION)
}
aremigrations aredatamodel rf2-accepted arenext

Most helpful comment

Will adding @scalarList(strategy:RELATION) enable list filtering using something like field_every, field_some and field_none? (as discussed here)

All 13 comments

Why id can't be used in embedded types ?

It can be useful to store a id in a embedded types as a reference when searching or updating for a specific element, it's a common practice in mongo

@lfades : You can still add a field like id: ID! to your embedded type if you want to. You just cannot mark it with @id. Our reasoning was that embedded types do not have an identity themselves and therefore should not allow this.

That's okay, but in the case of mongoose for example it will add an ObjectID to every embedded element and in most cases when you have updates over individual elements it can be very useful, having that said, adding your own id it's not a bad idea either.

@mavilein I assume @sequence maps to a sequence in postgres. What happens for other DBs, like mysql, where sequences do not exist?

Also, can sequences be shared between different fields?

@ejoebstl : In MySQL we simply translate it to a AUTO INCREMENT column. Sharing is possible i guess 🤷‍♂️

Regarding the default directive, what is the type of value argument. The example shows Int, but can it be used with String or others?

@sntran : Yes. The value has to have the type of the field.

Will adding @scalarList(strategy:RELATION) enable list filtering using something like field_every, field_some and field_none? (as discussed here)

Hey. I have a type:

type Mission{
   id: Int! @id(strategy: SEQUENCE) @sequence(name: "MISSION_SEQUENCE" initialValue:1 allocationSize:10000)
   description: String!
}

When creating an entry, Postgres gives the error:

ERROR: null value in column "id" violates not-null constraintn

Does it even work now or am I doing something wrong?

@id(strategy: SEQUENCE) @sequence(name: "MISSION_SEQUENCE" initialValue:1 allocationSize:10000)

prisma:1.34.0

@wmwart why do you pass id: Int! as a default scalar instead of ID!? then you can pass id directive

@irhamputra Because it says that I can. Scroll up the page. https://github.com/prisma/prisma/issues/3403#issue-376374918 The id directive and The sequence directive.

Like @wmwart , I'm attempting the same thing on Postgres and also experience the same error:

prisma_1    | org.postgresql.util.PSQLException: ERROR: null value in column "id" violates not-null constraint
type Instructor {
  id: Int! @id(strategy: SEQUENCE) @sequence(name: "INSTRUCTOR_SEQUENCE", initialValue: 1, allocationSize:10000)
}

Prisma 1.34.0 and also tested on 1.34.8

@wmwart So when I first created my model, when I originally deployed, it was of type ID! and not Int!. When I switched to Int!, it started to throw the error you were seeing (even though deploy had said it was updating the field id).

My guess is the updating of the ID type to something different isn't as expected (it deploys successfully because I never had any existing nodes). And so when it switched and I try to add a node, the error appears.

My solution was to delete the model altogether, and re-add with the ID type you want.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tbrannam picture tbrannam  ·  3Comments

sorenbs picture sorenbs  ·  3Comments

ragnorc picture ragnorc  ·  3Comments

marktani picture marktani  ·  3Comments

notrab picture notrab  ·  3Comments