Skip to content

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()