Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tidy up internal Prisma types #9053

Merged
merged 11 commits into from
Mar 6, 2024
6 changes: 3 additions & 3 deletions packages/auth/src/gql/getInitFirstItemSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ export function getInitFirstItemSchema ({
throw new Error('No session implementation available on context')
}

const dbItemAPI = context.sudo().db[listKey]
const sudoContext = context.sudo()

// should approximate hasInitFirstItemConditions
const count = await dbItemAPI.count({})
const count = await sudoContext.db[listKey].count()
if (count !== 0) {
throw new Error('Initial items can only be created when no items exist in that list')
}
Expand All @@ -59,7 +59,7 @@ export function getInitFirstItemSchema ({
// this is strictly speaking incorrect. the db API will do GraphQL coercion on a value which has already been coerced
// (this is also mostly fine, the chance that people are using things where
// the input value can't round-trip like the Upload scalar here is quite low)
const item = await dbItemAPI.createOne({ data: { ...data, ...itemData } })
const item = await sudoContext.db[listKey].createOne({ data: { ...data, ...itemData } })
const sessionToken = (await context.sessionStrategy.start({
data: { listKey, itemId: item.id.toString() },
context,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@ export {
generatePrismaAndGraphQLSchemas,
getCommittedArtifacts,
} from '../artifacts'
export type { PrismaModule } from '../artifacts'
11 changes: 0 additions & 11 deletions packages/core/src/artifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,14 +217,3 @@ async function generatePrismaClient (prismaSchemaPath: string, dataProxy: boolea
})
)
}

export type PrismaModule = {
PrismaClient: {
new (args: unknown): any
}
Prisma: {
DbNull: unknown
JsonNull: unknown
[key: string]: unknown
}
}
2 changes: 1 addition & 1 deletion packages/core/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ export function getContext<TypeInfo extends BaseKeystoneTypeInfo> (
PrismaModule: unknown
): KeystoneContext<TypeInfo> {
const system = createSystem(initConfig(config))
const { context } = system.getKeystone(PrismaModule as any)
const { context } = system.getKeystone(PrismaModule)
return context
}
38 changes: 30 additions & 8 deletions packages/core/src/lib/context/createContext.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
import type { IncomingMessage, ServerResponse } from 'http'
import { type ExecutionResult, graphql, type GraphQLSchema, print } from 'graphql'
import type { KeystoneContext, KeystoneGraphQLAPI, KeystoneConfig } from '../../types'

import type { PrismaClient } from '../core/utils'
import type { InitialisedList } from '../core/initialise-lists'
import {
type IncomingMessage,
type ServerResponse
} from 'http'
import {
type ExecutionResult,
type GraphQLSchema,
graphql,
print
} from 'graphql'
import {
type KeystoneConfig,
type KeystoneContext,
type KeystoneGraphQLAPI,
} from '../../types'

import { type InitialisedList } from '../core/initialise-lists'
import { createImagesContext } from '../assets/createImagesContext'
import { createFilesContext } from '../assets/createFilesContext'
import { getDbFactory, getQueryFactory } from './api'
Expand All @@ -14,12 +25,17 @@ export function createContext ({
graphQLSchema,
graphQLSchemaSudo,
prismaClient,
prismaTypes
}: {
config: KeystoneConfig
lists: Record<string, InitialisedList>
graphQLSchema: GraphQLSchema
graphQLSchemaSudo: GraphQLSchema
prismaClient: PrismaClient
prismaClient: unknown
prismaTypes: {
DbNull: unknown,
JsonNull: unknown
}
}) {
const dbFactories: Record<string, ReturnType<typeof getDbFactory>> = {}
for (const [listKey, list] of Object.entries(lists)) {
Expand Down Expand Up @@ -110,12 +126,18 @@ export function createContext ({
// TODO: deprecated, remove in breaking change
gqlNames: (listKey: string) => lists[listKey].graphql.names,

// TODO: rename __internal ?
// TODO: deprecated, remove in breaking change
...(config.experimental?.contextInitialisedLists
? {
experimental: { initialisedLists: lists },
}
: {}),

__internal: {
prisma: {
...prismaTypes
}
}
}

const _dbFactories = sudo ? dbFactoriesSudo : dbFactories
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/lib/context/executeGraphQLFieldToRootVal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ function getRootValGivenOutputType (originalType: OutputType, value: any): any {
return value[rawField]
}

export function executeGraphQLFieldToRootVal (field: GraphQLField<any, any>) {
export function executeGraphQLFieldToRootVal (field: GraphQLField<any, unknown>) {
const { argumentNodes, variableDefinitions } = getVariablesForGraphQLField(field)
const document: DocumentNode = {
kind: Kind.DOCUMENT,
Expand Down Expand Up @@ -174,7 +174,7 @@ export function executeGraphQLFieldToRootVal (field: GraphQLField<any, any>) {

const type = getTypeForField(field.type)

const fieldConfig: RequiredButStillAllowUndefined<GraphQLFieldConfig<any, any>> = {
const fieldConfig: RequiredButStillAllowUndefined<GraphQLFieldConfig<unknown, unknown>> = {
args: argsToArgsConfig(field.args),
astNode: undefined,
deprecationReason: field.deprecationReason,
Expand All @@ -195,7 +195,7 @@ export function executeGraphQLFieldToRootVal (field: GraphQLField<any, any>) {
})

return async (
args: Record<string, any>,
args: Record<string, unknown>,
context: KeystoneContext,
rootValue: Record<string, string> = {}
) => {
Expand Down
6 changes: 2 additions & 4 deletions packages/core/src/lib/core/access-control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,8 @@ import { type InitialisedList } from './initialise-lists'
import { type InputFilter } from './where-inputs'

export function cannotForItem (operation: string, list: InitialisedList) {
return (
`You cannot ${operation} that ${list.listKey}` +
(operation === 'create' ? '' : ' - it may not exist')
)
if (operation === 'create') return `You cannot ${operation} that ${list.listKey}`
return `You cannot ${operation} that ${list.listKey} - it may not exist`
}

export function cannotForItemFields (
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/lib/core/initialise-lists.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ function getIsEnabled (listKey: string, listConfig: KeystoneConfig['lists'][stri
create: notOmit,
update: notOmit,
delete: notOmit,
filter: notOmit && defaultIsFilterable,
orderBy: notOmit && defaultIsOrderable,
filter: notOmit ? defaultIsFilterable : false,
orderBy: notOmit ? defaultIsOrderable : false,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was confusing, && technically worked, but, the point is that it is false or a function

}
}

Expand Down
6 changes: 4 additions & 2 deletions packages/core/src/lib/core/mutations/access-control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import type { InitialisedList } from '../initialise-lists'
import { cannotForItem, cannotForItemFields } from '../access-control'
import {
type InputFilter,
type UniqueInputFilter,
resolveUniqueWhereInput,
resolveWhereInput,
type UniqueInputFilter,
type UniquePrismaFilter,
} from '../where-inputs'
import {
type UniquePrismaFilter,
} from '../../../types/prisma'

async function getFilteredItem (
list: InitialisedList,
Expand Down
64 changes: 44 additions & 20 deletions packages/core/src/lib/core/mutations/create-update.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
import type { KeystoneContext, BaseItem } from '../../../types'
import type { ResolvedDBField } from '../resolve-relationships'
import type { InitialisedList } from '../initialise-lists'
import {
type BaseItem,
type KeystoneContext
} from '../../../types'
import {
type ResolvedDBField
} from '../resolve-relationships'
import {
type InitialisedList
} from '../initialise-lists'
import {
type IdType,
promiseAllRejectWithAllErrors,
getDBFieldKeyForFieldOnMultiField,
type IdType,
getPrismaNamespace,
} from '../utils'
import { type InputFilter, resolveUniqueWhereInput, type UniqueInputFilter } from '../where-inputs'
import {
type InputFilter,
type UniqueInputFilter,
resolveUniqueWhereInput,
} from '../where-inputs'
import {
accessDeniedError,
extensionError,
Expand Down Expand Up @@ -82,8 +92,10 @@ export async function createOne (
const operationAccess = await getOperationAccess(list, context, 'create')
if (!operationAccess) throw accessDeniedError(cannotForItem('create', list))

// operation
const { item, afterOperation } = await createSingle(createInput, list, context)

// after operation
await afterOperation(item)

return item
Expand All @@ -100,8 +112,12 @@ export async function createMany (
// throw for each attempt
if (!operationAccess) throw accessDeniedError(cannotForItem('create', list))

// operation
const { item, afterOperation } = await createSingle({ data }, list, context)

// after operation
await afterOperation(item)

return item
})
}
Expand Down Expand Up @@ -137,13 +153,15 @@ async function updateSingle (
item
)

// operation
const updatedItem = await context.prisma[list.listKey].update({
where: { id: item.id },
data,
})

// after operation
await afterOperation(updatedItem)

return updatedItem
}

Expand Down Expand Up @@ -390,8 +408,7 @@ function transformInnerDBField (
value: unknown
) {
if (dbField.kind === 'scalar' && dbField.scalar === 'Json' && value === null) {
const Prisma = getPrismaNamespace(context)
return Prisma.DbNull
return context.__internal.prisma.DbNull
}
return value
}
Expand All @@ -402,18 +419,25 @@ function transformForPrismaClient (
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),
transformInnerDBField(dbField.fields[innerFieldKey], context, fieldValue),
]
})
}
[...function* () {
for (const fieldKey in data) {
const value = data[fieldKey]
const { dbField } = fields[fieldKey]

if (dbField.kind === 'multi') {
for (const innerFieldKey in value) {
const innerFieldValue = value[innerFieldKey]
yield [
getDBFieldKeyForFieldOnMultiField(fieldKey, innerFieldKey),
transformInnerDBField(dbField.fields[innerFieldKey], context, innerFieldValue),
]
}

continue
}

return [[fieldKey, transformInnerDBField(dbField, context, value)]]
})
yield [fieldKey, transformInnerDBField(dbField, context, value)]
}
}()]
)
}
2 changes: 1 addition & 1 deletion packages/core/src/lib/core/mutations/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { extensionError } from '../graphql-errors'
import type { InitialisedList } from '../initialise-lists'
import { type InitialisedList } from '../initialise-lists'

export async function runSideEffectOnlyHook<
HookName extends 'beforeOperation' | 'afterOperation',
Expand Down
25 changes: 15 additions & 10 deletions packages/core/src/lib/core/mutations/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import type { InitialisedList } from '../initialise-lists'

type DistributiveOmit<T, K extends keyof T> = T extends any ? Omit<T, K> : never

type UpdateCreateHookArgs = Parameters<
Exclude<InitialisedList['hooks']['validateInput'], undefined>
>[0]
type UpdateCreateHookArgs = Parameters<Exclude<InitialisedList['hooks']['validateInput'], undefined>>[0]
type DeleteHookArgs = Parameters<Exclude<InitialisedList['hooks']['validateDelete'], undefined>>[0]

export async function validateUpdateCreate ({
list,
hookArgs,
Expand All @@ -14,9 +14,9 @@ export async function validateUpdateCreate ({
hookArgs: DistributiveOmit<UpdateCreateHookArgs, 'addValidationError'>
}) {
const messages: string[] = []

const fieldsErrors: { error: Error, tag: string }[] = []
// Field validation hooks

// field validation hooks
await Promise.all(
Object.entries(list.fields).map(async ([fieldKey, field]) => {
const addValidationError = (msg: string) =>
Expand All @@ -33,20 +33,21 @@ export async function validateUpdateCreate ({
throw extensionError('validateInput', fieldsErrors)
}

// List validation hooks
// list validation hooks
const addValidationError = (msg: string) => messages.push(`${list.listKey}: ${msg}`)
try {
await list.hooks.validateInput({ ...hookArgs, addValidationError })
} catch (error: any) {
throw extensionError('validateInput', [{ error, tag: `${list.listKey}.hooks.validateInput` }])
throw extensionError('validateInput', [
{ error, tag: `${list.listKey}.hooks.validateInput` }
])
}

if (messages.length) {
throw validationFailureError(messages)
}
}

type DeleteHookArgs = Parameters<Exclude<InitialisedList['hooks']['validateDelete'], undefined>>[0]
export async function validateDelete ({
list,
hookArgs,
Expand All @@ -56,7 +57,8 @@ export async function validateDelete ({
}) {
const messages: string[] = []
const fieldsErrors: { error: Error, tag: string }[] = []
// Field validation

// field validation hooks
await Promise.all(
Object.entries(list.fields).map(async ([fieldKey, field]) => {
const addValidationError = (msg: string) =>
Expand All @@ -68,10 +70,12 @@ export async function validateDelete ({
}
})
)

if (fieldsErrors.length) {
throw extensionError('validateDelete', fieldsErrors)
}
// List validation

// list validation hooks
const addValidationError = (msg: string) => messages.push(`${list.listKey}: ${msg}`)
try {
await list.hooks.validateDelete({ ...hookArgs, addValidationError })
Expand All @@ -80,6 +84,7 @@ export async function validateDelete ({
{ error, tag: `${list.listKey}.hooks.validateDelete` },
])
}

if (messages.length) {
throw validationFailureError(messages)
}
Expand Down
Loading