Skip to content

Commit

Permalink
feat: directUrl support (#17210)
Browse files Browse the repository at this point in the history
* directUrl: types and helpers

* directUrl: use direct url when possible/needed

* directUrl: update error message to reflect changes

* directUrl: add test for migrate reset, fix some issues

* directUrl: rename getDirectUrl to getEffectiveUrl

* Update packages/migrate/src/utils/ensureDatabaseExists.ts

* Update packages/migrate/src/utils/ensureDatabaseExists.ts

Co-authored-by: Jan Piotrowski <piotrowski+github@gmail.com>
Co-authored-by: Joël Galeran <Jolg42@users.noreply.github.com>
  • Loading branch information
3 people committed Jan 12, 2023
1 parent 5353900 commit b3963d5
Show file tree
Hide file tree
Showing 10 changed files with 74 additions and 17 deletions.
3 changes: 2 additions & 1 deletion packages/cli/src/Doctor.ts
Expand Up @@ -7,6 +7,7 @@ import {
format,
getConfig,
getDMMF,
getEffectiveUrl,
HelpError,
IntrospectionEngine,
keyBy,
Expand Down Expand Up @@ -81,7 +82,7 @@ ${chalk.bold('Examples')}

console.error(`👩‍⚕️🏥 Prisma Doctor checking the database...`)

const connectionString = config.datasources[0].url
const connectionString = getEffectiveUrl(config.datasources[0])
// connectionString.value exists because `ignoreEnvVarErrors: false` would have thrown an error if not
const canConnect = await canConnectToDatabase(connectionString.value!, path.dirname(schemaPath))
if (typeof canConnect !== 'boolean') {
Expand Down
1 change: 1 addition & 0 deletions packages/generator-helper/src/types.ts
Expand Up @@ -72,6 +72,7 @@ export interface DataSource {
provider: ConnectorType
activeProvider: ConnectorType
url: EnvValue
directUrl?: EnvValue
schemas: string[] | []
}

Expand Down
9 changes: 5 additions & 4 deletions packages/internals/src/cli/checkUnsupportedDataProxy.ts
Expand Up @@ -2,7 +2,7 @@ import chalk from 'chalk'
import fs from 'fs'
import { O } from 'ts-toolbelt'

import { getConfig, getSchemaPath, link } from '..'
import { getConfig, getEffectiveUrl, getSchemaPath, link } from '..'
import { loadEnvFile } from '../utils/loadEnvFile'

/**
Expand Down Expand Up @@ -32,7 +32,7 @@ Using the Data Proxy (connection URL starting with protocol ${chalk.green(
'prisma://',
)}) is not supported for this CLI command ${chalk.green(
`prisma ${command}`,
)} yet. Please use a direct connection to your database for now.
)} yet. Please use a direct connection to your database via the datasource 'directUrl' setting.
More information about Data Proxy: ${link('https://pris.ly/d/data-proxy-cli')}
`
Expand Down Expand Up @@ -62,8 +62,9 @@ async function checkUnsupportedDataProxyMessage(command: string, args: Args, imp

const datamodel = await fs.promises.readFile(argValue, 'utf-8')
const config = await getConfig({ datamodel, ignoreEnvVarErrors: true })
const urlFromValue = config.datasources[0]?.url.value
const urlEnvVarName = config.datasources[0]?.url.fromEnvVar
const url = getEffectiveUrl(config.datasources[0])
const urlFromValue = url.value
const urlEnvVarName = url.fromEnvVar
const urlEnvVarValue = urlEnvVarName ? process.env[urlEnvVarName] : undefined

if ((urlFromValue ?? urlEnvVarValue)?.startsWith('prisma://')) {
Expand Down
8 changes: 7 additions & 1 deletion packages/internals/src/engine-commands/getConfig.ts
@@ -1,7 +1,7 @@
import Debug from '@prisma/debug'
import { getCliQueryEngineBinaryType } from '@prisma/engines'
import { BinaryType } from '@prisma/fetch-engine'
import type { DataSource, GeneratorConfig } from '@prisma/generator-helper'
import type { DataSource, EnvValue, GeneratorConfig } from '@prisma/generator-helper'
import chalk from 'chalk'
import execa from 'execa'
import * as E from 'fp-ts/Either'
Expand Down Expand Up @@ -83,6 +83,12 @@ ${detailsHeader} ${message}`
}
}

export function getEffectiveUrl(ds: DataSource): EnvValue {
if (ds.directUrl !== undefined) return ds.directUrl

return ds.url
}

export async function getConfig(options: GetConfigOptions): Promise<ConfigMetaFormat> {
const cliEngineBinaryType = getCliQueryEngineBinaryType()

Expand Down
2 changes: 1 addition & 1 deletion packages/internals/src/engine-commands/index.ts
@@ -1,6 +1,6 @@
export { formatSchema } from './formatSchema'
export type { ConfigMetaFormat } from './getConfig'
export { getConfig } from './getConfig'
export { getConfig, getEffectiveUrl } from './getConfig'
export type { GetDMMFOptions } from './getDmmf'
export { getDMMF } from './getDmmf'
export { getEnginesMetaInfo } from './getEnginesMetaInfo'
Expand Down
29 changes: 27 additions & 2 deletions packages/migrate/src/__tests__/MigrateReset.test.ts
Expand Up @@ -173,7 +173,7 @@ describe('reset', () => {
Reset cancelled.
`)
expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``)
expect(mockExit).toBeCalledWith(130)
expect(mockExit).toHaveBeenCalledWith(130)
})

it('reset should error in unattended environment', async () => {
Expand Down Expand Up @@ -270,7 +270,7 @@ describe('reset', () => {
An error occurred while running the seed command:
Error: Command failed with exit code 1: node prisma/seed.js
`)
expect(mockExit).toBeCalledWith(1)
expect(mockExit).toHaveBeenCalledWith(1)
})

testIf(process.platform !== 'win32')(
Expand Down Expand Up @@ -325,4 +325,29 @@ describe('reset', () => {
expect(ctx.mocked['console.warn'].mock.calls.join('\n')).toMatchInlineSnapshot(``)
expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``)
})

it('should work with directUrl', async () => {
ctx.fixture('reset-directurl')

prompt.inject(['y']) // simulate user yes input

const result = MigrateReset.new().parse([])
await expect(result).resolves.toMatchInlineSnapshot(``)
expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(`
Prisma schema loaded from prisma/schema.prisma
Datasource "my_db": SQLite database "dev.db" at "file:dev.db"
Applying migration \`20201231000000_init\`
Database reset successful
The following migration(s) have been applied:
migrations/
└─ 20201231000000_init/
└─ migration.sql
`)
expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``)
})
})
Binary file not shown.
@@ -0,0 +1,5 @@
-- CreateTable
CREATE TABLE "Blog" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"viewCount20" INTEGER NOT NULL
);
@@ -0,0 +1,15 @@
datasource my_db {
provider = "sqlite"
url = "file:invalidfile.db"
directUrl = "file:dev.db"
}

generator client {
provider = "prisma-client-js"
output = "@prisma/client"
}

model Blog {
id Int @id
viewCount20 Int
}
19 changes: 11 additions & 8 deletions packages/migrate/src/utils/ensureDatabaseExists.ts
Expand Up @@ -3,6 +3,7 @@ import {
canConnectToDatabase,
createDatabase,
getConfig,
getEffectiveUrl,
getSchema,
getSchemaDir,
uriToCredentials,
Expand Down Expand Up @@ -61,7 +62,7 @@ export async function getDatasourceInfo({
}

const prettyProvider = prettifyProvider(firstDatasource.provider)
const url = firstDatasource.url.value
const url = getEffectiveUrl(firstDatasource).value

// url parsing for sql server is not implemented
if (!url || firstDatasource.provider === 'sqlserver') {
Expand All @@ -70,7 +71,7 @@ export async function getDatasourceInfo({
prettyProvider,
dbName: undefined,
dbLocation: undefined,
url: firstDatasource.url.value || undefined,
url: url || undefined,
schema: undefined,
schemas: firstDatasource.schemas,
}
Expand Down Expand Up @@ -132,9 +133,10 @@ export async function ensureCanConnectToDatabase(schemaPath?: string): Promise<B
}

const schemaDir = (await getSchemaDir(schemaPath))!
const url = getEffectiveUrl(firstDatasource).value

// url.value exists because `ignoreEnvVarErrors: false` would have thrown an error if not
const canConnect = await canConnectToDatabase(firstDatasource.url.value!, schemaDir)
// url exists because `ignoreEnvVarErrors: false` would have thrown an error if not
const canConnect = await canConnectToDatabase(url!, schemaDir)

if (canConnect === true) {
return true
Expand All @@ -154,9 +156,10 @@ export async function ensureDatabaseExists(action: MigrateAction, schemaPath?: s
}

const schemaDir = (await getSchemaDir(schemaPath))!
const url = getEffectiveUrl(firstDatasource).value

// url.value exists because `ignoreEnvVarErrors: false` would have thrown an error if not
const canConnect = await canConnectToDatabase(firstDatasource.url.value!, schemaDir)
// url exists because `ignoreEnvVarErrors: false` would have thrown an error if not
const canConnect = await canConnectToDatabase(url!, schemaDir)
if (canConnect === true) {
return
}
Expand All @@ -175,15 +178,15 @@ export async function ensureDatabaseExists(action: MigrateAction, schemaPath?: s
}

// url.value exists because `ignoreEnvVarErrors: false` would have thrown an error if not
if (await createDatabase(firstDatasource.url.value!, schemaDir)) {
if (await createDatabase(url!, schemaDir)) {
// URI parsing is not implemented for SQL server yet
if (firstDatasource.provider === 'sqlserver') {
return `SQL Server database created.\n`
}

// parse the url
// url.value exists because `ignoreEnvVarErrors: false` would have thrown an error if not
const credentials = uriToCredentials(firstDatasource.url.value!)
const credentials = uriToCredentials(url!)
const prettyProvider = prettifyProvider(firstDatasource.provider)

let message = `${prettyProvider} database${credentials.database ? ` ${credentials.database} ` : ' '}created`
Expand Down

0 comments on commit b3963d5

Please sign in to comment.