diff --git a/.changeset/gentle-flies-invent.md b/.changeset/gentle-flies-invent.md index 83245fdaafd..3ee45460f0a 100644 --- a/.changeset/gentle-flies-invent.md +++ b/.changeset/gentle-flies-invent.md @@ -1,6 +1,7 @@ --- '@keystone-next/keystone': major '@keystone-next/types': major +'@keystone-next/test-utils-legacy': patch --- -Removed the `none` case in `MigrationAction` and require that the PrismaClient is passed to be able to connect to the database for the `none-skip-client-generation` case. +Removed `migrationAction` argument to `createSystem` and require that the PrismaClient is passed to `createSystem` to be able to connect to the database. diff --git a/.changeset/great-tables-juggle.md b/.changeset/great-tables-juggle.md new file mode 100644 index 00000000000..ebb3eb8b286 --- /dev/null +++ b/.changeset/great-tables-juggle.md @@ -0,0 +1,6 @@ +--- +'@keystone-next/keystone': major +'@keystone-next/adapter-prisma-legacy': major +--- + +Removed `getDbSchemaName` and `getPrismaPath` database adapter options. To change the database schema that Keystone uses, you can add `?schema=whatever` to the database url. diff --git a/.changeset/two-owls-pump.md b/.changeset/two-owls-pump.md new file mode 100644 index 00000000000..51440564dc3 --- /dev/null +++ b/.changeset/two-owls-pump.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/adapter-prisma-legacy': major +--- + +Removed migrationMode and all migration related methods on the adapter and instead require that a prisma client is passed to the adapter to be able to connect to the database diff --git a/docs-next/pages/apis/config.mdx b/docs-next/pages/apis/config.mdx index f1e488f4fdf..731a8bdd25a 100644 --- a/docs-next/pages/apis/config.mdx +++ b/docs-next/pages/apis/config.mdx @@ -69,12 +69,8 @@ As well as these common options, each adapter supports a number of optional adva Advanced configuration: - `enableLogging` (default: `false`): Enable logging from the Prisma client. -- `getPrismaPath` (default: `() => '.keystone/prisma'` ): Set the location of the generated Prisma schema and client. -- `getDbSchemaName` (default: `() => 'public'` ): Set the schema named used in the database. - `useMigrations` (default: `false`): Determines whether to use migrations or automatically force-update the database with the latest schema and potentially lose data. -The functions for `getPrismaPath` and `getDbSchemaName` are each provided with the generated Prisma schema as a `string` in the `{ prismaSchema }` argument. - ```typescript export default config({ db: { @@ -83,8 +79,6 @@ export default config({ onConnect: async context => { /* ... */ }, // Optional advanced configuration enableLogging: true, - getPrismaPath: ({ prismaSchema }) => '.prisma', - getDbSchemaName: ({ prismaSchema }) => 'prisma', useMigrations: true, }, /* ... */ @@ -99,11 +93,8 @@ To use this option you must also set `{ experimental: { prismaSqlite: true } }`. Advanced configuration: - `enableLogging` (default: `false`): Enable logging from the Prisma client. -- `getPrismaPath` (default: `() => '.keystone/prisma'` ): Set the location of the generated Prisma schema and client. - `useMigrations` (default: `false`): Determines whether to use migrations or automatically force-update the database with the latest schema and potentially lose data. -The function for `getPrismaPath` is provided with the generated Prisma schema as a `string` in the `{ prismaSchema }` argument. - ```typescript export default config({ db: { @@ -112,7 +103,6 @@ export default config({ onConnect: async context => { /* ... */ }, // Optional advanced configuration enableLogging: true, - getPrismaPath: ({ prismaSchema }) => '.prisma', useMigrations: true, }, /* ... */ diff --git a/packages-next/keystone/src/lib/createKeystone.ts b/packages-next/keystone/src/lib/createKeystone.ts index 4e1f2a76652..22ae256b000 100644 --- a/packages-next/keystone/src/lib/createKeystone.ts +++ b/packages-next/keystone/src/lib/createKeystone.ts @@ -1,13 +1,9 @@ // @ts-ignore import { Keystone } from '@keystone-next/keystone-legacy'; import { PrismaAdapter } from '@keystone-next/adapter-prisma-legacy'; -import type { KeystoneConfig, BaseKeystone, MigrationAction } from '@keystone-next/types'; +import type { KeystoneConfig, BaseKeystone } from '@keystone-next/types'; -export function createKeystone( - config: KeystoneConfig, - migrationAction: MigrationAction, - prismaClient?: any -) { +export function createKeystone(config: KeystoneConfig, prismaClient?: any) { // Note: For backwards compatibility we may want to expose // this as a public API so that users can start their transition process // by using this pattern for creating their Keystone object before using @@ -16,8 +12,6 @@ export function createKeystone( let adapter; if (db.adapter === 'prisma_postgresql') { adapter = new PrismaAdapter({ - migrationMode: - migrationAction === 'dev' ? (db.useMigrations ? 'dev' : 'prototype') : migrationAction, prismaClient, ...db, provider: 'postgresql', @@ -30,8 +24,6 @@ export function createKeystone( } adapter = new PrismaAdapter({ prismaClient, - migrationMode: - migrationAction === 'dev' ? (db.useMigrations ? 'dev' : 'prototype') : migrationAction, ...db, provider: 'sqlite', }); diff --git a/packages-next/keystone/src/lib/createSystem.ts b/packages-next/keystone/src/lib/createSystem.ts index 564fa414577..dba9670d4c4 100644 --- a/packages-next/keystone/src/lib/createSystem.ts +++ b/packages-next/keystone/src/lib/createSystem.ts @@ -1,15 +1,11 @@ -import type { KeystoneConfig, MigrationAction } from '@keystone-next/types'; +import type { KeystoneConfig } from '@keystone-next/types'; import { createGraphQLSchema } from './createGraphQLSchema'; import { makeCreateContext } from './createContext'; import { createKeystone } from './createKeystone'; -export function createSystem( - config: KeystoneConfig, - migrationAction: MigrationAction, - prismaClient?: any -) { - const keystone = createKeystone(config, migrationAction, prismaClient); +export function createSystem(config: KeystoneConfig, prismaClient?: any) { + const keystone = createKeystone(config, prismaClient); const graphQLSchema = createGraphQLSchema(config, keystone, 'public'); diff --git a/packages-next/keystone/src/scripts/build/build.ts b/packages-next/keystone/src/scripts/build/build.ts index 000aaaaaa4a..c31349cb628 100644 --- a/packages-next/keystone/src/scripts/build/build.ts +++ b/packages-next/keystone/src/scripts/build/build.ts @@ -87,7 +87,7 @@ export async function build(cwd: string) { const config = initConfig(requireSource(CONFIG_PATH).default); - const { keystone, graphQLSchema } = createSystem(config, 'none-skip-client-generation'); + const { keystone, graphQLSchema } = createSystem(config); await validateCommittedArtifacts(graphQLSchema, keystone, cwd); diff --git a/packages-next/keystone/src/scripts/postinstall.ts b/packages-next/keystone/src/scripts/postinstall.ts index 6b5540ab1e7..79105db2f35 100644 --- a/packages-next/keystone/src/scripts/postinstall.ts +++ b/packages-next/keystone/src/scripts/postinstall.ts @@ -11,7 +11,7 @@ import { CONFIG_PATH } from './utils'; export async function postinstall(cwd: string, shouldFix: boolean) { const config = initConfig(requireSource(CONFIG_PATH).default); - const { keystone, graphQLSchema } = createSystem(config, 'none-skip-client-generation'); + const { keystone, graphQLSchema } = createSystem(config); if (shouldFix) { await generateCommittedArtifacts(graphQLSchema, keystone, cwd); diff --git a/packages-next/keystone/src/scripts/prisma.ts b/packages-next/keystone/src/scripts/prisma.ts index 53b983da7ac..1218386cb1c 100644 --- a/packages-next/keystone/src/scripts/prisma.ts +++ b/packages-next/keystone/src/scripts/prisma.ts @@ -8,7 +8,7 @@ import { CONFIG_PATH } from './utils'; export async function prisma(cwd: string, args: string[]) { const config = initConfig(requireSource(CONFIG_PATH).default); - const { keystone, graphQLSchema } = createSystem(config, 'none-skip-client-generation'); + const { keystone, graphQLSchema } = createSystem(config); await validateCommittedArtifacts(graphQLSchema, keystone, cwd); await generateNodeModulesArtifacts(graphQLSchema, keystone, cwd); diff --git a/packages-next/keystone/src/scripts/run/dev.ts b/packages-next/keystone/src/scripts/run/dev.ts index dc18152fba4..76f22bcb285 100644 --- a/packages-next/keystone/src/scripts/run/dev.ts +++ b/packages-next/keystone/src/scripts/run/dev.ts @@ -31,7 +31,7 @@ export const dev = async (cwd: string) => { const config = initConfig(requireSource(CONFIG_PATH).default); const initKeystone = async () => { { - const { keystone, graphQLSchema } = createSystem(config, 'none-skip-client-generation'); + const { keystone, graphQLSchema } = createSystem(config); console.log('✨ Generating GraphQL and Prisma schemas'); const prismaSchema = (await generateCommittedArtifacts(graphQLSchema, keystone, cwd)).prisma; @@ -48,11 +48,7 @@ export const dev = async (cwd: string) => { const prismaClient = requirePrismaClient(cwd); - const { keystone, graphQLSchema, createContext } = createSystem( - config, - 'none-skip-client-generation', - prismaClient - ); + const { keystone, graphQLSchema, createContext } = createSystem(config, prismaClient); console.log('✨ Connecting to the database'); await keystone.connect({ context: createContext().sudo() }); diff --git a/packages-next/keystone/src/scripts/run/start.ts b/packages-next/keystone/src/scripts/run/start.ts index d6e4875799d..7d430e14d4b 100644 --- a/packages-next/keystone/src/scripts/run/start.ts +++ b/packages-next/keystone/src/scripts/run/start.ts @@ -16,11 +16,7 @@ export const start = async (cwd: string) => { throw new Error('keystone-next build must be run before running keystone-next start'); } const config = initConfig(require(apiFile).config); - const { keystone, graphQLSchema, createContext } = createSystem( - config, - 'none-skip-client-generation', - requirePrismaClient(cwd) - ); + const { keystone, graphQLSchema, createContext } = createSystem(config, requirePrismaClient(cwd)); console.log('✨ Connecting to the database'); await keystone.connect({ context: createContext().sudo() }); diff --git a/packages-next/types/src/config/index.ts b/packages-next/types/src/config/index.ts index 362975add1b..60338a5d500 100644 --- a/packages-next/types/src/config/index.ts +++ b/packages-next/types/src/config/index.ts @@ -65,14 +65,11 @@ export type DatabaseConfig = DatabaseCommon & adapter: 'prisma_postgresql'; useMigrations?: boolean; enableLogging?: boolean; - getPrismaPath?: (arg: { prismaSchema: any }) => string; - getDbSchemaName?: (arg: { prismaSchema: any }) => string; } | { adapter: 'prisma_sqlite'; useMigrations?: boolean; enableLogging?: boolean; - getPrismaPath?: (arg: { prismaSchema: any }) => string; } ); diff --git a/packages-next/types/src/core.ts b/packages-next/types/src/core.ts index 0aecfdd0b96..7c05de22361 100644 --- a/packages-next/types/src/core.ts +++ b/packages-next/types/src/core.ts @@ -66,5 +66,3 @@ export function getGqlNames({ relateToOneInputName: `${_itemQueryName}RelateToOneInput`, }; } - -export type MigrationAction = 'none-skip-client-generation' | 'dev'; diff --git a/packages/adapter-prisma/README.md b/packages/adapter-prisma/README.md index 370be64edd8..a8c72c3814b 100644 --- a/packages/adapter-prisma/README.md +++ b/packages/adapter-prisma/README.md @@ -35,32 +35,12 @@ _**Default:**_ `DATABASE_URL` The connection string for your database, in the form `postgres://:@:/`. By default it will use the value of the environment variable `DATABASE_URL`. You can learn more about the connection string format used in the [Prisma docs](https://www.prisma.io/docs/reference/database-connectors/connection-urls). -### `getPrismaPath` - -_**Default:**_ `({ prismaSchema }) => '.prisma'` - -A function which returns a directory name for storing the generated Prisma schema and client. - -### `getDbSchemaName` - -_**Default:**_ `({ prismaSchema }) => 'public'` - -A function which returns a database schema name to use for storage of all Keystone tables in your database. - -> You can also set the schema name by including the suffix `?schema=...` in your `DATABASE_URL` or `url`. In this case you should set this value to `() => null`. - ### `enableLogging` _**Default:**_ `false` Enables logging at the [`query`](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/logging#overview) level in the Prisma client. -### `migrationMode` - -_**Default:**_ `'dev'` - -Controls how and when migrations are applied. One of `'dev'`, `'prototype'`, `'createOnly'`, or `'none'`. In `prototype` mode, `prisma db push` is used to sync the database tables without generating migration files. In `dev` mode, migrations files are generated and applied whenever the schema changes. In `createOnly` mode, migrations are generated but not applied. In `none` mode, no migrations are generated or applied. - ## Setup Before running Keystone with the Prisma adapter you will need to have a PostgreSQL database to connect to. diff --git a/packages/adapter-prisma/src/adapter-prisma.js b/packages/adapter-prisma/src/adapter-prisma.js index 0f53299ddff..b8f4ed357a7 100644 --- a/packages/adapter-prisma/src/adapter-prisma.js +++ b/packages/adapter-prisma/src/adapter-prisma.js @@ -1,29 +1,17 @@ -import fs from 'fs'; -import path from 'path'; import pWaterfall from 'p-waterfall'; -import { getGenerator, formatSchema } from '@prisma/sdk'; +import { formatSchema } from '@prisma/sdk'; import { defaultObj, mapKeys, identity, flatten } from '@keystone-next/utils-legacy'; -import { - runPrototypeMigrations, - devMigrations, - deployMigrations, - // eslint-disable-next-line import/no-unresolved -} from './migrations'; class PrismaAdapter { constructor(config = {}) { this.config = { ...config }; this.listAdapters = {}; this.listAdapterClass = undefined; - this._prismaClient = config.prismaClient; this.listAdapterClass = PrismaListAdapter; this.name = 'prisma'; this.provider = this.config.provider || 'postgresql'; - this.migrationMode = this.config.migrationMode || 'prototype'; - this.getPrismaPath = this.config.getPrismaPath || (() => '.prisma'); - this.getDbSchemaName = this.config.getDbSchemaName || (() => 'public'); this.enableLogging = this.config.enableLogging || false; this.url = this.config.url || process.env.DATABASE_URL; } @@ -70,45 +58,7 @@ class PrismaAdapter { } } - async _prepareSchema(rels) { - const clientDir = 'generated-client'; - const prismaSchema = await this._generatePrismaSchema({ rels, clientDir }); - // See if there is a prisma client available for this hash - const prismaPath = this.getPrismaPath({ prismaSchema }); - this.schemaPath = path.join(prismaPath, 'schema.prisma'); - this.clientPath = path.resolve(`${prismaPath}/${clientDir}`); - this.dbSchemaName = this.getDbSchemaName({ prismaSchema }); - this.prismaSchema = prismaSchema; - return { prismaSchema }; - } - - _url() { - // By default we put `schema=public` onto all `DATABASE_URL` values. - // If this isn't what a user wants, they can update `getSchemaName` to return either - // a different dbSchemaName, or null if they just want to use the DATABASE_URL as it is. - // TODO: Should we default to 'public' or null? - if (this.provider === 'postgresql') { - return this.dbSchemaName ? `${this.url}?schema=${this.dbSchemaName}` : this.url; - } else if (this.provider === 'sqlite') { - return this.url; - } - } - - async deploy(rels) { - // Apply any migrations which haven't already been applied - await this._prepareSchema(rels); - await deployMigrations(this._url(), path.resolve(this.schemaPath)); - } - - async _getPrismaClient({ rels }) { - if (this._prismaClient) { - return this._prismaClient; - } - await this._generateClient(rels); - return require(this.clientPath).PrismaClient; - } - - async _connect({ rels }) { + async _connect() { // the adapter was already connected since we have a prisma client // it may have been disconnected since it was connected though // so connect but don't regenerate the prisma client @@ -116,58 +66,17 @@ class PrismaAdapter { await this.prisma.$connect(); return; } - const PrismaClient = await this._getPrismaClient({ rels }); + if (!this.config.prismaClient) { + throw new Error('You must pass the prismaClient option to connect to a database'); + } + const PrismaClient = this.config.prismaClient; this.prisma = new PrismaClient({ log: this.enableLogging && ['query'], - datasources: { [this.provider]: { url: this._url() } }, + datasources: { [this.provider]: { url: this.url } }, }); await this.prisma.$connect(); } - async _generateClient(rels) { - // Generate a formatted schema - // note that we currently still need to call _prepareSchema even during - // a `keystone-next start` because it has various side effects - const { prismaSchema } = await this._prepareSchema(rels); - - if (this.migrationMode !== 'none-skip-client-generation') { - this._writePrismaSchema({ prismaSchema }); - - // Generate prisma client and run prisma migrations - await Promise.all([this._generatePrismaClient(), this._runMigrations({ prismaSchema })]); - } - } - - async _runMigrations({ prismaSchema }) { - if (this.migrationMode === 'prototype') { - // Sync the database directly, without generating any migration - await runPrototypeMigrations(this._url(), prismaSchema, path.resolve(this.schemaPath)); - } else if (this.migrationMode === 'dev') { - // Generate and apply a migration if required. - await devMigrations(this._url(), prismaSchema, path.resolve(this.schemaPath)); - } else if (this.migrationMode === 'none') { - // Explicitly disable running any migrations - } else { - throw new Error( - `migrationMode must be one of 'dev', 'prototype', 'none-skip-client-generation', or 'none` - ); - } - } - - async _writePrismaSchema({ prismaSchema }) { - // Make output dir (you know, just in case!) - fs.mkdirSync(this.clientPath, { recursive: true }); - - // Write prisma file - fs.writeSync(fs.openSync(this.schemaPath, 'w'), prismaSchema); - } - - async _generatePrismaClient() { - const generator = await getGenerator({ schemaPath: this.schemaPath }); - await generator.generate(); - generator.stop(); - } - async _generatePrismaSchema({ rels, clientDir }) { const models = Object.values(this.listAdapters).map(listAdapter => { const scalarFields = flatten( diff --git a/packages/test-utils/src/index.ts b/packages/test-utils/src/index.ts index 91993a66a70..0d62d2fa8b6 100644 --- a/packages/test-utils/src/index.ts +++ b/packages/test-utils/src/index.ts @@ -26,7 +26,6 @@ const hashPrismaSchema = memoizeOne(prismaSchema => const argGenerator = { prisma_postgresql: () => ({ - migrationMode: 'none-skip-client-generation', url: process.env.DATABASE_URL!, provider: 'postgresql', getDbSchemaName: () => null as any, @@ -34,7 +33,6 @@ const argGenerator = { enableLogging: false, }), prisma_sqlite: () => ({ - migrationMode: 'none-skip-client-generation', url: process.env.DATABASE_URL!, provider: 'sqlite', // Turn this on if you need verbose debug info @@ -70,7 +68,7 @@ async function setupFromConfig({ const config = initConfig({ ..._config, db: db!, ui: { isDisabled: true } }); const prismaClient = await (async () => { - const { keystone, graphQLSchema } = createSystem(config, 'none-skip-client-generation'); + const { keystone, graphQLSchema } = createSystem(config); const artifacts = await getCommittedArtifacts(graphQLSchema, keystone); const hash = hashPrismaSchema(artifacts.prisma); if (adapterName === 'prisma_postgresql') { @@ -92,11 +90,7 @@ async function setupFromConfig({ return requirePrismaClient(cwd); })(); - const { keystone, createContext, graphQLSchema } = createSystem( - config, - 'none-skip-client-generation', - prismaClient - ); + const { keystone, createContext, graphQLSchema } = createSystem(config, prismaClient); const app = await createExpressServer(config, graphQLSchema, createContext, true, '', false);