Created
May 17, 2021 03:04
-
-
Save deckchairlabs/8a11c33311c01273deec7e739417dbc9 to your computer and use it in GitHub Desktop.
Prisma Custom Generator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env node | |
| const path = require('path') | |
| const generatorHelper = require('@prisma/generator-helper') | |
| const { Project, StructureKind, VariableDeclarationKind } = require('ts-morph') | |
| generatorHelper.generatorHandler({ | |
| onManifest(config) { | |
| return { | |
| prettyName: 'Filters', | |
| defaultOutput: path.resolve(__dirname, 'filters'), | |
| requiresGenerators: ['nexus-prisma'], | |
| } | |
| }, | |
| onGenerate(options) { | |
| const project = new Project({ | |
| skipAddingFilesFromTsConfig: true, | |
| }) | |
| const outputPath = options.generator.output.value | |
| const enums = options.dmmf.datamodel.enums | |
| const models = options.dmmf.datamodel.models | |
| const indexSource = project.createSourceFile( | |
| `${outputPath}/index.ts`, | |
| { | |
| statements: [ | |
| { | |
| kind: StructureKind.ImportDeclaration, | |
| namedImports: ['Prisma'], | |
| moduleSpecifier: '@prisma/client', | |
| }, | |
| { | |
| kind: StructureKind.ImportDeclaration, | |
| namedImports: ['enumType', 'inputObjectType'], | |
| moduleSpecifier: 'nexus', | |
| }, | |
| ], | |
| }, | |
| { | |
| overwrite: true, | |
| } | |
| ) | |
| if (models.length > 0) { | |
| indexSource.addVariableStatement({ | |
| declarationKind: VariableDeclarationKind.Const, | |
| isExported: true, | |
| declarations: [ | |
| { | |
| name: 'SortOrderEnum', | |
| initializer(writer) { | |
| writer | |
| .write('enumType(') | |
| .indent(1) | |
| .inlineBlock(() => { | |
| writer.writeLine(`name: 'SortOrder',`) | |
| writer.writeLine('members: Prisma.SortOrder') | |
| }) | |
| .write(')') | |
| .newLine() | |
| }, | |
| }, | |
| ], | |
| }) | |
| indexSource.addVariableStatement({ | |
| declarationKind: VariableDeclarationKind.Const, | |
| isExported: true, | |
| declarations: [ | |
| { | |
| name: 'IDFilterInputType', | |
| initializer(writer) { | |
| writer | |
| .write('inputObjectType(') | |
| .indent(1) | |
| .inlineBlock(() => { | |
| writer.writeLine(`name: 'IDFilterInput',`) | |
| writer.write('definition(t)') | |
| writer.block(() => { | |
| writer.writeLine(`t.id('equals')`) | |
| writer.writeLine(`t.list.id('in')`) | |
| writer.writeLine(`t.list.id('notIn')`) | |
| writer.writeLine(`t.id('lt')`) | |
| writer.writeLine(`t.id('lte')`) | |
| writer.writeLine(`t.id('gt')`) | |
| writer.writeLine(`t.id('gte')`) | |
| writer.writeLine( | |
| `t.field('not', { type: 'IDFilterInput' })` | |
| ) | |
| }) | |
| }) | |
| .write(')') | |
| .newLine() | |
| }, | |
| }, | |
| ], | |
| }) | |
| indexSource.addVariableStatement({ | |
| declarationKind: VariableDeclarationKind.Const, | |
| isExported: true, | |
| declarations: [ | |
| { | |
| name: 'StringFilterInputType', | |
| initializer(writer) { | |
| writer | |
| .write('inputObjectType(') | |
| .indent(1) | |
| .inlineBlock(() => { | |
| writer.writeLine(`name: 'StringFilterInput',`) | |
| writer.write('definition(t)') | |
| writer.block(() => { | |
| writer.writeLine(`t.string('equals')`) | |
| writer.writeLine(`t.string('contains')`) | |
| writer.writeLine(`t.string('startsWith')`) | |
| writer.writeLine(`t.string('endsWith')`) | |
| writer.writeLine(`t.list.string('in')`) | |
| writer.writeLine(`t.list.string('notIn')`) | |
| writer.writeLine(`t.string('lt')`) | |
| writer.writeLine(`t.string('lte')`) | |
| writer.writeLine(`t.string('gt')`) | |
| writer.writeLine(`t.string('gte')`) | |
| writer.writeLine( | |
| `t.field('not', { type: 'StringFilterInput' })` | |
| ) | |
| }) | |
| }) | |
| .write(')') | |
| .newLine() | |
| }, | |
| }, | |
| ], | |
| }) | |
| indexSource.addVariableStatement({ | |
| declarationKind: VariableDeclarationKind.Const, | |
| isExported: true, | |
| declarations: [ | |
| { | |
| name: 'DateTimeFilterInputType', | |
| initializer(writer) { | |
| writer | |
| .write('inputObjectType(') | |
| .indent(1) | |
| .inlineBlock(() => { | |
| writer.writeLine(`name: 'DateTimeFilterInput',`) | |
| writer.write('definition(t)') | |
| writer.block(() => { | |
| writer.writeLine(`t.field('equals', { type: 'DateTime' })`) | |
| writer.writeLine(`t.list.field('in', { type: 'DateTime' })`) | |
| writer.writeLine( | |
| `t.list.field('notIn', { type: 'DateTime' })` | |
| ) | |
| writer.writeLine(`t.field('lt', { type: 'DateTime' })`) | |
| writer.writeLine(`t.field('lte', { type: 'DateTime' })`) | |
| writer.writeLine(`t.field('gt', { type: 'DateTime' })`) | |
| writer.writeLine(`t.field('gte', { type: 'DateTime' })`) | |
| writer.writeLine( | |
| `t.field('not', { type: 'DateTimeFilterInput' })` | |
| ) | |
| }) | |
| }) | |
| .write(')') | |
| .newLine() | |
| }, | |
| }, | |
| ], | |
| }) | |
| indexSource.addVariableStatement({ | |
| declarationKind: VariableDeclarationKind.Const, | |
| isExported: true, | |
| declarations: [ | |
| { | |
| name: 'IntFilterInputType', | |
| initializer(writer) { | |
| writer | |
| .write('inputObjectType(') | |
| .indent(1) | |
| .inlineBlock(() => { | |
| writer.writeLine(`name: 'IntFilterInput',`) | |
| writer.write('definition(t)') | |
| writer.block(() => { | |
| writer.writeLine(`t.int('equals')`) | |
| writer.writeLine(`t.list.int('in')`) | |
| writer.writeLine(`t.list.int('notIn')`) | |
| writer.writeLine(`t.int('lt')`) | |
| writer.writeLine(`t.int('lte')`) | |
| writer.writeLine(`t.int('gt')`) | |
| writer.writeLine(`t.int('gte')`) | |
| writer.writeLine( | |
| `t.field('not', { type: 'IntFilterInput' })` | |
| ) | |
| }) | |
| }) | |
| .write(')') | |
| .newLine() | |
| }, | |
| }, | |
| ], | |
| }) | |
| indexSource.addVariableStatement({ | |
| declarationKind: VariableDeclarationKind.Const, | |
| isExported: true, | |
| declarations: [ | |
| { | |
| name: 'BooleanFilterInputType', | |
| initializer(writer) { | |
| writer | |
| .write('inputObjectType(') | |
| .indent(1) | |
| .inlineBlock(() => { | |
| writer.writeLine(`name: 'BooleanFilterInput',`) | |
| writer.write('definition(t)') | |
| writer.block(() => { | |
| writer.writeLine(`t.boolean('equals')`) | |
| writer.writeLine( | |
| `t.field('not', { type: 'BooleanFilterInput' })` | |
| ) | |
| }) | |
| }) | |
| .write(')') | |
| .newLine() | |
| }, | |
| }, | |
| ], | |
| }) | |
| models.forEach((model) => { | |
| indexSource.addExportDeclaration({ | |
| moduleSpecifier: `./${model.name}`, | |
| namespaceExport: model.name, | |
| }) | |
| const whereUniqueInputTypeName = `${model.name}WhereUniqueInput` | |
| const whereInputTypeName = `${model.name}WhereInput` | |
| const orderByInputTypeName = `${model.name}OrderByInput` | |
| const modelRelationFilterName = `${model.name}RelationFilterInput` | |
| const modelListRelationFilterName = `${model.name}ListRelationFilterInput` | |
| const sourceFile = project.createSourceFile( | |
| `${outputPath}/${model.name}.ts`, | |
| { | |
| statements: [ | |
| { | |
| kind: StructureKind.ImportDeclaration, | |
| namedImports: ['inputObjectType'], | |
| moduleSpecifier: 'nexus', | |
| }, | |
| ], | |
| }, | |
| { | |
| overwrite: true, | |
| } | |
| ) | |
| sourceFile.addVariableStatement({ | |
| declarationKind: VariableDeclarationKind.Const, | |
| isExported: true, | |
| declarations: [ | |
| { | |
| name: `${whereUniqueInputTypeName}Type`, | |
| initializer(writer) { | |
| writer | |
| .write('inputObjectType(') | |
| .inlineBlock(() => { | |
| writer.writeLine(`name: '${whereUniqueInputTypeName}',`) | |
| writer.writeLine('definition(t)') | |
| writer.inlineBlock(() => { | |
| writer.writeLine(`t.nonNull.id('id')`) | |
| }) | |
| }) | |
| .write(')') | |
| .newLine() | |
| }, | |
| }, | |
| ], | |
| }) | |
| sourceFile.addVariableStatement({ | |
| declarationKind: VariableDeclarationKind.Const, | |
| isExported: true, | |
| declarations: [ | |
| { | |
| name: `${whereInputTypeName}Type`, | |
| initializer(writer) { | |
| writer | |
| .write('inputObjectType(') | |
| .inlineBlock(() => { | |
| writer.writeLine(`name: '${whereInputTypeName}',`) | |
| writer.writeLine('definition(t)') | |
| writer.inlineBlock(() => { | |
| model.fields.forEach((field) => { | |
| if (field.kind === 'scalar') { | |
| if ( | |
| field.name === 'id' || | |
| field.name.endsWith('Id') | |
| ) { | |
| writer.write(`t.field('${field.name}',`) | |
| writer | |
| .inlineBlock(() => { | |
| writer.writeLine(`type: 'IDFilterInput'`) | |
| }) | |
| .write(')') | |
| .newLine() | |
| } else { | |
| writer.write(`t.field('${field.name}',`) | |
| writer | |
| .inlineBlock(() => { | |
| writer.writeLine( | |
| `type: '${field.type}FilterInput'` | |
| ) | |
| }) | |
| .write(')') | |
| .newLine() | |
| } | |
| } else if (field.kind === 'object') { | |
| if (field.isList) { | |
| writer | |
| .write(`t.field('${field.name}',`) | |
| .inlineBlock(() => { | |
| writer.writeLine( | |
| `type: '${field.type}ListRelationFilterInput'` | |
| ) | |
| }) | |
| .write(')') | |
| .newLine() | |
| } else { | |
| writer | |
| .write(`t.field('${field.name}',`) | |
| .inlineBlock(() => { | |
| writer.writeLine( | |
| `type: '${field.type}RelationFilterInput'` | |
| ) | |
| }) | |
| .write(')') | |
| .newLine() | |
| } | |
| } else if (field.kind === 'enum') { | |
| writer | |
| .write(`t.field('${field.name}',`) | |
| .inlineBlock(() => { | |
| writer.writeLine( | |
| `type: '${field.type}EnumFilterInput'` | |
| ) | |
| }) | |
| .write(')') | |
| .newLine() | |
| } | |
| }) | |
| writer.writeLine( | |
| `t.list.field('AND', { type: '${whereInputTypeName}' })` | |
| ) | |
| writer.writeLine( | |
| `t.list.field('OR', { type: '${whereInputTypeName}' })` | |
| ) | |
| writer.writeLine( | |
| `t.list.field('NOT', { type: '${whereInputTypeName}' })` | |
| ) | |
| }) | |
| }) | |
| .write(')') | |
| .newLine() | |
| }, | |
| }, | |
| ], | |
| }) | |
| sourceFile.addVariableStatement({ | |
| declarationKind: VariableDeclarationKind.Const, | |
| isExported: true, | |
| declarations: [ | |
| { | |
| name: `${modelRelationFilterName}Type`, | |
| initializer(writer) { | |
| writer | |
| .write('inputObjectType(') | |
| .inlineBlock(() => { | |
| writer.writeLine(`name: '${modelRelationFilterName}',`) | |
| writer.writeLine('definition(t)') | |
| writer.inlineBlock(() => { | |
| writer.writeLine( | |
| `t.field('is', { type: '${whereInputTypeName}' })` | |
| ) | |
| writer.writeLine( | |
| `t.field('isNot', { type: '${whereInputTypeName}' })` | |
| ) | |
| }) | |
| }) | |
| .write(')') | |
| .newLine() | |
| }, | |
| }, | |
| ], | |
| }) | |
| sourceFile.addVariableStatement({ | |
| declarationKind: VariableDeclarationKind.Const, | |
| isExported: true, | |
| declarations: [ | |
| { | |
| name: `${modelListRelationFilterName}Type`, | |
| initializer(writer) { | |
| writer | |
| .write('inputObjectType(') | |
| .inlineBlock(() => { | |
| writer.writeLine(`name: '${modelListRelationFilterName}',`) | |
| writer.writeLine('definition(t)') | |
| writer.inlineBlock(() => { | |
| writer.writeLine( | |
| `t.field('every', { type: '${whereInputTypeName}' })` | |
| ) | |
| writer.writeLine( | |
| `t.field('some', { type: '${whereInputTypeName}' })` | |
| ) | |
| writer.writeLine( | |
| `t.field('none', { type: '${whereInputTypeName}' })` | |
| ) | |
| }) | |
| }) | |
| .write(')') | |
| .newLine() | |
| }, | |
| }, | |
| ], | |
| }) | |
| sourceFile.addVariableStatement({ | |
| declarationKind: VariableDeclarationKind.Const, | |
| isExported: true, | |
| declarations: [ | |
| { | |
| name: `${orderByInputTypeName}Type`, | |
| initializer(writer) { | |
| writer | |
| .write('inputObjectType(') | |
| .inlineBlock(() => { | |
| writer.writeLine(`name: '${orderByInputTypeName}',`) | |
| writer.writeLine('definition(t)') | |
| writer.inlineBlock(() => { | |
| model.fields.forEach((field) => { | |
| if (field.kind === 'scalar' || field.kind === 'enum') { | |
| writer.writeLine( | |
| `t.field('${field.name}', { type: 'SortOrder' })` | |
| ) | |
| } else if (field.kind === 'object') { | |
| const relatedModel = models.find( | |
| (model) => model.name === field.type | |
| ) | |
| if (relatedModel) { | |
| writer.writeLine( | |
| `t.field('${field.name}', { type: '${relatedModel.name}OrderByInput' })` | |
| ) | |
| } | |
| } | |
| }) | |
| }) | |
| }) | |
| .write(')') | |
| .newLine() | |
| }, | |
| }, | |
| ], | |
| }) | |
| sourceFile.formatText({ | |
| indentSize: 2, | |
| convertTabsToSpaces: true, | |
| semicolons: 'remove', | |
| }) | |
| }) | |
| if (enums.length > 0) { | |
| enums.forEach((enumModel) => { | |
| indexSource.addVariableStatement({ | |
| declarationKind: VariableDeclarationKind.Const, | |
| isExported: true, | |
| declarations: [ | |
| { | |
| name: `${enumModel.name}EnumFilterInputType`, | |
| initializer(writer) { | |
| writer | |
| .write('inputObjectType(') | |
| .indent(1) | |
| .inlineBlock(() => { | |
| writer.writeLine( | |
| `name: '${enumModel.name}EnumFilterInput',` | |
| ) | |
| writer.write('definition(t)') | |
| writer.block(() => { | |
| writer.writeLine( | |
| `t.field('equals', { type: '${enumModel.name}' })` | |
| ) | |
| writer.writeLine( | |
| `t.list.field('in', { type: '${enumModel.name}' })` | |
| ) | |
| writer.writeLine( | |
| `t.list.field('notIn', { type: '${enumModel.name}' })` | |
| ) | |
| writer.writeLine( | |
| `t.field('lt', { type: '${enumModel.name}' })` | |
| ) | |
| writer.writeLine( | |
| `t.field('lte', { type: '${enumModel.name}' })` | |
| ) | |
| writer.writeLine( | |
| `t.field('gt', { type: '${enumModel.name}' })` | |
| ) | |
| writer.writeLine( | |
| `t.field('gte', { type: '${enumModel.name}' })` | |
| ) | |
| writer.writeLine( | |
| `t.field('not', { type: '${enumModel.name}EnumFilterInput' })` | |
| ) | |
| }) | |
| }) | |
| .write(')') | |
| .newLine() | |
| }, | |
| }, | |
| ], | |
| }) | |
| }) | |
| } | |
| indexSource.formatText({ | |
| indentSize: 2, | |
| convertTabsToSpaces: true, | |
| semicolons: 'remove', | |
| }) | |
| } | |
| project.save() | |
| }, | |
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| generator prisma_client { | |
| provider = "prisma-client-js" | |
| previewFeatures = ["orderByRelation"] | |
| } | |
| // Add your custom generator | |
| generator filters { | |
| provider = "./prisma/filters.js" | |
| output = "./api/src/generated/filters" | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you for this nice gist!
In my case to make it work, I needed to make
onGeneratean async function, and wait forproject.save()to finish, otherwise I could not find any generated files in the folder.Line 14:
async onGenerate(options) {Line 535:
await project.save()