From a5dc5b37b11d66ab159dface703b759e155429f3 Mon Sep 17 00:00:00 2001 From: Daniel Cousens <413395+dcousens@users.noreply.github.com> Date: Tue, 9 Jul 2024 11:24:05 +1000 Subject: [PATCH] add multiselect nullable changeset + add tests --- .changeset/add-isnullable-multiselect.md | 5 ++++ .../src/fields/types/multiselect/index.ts | 27 +++++++++---------- .../fixtures/multiselect/test-fixtures.ts | 4 +-- 3 files changed, 19 insertions(+), 17 deletions(-) create mode 100644 .changeset/add-isnullable-multiselect.md diff --git a/.changeset/add-isnullable-multiselect.md b/.changeset/add-isnullable-multiselect.md new file mode 100644 index 00000000000..edf3088e6da --- /dev/null +++ b/.changeset/add-isnullable-multiselect.md @@ -0,0 +1,5 @@ +--- +'@keystone-6/core': minor +--- + +Add `db.isNullable` support for multiselect field type, defaults to false diff --git a/packages/core/src/fields/types/multiselect/index.ts b/packages/core/src/fields/types/multiselect/index.ts index 53fe9ad1830..068a59a4221 100644 --- a/packages/core/src/fields/types/multiselect/index.ts +++ b/packages/core/src/fields/types/multiselect/index.ts @@ -8,7 +8,6 @@ import { jsonFieldTypePolyfilledForSQLite, } from '../../../types' import { graphql } from '../../..' -import { userInputError } from '../../../lib/core/graphql-errors' import { makeValidateHook } from '../../non-null-graphql' import { mergeFieldHooks } from '../../resolve-hooks' @@ -25,12 +24,12 @@ export type MultiselectFieldConfig = * If `enum` is provided on SQLite, it will use an enum in GraphQL but a string in the database. */ type?: 'string' | 'enum' - defaultValue?: readonly string[] + defaultValue?: readonly string[] | null } | { options: readonly { label: string, value: number }[] type: 'integer' - defaultValue?: readonly number[] + defaultValue?: readonly number[] | null } ) & { db?: { @@ -48,7 +47,7 @@ export function multiselect ( config: MultiselectFieldConfig ): FieldTypeFunc { const { - defaultValue = [], + defaultValue = [], // TODO: deprecated, remove in breaking change } = config config.db ??= {} @@ -64,7 +63,7 @@ export function multiselect ( return graphql.arg({ type: nonNullList(type) }) } - const resolveCreate = (val: T[] | null | undefined): T[] => { + const resolveCreate = (val: T[] | null | undefined): T[] | null => { const resolved = resolveUpdate(val) if (resolved === undefined) { return defaultValue as T[] @@ -74,15 +73,11 @@ export function multiselect ( const resolveUpdate = ( val: T[] | null | undefined - ): T[] | undefined => { - if (val === null) { - throw userInputError('multiselect fields cannot be set to null') - } + ): T[] | null | undefined => { return val } const transformedConfig = configToOptionsAndGraphQLType(config, meta) - const accepted = new Set(transformedConfig.options.map(x => x.value)) if (accepted.size !== transformedConfig.options.length) { throw new Error(`${meta.listKey}.${meta.fieldKey} has duplicate options, this is not allowed`) @@ -94,8 +89,8 @@ export function multiselect ( } = makeValidateHook(meta, config, ({ inputData, operation, addValidationError }) => { if (operation === 'delete') return - const values: readonly (string | number)[] | undefined = inputData[meta.fieldKey] // resolvedData is JSON - if (values !== undefined) { + const values: readonly (string | number)[] | null | undefined = inputData[meta.fieldKey] // resolvedData is JSON + if (values != null) { for (const value of values) { if (!accepted.has(value)) { addValidationError(`'${value}' is not an accepted option`) @@ -137,7 +132,10 @@ export function multiselect ( mode, map: config?.db?.map, extendPrismaSchema: config.db?.extendPrismaSchema, - default: { kind: 'literal', value: JSON.stringify(defaultValue) }, + default: { + kind: 'literal', + value: JSON.stringify(defaultValue ?? null) + }, } ) } @@ -191,5 +189,4 @@ function configToOptionsAndGraphQLType ( } } -const nonNullList = (type: T) => - graphql.list(graphql.nonNull(type)) +const nonNullList = (type: T) => graphql.list(graphql.nonNull(type)) diff --git a/tests/api-tests/fields/types/fixtures/multiselect/test-fixtures.ts b/tests/api-tests/fields/types/fixtures/multiselect/test-fixtures.ts index 9e1bb81cc20..2b44beaa34b 100644 --- a/tests/api-tests/fields/types/fixtures/multiselect/test-fixtures.ts +++ b/tests/api-tests/fields/types/fixtures/multiselect/test-fixtures.ts @@ -17,10 +17,10 @@ export const exampleValue2 = (matrixValue: MatrixValue) => ? ['a string', '1number'] : [2, 4] export const supportsNullInput = false -export const neverNull = true +export const neverNull = false export const supportsUnique = false export const supportsDbMap = true -export const skipRequiredTest = true +export const skipRequiredTest = false export const fieldConfig = (matrixValue: MatrixValue) => { if (matrixValue === 'enum' || matrixValue === 'string') { return {