Skip to content

Commit

Permalink
feat: create no models flag for generate command (#24160)
Browse files Browse the repository at this point in the history
Added a new flag to `prisma generate`
- `--allow-no-models`
Which allows generation of clients for schemas which contain no models

---------

Co-authored-by: Joël Galeran <Jolg42@users.noreply.github.com>
Co-authored-by: Sophie <29753584+Druue@users.noreply.github.com>
  • Loading branch information
3 people committed May 13, 2024
1 parent 51ff5e4 commit d2701d4
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 17 deletions.
13 changes: 8 additions & 5 deletions packages/cli/src/Generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,12 @@ ${bold('Usage')}
${bold('Options')}
-h, --help Display this help message
--schema Custom path to your Prisma schema
--watch Watch the Prisma schema and rerun after a change
--generator Generator to use (may be provided multiple times)
--no-engine Generate a client for use with Accelerate only
-h, --help Display this help message
--schema Custom path to your Prisma schema
--watch Watch the Prisma schema and rerun after a change
--generator Generator to use (may be provided multiple times)
--no-engine Generate a client for use with Accelerate only
--allow-no-models Allow generating a client without models
${bold('Examples')}
Expand Down Expand Up @@ -107,6 +108,7 @@ ${bold('Examples')}
// Only used for checkpoint information
'--postinstall': String,
'--telemetry-information': String,
'--allow-no-models': Boolean,
})

const isPostinstall = process.env.PRISMA_GENERATE_IN_POSTINSTALL
Expand Down Expand Up @@ -152,6 +154,7 @@ ${bold('Examples')}
Boolean(process.env.PRISMA_GENERATE_DATAPROXY) || // legacy, keep for backwards compatibility
Boolean(process.env.PRISMA_GENERATE_ACCELERATE) || // legacy, keep for backwards compatibility
Boolean(process.env.PRISMA_GENERATE_NO_ENGINE),
allowNoModels: Boolean(args['--allow-no-models']),
})

