@theoxfordhealthcompany/zenstack-nestjs-graphql-plugin v1.1.4
zenstack-nestjs-graphql-plugin
Zenstack plugin to create graphql models, enums, repositories, and services for use with NestJS and GraphQL.
Generator Options
Option | Type | Default | Description |
---|---|---|---|
outputDir | string | ../generated | The output directory for the generated files. This is relative to the schema.zmodel file |
interface_[INTERFACE_NAME] | string | Define an interface that a model can implement. The value is the path relative to model file |
Attributes
The are several attributes that can be used in the schema to control the generation of the files.
Model Attributes
Attribute | Description | Extra |
---|---|---|
@@gqlgen.archivable | Change the delete behaviour of the model to archive instead of delete | The field isArchived (boolean) must be present on the model |
@@gqlgen.loggable | Log all the changes to the model in the change log | See (Change Log)#change-log for more information |
@@gqlgen.interface | Create the model with GQLs @InterfaceType instead of @ObjectType , useful for inheritance | |
@@gqlgen.no_delete | Removes the delete mutation from the repository | |
@@gqlgen.no_repository | Skip generating a repository for the model | |
@@gqlgen.implements(string[]) | Define interfaces that the model implements, the value is a list of interface names | Define the avaiable interfaces in the generator options |
@@gqlgen.resolve_type(name: string, filePath: string) | Define the resolveType function for polymorphic models | |
@@gqlgen.extends(name: string, filePath: string) | Define a model that this model extends from | Also adds the model to the GQL implements array |
Field Attributes
Attribute | Description | Extra |
---|---|---|
@@gqlgen.skip | Omits the field from the generated model | |
@@gqlgen.nullable | Forces the field to be nullable in the generated model | |
@@gqlgen.non-nullable | Forces the field to not be nullable in the generated model | |
@@gqlgen.log-always-include | Always fetch this field when logging changes |
Change Log
You will need a User
model.
To use the change log function, you must add the following models to your schema:
model LoggableEntity {
id Int @id @default(autoincrement())
changes ChangeLog[]
YOUR_MODELS MODEL_TYPE[] @gqlgen.skip()
@@gqlgen.no_repository()
}
enum ChangeOperation {
CREATE
UPDATE
ARCHIVE
RESTORE
}
// A change a user makes to a model
model ChangeLog {
id Int @id @default(autoincrement())
loggableEntityId Int @gqlgen.skip()
loggableEntity LoggableEntity @relation(fields: [loggableEntityId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id])
userId Int
operation ChangeOperation
date DateTime @default(now())
reason String?
diff Json?
@@gqlgen.no_delete()
}
Each model you want to log changes for should have the @@gqlgen.loggable
attribute.
It should also have a LoggableEntity
field, which is a relation to the LoggableEntity
model.
Example:
// A supplier of a service or product
model Supplier {
id Int @id @default(autoincrement())
type SupplierType
name String
country String @db.Char(2)
notes String?
address String?
website String?
loggableEntity LoggableEntity @relation(fields: [loggableEntityId], references: [id]) @gqlgen.skip()
loggableEntityId Int @unique @gqlgen.skip()
@@gqlgen.archivable()
@@gqlgen.interface()
@@gqlgen.loggable()
}
Models
The generated models are designed to be used with NestJS and GraphQL. When a field is a relation (e.g. A user's posts), the typescript type is set to optional, even if the field is required in the schema. This is because when you are working with an instance of the model, there is no guarantee that the relation will be populated.
If a model has the @@gqlgen.interface
attribute, the model will be generated with @InterfaceType()
instead of @ObjectType()
.
If a model has the @@gqlgen.loggable
attribute, the model will implement the Loggable
interface.
If a model has the @@gqlgen.loggable
and @@gqlgen.archivable
attributes, the model will implement the LoggableArchive
interface.
Enums
The generated enums are designed to be used with NestJS and GraphQL.
Each enum is registered with registerEnumType()
from @nestjs/graphql
.
Repositories
The generated repositories are designed to be used with NestJS and Prisma.
Each repository is automatically tagged with @Injectable()
from @nestjs/common
.
Each method can take a PrismaTransaction
instance as an optional parameter, which will be used instead of the default transaction.
When a mutation is called (create
, update
, delete
, archive
, restore
) a method will be called in BaseRepository
(onCreate
, etc...), this can be used to log changes, or perform other actions.
Each repository has the following methods:
| Method | Return Type | Description | Available if |
| -- | -- | -- | -- |
| create
| Promise\<T\>
| Creates a new instance of the model | Always |
| createMany
| Promise<{ count: number }>
| Creates many instances of the model | Not an SQLite database |
| createManyAndReturn
| Promise<T[]>
| Creates many instances of the model and returns them | Always |
| exists
| Promise\<boolean\>
| Checks if an instance of the model exists | Always |
| count
| Promise<number>
| Gets the number of instances of the model, with optional search parameters | Always |
| update
| Promise\<T\>
| Updates an instance of the model | Always |
| updateMany
| Promise\<{ count: number }>
| Updates many instances of the model | Always |
| delete
| Promise\<T\>
| Deletes an instance of the model | @no-delete is not present |
| deleteMany
| Promise\<{ count: number }>
| Deletes many instances of the model | @no-delete is not present |
| archive
| Promise\<T\>
| Archives an instance of the model | @archivable is present |
| archiveMany
| Promise\<{ count: number }>
| Archives many instances of the model | @archivable is present |
| restore
| Promise\<T\>
| Restores an instance of the model | @archivable is present |
| restoreMany
| Promise\<{ count: number }>
| Restores many instances of the model | @archivable is present |
A global repository module is also created which provides and registers all of the repositories.