Custom Generators
Want to do anything with your prisma schema?
You can easily write your own prisma generator in python!
How does it work?
A Prisma generator consists of two steps:
- generator metadata
- asset generation
Metadata
The metadata step is used by Prisma to collect information about your generator, this includes information like:
- The name of the generator
- The default output location
This data is represented in Prisma Client Python with the Manifest
model:
from prisma.generator import BaseGenerator, Manifest
class MyGenerator(BaseGenerator):
def get_manifest(self) -> Manifest:
return Manifest(
name='Custom Prisma Generator'
default_output='out.txt',
)
Generation
Prisma sends generators the Prisma Schema DMMF during the generate step, this is your Prisma Schema in AST form.
The DMMF is represented in Prisma Client python with the Data
model:
from pathlib import Path
from prisma.generator import BaseGenerator, DefaultData
class MyGenerator(BaseGenerator):
# some code has been ommited from this example for brevity
# the full boilerplate example can be found below
def generate(self, data: DaDefaultDatata) -> None:
content = [
model.name
for model in data.dmmf.datamodel.models
]
file = Path(data.generator.output.value)
file.write_text('\n'.join(content))
Warning
Changes to the structure of the DMMF are not considered breaking changes
Boilerplate
The minimum code required to get started writing your own Prisma generator:
from prisma.generator import BaseGenerator, Manifest, DefaultData
class MyGenerator(BaseGenerator):
def get_manifest(self) -> Manifest:
return Manifest(
name='My Generator',
default_output='output.txt',
)
def generate(self, data: DefaultData) -> None:
pass
if __name__ == '__main__':
MyGenerator.invoke()
Custom Configuration Options
You can also add custom config options directly in the Prisma Schema file! For example, consider the following schema:
generator my_generator {
provder = "python my_generator.py"
my_option = 1
}
To support defining custom options you need to define the generator slightly differently:
from pydantic import BaseModel
from prisma.generator import Manifest, GenericData, GenericGenerator
# custom options must be defined using a pydantic BaseModel
class Config(BaseModel):
my_option: int
# we don't technically need to define our own Data class
# but it makes typing easier
class Data(GenericData[Config]):
pass
# the GenericGenerator[Data] part is what tells Prisma Client Python to use our
# custom Data class with our custom Config class
class MyGenerator(GenericGenerator[Data]):
def get_manifest(self) -> Manifest:
return Manifest(
name='My Custom Generator Options',
default_output='schema.md',
)
def generate(self, data: Data) -> None:
# generate some assets here
pass
if __name__ == '__main__':
MyGenerator.invoke()
Example
In this example we're going to create a simple generator that creates a markdown file like this:
# My Prisma Schema
This file is automatically generated every time `prisma generate` is ran.
## User Model
## Post Model
Create a new file called my_generator.py
and add the following code:
from pathlib import Path
from prisma.generator import Manifest, DefaultData, BaseGenerator
TEMPLATE = """
# My Prisma Schema
This file is automatically generated every time `prisma generate` is ran.
"""
MODEL_TEMPLATE = """
## {0.name} Model
"""
class MyGenerator(BaseGenerator):
def get_manifest(self) -> Manifest:
return Manifest(
name='My Cool Generator',
default_output='schema.md',
)
def generate(self, data: DefaultData) -> None:
content = TEMPLATE
for model in data.dmmf.datamodel.models:
content += MODEL_TEMPLATE.format(model)
# make sure you use the output value given in the Prisma DMMF
# as the output location can be customised!
file = Path(data.generator.output.value)
file.write_text(content)
if __name__ == '__main__':
MyGenerator.invoke()
Now all we need to do is add a new generator to our Prisma Schema file:
generator my_generator {
provider = "python my_generator.py"
}
Limitations
Redundant Validation
It is currently not possible to disable any data validation that only applies to Prisma Client Python. For example, the following schema will raise a validation error as the field name would generate invalid python code.
model User {
id Int @default(autoincrement())
from String
}
However you may not be generating python code or even be using the Prisma Client Python generator in your project which would make this validation error redundant.