Skip to content

Commit

Permalink
fix: use import id @prisma/client by default when possible (#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonkuhrt authored Jun 22, 2021
1 parent 88fd092 commit 5599a65
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 8 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"build:module-facades": "ts-node scripts/build-module-facades",
"build": "yarn clean && yarn build:module-facades && tsc",
"test": "cross-env DEBUG=e2e jest",
"test:ci": "cross-env DEBUG=e2e jest --coverage --forceExit --runInBand",
"test:ci": "cross-env DEBUG='e2e' jest --coverage --forceExit --runInBand",
"tdd": "jest --watch",
"tdd:e2e:debug": "cross-env test_project_reuse=true jest --watch e2e",
"clean": "rm -rf dist && rm -rf node_modules/.cache",
Expand Down
91 changes: 85 additions & 6 deletions src/cli/nexus-prisma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@

process.env.DEBUG_COLORS = 'true'
process.env.DEBUG_HIDE_DATE = 'true'
import { generatorHandler } from '@prisma/generator-helper'
import { GeneratorConfig, generatorHandler } from '@prisma/generator-helper'
import * as Path from 'path'
import { generateRuntimeAndEmit } from '../generator'
import { loadUserGentimeSettings } from '../generator/gentime/settingsLoader'
import { Gentime } from '../generator/gentime/settingsSingleton'
import { d } from '../helpers/debugNexusPrisma'
import { externalToInternalDmmf } from '../helpers/prismaExternalToInternalDMMF'

// todo by default error in ci and warn in local
Expand All @@ -28,13 +29,19 @@ generatorHandler({
async onGenerate({ dmmf, otherGenerators }) {
const prismaClientGenerator = otherGenerators.find((g) => g.provider.value === 'prisma-client-js')

// TODO test showing this pretty error in action
if (!prismaClientGenerator) {
// TODO consider a prisma-client-less mode
throw new Error(
`Nexus Prisma cannot be used without Prisma Client. Please add it to your Prisma Schema file.`
)
}

// WARNING: Make sure this logic comes before `loadUserGentimeSettings` below
// otherwise we will overwrite the user's choice for this setting if they have set it.
if (prismaClientGenerator?.output?.value) {
Gentime.settings.change({
prismaClientImportId: prismaClientGenerator.output.value,
})
}
Gentime.settings.change({
prismaClientImportId: getPrismaClientImportIdForItsGeneratorOutputConfig(prismaClientGenerator),
})

const internalDMMF = externalToInternalDmmf(dmmf)
loadUserGentimeSettings()
Expand All @@ -44,3 +51,75 @@ generatorHandler({
)
},
})

/**
* Helpers
*/

/**
* Get the appropiate import ID for Prisma Client.
*
* When generator output is set to its default location within node_modules, then we return the import ID of just its npm moniker "@prisma/client".
*
* Othewise we return an import ID as an absolute path to the output location.
*/
function getPrismaClientImportIdForItsGeneratorOutputConfig(
prismaClientGeneratorConfig: GeneratorConfig
): string {
const prismaClientPackageMoniker = `@prisma/client`
const prismaClientDefaultOutput = Path.join(`node_modules`, `@prisma`, `client`)

if (!prismaClientGeneratorConfig.output || !prismaClientGeneratorConfig.output.value) {
return prismaClientPackageMoniker
}

if (prismaClientGeneratorConfig.output.value.endsWith(prismaClientDefaultOutput)) {
/**
* Goal of this code:
*
* Find out if we can import Prisma Client by simplify specifying its moniker (@prisma/client).
*
* Why do we want to import by Moniker? Because it is a good default because it is what a user would
* do in their own code. Also because not doing so has led to bugs https://github.com/prisma/nexus-prisma/issues/76.
*
* How this works:
*
* 1. Get the Prisma Client generatour output path minus the trailing node_moudles/@prisma/client (if present, it could be totally custom).
*
* Note that even if the user has not explicitly configured an output path in their PSL file by the time we get the geneator config from
* Prisma generator system the output default has been supplied so we always have a value here to work with.
*
* 2. Get the Nexus Prisma package path on the user's machine by starting from this module and going four directories up. Four directories
* up goes above the node_modules directory into their code.
*
* Note that we must go four up, not three up (which would be node_modules), because when using Yalc (used for development and E2E tests)
* Nexus Prisma is placed into <project>/.yalc rather than <project>/node_modules. And therefore, the check we want to achieve here would
* fail when it shouldn't.
*
* 3. With the two paths we check what the relative path between them is. If its an empty string, it means they are the same.
*
* Note this technique is better than string comparison because it guards against meaningless path difference details like windows vs posix.
* We're not certain what path standard we'll get from Prisma for example and ideally we don't care. Path.relative function should let us not
* care.
*/
const dirPrismaClientOutputWithoutTrailingNodeModulesMoniker =
prismaClientGeneratorConfig.output.value.replace(prismaClientDefaultOutput, '')
const dirProjectForThisNexusPrisma = Path.join(__dirname, '../../../..')
const dirDiff = Path.relative(
dirPrismaClientOutputWithoutTrailingNodeModulesMoniker,
dirProjectForThisNexusPrisma
)

d(`found prisma client/nexus prisma layout:`, {
dirPrismaClientOutputWithoutTrailingNodeModulesMoniker,
dirProjectForThisNexusPrisma,
dirDiff,
})

if (dirDiff === '') {
return prismaClientPackageMoniker
}
}

return prismaClientGeneratorConfig.output.value
}
1 change: 1 addition & 0 deletions src/helpers/prisma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import kleur = require('kleur')

export const getPrismaClientDmmf = (importId = '@prisma/client'): DMMF.Document => {
d('get dmmf from @prisma/client')
console.log(importId)

let maybeDmmf: DMMF.Document | undefined

Expand Down
10 changes: 9 additions & 1 deletion tests/e2e/e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ function setupTestNexusPrismaProject(): TestProject {
license: 'MIT',
scripts: {
reflect: 'yarn -s reflect:prisma && yarn -s reflect:nexus',
'reflect:prisma': 'prisma generate',
'reflect:prisma': "cross-env DEBUG='*' prisma generate",
// peer dependency check will fail since we're using yalc, e.g.:
// " ... nexus-prisma@0.0.0-dripip+c2653557 does not officially support @prisma/client@2.22.1 ... "
'reflect:nexus': 'cross-env REFLECT=true ts-node --transpile-only src/schema',
Expand Down Expand Up @@ -334,6 +334,14 @@ it('When bundled custom scalars are used the project type checks and generates e

expect(results.fileTypegen).toMatchSnapshot('nexus typegen')

/**
* Sanity check the Prisma Client import ID
*/

expect(testProject.fs.read('node_modules/nexus-prisma/dist/runtime/index.js')).toMatch(
/.*"prismaClientImportId": "@prisma\/client".*/
)

/**
* Sanity check the runtime
*/
Expand Down

0 comments on commit 5599a65

Please sign in to comment.