跳至内容

自定义生成器

想用你的 prisma 模式做任何事吗?

你可以轻松地用 python 编写你自己的 prisma 生成器

它是如何工作的?

Prisma 生成器包含两个步骤

  • 生成器元数据
  • 资产生成

元数据

元数据步骤由 Prisma 用于收集有关您的生成器的信息,包括以下信息:

  • 生成器的名称
  • 默认输出位置

此数据在 Prisma Client Python 中使用 Manifest 模型表示

from prisma.generator import BaseGenerator, Manifest

class MyGenerator(BaseGenerator):
    def get_manifest(self) -> Manifest:
        return Manifest(
            name='Custom Prisma Generator'
            default_output='out.txt',
        )

生成

Prisma 在生成步骤中向生成器发送 Prisma Schema DMMF,这是您的 Prisma Schema 的 AST 形式。

DMMF 在 Prisma Client Python 中使用 Data 模型表示

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

警告

对 DMMF 结构的更改不被视为重大更改

样板

开始编写您自己的 Prisma 生成器所需的最小代码

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

自定义配置选项

您也可以直接在 Prisma Schema 文件中添加自定义配置选项!例如,考虑以下模式

generator my_generator {
  provder   = "python my_generator.py"
  my_option = 1
}

为了支持定义自定义选项,您需要以略微不同的方式定义生成器

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

示例

在本例中,我们将创建一个简单的生成器,它会创建一个类似于此的 markdown 文件

# My Prisma Schema

This file is automatically generated every time `prisma generate` is ran.

## User Model

## Post Model

创建一个名为 my_generator.py 的新文件,并添加以下代码

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

现在,我们只需要在 Prisma Schema 文件中添加一个新的生成器

generator my_generator {
  provider = "python my_generator.py"
}

限制

冗余验证

目前无法禁用仅适用于 Prisma Client Python 的任何数据验证。例如,以下模式将引发验证错误,因为字段名称将生成无效的 Python 代码。

model User {
  id   Int @default(autoincrement())
  from String
}

但是,您可能没有生成 Python 代码,甚至可能没有在项目中使用 Prisma Client Python 生成器,这将使此验证错误变得多余。