Skip to main content
Glama

Prisma MCP Server

Official
by prisma
Apache 2.0
4
44,192
  • Linux
  • Apple
loadConfigFromFile.test.ts33.7 kB
/* eslint-disable @typescript-eslint/no-redundant-type-constituents */ import path from 'node:path' import { bindMigrationAwareSqlAdapterFactory, mockMigrationAwareAdapterFactory, SqlMigrationAwareDriverAdapterFactory, } from '@prisma/driver-adapter-utils' import { vitestContext } from '@prisma/get-platform/src/test-utils/vitestContext' import type { ParseError } from 'effect/ParseResult' import { PrismaConfigInternal } from 'src/PrismaConfig' import { beforeEach, describe, expect, it, test, vi } from 'vitest' import { defaultConfig } from '../defaultConfig' import { loadConfigFromFile, type LoadConfigFromFileError, SUPPORTED_EXTENSIONS } from '../loadConfigFromFile' const ctx = vitestContext.new().assemble() describe('loadConfigFromFile', () => { function assertConfigDefined(config: PrismaConfigInternal | undefined): asserts config is PrismaConfigInternal { expect(config).toBeDefined() } function assertErrorConfigLoadError(error: LoadConfigFromFileError | undefined): asserts error is { _tag: 'ConfigLoadError' error: Error } { expect(error).toMatchObject({ _tag: 'ConfigLoadError' }) } function assertErrorConfigFileSyntaxError(error: LoadConfigFromFileError | undefined): asserts error is { _tag: 'ConfigFileSyntaxError' error: ParseError } { expect(error).toMatchObject({ _tag: 'ConfigFileSyntaxError' }) } function assertConfigWithEngineJs(config: PrismaConfigInternal): asserts config is PrismaConfigInternal & { engine: 'js' adapter: () => SqlMigrationAwareDriverAdapterFactory } { expect(config['engine']).toBe('js') } function assertConfigWithEngineClassic(config: PrismaConfigInternal): asserts config is PrismaConfigInternal & { engine: 'classic' datasource: { url: string directUrl?: string shadowDatabaseUrl?: string } } { expect(config['engine']).toBe('classic') } describe('no-define-config', () => { it('successfully loads a Prisma config file that does not use the `defineConfig` function', async () => { ctx.fixture('loadConfigFromFile/no-define-config') const cwd = ctx.fs.cwd() const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), 'prisma.config.ts')) expect(error).toBeUndefined() assertConfigDefined(config) expect(config).toMatchObject({ experimental: { studio: true, }, schema: path.join(cwd, 'schema.prisma'), }) }) describe('engine', () => { test('if `engine === "js"` configuration is provided, it should configure Prisma Migrate using the provided adapter', async () => { ctx.fixture('loadConfigFromFile/engine/js') const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), 'prisma.config.ts')) expect(error).toBeUndefined() assertConfigDefined(config) const expectedAdapter = bindMigrationAwareSqlAdapterFactory(mockMigrationAwareAdapterFactory('postgres')) assertConfigWithEngineJs(config) expect(config.adapter).toStrictEqual(expect.any(Function)) const { adapter: adapterFactory } = config expect(adapterFactory).toBeDefined() const adapter = await adapterFactory() Object.entries(expectedAdapter).forEach(([key, value]) => { if (typeof value === 'function') { // avoid `Compared values have no visual difference` error on functions expect(adapter[key]).toBeInstanceOf(Function) expect(JSON.stringify(adapter[key])).toEqual(JSON.stringify(value)) } else { expect(adapter[key]).toEqual(value) } }) }) test('if `engine === "classic"` configuration is provided, it should configure Prisma Migrate using the provided adapter', async () => { ctx.fixture('loadConfigFromFile/engine/classic') const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), 'prisma.config.ts')) expect(error).toBeUndefined() assertConfigDefined(config) assertConfigWithEngineClassic(config) expect(config.datasource).toMatchObject({ url: 'postgresql://DATABASE_URL', directUrl: 'https://DIRECT_DATABASE_URL', shadowDatabaseUrl: 'postgresql://SHADOW_DATABASE_URL', }) }) }) }) describe('paths', () => { it('supports relative paths', async () => { ctx.fixture('loadConfigFromFile/relative-paths') const cwd = ctx.fs.cwd() const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(cwd, 'prisma.config.ts')) expect(error).toBeUndefined() expect(config).toMatchObject({ loadedFromFile: resolvedPath, schema: path.join(cwd, 'custom', 'schema.prisma'), migrations: { path: path.join(cwd, 'custom', 'migrations'), }, typedSql: { path: path.join(cwd, 'custom', 'typedSql'), }, views: { path: path.join(cwd, 'custom', 'views'), }, }) }, 15_000) // Somehow, this test is flaky on Windows, so we increase the timeout it('supports absolute paths', async () => { ctx.fixture('loadConfigFromFile/absolute-paths') const cwd = ctx.fs.cwd() const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(cwd, 'prisma.config.ts')) expect(error).toBeUndefined() expect(config).toMatchObject({ loadedFromFile: resolvedPath, schema: path.join(cwd, 'custom', 'schema.prisma'), migrations: { path: path.join(cwd, 'custom', 'migrations'), }, typedSql: { path: path.join(cwd, 'custom', 'typedSql'), }, views: { path: path.join(cwd, 'custom', 'views'), }, }) }, 15_000) // Somehow, this test is flaky on Windows, so we increase the timeout }) describe('tables', () => { it('loads tables config', async () => { ctx.fixture('loadConfigFromFile/tables') const { config, error } = await loadConfigFromFile({}) expect(config).toMatchObject({ tables: { external: ['table1', 'specific_schema.table2'], }, }) expect(error).toBeUndefined() }) }) describe('enums', () => { it('loads enums config', async () => { ctx.fixture('loadConfigFromFile/enums') const { config, error } = await loadConfigFromFile({}) expect(config).toMatchObject({ enums: { external: ['some_enum'], }, }) expect(error).toBeUndefined() }) }) describe('migrations', () => { it('loads initShadowDb', async () => { ctx.fixture('loadConfigFromFile/setup-external-tables') const { config, error } = await loadConfigFromFile({}) expect(config).toMatchObject({ migrations: { initShadowDb: `CREATE TABLE "User" ("id" SERIAL PRIMARY KEY, "name" TEXT NOT NULL);`, }, }) expect(error).toBeUndefined() }) }) describe('schema', () => { describe('single', () => { it('succeeds when it points to a single Prisma schema file that exists via an absolute path', async () => { ctx.fixture('loadConfigFromFile/schema/single-exists') const cwd = ctx.fs.cwd() const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(cwd, 'prisma.config.ts')) expect(error).toBeUndefined() expect(config).toMatchObject({ loadedFromFile: resolvedPath, schema: path.join(cwd, 'prisma', 'schema.prisma'), }) }) it('[.config/prisma.ts] succeeds when it points to a single Prisma schema file that exists via an absolute path', async () => { ctx.fixture('loadConfigFromFile/schema/with-config-dir-proposal/single-exists') const cwd = ctx.fs.cwd() const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(cwd, '.config', 'prisma.ts')) expect(error).toBeUndefined() expect(config).toMatchObject({ loadedFromFile: resolvedPath, schema: path.join(cwd, 'prisma', 'schema.prisma'), }) }) it('succeeds when it points to a single Prisma schema file that exists via a relative path', async () => { ctx.fixture('loadConfigFromFile/schema/single-exists-relative') const cwd = ctx.fs.cwd() const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(cwd, 'prisma.config.ts')) expect(error).toBeUndefined() expect(config).toMatchObject({ loadedFromFile: resolvedPath, schema: path.join(cwd, 'prisma', 'schema.prisma'), }) }) it('[.config/prisma.ts] succeeds when it points to a single Prisma schema file that exists via a relative path', async () => { ctx.fixture('loadConfigFromFile/schema/with-config-dir-proposal/single-exists-relative') const cwd = ctx.fs.cwd() const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(cwd, '.config', 'prisma.ts')) expect(error).toBeUndefined() expect(config).toMatchObject({ loadedFromFile: resolvedPath, schema: path.join(cwd, 'prisma', 'schema.prisma'), }) }) it('succeeds when it points to a single Prisma schema file that does not exists', async () => { ctx.fixture('loadConfigFromFile/schema/single-does-not-exist') const cwd = ctx.fs.cwd() const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(cwd, 'prisma.config.ts')) expect(error).toBeUndefined() expect(config).toMatchObject({ loadedFromFile: resolvedPath, schema: path.join(cwd, 'prisma', 'schema.prisma'), }) }) }) describe('multi', () => { it('succeeds when it points to multiple Prisma schema files that exist via an absolute path', async () => { ctx.fixture('loadConfigFromFile/schema/multi-exist') const cwd = ctx.fs.cwd() const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(cwd, 'prisma.config.ts')) expect(error).toBeUndefined() expect(config).toMatchObject({ loadedFromFile: resolvedPath, schema: path.join(cwd, 'prisma', 'schema'), }) }) it('[.config/prisma.ts] succeeds when it points to multiple Prisma schema files that exist via an absolute path', async () => { ctx.fixture('loadConfigFromFile/schema/with-config-dir-proposal/multi-exist') const cwd = ctx.fs.cwd() const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(cwd, '.config', 'prisma.ts')) expect(error).toBeUndefined() expect(config).toMatchObject({ loadedFromFile: resolvedPath, schema: path.join(cwd, 'prisma', 'schema'), }) }) it('succeeds when it points to multiple Prisma schema files that exist via a relative path ', async () => { ctx.fixture('loadConfigFromFile/schema/multi-exist-relative') const cwd = ctx.fs.cwd() const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(cwd, 'prisma.config.ts')) expect(error).toBeUndefined() expect(config).toMatchObject({ loadedFromFile: resolvedPath, schema: path.join(cwd, 'prisma', 'schema'), }) }) it('[.config/prisma.ts] succeeds when it points to multiple Prisma schema files that exist via a relative path ', async () => { ctx.fixture('loadConfigFromFile/schema/with-config-dir-proposal/multi-exist-relative') const cwd = ctx.fs.cwd() const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(cwd, '.config', 'prisma.ts')) expect(error).toBeUndefined() expect(config).toMatchObject({ loadedFromFile: resolvedPath, schema: path.join(cwd, 'prisma', 'schema'), }) }) it('succeeds when it points to multiple Prisma schema files that do not exist', async () => { ctx.fixture('loadConfigFromFile/schema/multi-do-not-exist') const cwd = ctx.fs.cwd() const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(cwd, 'prisma.config.ts')) expect(error).toBeUndefined() expect(config).toMatchObject({ loadedFromFile: resolvedPath, schema: path.join(cwd, 'prisma', 'schema'), }) }) it('[.config/prisma.ts] succeeds when it points to multiple Prisma schema files that do not exist', async () => { ctx.fixture('loadConfigFromFile/schema/with-config-dir-proposal/multi-do-not-exist') const cwd = ctx.fs.cwd() const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(cwd, '.config', 'prisma.ts')) expect(error).toBeUndefined() expect(config).toMatchObject({ loadedFromFile: resolvedPath, schema: path.join(cwd, 'prisma', 'schema'), }) }) }) }) describe('invalid', () => { it('fails with `ConfigLoadError` when the Prisma config file has a syntax error', async () => { ctx.fixture('loadConfigFromFile/invalid/syntax-error') const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), 'prisma.config.ts')) expect(config).toBeUndefined() assertErrorConfigLoadError(error) const { message: errorMessage } = error.error const { normalisedPath } = (() => { if (process.platform === 'win32') { const actualPath = resolvedPath.replace(/\\/g, '/') return { normalisedPath: actualPath } } else { return { normalisedPath: resolvedPath } } })() expect(errorMessage).toContain('ParseError:') expect(errorMessage).toContain('Unexpected token') expect(errorMessage).toContain(normalisedPath) }) // TODO: if we want to support the behavior of this test suite, we need c12@2.0.1, jiti@2.2.0, or we need to patch // https://github.com/unjs/c12/blob/1efbcbce0e094a8f8a0ba676324affbef4a0ba8b/src/loader.ts#L401-L403 to remove // `{ default: true }` from `jiti!.import(...)` and explicitly look for `configModule['default']` in `loadConfigFromFile`. describe.skip('default-export', () => { it('fails with `ConfigFileSyntaxError` when the Prisma config file has no default export', async () => { ctx.fixture('loadConfigFromFile/invalid/no-default-export') // const { createJiti } = await import('jiti') // const jiti = createJiti(path.join(ctx.fs.cwd(), 'prisma.config'), { // interopDefault: false, // moduleCache: false, // extensions: ['.ts', '.mts', '.cts', '.js', '.mjs', '.cjs'], // }) // const modDefault = await jiti.import(path.join(ctx.fs.cwd(), 'prisma.config'), { default: true }) // expect(modDefault).toEqual({}) // const mod = await jiti.import(path.join(ctx.fs.cwd(), 'prisma.config')) // expect(mod).toEqual({}) // // @ts-ignore // expect(mod['default']).toBeUndefined() const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), 'prisma.config.ts')) expect(config).toBeUndefined() assertErrorConfigFileSyntaxError(error) expect(error.error.message.replaceAll(resolvedPath!, '<prisma-config>.ts')).toMatchInlineSnapshot( `"Expected { readonly schema?: string | undefined; readonly studio?: { readonly adapter: SqlMigrationAwareDriverAdapterFactory } | undefined; readonly migrations?: { readonly path?: string | undefined; readonly initShadowDb?: initShadowDb | undefined } | undefined; readonly tables?: { readonly external?: ReadonlyArray<string> | undefined } | undefined; readonly views?: { readonly path?: string | undefined } | undefined; readonly typedSql?: { readonly path?: string | undefined } | undefined; readonly adapter?: ErrorCapturingSqlMigrationAwareDriverAdapterFactory | undefined; readonly loadedFromFile: string | null }, actual undefined"`, ) }) it(`fails with \`ConfigFileSyntaxError\` when the default export in the Prisma config file does not conform to the expected schema shape`, async () => { ctx.fixture('loadConfigFromFile/invalid/no-schema-shape-conformance') const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), 'prisma.config.ts')) expect(config).toBeUndefined() assertErrorConfigFileSyntaxError(error) expect(error.error.message.replaceAll(resolvedPath!, '<prisma-config>.ts')).toMatchInlineSnapshot(` "{ readonly schema?: string | undefined; readonly studio?: { readonly adapter: SqlMigrationAwareDriverAdapterFactory } | undefined; readonly migrations?: { readonly path?: string | undefined; readonly initShadowDb?: initShadowDb | undefined } | undefined; readonly tables?: { readonly external?: ReadonlyArray<string> | undefined } | undefined; readonly views?: { readonly path?: string | undefined } | undefined; readonly typedSql?: { readonly path?: string | undefined } | undefined; readonly adapter?: ErrorCapturingSqlMigrationAwareDriverAdapterFactory | undefined; readonly loadedFromFile: string | null } └─ ["thisShouldFail"] └─ is unexpected, expected: "schema" | "studio" | "migrations" | "tables" | "views" | "typedSql" | "adapter" | "loadedFromFile"" `) }) }) }) describe('precedence', () => { it('prisma.config.js is 1st choice', async () => { ctx.fixture('loadConfigFromFile/precedence') const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), 'prisma.config.js')) expect(error).toBeUndefined() expect(config).toMatchObject({ loadedFromFile: resolvedPath, }) }) it('prisma.config.ts is 2nd choice', async () => { ctx.fixture('loadConfigFromFile/precedence') await ctx.fs.removeAsync('prisma.config.js') const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), 'prisma.config.ts')) expect(error).toBeUndefined() expect(config).toMatchObject({ loadedFromFile: resolvedPath, }) }) it('prisma.config.mjs is 3rd choice', async () => { ctx.fixture('loadConfigFromFile/precedence') await Promise.all([ctx.fs.removeAsync('prisma.config.js'), ctx.fs.removeAsync('prisma.config.ts')]) const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), 'prisma.config.mjs')) expect(error).toBeUndefined() expect(config).toMatchObject({ loadedFromFile: resolvedPath, }) }) it('prisma.config.cjs is 4th choice', async () => { ctx.fixture('loadConfigFromFile/precedence') await Promise.all([ ctx.fs.removeAsync('prisma.config.js'), ctx.fs.removeAsync('prisma.config.ts'), ctx.fs.removeAsync('prisma.config.mjs'), ]) const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), 'prisma.config.cjs')) expect(error).toBeUndefined() expect(config).toMatchObject({ loadedFromFile: resolvedPath, }) }) it('prisma.config.mts is 5th choice', async () => { ctx.fixture('loadConfigFromFile/precedence') await Promise.all([ ctx.fs.removeAsync('prisma.config.js'), ctx.fs.removeAsync('prisma.config.ts'), ctx.fs.removeAsync('prisma.config.mjs'), ctx.fs.removeAsync('prisma.config.cjs'), ]) const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), 'prisma.config.mts')) expect(error).toBeUndefined() expect(config).toMatchObject({ loadedFromFile: resolvedPath, }) }) it('prisma.config.cts is 6th choice', async () => { ctx.fixture('loadConfigFromFile/precedence') await Promise.all([ ctx.fs.removeAsync('prisma.config.js'), ctx.fs.removeAsync('prisma.config.ts'), ctx.fs.removeAsync('prisma.config.mjs'), ctx.fs.removeAsync('prisma.config.cjs'), ctx.fs.removeAsync('prisma.config.mts'), ]) const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), 'prisma.config.cts')) expect(error).toBeUndefined() expect(config).toMatchObject({ loadedFromFile: resolvedPath, }) }) // Note: As of c12@3.1.0, it tries loading `.json` even when such extension is excluded // from `jiti` or `jitiOptions.extensions`. // See: https://github.com/unjs/c12/blob/1efbcbce0e094a8f8a0ba676324affbef4a0ba8b/src/loader.ts#L443. it('prisma.config.json is 7th choice', async () => { ctx.fixture('loadConfigFromFile/precedence') await Promise.all([ ctx.fs.removeAsync('prisma.config.js'), ctx.fs.removeAsync('prisma.config.ts'), ctx.fs.removeAsync('prisma.config.mjs'), ctx.fs.removeAsync('prisma.config.cjs'), ctx.fs.removeAsync('prisma.config.mts'), ctx.fs.removeAsync('prisma.config.cts'), ]) const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), 'prisma.config.json')) expect(error).toMatchObject({ _tag: 'ConfigLoadError', error: { message: expect.stringContaining('Unsupported Prisma config file extension: .json'), }, }) expect(config).toBeUndefined() }) // Note: As of c12@3.1.0, it tries loading `.jsonc` even when such extension is excluded // from `jiti` or `jitiOptions.extensions`. // This is because there's currently no way to exclude confbox options. // See: https://github.com/unjs/c12/blob/1efbcbce0e094a8f8a0ba676324affbef4a0ba8b/src/loader.ts#L44-L49. it('prisma.config.jsonc is 8th choice', async () => { ctx.fixture('loadConfigFromFile/precedence') await Promise.all([ ctx.fs.removeAsync('prisma.config.js'), ctx.fs.removeAsync('prisma.config.ts'), ctx.fs.removeAsync('prisma.config.mjs'), ctx.fs.removeAsync('prisma.config.cjs'), ctx.fs.removeAsync('prisma.config.mts'), ctx.fs.removeAsync('prisma.config.cts'), ctx.fs.removeAsync('prisma.config.json'), ]) const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), 'prisma.config.jsonc')) expect(error).toMatchObject({ _tag: 'ConfigLoadError', error: { message: expect.stringContaining('Unsupported Prisma config file extension: .jsonc'), }, }) expect(config).toBeUndefined() }) it('.config/prisma.js is chosen when no other `prisma.config.*` exists', async () => { ctx.fixture('loadConfigFromFile/precedence') await Promise.all([ ctx.fs.removeAsync('prisma.config.js'), ctx.fs.removeAsync('prisma.config.ts'), ctx.fs.removeAsync('prisma.config.mjs'), ctx.fs.removeAsync('prisma.config.cjs'), ctx.fs.removeAsync('prisma.config.mts'), ctx.fs.removeAsync('prisma.config.cts'), ctx.fs.removeAsync('prisma.config.json'), ctx.fs.removeAsync('prisma.config.jsonc'), ]) const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), '.config', 'prisma.js')) expect(error).toBeUndefined() expect(config).toMatchObject({ loadedFromFile: resolvedPath, }) }) }) describe('default-location', () => { describe.each(SUPPORTED_EXTENSIONS)(`extension: %s`, (extension) => { it('succeeds when the Prisma config file exists and is in a valid format', async () => { ctx.fixture(`loadConfigFromFile/default-location/${extension.slice(1)}`) const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), `prisma.config${extension}`)) expect(config).toMatchObject({ loadedFromFile: resolvedPath, }) expect(error).toBeUndefined() }) it('succeeds when the explicitly specified Prisma config file exists and is in a valid format', async () => { ctx.fixture(`loadConfigFromFile/default-location/${extension.slice(1)}`) const { config, error, resolvedPath } = await loadConfigFromFile({ configFile: `prisma.config${extension}` }) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), `prisma.config${extension}`)) expect(error).toBeUndefined() expect(config).toMatchObject({ loadedFromFile: resolvedPath, }) }) }) describe('.config', () => { it('succeeds when the Prisma config file exists and is in a valid format', async () => { ctx.fixture(`loadConfigFromFile/default-location/with-config-dir-proposal`) const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(error).toBeUndefined() expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), '.config', 'prisma.ts')) expect(config).toMatchObject({ loadedFromFile: resolvedPath, }) }) it('succeeds when the explicitly specified Prisma config file exists and is in a valid format', async () => { ctx.fixture(`loadConfigFromFile/default-location/with-config-dir-proposal`) const { config, error, resolvedPath } = await loadConfigFromFile({ configFile: path.join(ctx.fs.cwd(), '.config', 'prisma.ts'), }) expect(error).toBeUndefined() expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), '.config', 'prisma.ts')) expect(config).toMatchObject({ loadedFromFile: resolvedPath, }) }) }) it('fails when trying to load a .json config file', async () => { ctx.fixture('loadConfigFromFile/default-location/json') const { config, error, resolvedPath } = await loadConfigFromFile({ configFile: 'prisma.config.json' }) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), 'prisma.config.json')) expect(config).toBeUndefined() expect(error).toMatchObject({ _tag: 'ConfigLoadError', error: { message: expect.stringContaining('Unsupported Prisma config file extension: .json'), }, }) }) it('fails when trying to load a .rc config file', async () => { ctx.fixture('loadConfigFromFile/default-location/rc') const { config, error, resolvedPath } = await loadConfigFromFile({ configFile: 'prisma.config.rc' }) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), 'prisma.config.rc')) expect(config).toBeUndefined() expect(error).toMatchObject({ _tag: 'ConfigLoadError', error: { message: expect.stringContaining('Unknown file extension ".rc"'), }, }) }) it('fails when the explicitly specified Prisma config file does not exist', async () => { ctx.fixture('loadConfigFromFile/default-location/ts') const { config, error, resolvedPath } = await loadConfigFromFile({ configFile: 'prisma.config.js' }) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), 'prisma.config.js')) expect(config).toBeUndefined() expect(error).toMatchObject({ _tag: 'ConfigFileNotFound', }) }) it('returns default config when the Prisma config file does not exist', async () => { ctx.fixture('loadConfigFromFile/default-location/ignore') const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toBeNull() expect(error).toBeUndefined() expect(config).toMatchObject(defaultConfig()) }) }) describe('custom-location', () => { beforeEach(() => { ctx.fixture('loadConfigFromFile/custom-location') }) it('fails when the given file does not exist', async () => { const customConfigPath = path.join('does', 'not', 'exist.ts') const { config, error, resolvedPath } = await loadConfigFromFile({ configFile: customConfigPath, }) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), customConfigPath)) expect(error).toMatchObject({ _tag: 'ConfigFileNotFound' }) expect(config).toBeUndefined() }) it('succeeds when TypeScript file exists and is in a valid format', async () => { const customConfigPath = path.join('valid', 'prisma-config.ts') const { config, error, resolvedPath } = await loadConfigFromFile({ configFile: customConfigPath, }) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), customConfigPath)) expect(error).toBeUndefined() expect(config).toMatchObject({ loadedFromFile: resolvedPath, }) }) }) it('typescript-cjs-ext-ts', async () => { ctx.fixture('loadConfigFromFile/typescript-cjs-ext-ts') const expectedAdapter = mockMigrationAwareAdapterFactory('postgres') const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), 'prisma.config.ts')) expect(config).toMatchObject({ experimental: { studio: true, }, studio: { adapter: expect.any(Function), }, loadedFromFile: resolvedPath, }) expect(error).toBeUndefined() if (!config?.studio) { throw new Error('Expected config.studio to be defined') } const { adapter: adapterFactory } = config.studio expect(adapterFactory).toBeDefined() // @ts-ignore const adapter = await adapterFactory(process.env) expect(JSON.stringify(adapter)).toEqual(JSON.stringify(expectedAdapter)) expect(adapter).toBeDefined() expect(adapter.provider).toEqual('postgres') }) it('typescript-esm-ext-ts', async () => { ctx.fixture('loadConfigFromFile/typescript-esm-ext-ts') const expectedAdapter = mockMigrationAwareAdapterFactory('postgres') const { config, error, resolvedPath } = await loadConfigFromFile({}) expect(resolvedPath).toMatch(path.join(ctx.fs.cwd(), 'prisma.config.ts')) expect(config).toMatchObject({ experimental: { studio: true, }, studio: { adapter: expect.any(Function), }, loadedFromFile: resolvedPath, }) expect(error).toBeUndefined() if (!config?.studio) { throw new Error('Expected config.studio to be defined') } const { adapter: adapterFactory } = config.studio expect(adapterFactory).toBeDefined() // @ts-ignore const adapter = await adapterFactory(process.env) expect(JSON.stringify(adapter)).toEqual(JSON.stringify(expectedAdapter)) expect(adapter).toBeDefined() expect(adapter.provider).toEqual('postgres') }) describe('environment variables', () => { function assertLoadConfigFromFileErrorIsUndefined( error: LoadConfigFromFileError | undefined, ): asserts error is undefined { expect(error).toBeUndefined() } test('if no custom env-var loading function is imported, it should skip loading any environment variables', async () => { vi.stubEnv('TEST_CONNECTION_STRING', undefined) ctx.fixture('loadConfigFromFile/env-baseline') const { config, error } = await loadConfigFromFile({}) assertLoadConfigFromFileErrorIsUndefined(error) expect(config).toMatchObject({}) expect(process.env.TEST_CONNECTION_STRING).toBeUndefined() }) test('if a sync custom env-var loading function is imported, it should load environment variables using the provided function', async () => { vi.stubEnv('TEST_CONNECTION_STRING', undefined) ctx.fixture('loadConfigFromFile/env-load-cjs') const { config, error } = await loadConfigFromFile({}) assertLoadConfigFromFileErrorIsUndefined(error) expect(config).toMatchObject({}) expect(process.env.TEST_CONNECTION_STRING).toEqual('postgres://test-connection-string-from-env-cjs') }) test('if an async custom env-var loading function is used, it should load environment variables using the provided function', async () => { ctx.fixture('loadConfigFromFile/env-load-esm') const { config, error, resolvedPath } = await loadConfigFromFile({}) assertLoadConfigFromFileErrorIsUndefined(error) expect(config).toMatchObject({ loadedFromFile: resolvedPath, }) expect(process.env.TEST_CONNECTION_STRING).toEqual('postgres://test-connection-string-from-env-esm') }) }) })

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/prisma/prisma'

If you have feedback or need assistance with the MCP directory API, please join our Discord server