Skip to content

Commit

Permalink
fix(deps): update prisma monorepo to v4 (major) (#7671)
Browse files Browse the repository at this point in the history
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: mitchellhamilton <mitchell@hamil.town>
Co-authored-by: Daniel Cousens <413395+dcousens@users.noreply.github.com>
Co-authored-by: Daniel Cousens <dcousens@users.noreply.github.com>
  • Loading branch information
4 people authored Aug 22, 2022
1 parent 48b3170 commit c06c5d6
Show file tree
Hide file tree
Showing 17 changed files with 274 additions and 258 deletions.
5 changes: 5 additions & 0 deletions .changeset/great-sloths-bake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@keystone-6/core': major
---

Updates Prisma to 4.2.1
6 changes: 6 additions & 0 deletions .changeset/slow-games-greet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@keystone-6/core': major
---

Changes the return type for the `resolveInput` hook with `json` fields. Previously you may have used `'DbNull'` or `'JsonNull'` as respective null magic values - you can now always use a Javascript `null` value.
Unlike previous behaviour, a null value will now consistently map to a `Prisma.DbNull`.
9 changes: 5 additions & 4 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@
"@keystone-ui/tooltip": "^6.0.1",
"@nodelib/fs.walk": "^1.2.8",
"@preconstruct/next": "^4.0.0",
"@prisma/client": "3.14.0",
"@prisma/migrate": "3.14.0",
"@prisma/sdk": "3.14.0",
"@prisma/client": "4.2.1",
"@prisma/internals": "4.2.1",
"@prisma/migrate": "4.2.1",
"@sindresorhus/slugify": "^1.1.2",
"@types/apollo-upload-client": "17.0.1",
"@types/bcryptjs": "^2.4.2",
Expand Down Expand Up @@ -113,13 +113,14 @@
"pirates": "4.0.4",
"pluralize": "^8.0.0",
"prettier": "^2.5.0",
"prisma": "3.14.0",
"prisma": "4.2.1",
"prompts": "^2.4.2",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"resolve": "^1.20.0",
"source-map-support": "^0.5.20",
"supertest": "^6.1.6",
"ts-toolbelt": "^9.6.0",
"uid-safe": "^2.1.5",
"uuid": "^8.3.2"
},
Expand Down
28 changes: 19 additions & 9 deletions packages/core/src/artifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import path from 'path';
import { createRequire } from 'module';
import { printSchema, GraphQLSchema } from 'graphql';
import * as fs from 'fs-extra';
import { getGenerator, formatSchema } from '@prisma/sdk';
import { getGenerator, formatSchema } from '@prisma/internals';
import { format } from 'prettier';
import type { KeystoneConfig } from './types';
import { confirmPrompt, shouldPrompt } from './lib/prompts';
Expand Down Expand Up @@ -54,17 +54,17 @@ async function ensurePrismaBinariesExist() {
// ensureBinariesExist does a bunch of slightly expensive things
// so if we can avoid running it a bunch in tests, that's ideal
if (hasEnsuredBinariesExist) return;
// we're resolving @prisma/engines from @prisma/sdk
// we're resolving @prisma/engines from @prisma/internals
// because we don't want to depend on @prisma/engines
// since its version includes a commit hash from https://github.com/prisma/prisma-engines
// and we just want to use whatever version @prisma/sdk is using
// also note we use an exact version of @prisma/sdk
// so if @prisma/sdk suddenly stops depending on @prisma/engines
// and we just want to use whatever version @prisma/internals is using
// also note we use an exact version of @prisma/internals
// so if @prisma/internals suddenly stops depending on @prisma/engines
// that won't break a released version of Keystone
// also, we're not just directly importing @prisma/engines
// since stricter package managers(e.g. pnpm, Yarn Berry)
// don't allow importing packages that aren't explicitly depended on
const requireFromPrismaSdk = createRequire(require.resolve('@prisma/sdk'));
const requireFromPrismaSdk = createRequire(require.resolve('@prisma/internals'));
const prismaEngines = requireFromPrismaSdk('@prisma/engines') as typeof import('@prisma/engines');
await prismaEngines.ensureBinariesExist();
hasEnsuredBinariesExist = true;
Expand Down Expand Up @@ -248,7 +248,10 @@ export async function generateNodeModulesArtifacts(
}

async function generatePrismaClient(cwd: string) {
const generator = await getGenerator({ schemaPath: getSchemaPaths(cwd).prisma });
const generator = await getGenerator({
schemaPath: getSchemaPaths(cwd).prisma,
dataProxy: false,
});
try {
await generator.generate();
} finally {
Expand All @@ -264,6 +267,13 @@ async function generatePrismaClient(cwd: string) {
}
}

export function requirePrismaClient(cwd: string) {
return require(path.join(cwd, 'node_modules/.prisma/client')).PrismaClient;
export type PrismaModule = {
PrismaClient: {
new (args: unknown): any;
};
Prisma: { DbNull: unknown; JsonNull: unknown; [key: string]: unknown };
};

export function requirePrismaClient(cwd: string): PrismaModule {
return require(path.join(cwd, 'node_modules/.prisma/client'));
}
14 changes: 3 additions & 11 deletions packages/core/src/fields/types/json/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,6 @@ export const json =
throw Error("isIndexed: 'unique' is not a supported option for field type json");
}

const resolve = (val: JSONValue | undefined) =>
val === null && (meta.provider === 'postgresql' || meta.provider === 'mysql')
? 'DbNull'
: val;

return jsonFieldTypePolyfilledForSQLite(
meta.provider,
{
Expand All @@ -37,10 +32,10 @@ export const json =
create: {
arg: graphql.arg({ type: graphql.JSON }),
resolve(val) {
return resolve(val === undefined ? defaultValue : val);
return val === undefined ? defaultValue : val;
},
},
update: { arg: graphql.arg({ type: graphql.JSON }), resolve },
update: { arg: graphql.arg({ type: graphql.JSON }) },
},
output: graphql.field({ type: graphql.JSON }),
views: resolveView('json/views'),
Expand All @@ -50,10 +45,7 @@ export const json =
default:
defaultValue === null
? undefined
: {
kind: 'literal',
value: JSON.stringify(defaultValue),
},
: { kind: 'literal', value: JSON.stringify(defaultValue) },
map: config.db?.map,
}
);
Expand Down
26 changes: 22 additions & 4 deletions packages/core/src/lib/core/mutations/create-update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
IdType,
runWithPrisma,
getWriteLimit,
getPrismaNamespace,
} from '../utils';
import { InputFilter, resolveUniqueWhereInput, UniqueInputFilter } from '../where-inputs';
import {
Expand Down Expand Up @@ -363,7 +364,7 @@ async function resolveInputForCreateOrUpdate(
// Return the full resolved input (ready for prisma level operation),
// and the afterOperation hook to be applied
return {
data: transformForPrismaClient(list.fields, hookArgs.resolvedData),
data: transformForPrismaClient(list.fields, hookArgs.resolvedData, context),
afterOperation: async (updatedItem: BaseItem) => {
await nestedMutationState.afterOperation();
await runSideEffectOnlyHook(
Expand All @@ -381,19 +382,36 @@ async function resolveInputForCreateOrUpdate(
};
}

function transformInnerDBField(
dbField: Exclude<ResolvedDBField, { kind: 'multi' }>,
context: KeystoneContext,
value: unknown
) {
if (dbField.kind === 'scalar' && dbField.scalar === 'Json' && value === null) {
const Prisma = getPrismaNamespace(context);
return Prisma.DbNull;
}
return value;
}

function transformForPrismaClient(
fields: Record<string, { dbField: ResolvedDBField }>,
data: Record<string, any>
data: Record<string, any>,
context: KeystoneContext
) {
return Object.fromEntries(
Object.entries(data).flatMap(([fieldKey, value]) => {
const { dbField } = fields[fieldKey];
if (dbField.kind === 'multi') {
return Object.entries(value).map(([innerFieldKey, fieldValue]) => {
return [getDBFieldKeyForFieldOnMultiField(fieldKey, innerFieldKey), fieldValue];
return [
getDBFieldKeyForFieldOnMultiField(fieldKey, innerFieldKey),
transformInnerDBField(dbField.fields[innerFieldKey], context, fieldValue),
];
});
}
return [[fieldKey, value]];

return [[fieldKey, transformInnerDBField(dbField, context, value)]];
})
);
}
25 changes: 21 additions & 4 deletions packages/core/src/lib/core/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Limit } from 'p-limit';
import pluralize from 'pluralize';
import { PrismaModule } from '../../artifacts';
import { BaseItem, KeystoneConfig, KeystoneContext } from '../../types';
import { humanize } from '../utils';
import { prismaError } from './graphql-errors';
Expand Down Expand Up @@ -164,16 +165,32 @@ export function getDBFieldKeyForFieldOnMultiField(fieldKey: string, subField: st
// because even across requests, we want to apply the limit on SQLite
const writeLimits = new WeakMap<object, Limit>();

export const setWriteLimit = (prismaClient: object, limit: Limit) => {
export function setWriteLimit(prismaClient: object, limit: Limit) {
writeLimits.set(prismaClient, limit);
};
}

// this accepts the context instead of the prisma client because the prisma client on context is `any`
// so by accepting the context, it'll be less likely the wrong thing will be passed.
export const getWriteLimit = (context: KeystoneContext) => {
export function getWriteLimit(context: KeystoneContext) {
const limit = writeLimits.get(context.prisma);
if (limit === undefined) {
throw new Error('unexpected write limit not set for prisma client');
}
return limit;
};
}

const prismaNamespaces = new WeakMap<object, PrismaModule['Prisma']>();

export function setPrismaNamespace(prismaClient: object, prismaNamespace: PrismaModule['Prisma']) {
prismaNamespaces.set(prismaClient, prismaNamespace);
}

// this accepts the context instead of the prisma client because the prisma client on context is `any`
// so by accepting the context, it'll be less likely the wrong thing will be passed.
export function getPrismaNamespace(context: KeystoneContext) {
const limit = prismaNamespaces.get(context.prisma);
if (limit === undefined) {
throw new Error('unexpected prisma namespace not set for prisma client');
}
return limit;
}
8 changes: 5 additions & 3 deletions packages/core/src/lib/createSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import pLimit from 'p-limit';
import { FieldData, KeystoneConfig, getGqlNames } from '../types';

import { createAdminMeta } from '../admin-ui/system/createAdminMeta';
import { PrismaModule } from '../artifacts';
import { createGraphQLSchema } from './createGraphQLSchema';
import { makeCreateContext } from './context/createContext';
import { initialiseLists } from './core/types-for-lists';
import { setWriteLimit } from './core/utils';
import { setPrismaNamespace, setWriteLimit } from './core/utils';

function getSudoGraphQLSchema(config: KeystoneConfig) {
// This function creates a GraphQLSchema based on a modified version of the provided config.
Expand Down Expand Up @@ -72,12 +73,13 @@ export function createSystem(config: KeystoneConfig, isLiveReload?: boolean) {
return {
graphQLSchema,
adminMeta,
getKeystone: (PrismaClient: any) => {
const prismaClient = new PrismaClient({
getKeystone: (prismaModule: PrismaModule) => {
const prismaClient = new prismaModule.PrismaClient({
log: config.db.enableLogging ? ['query'] : undefined,
datasources: { [config.db.provider]: { url: config.db.url } },
});
setWriteLimit(prismaClient, pLimit(config.db.provider === 'sqlite' ? 1 : Infinity));
setPrismaNamespace(prismaClient, prismaModule.Prisma);
prismaClient.$on('beforeExit', async () => {
// Prisma is failing to properly clean up its child processes
// https://github.com/keystonejs/keystone/issues/5477
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/lib/migrations.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import path from 'path';
import { createDatabase, uriToCredentials, DatabaseCredentials } from '@prisma/sdk';
import { createDatabase, uriToCredentials, DatabaseCredentials } from '@prisma/internals';
import { Migrate } from '@prisma/migrate';
import chalk from 'chalk';
import slugify from '@sindresorhus/slugify';
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/lib/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// @prisma/migrate's types seem to not be right
declare module '@prisma/migrate' {
export * from '@prisma/migrate/dist/migrate/src';
}
35 changes: 23 additions & 12 deletions packages/core/src/scripts/run/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,16 @@ export const dev = async (cwd: string, shouldDropDatabase: boolean) => {
const p = serializePathForImport(
path.relative(path.join(getAdminPath(cwd), 'pages', 'api'), `${cwd}/keystone`)
);
const { adminMeta, graphQLSchema, createContext, prismaSchema, apolloServer, ...rest } =
await setupInitialKeystone(config, cwd, shouldDropDatabase);

const {
adminMeta,
graphQLSchema,
createContext,
prismaSchema,
apolloServer,
prismaClientModule,
...rest
} = await setupInitialKeystone(config, cwd, shouldDropDatabase);

if (configWithHTTP?.server?.extendHttpServer) {
const createRequestContext = async (req: IncomingMessage, res: ServerResponse) =>
Expand Down Expand Up @@ -195,8 +203,11 @@ exports.default = function (req, res) { return res.send(x.toString()) }

await generateNodeModulesArtifactsWithoutPrismaClient(graphQLSchema, newConfig, cwd);
await generateAdminUI(newConfig, graphQLSchema, adminMeta, getAdminPath(cwd), true);
const keystone = getKeystone(function fakePrismaClientClass() {
return prismaClient;
const keystone = getKeystone({
PrismaClient: function fakePrismaClientClass() {
return prismaClient;
} as unknown as new (args: unknown) => any,
Prisma: prismaClientModule.Prisma,
});
await keystone.connect();
const servers = await createExpressServer(
Expand Down Expand Up @@ -346,10 +357,8 @@ async function setupInitialKeystone(
// Generate the Artifacts
console.log('✨ Generating GraphQL and Prisma schemas');
const prismaSchema = (await generateCommittedArtifacts(graphQLSchema, config, cwd)).prisma;
let keystonePromise = generateNodeModulesArtifacts(graphQLSchema, config, cwd).then(() => {
const prismaClient = requirePrismaClient(cwd);
return getKeystone(prismaClient);
});

let prismaClientGenerationPromise = generateNodeModulesArtifacts(graphQLSchema, config, cwd);

let migrationPromise: Promise<void>;

Expand All @@ -372,8 +381,9 @@ async function setupInitialKeystone(
);
}

const [keystone] = await Promise.all([keystonePromise, migrationPromise]);
const { createContext } = keystone;
await Promise.all([prismaClientGenerationPromise, migrationPromise]);
const prismaClientModule = requirePrismaClient(cwd);
const keystone = getKeystone(prismaClientModule);

// Connect to the Database
console.log('✨ Connecting to the database');
Expand All @@ -384,7 +394,7 @@ async function setupInitialKeystone(
const { apolloServer, expressServer } = await createExpressServer(
config,
graphQLSchema,
createContext
keystone.createContext
);
console.log(`✅ GraphQL API ready`);

Expand All @@ -402,8 +412,9 @@ async function setupInitialKeystone(
expressServer,
apolloServer,
graphQLSchema,
createContext,
createContext: keystone.createContext,
prismaSchema,
prismaClientModule,
};
}

Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/scripts/tests/migrations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ async function setupAndStopDevServerForMigrations(cwd: string, resetDb: boolean
}

function getPrismaClient(cwd: string) {
const prismaClient = new (requirePrismaClient(cwd))({
const prismaClient = new (requirePrismaClient(cwd).PrismaClient)({
datasources: { sqlite: { url: dbUrl } },
});
return prismaClient;
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/scripts/tests/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import fastGlob from 'fast-glob';
import fixturez from 'fixturez';
import outdent from 'outdent';
import { parseArgsStringToArgv } from 'string-argv';
import { IntrospectionEngine, uriToCredentials } from '@prisma/sdk';
import { IntrospectionEngine, uriToCredentials } from '@prisma/internals';
import { KeystoneConfig } from '../../types';
import { cli } from '../cli';
import { mockPrompts } from '../../lib/prompts';
Expand Down
4 changes: 2 additions & 2 deletions prisma-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"private": true,
"main": "dist/keystone-6-prisma-utils.cjs.js",
"dependencies": {
"@prisma/generator-helper": "3.14.0",
"@prisma/sdk": "3.14.0",
"@prisma/generator-helper": "4.2.1",
"@prisma/internals": "4.2.1",
"fs-extra": "^10.0.0",
"prettier": "^2.5.0"
},
Expand Down
2 changes: 1 addition & 1 deletion prisma-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { deepStrictEqual } from 'assert';
import { isDeepStrictEqual } from 'util';
import fs from 'fs-extra';
import { DMMF } from '@prisma/generator-helper';
import { getDMMF } from '@prisma/sdk';
import { getDMMF } from '@prisma/internals';
import { format, resolveConfig } from 'prettier';

const providers = ['postgresql', 'sqlite', 'mysql'] as const;
Expand Down
Loading

0 comments on commit c06c5d6

Please sign in to comment.