if (!generators || generators.length === 0) {
Expand Down
15 changes: 13 additions & 2 deletions packages/client/src/generation/TSClient/PrismaClient.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { DataSource, GeneratorConfig } from '@prisma/generator-helper'
import type { DataSource, DMMF, GeneratorConfig } from '@prisma/generator-helper'
import { assertNever } from '@prisma/internals'
import indent from 'indent-string'

Expand Down Expand Up @@ -350,7 +350,18 @@ export class PrismaClientClass implements Generable {
private get jsDoc(): string {
const { dmmf } = this

const example = dmmf.mappings.modelOperations[0]
let example: DMMF.ModelMapping

if (dmmf.mappings.modelOperations.length) {
example = dmmf.mappings.modelOperations[0]
} else {
// because generator models is empty we need to create a fake example
example = {
model: 'User',
plural: 'users',
}
}

return `/**
* ## Prisma Client ʲˢ
*
Expand Down
12 changes: 6 additions & 6 deletions packages/client/src/generation/TSClient/TSClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ ${buildRequirePath(edge)}
/**
* Enums
*/
${this.dmmf.schema.enumTypes.prisma.map((type) => new Enum(type, true).toJS()).join('\n\n')}
${this.dmmf.schema.enumTypes.prisma?.map((type) => new Enum(type, true).toJS()).join('\n\n')}
${this.dmmf.schema.enumTypes.model?.map((type) => new Enum(type, false).toJS()).join('\n\n') ?? ''}
${new Enum(
Expand Down Expand Up @@ -193,7 +193,7 @@ ${buildNFTAnnotations(edge || !copyEngine, clientEngineType, binaryTargets, rela

// TODO: Make this code more efficient and directly return 2 arrays

const prismaEnums = this.dmmf.schema.enumTypes.prisma.map((type) => new Enum(type, true).toTS())
const prismaEnums = this.dmmf.schema.enumTypes.prisma?.map((type) => new Enum(type, true).toTS())

const modelEnums: string[] = []
const modelEnumsAliases: string[] = []
Expand All @@ -210,7 +210,7 @@ ${buildNFTAnnotations(edge || !copyEngine, clientEngineType, binaryTargets, rela
const fieldRefs = this.dmmf.schema.fieldRefTypes.prisma?.map((type) => new FieldRefInput(type).toTS()) ?? []

const countTypes: Count[] = this.dmmf.schema.outputObjectTypes.prisma
.filter((t) => t.name.endsWith('CountOutputType'))
?.filter((t) => t.name.endsWith('CountOutputType'))
.map((t) => new Count(t, context))

const code = `
Expand Down Expand Up @@ -268,7 +268,7 @@ ${modelAndTypes.map((model) => model.toTS()).join('\n')}
* Enums
*/
${prismaEnums.join('\n\n')}
${prismaEnums?.join('\n\n')}
${
fieldRefs.length > 0
? `
Expand All @@ -284,7 +284,7 @@ ${fieldRefs.join('\n\n')}`
*/
${this.dmmf.inputObjectTypes.prisma
.reduce((acc, inputType) => {
?.reduce((acc, inputType) => {
if (inputType.name.includes('Json') && inputType.name.includes('Filter')) {
const needsGeneric = this.genericsInfo.typeNeedsGenericModelArg(inputType)
const innerName = needsGeneric ? `${inputType.name}Base<$PrismaModel>` : `${inputType.name}Base`
Expand Down Expand Up @@ -344,7 +344,7 @@ export const dmmf: runtime.BaseDMMF
* Enums
*/
${this.dmmf.schema.enumTypes.prisma.map((type) => new Enum(type, true).toJS()).join('\n\n')}
${this.dmmf.schema.enumTypes.prisma?.map((type) => new Enum(type, true).toJS()).join('\n\n')}
${this.dmmf.schema.enumTypes.model?.map((type) => new Enum(type, false).toJS()).join('\n\n') ?? ''}
${new Enum(
Expand Down
7 changes: 7 additions & 0 deletions packages/client/src/generation/dmmf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ export class DMMFHelper implements DMMF.Document {
}

private buildMergedOutputTypeMap(): NamespacedTypeMap<DMMF.OutputType> {
if (!this.schema.outputObjectTypes.prisma) {
return {
model: keyBy(this.schema.outputObjectTypes.model, 'name'),
prisma: keyBy([], 'name'),
}
}

return {
model: keyBy(this.schema.outputObjectTypes.model, 'name'),
prisma: keyBy(this.schema.outputObjectTypes.prisma, 'name'),
Expand Down
1 change: 1 addition & 0 deletions packages/generator-helper/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export type GeneratorOptions = {
binaryPaths?: BinaryPaths
postinstall?: boolean
noEngine?: boolean
allowNoModels?: boolean
}

export type EngineType = 'queryEngine' | 'libqueryEngine' | 'schemaEngine'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,7 @@ describe('getGenerators', () => {
test('fail if no model(s) found - mongodb', async () => {
expect.assertions(5)
const aliases = {
'predefined-generator': {
'prisma-client-js': {
generatorPath: generatorPath,
outputPath: __dirname,
},
Expand Down Expand Up @@ -823,4 +823,42 @@ describe('getGenerators', () => {
)
}
})

test('pass if no model(s) found but allow-no-models flag is passed - sqlite', async () => {
expect.assertions(1)

const aliases = {
'predefined-generator': {
generatorPath: generatorPath,
outputPath: __dirname,
},
}

const generators = await getGenerators({
schemaPath: path.join(__dirname, 'missing-models-sqlite-schema.prisma'),
providerAliases: aliases,
allowNoModels: true,
})

return expect(generators.length).toBeGreaterThanOrEqual(1)
})

test('pass if no model(s) found but allow-no-models flag is passed - mongodb', async () => {
expect.assertions(1)

const aliases = {
'prisma-client-js': {
generatorPath: generatorPath,
outputPath: __dirname,
},
}

const generators = await getGenerators({
schemaPath: path.join(__dirname, 'missing-models-mongodb-schema.prisma'),
providerAliases: aliases,
allowNoModels: true,
})

expect(generators.length).toBeGreaterThanOrEqual(1)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@ datasource db {

generator gen {
provider = "predefined-generator"
binaryTargets = ["darwin"]
binaryTargets = ["darwin", "darwin-arm64"]
}

5 changes: 4 additions & 1 deletion packages/internals/src/get-generators/getGenerators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export type GetGeneratorOptions = {
generatorNames?: string[]
postinstall?: boolean
noEngine?: boolean
allowNoModels?: boolean
}
/**
* Makes sure that all generators have the binaries they deserve and returns a
Expand All @@ -75,6 +76,7 @@ export async function getGenerators(options: GetGeneratorOptions): Promise<Gener
generatorNames = [],
postinstall,
noEngine,
allowNoModels,
} = options

if (!schemaPath) {
Expand Down Expand Up @@ -139,7 +141,7 @@ export async function getGenerators(options: GetGeneratorOptions): Promise<Gener
previewFeatures,
})

if (dmmf.datamodel.models.length === 0) {
if (dmmf.datamodel.models.length === 0 && !allowNoModels) {
// MongoDB needs extras for @id: @map("_id") @db.ObjectId
if (config.datasources.some((d) => d.provider === 'mongodb')) {
throw new Error(missingModelMessageMongoDB)
Expand Down Expand Up @@ -220,6 +222,7 @@ The generator needs to either define the \`defaultOutput\` path in the manifest
version: version || enginesVersion, // this version makes no sense anymore and should be ignored
postinstall,
noEngine,
allowNoModels,
}

// we set the options here a bit later after instantiating the Generator,
Expand Down

0 comments on commit d2701d4

Please sign in to comment.