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, Data
class MyGenerator(BaseGenerator):
def generate(self, data: Data) -> 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, Data
class MyGenerator(BaseGenerator):
def get_manifest(self) -> Manifest:
return Manifest(
name='My Generator',
default_output='output.txt',
)
def generate(self, data: Data) -> None:
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 BaseGenerator, Manifest, Data
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: Data) -> None:
content = TEMPLATE
for model in data.dmmf.datamodel.models:
content += MODEL_TEMPLATE.format(model)
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
Custom Options
Custom configuration options are supported albeit using a verbose and sub-optimal method that overrides type safety.
generator my_generator {
provder = "python my_generator.py"
option = "value"
}
from pydantic import BaseModel
from prisma.generator import GenericGenerator, models
class Data(models.Data):
generator: 'GeneratorData'
class GeneratorData(models.Generator):
config: 'Config' # type: ignore
class Config(BaseModel):
value: int
class MyGenerator(GenericGenerator[Data]):
# TODO: methods
pass
Data.update_forward_refs()
GeneratorData.update_forward_refs()