Skip to content

Commit

Permalink
feat(cli): ground work for prismaSchemaFolder, implementing `validate…
Browse files Browse the repository at this point in the history
…`, `format`, and adapting `migrate *` + `db *` cli commands (prisma#24057)

* feat(cli): ground work for prismaSchemaFolder, implementing "validate", "format", and preparing "migrate *" and "db *" commands

* feat(cli): address PR + chat comments, turn formatSchema, lintSchema, validate as multi-file schema-first "engine command" utilities

* tests(internals): fix tests for formatSchema

* tests(internals): fixed most tests, add comments

* feat(internals): fix getSchemaPathInternal

* test(cli): fix incomplete-schemas test suite

* test(cli): fix incomplete-schemas test suite, fix almost all getSchema test suite

* test(cli): fix other tests

* test(cli): update artificial-panic

* fix(migrate): restore schema engine interoperability

* fix(migrate): use absolute path when starting SchemaEngine, while still treating paths relatively to process.cwd() in psl validation

* fix(cli): fix most studio tests, restore previous snapshot in "artificial-panic introspection"

* fix(cli): minor updates to Format, DebugInfo

* fix(cli): restore failing test in "getSchema" suite

* fix(migrate): fix most "migrate" tests

* fix(cli): fix all tests but "postgresql-views"??? Used trick for displaying relative paths in "validate" and "getConfig"

* fix(migrate): postgresql-views test suite

* fix(client): fix integration-tests suite

* fix(internals): type issues with getSchema

* chore: address review comments

* chore(migrate): remove need for more relative paths

* chore(internals): restore validate panic snapshot

* chore(cli): don't manipulate schemaPath in Studio

* test(migrate): fix DbPush snapshot
  • Loading branch information
jkomyno authored May 8, 2024
1 parent 2ddab85 commit c22724e
Show file tree
Hide file tree
Showing 46 changed files with 485 additions and 348 deletions.
2 changes: 1 addition & 1 deletion packages/cli/src/DebugInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export class DebugInfo implements Command {

let schemaPath
try {
schemaPath = link(await getSchemaPath(args['--schema']))
schemaPath = link((await getSchemaPath(args['--schema']))?.schemaPath)
} catch (e) {
schemaPath = e.message
}
Expand Down
14 changes: 9 additions & 5 deletions packages/cli/src/Format.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fs from 'node:fs/promises'

import { arg, Command, format, formatms, formatSchema, HelpError, validate } from '@prisma/internals'
import { getSchemaPathAndPrint } from '@prisma/migrate'
import fs from 'fs'
import { bold, dim, red, underline } from 'kleur/colors'

/**
Expand Down Expand Up @@ -50,16 +51,19 @@ Or specify a Prisma schema path
return this.help()
}

const schemaPath = await getSchemaPathAndPrint(args['--schema'])
const { schemaPath, schemas } = await getSchemaPathAndPrint(args['--schema'])

const output = await formatSchema({ schemaPath })
const formattedDatamodel = await formatSchema({ schemas })

// Validate whether the formatted output is a valid schema
validate({
datamodel: output,
schemas: formattedDatamodel,
})

fs.writeFileSync(schemaPath, output)
for (const [filename, data] of formattedDatamodel) {
await fs.writeFile(filename, data)
}

const after = Math.round(performance.now())

return `Formatted ${underline(schemaPath)} in ${formatms(after - before)} 🚀`
Expand Down
9 changes: 5 additions & 4 deletions packages/cli/src/Generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,19 +126,20 @@ ${bold('Examples')}

loadEnvFile({ schemaPath: args['--schema'], printMessage: true })

const schemaPath = await getSchemaPathAndPrint(args['--schema'], cwd)
const schemaResult = await getSchemaPathAndPrint(args['--schema'], cwd)

if (!schemaPath) return ''
if (!schemaResult) return ''

const datamodel = await fs.promises.readFile(schemaPath, 'utf-8')
const config = await getConfig({ datamodel, ignoreEnvVarErrors: true })
const { schemas, schemaPath } = schemaResult
const config = await getConfig({ datamodel: schemas, ignoreEnvVarErrors: true })

// TODO Extract logic from here
let hasJsClient
let generators: Generator[] | undefined
let clientGeneratorVersion: string | null = null
try {
generators = await getGenerators({
// TODO: pass the schemas rather than the schemaPath
schemaPath,
printDownloadProgress: !watchMode,
version: enginesVersion,
Expand Down
6 changes: 2 additions & 4 deletions packages/cli/src/Studio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
} from '@prisma/internals'
import { getSchemaPathAndPrint } from '@prisma/migrate'
import { StudioServer } from '@prisma/studio-server'
import fs from 'fs'
import getPort from 'get-port'
import { bold, dim, red } from 'kleur/colors'
import open from 'open'
Expand Down Expand Up @@ -97,16 +96,15 @@ ${bold('Examples')}

loadEnvFile({ schemaPath: args['--schema'], printMessage: true })

const schemaPath = await getSchemaPathAndPrint(args['--schema'])
const { schemaPath, schemas } = await getSchemaPathAndPrint(args['--schema'])

const hostname = args['--hostname']
const port = args['--port'] || (await getPort({ port: getPort.makeRange(5555, 5600) }))
const browser = args['--browser'] || process.env.BROWSER

const staticAssetDir = path.resolve(__dirname, '../build/public')

const schema = await fs.promises.readFile(schemaPath, 'utf-8')
const config = await getConfig({ datamodel: schema, ignoreEnvVarErrors: true })
const config = await getConfig({ datamodel: schemas, ignoreEnvVarErrors: true })

process.env.PRISMA_DISABLE_WARNINGS = 'true' // disable client warnings
const studio = new StudioServer({
Expand Down
13 changes: 5 additions & 8 deletions packages/cli/src/Validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
validate,
} from '@prisma/internals'
import { getSchemaPathAndPrint } from '@prisma/migrate'
import fs from 'fs'
import { bold, dim, red, underline } from 'kleur/colors'

/**
Expand Down Expand Up @@ -63,17 +62,15 @@ ${bold('Examples')}

loadEnvFile({ schemaPath: args['--schema'], printMessage: true })

const schemaPath = await getSchemaPathAndPrint(args['--schema'])

const schema = fs.readFileSync(schemaPath, 'utf-8')
const { schemaPath, schemas } = await getSchemaPathAndPrint(args['--schema'])

const { lintDiagnostics } = handleLintPanic(
() => {
// the only possible error here is a Rust panic
const lintDiagnostics = lintSchema({ schema })
const lintDiagnostics = lintSchema({ schemas })
return { lintDiagnostics }
},
{ schema },
{ schemas },
)

const lintWarnings = getLintWarningsAsText(lintDiagnostics)
Expand All @@ -83,12 +80,12 @@ ${bold('Examples')}
}

validate({
datamodel: schema,
schemas,
})

// We could have a CLI flag to ignore env var validation
await getConfig({
datamodel: schema,
datamodel: schemas,
ignoreEnvVarErrors: false,
})

Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/Version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export class Version implements Command {
enginesMetaInfoErrors.forEach((e) => console.error(e))
}

const schemaPath = await getSchemaPath()
const schemaPath = (await getSchemaPath())?.schemaPath ?? null
const featureFlags = await this.getFeatureFlags(schemaPath)
if (featureFlags && featureFlags.length > 0) {
rows.push(['Preview Features', featureFlags.join(', ')])
Expand Down
25 changes: 16 additions & 9 deletions packages/cli/src/__tests__/artificial-panic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,20 @@ describe('artificial-panic formatter', () => {
expect(e.rustStack).toBeTruthy()
expect(e.schemaPath.replace(/\\/g, '/')) // replace due to Windows CI
.toContain('prisma/schema.prisma')
expect(e).toMatchObject({
schema: undefined,
})
expect(e.schema).toMatchInlineSnapshot(`
"// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = "postgres://user:password@randomhost:5432"
}
"
`)
}
})
})
Expand Down Expand Up @@ -169,9 +180,7 @@ describe('artificial-panic validate', () => {
}
"
`)
expect(e).toMatchObject({
schemaPath: undefined,
})
expect(e.schemaPath).toBeTruthy()
}
})

Expand Down Expand Up @@ -204,9 +213,7 @@ describe('artificial-panic validate', () => {
}
"
`)
expect(e).toMatchObject({
schemaPath: undefined,
})
expect(e.schemaPath).toBeTruthy()
}
})
})
Expand Down
8 changes: 4 additions & 4 deletions packages/cli/src/__tests__/commands/DebugInfo.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { jestConsoleContext, jestContext } from '@prisma/get-platform'
import path from 'path'
import { cwd } from 'process'
import stripAnsi from 'strip-ansi'

import { DebugInfo } from '../../DebugInfo'

Expand Down Expand Up @@ -429,9 +429,9 @@ describe('debug', () => {

it('should succeed with --schema', async () => {
ctx.fixture('example-project/prisma')
await expect(DebugInfo.new().parse(['--schema=schema.prisma'])).resolves.toContain(
path.join(cwd(), 'schema.prisma'),
)
const result = stripAnsi((await DebugInfo.new().parse(['--schema=schema.prisma'])) as string)

expect(result).toContain(`Path: ${path.join(process.cwd(), 'schema.prisma')}`)
})

it('should succeed with incorrect --schema path', async () => {
Expand Down
8 changes: 4 additions & 4 deletions packages/cli/src/__tests__/commands/Validate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,13 @@ describe('validate', () => {
"Prisma schema validation - (validate wasm)
Error code: P1012
error: Error validating: Invalid referential action: \`NoAction\`. Allowed values: (\`Cascade\`, \`Restrict\`, \`SetNull\`). \`NoAction\` is not implemented for Postgres when using \`relationMode = "prisma"\`, you could try using \`Restrict\` instead. Learn more at https://pris.ly/d/relation-mode
--> schema.prisma:21
--> prisma/postgres.prisma:21
|
20 | id String @id @default(cuid())
21 | user SomeUser @relation(fields: [userId], references: [id], onUpdate: NoAction)
|
error: Error validating: Invalid referential action: \`NoAction\`. Allowed values: (\`Cascade\`, \`Restrict\`, \`SetNull\`). \`NoAction\` is not implemented for Postgres when using \`relationMode = "prisma"\`, you could try using \`Restrict\` instead. Learn more at https://pris.ly/d/relation-mode
--> schema.prisma:28
--> prisma/postgres.prisma:28
|
27 | id String @id @default(cuid())
28 | user SomeUser @relation(fields: [userId], references: [id], onDelete: NoAction)
Expand All @@ -117,13 +117,13 @@ describe('validate', () => {
"Prisma schema validation - (validate wasm)
Error code: P1012
error: Error validating: Invalid referential action: \`NoAction\`. Allowed values: (\`Cascade\`, \`Restrict\`, \`SetNull\`). \`NoAction\` is not implemented for Postgres when using \`relationMode = "prisma"\`, you could try using \`Restrict\` instead. Learn more at https://pris.ly/d/relation-mode
--> schema.prisma:21
--> prisma/postgres.prisma:21
|
20 | id String @id @default(cuid())
21 | user SomeUser @relation(fields: [userId], references: [id], onUpdate: NoAction)
|
error: Error validating: Invalid referential action: \`NoAction\`. Allowed values: (\`Cascade\`, \`Restrict\`, \`SetNull\`). \`NoAction\` is not implemented for Postgres when using \`relationMode = "prisma"\`, you could try using \`Restrict\` instead. Learn more at https://pris.ly/d/relation-mode
--> schema.prisma:28
--> prisma/postgres.prisma:28
|
27 | id String @id @default(cuid())
28 | user SomeUser @relation(fields: [userId], references: [id], onDelete: NoAction)
Expand Down
10 changes: 5 additions & 5 deletions packages/client/src/utils/getTestClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ import {
getClientEngineType,
getConfig,
getEnvPaths,
getRelativeSchemaPath,
getSchemaPath,
parseEnvValue,
printConfigWarnings,
} from '@prisma/internals'
import fs from 'fs'
import path from 'path'
import { parse } from 'stacktrace-parser'

Expand All @@ -27,8 +26,9 @@ import { generateInFolder } from './generateInFolder'
export async function getTestClient(schemaDir?: string, printWarnings?: boolean): Promise<any> {
const callSite = path.dirname(require.main?.filename ?? '')
const absSchemaDir = path.resolve(callSite, schemaDir ?? '')
const schemaPath = await getRelativeSchemaPath(absSchemaDir)
const datamodel = await fs.promises.readFile(schemaPath!, 'utf-8')

const { schemaPath, schemas: datamodel } = (await getSchemaPath(undefined, { cwd: absSchemaDir }))!

const config = await getConfig({ datamodel, ignoreEnvVarErrors: true })
if (printWarnings) {
printConfigWarnings(config.warnings)
Expand Down Expand Up @@ -60,7 +60,7 @@ export async function getTestClient(schemaDir?: string, printWarnings?: boolean)
datasourceNames: config.datasources.map((d) => d.name),
activeProvider,
inlineDatasources: { db: { url: config.datasources[0].url } },
inlineSchema: datamodel,
inlineSchema: datamodel[0][1], // TODO: merge schemas
inlineSchemaHash: '',
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`format nothing 1`] = `"Parameter schema or schemaPath must be passed."`;

exports[`format valid blog schema 1`] = `
"datasource db {
provider = "sqlite"
Expand Down
Loading

0 comments on commit c22724e

Please sign in to comment.