Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions packages/adapter-pg/src/__tests__/errors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,22 @@ describe('convertDriverError', () => {
})
})

it('should handle ColumnNotFound (42703)', () => {
const error = { code: '42703', message: 'column "foo" does not exist', severity: 'ERROR' }
it.each([
['unquoted column name', 'column foo does not exist', 'foo'],
['quoted column name', 'column "foo" does not exist', 'foo'],
['unquoted qualified column name', 'column users.first_name does not exist', 'users.first_name'],
['quoted qualified column name', 'column "users"."first name" does not exist', 'users.first name'],
['partially quoted qualified column name (1)', 'column users."first name" does not exist', 'users.first name'],
['partially quoted qualified column name (2)', 'column "users".first_name does not exist', 'users.first_name'],
['quoted column name containing spaces', 'column "first name" does not exist', 'first name'],
['quoted column name containing dots', 'column "first.name" does not exist', 'first.name'],
['quoted qualified column name containing dots', 'column "users"."first.name" does not exist', 'users.first.name'],
['quoted column name containing escaped quotes', 'column "a""b" does not exist', 'a"b'],
])('should handle ColumnNotFound (42703) with %s', (description, message, expectedColumn) => {
const error = { code: '42703', message, severity: 'ERROR' }
expect(convertDriverError(error)).toEqual({
kind: 'ColumnNotFound',
column: 'foo',
column: expectedColumn,
originalCode: error.code,
originalMessage: error.message,
})
Expand Down
11 changes: 11 additions & 0 deletions packages/adapter-pg/src/__tests__/pg.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ describe('PrismaPgAdapterFactory', () => {
await adapter.dispose()
})

it('should accept a connection string URL', async () => {
const connectionString = 'postgresql://test:test@localhost:5432/test'
const factory = new PrismaPgAdapterFactory(connectionString)

expect((factory as any).config).toEqual({ connectionString })

const adapter = await factory.connect()
expect(adapter.underlyingDriver().options.connectionString).toBe(connectionString)
await adapter.dispose()
})

it('should add and remove error event listener when using an external Pool', async () => {
const pool = new pg.Pool({ user: 'test', password: 'test', database: 'test', port: 5432, host: 'localhost' })
pool.on('error', () => {})
Expand Down
6 changes: 4 additions & 2 deletions packages/adapter-pg/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,13 @@ function mapDriverError(error: DatabaseError): MappedError {
kind: 'TableDoesNotExist',
table: error.message.split(' ').at(1)?.split('"').at(1),
}
case '42703':
case '42703': {
const rawColumn = error.message.match(/^column (.+) does not exist$/)?.at(1)
return {
kind: 'ColumnNotFound',
column: error.message.split(' ').at(1)?.split('"').at(1),
column: rawColumn?.replace(/"((?:""|[^"])*)"/g, (_, id) => id.replaceAll('""', '"')),
}
}
case '42P04':
return {
kind: 'DatabaseAlreadyExists',
Expand Down
5 changes: 4 additions & 1 deletion packages/adapter-pg/src/pg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,12 +278,15 @@ export class PrismaPgAdapterFactory implements SqlMigrationAwareDriverAdapterFac
private externalPool: pg.Pool | null

constructor(
poolOrConfig: pg.Pool | pg.PoolConfig,
poolOrConfig: pg.Pool | pg.PoolConfig | string,
private readonly options?: PrismaPgOptions,
) {
if (poolOrConfig instanceof pg.Pool) {
this.externalPool = poolOrConfig
this.config = poolOrConfig.options
} else if (typeof poolOrConfig === 'string') {
this.externalPool = null
this.config = { connectionString: poolOrConfig }
} else {
this.externalPool = null
this.config = poolOrConfig
Expand Down
5 changes: 3 additions & 2 deletions packages/cli/src/Generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { enginesVersion } from '@prisma/engines'
import { SqlQueryOutput } from '@prisma/generator'
import {
arg,
BuiltInProvider,
Command,
createSchemaPathInput,
format,
Expand Down Expand Up @@ -179,7 +180,7 @@ ${bold('Examples')}
} else {
// Only used for CLI output, ie Go client doesn't want JS example output
const jsClient = generators.find(
(g) => g.options && parseEnvValue(g.options.generator.provider) === 'prisma-client-js',
(g) => g.options && parseEnvValue(g.options.generator.provider) === BuiltInProvider.PrismaClientJs,
)

clientGeneratorVersion = jsClient?.manifest?.version ?? null
Expand Down Expand Up @@ -230,7 +231,7 @@ Please run \`prisma generate\` manually.`
if (!watchMode) {
const prismaClientJSGenerator = generators?.find(
({ options }) =>
options?.generator.provider && parseEnvValue(options?.generator.provider) === 'prisma-client-js',
options?.generator.provider && parseEnvValue(options?.generator.provider) === BuiltInProvider.PrismaClientJs,
)

let hint = ''
Expand Down
3 changes: 2 additions & 1 deletion packages/cli/src/utils/checkpoint.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Debug } from '@prisma/debug'
import {
arg,
BuiltInProvider,
createSchemaPathInput,
getCLIPathHash,
getProjectHash,
Expand Down Expand Up @@ -134,7 +135,7 @@ export async function tryToReadDataFromSchema(schemaPath: SchemaPathInput) {
.filter((generator) => generator && generator.provider)
.map((generator) => parseEnvValue(generator.provider))

const clientGeneratorProviders = ['prisma-client', 'prisma-client-js']
const clientGeneratorProviders: string[] = [BuiltInProvider.PrismaClientTs, BuiltInProvider.PrismaClientJs]
const previewFeatures = schemaContext.generators
.filter((generator) => {
const provider = generator?.provider ? parseEnvValue(generator.provider) : undefined
Expand Down
4 changes: 2 additions & 2 deletions packages/client-generator-js/src/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import path from 'node:path'

import { enginesVersion } from '@prisma/engines-version'
import { Generator, GeneratorConfig, GeneratorManifest, GeneratorOptions } from '@prisma/generator'
import { parseEnvValue } from '@prisma/internals'
import { BuiltInProvider, parseEnvValue } from '@prisma/internals'

import { version as clientVersion } from '../package.json'
import { generateClient } from './generateClient'
Expand All @@ -20,7 +20,7 @@ type PrismaClientJsGeneratorOptions = {
// visit https://pris.ly/cli/output-path`

export class PrismaClientJsGenerator implements Generator {
readonly name = 'prisma-client-js'
readonly name = BuiltInProvider.PrismaClientJs

#shouldResolvePrismaClient: boolean
#runtimePath?: string
Expand Down
5 changes: 3 additions & 2 deletions packages/client-generator-js/src/utils/types/dmmfToTypes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import path from 'node:path'

import type * as DMMF from '@prisma/dmmf'
import { BuiltInProvider } from '@prisma/internals'

import { TSClient } from '../../TSClient/TSClient'

Expand All @@ -24,9 +25,9 @@ export function dmmfToTypes(dmmf: DMMF.Document) {
generator: {
binaryTargets: [],
config: {},
name: 'prisma-client-js',
name: BuiltInProvider.PrismaClientJs,
output: null,
provider: { value: 'prisma-client-js', fromEnvVar: null },
provider: { value: BuiltInProvider.PrismaClientJs, fromEnvVar: null },
previewFeatures: [],
isCustomOutput: false,
sourceFilePath: 'schema.prisma',
Expand Down
2 changes: 1 addition & 1 deletion packages/client-generator-ts/src/TSClient/Model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ ${indent(

${ts.stringify(buildOutputType(groupByType))}

type ${getGroupByPayloadName(model.name)}<T extends ${groupByArgsName}> = Prisma.PrismaPromise<
export type ${getGroupByPayloadName(model.name)}<T extends ${groupByArgsName}> = Prisma.PrismaPromise<
Array<
Prisma.PickEnumerable<${groupByType.name}, T['by']> &
{
Expand Down
3 changes: 2 additions & 1 deletion packages/client/src/utils/getTestClient.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { dmmfToRuntimeDataModel, GetPrismaClientConfig } from '@prisma/client-common'
import { getDMMF } from '@prisma/client-generator-js'
import {
BuiltInProvider,
extractPreviewFeatures,
getConfig,
getSchemaWithPath,
Expand Down Expand Up @@ -34,7 +35,7 @@ export async function getTestClient(schemaDir?: string, printWarnings?: boolean)
printConfigWarnings(config.warnings)
}

const generator = config.generators.find((g) => parseEnvValue(g.provider) === 'prisma-client-js')
const generator = config.generators.find((g) => parseEnvValue(g.provider) === BuiltInProvider.PrismaClientJs)
const previewFeatures = extractPreviewFeatures(config.generators)
;(global as any).TARGET_BUILD_TYPE = 'client'

Expand Down
5 changes: 5 additions & 0 deletions packages/internals/src/built-in-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/** Built-in generator provider identifiers used across Prisma packages. */
export const BuiltInProvider = {
PrismaClientJs: 'prisma-client-js',
PrismaClientTs: 'prisma-client',
} as const
3 changes: 2 additions & 1 deletion packages/internals/src/cli/getGeneratorSuccessMessage.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { bold, dim } from 'kleur/colors'
import path from 'path'

import { BuiltInProvider } from '../built-in-provider'
import type { Generator } from '../Generator'
import { formatms } from '../utils/formatms'
import { parseEnvValue } from '../utils/parseEnvValue'
Expand All @@ -20,7 +21,7 @@ export function getGeneratorSuccessMessage(generator: Generator, time: number):
function formatVersion(generator: Generator): string | undefined {
const version = generator.manifest?.version

if (generator.getProvider() === 'prisma-client-js') {
if (generator.getProvider() === BuiltInProvider.PrismaClientJs) {
// version is always defined for prisma-client-js
return `v${version ?? '?.?.?'}`
}
Expand Down
1 change: 1 addition & 0 deletions packages/internals/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { BuiltInProvider } from './built-in-provider'
export { checkUnsupportedDataProxy } from './cli/checkUnsupportedDataProxy'
export { type DirectoryConfig, inferDirectoryConfig } from './cli/directoryConfig'
export { getGeneratorSuccessMessage } from './cli/getGeneratorSuccessMessage'
Expand Down
3 changes: 2 additions & 1 deletion packages/internals/src/utils/extractPreviewFeatures.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { GeneratorConfig } from '@prisma/generator'

import { BuiltInProvider } from '../built-in-provider'
import { parseEnvValue } from './parseEnvValue'

export function extractPreviewFeatures(generators: GeneratorConfig[]): string[] {
return generators.find((g) => parseEnvValue(g.provider) === 'prisma-client-js')?.previewFeatures || []
return generators.find((g) => parseEnvValue(g.provider) === BuiltInProvider.PrismaClientJs)?.previewFeatures || []
}
Loading