From 9f4e38507a1d94d3a410b7fa7959bf0ffdae09e6 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 17 Oct 2022 13:37:56 +1100 Subject: [PATCH 1/6] fix bigInt deserialisation --- examples/default-values/schema.graphql | 18 ++++++++++++++ examples/default-values/schema.prisma | 1 + examples/default-values/schema.ts | 7 +++++- .../src/fields/types/bigInt/views/index.tsx | 24 +++++++++---------- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/examples/default-values/schema.graphql b/examples/default-values/schema.graphql index c3bc4b10f58..aa67d35a1a7 100644 --- a/examples/default-values/schema.graphql +++ b/examples/default-values/schema.graphql @@ -8,6 +8,7 @@ type Task { isComplete: Boolean assignedTo: Person finishBy: DateTime + viewCount: BigInt } enum TaskPriorityType { @@ -18,6 +19,8 @@ enum TaskPriorityType { scalar DateTime @specifiedBy(url: "https://datatracker.ietf.org/doc/html/rfc3339#section-5.6") +scalar BigInt + input TaskWhereUniqueInput { id: ID } @@ -32,6 +35,7 @@ input TaskWhereInput { isComplete: BooleanFilter assignedTo: PersonWhereInput finishBy: DateTimeNullableFilter + viewCount: BigIntNullableFilter } input IDFilter { @@ -96,12 +100,24 @@ input DateTimeNullableFilter { not: DateTimeNullableFilter } +input BigIntNullableFilter { + equals: BigInt + in: [BigInt!] + notIn: [BigInt!] + lt: BigInt + lte: BigInt + gt: BigInt + gte: BigInt + not: BigIntNullableFilter +} + input TaskOrderByInput { id: OrderDirection label: OrderDirection priority: OrderDirection isComplete: OrderDirection finishBy: OrderDirection + viewCount: OrderDirection } enum OrderDirection { @@ -115,6 +131,7 @@ input TaskUpdateInput { isComplete: Boolean assignedTo: PersonRelateToOneForUpdateInput finishBy: DateTime + viewCount: BigInt } input PersonRelateToOneForUpdateInput { @@ -134,6 +151,7 @@ input TaskCreateInput { isComplete: Boolean assignedTo: PersonRelateToOneForCreateInput finishBy: DateTime + viewCount: BigInt } input PersonRelateToOneForCreateInput { diff --git a/examples/default-values/schema.prisma b/examples/default-values/schema.prisma index 974677659d4..27c848fdb8f 100644 --- a/examples/default-values/schema.prisma +++ b/examples/default-values/schema.prisma @@ -20,6 +20,7 @@ model Task { assignedTo Person? @relation("Task_assignedTo", fields: [assignedToId], references: [id]) assignedToId String? @map("assignedTo") finishBy DateTime? + viewCount BigInt? @default(0) @@index([assignedToId]) } diff --git a/examples/default-values/schema.ts b/examples/default-values/schema.ts index 93ba2ceee66..6652996df91 100644 --- a/examples/default-values/schema.ts +++ b/examples/default-values/schema.ts @@ -1,5 +1,5 @@ import { list } from '@keystone-6/core'; -import { checkbox, relationship, text, timestamp } from '@keystone-6/core/fields'; +import { bigInt, checkbox, relationship, text, timestamp } from '@keystone-6/core/fields'; import { select } from '@keystone-6/core/fields'; import { allowAll } from '@keystone-6/core/access'; import { Lists } from '.keystone/types'; @@ -19,6 +19,7 @@ export const lists: Lists = { hooks: { resolveInput({ resolvedData, inputData }) { if (inputData.priority === undefined) { + // default to high if "urgent" is in the label if (inputData.label && inputData.label.toLowerCase().includes('urgent')) { return 'high'; } else { @@ -64,6 +65,10 @@ export const lists: Lists = { }, }, }), + // Static default: When a task is first created, it has been viewed zero times + viewCount: bigInt({ + defaultValue: 0n + }) }, }), Person: list({ diff --git a/packages/core/src/fields/types/bigInt/views/index.tsx b/packages/core/src/fields/types/bigInt/views/index.tsx index aca2ee9e396..c051f11c484 100644 --- a/packages/core/src/fields/types/bigInt/views/index.tsx +++ b/packages/core/src/fields/types/bigInt/views/index.tsx @@ -14,6 +14,16 @@ import { import { CellLink, CellContainer } from '../../../../admin-ui/components'; import { useFormattedInput } from '../../integer/views/utils'; +type Validation = { + isRequired: boolean; + min: bigint; + max: bigint; +}; + +type Value = + | { kind: 'create'; value: string | bigint | null } + | { kind: 'update'; value: string | bigint | null; initial: bigint | null; }; + function BigIntInput({ value, onChange, @@ -138,7 +148,7 @@ function validate( ): string | undefined { const val = value.value; if (typeof val === 'string') { - return `${label} must be a whole number`; + return `${label} must be a BigInt`; } // if we recieve null initially on the item view and the current value is null, @@ -168,16 +178,6 @@ function validate( return undefined; } -type Validation = { - isRequired: boolean; - min: bigint; - max: bigint; -}; - -type Value = - | { kind: 'update'; initial: bigint | null; value: string | bigint | null } - | { kind: 'create'; value: string | bigint | null }; - export const controller = ( config: FieldControllerConfig<{ validation: { @@ -214,7 +214,7 @@ export const controller = ( ? BigInt(config.fieldMeta.defaultValue) : null, }, - deserialize: data => ({ kind: 'update', value: data[config.path], initial: data[config.path] }), + deserialize: data => ({ kind: 'update', value: BigInt(data[config.path]), initial: data[config.path] }), serialize: value => ({ [config.path]: value.value === null ? null : value.value.toString() }), hasAutoIncrementDefault, validate: value => From 563bb05349a6369c044a00c42aae58166b73fd02 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 17 Oct 2022 13:39:22 +1100 Subject: [PATCH 2/6] add changeset --- .changeset/lazy-strings-guess.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/lazy-strings-guess.md diff --git a/.changeset/lazy-strings-guess.md b/.changeset/lazy-strings-guess.md new file mode 100644 index 00000000000..09f3d8e0741 --- /dev/null +++ b/.changeset/lazy-strings-guess.md @@ -0,0 +1,5 @@ +--- +'@keystone-6/core': patch +--- + +Fixes BigInt values throwing on deserialisation in the item view From ea0754912adb96ad13d7fa0b44ee487e67bf789e Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 17 Oct 2022 14:03:21 +1100 Subject: [PATCH 3/6] dont use JSON.stringify for unknown values --- packages/core/src/fields/types/integer/views/utils.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/core/src/fields/types/integer/views/utils.tsx b/packages/core/src/fields/types/integer/views/utils.tsx index de28a5ddeac..388b8903b44 100644 --- a/packages/core/src/fields/types/integer/views/utils.tsx +++ b/packages/core/src/fields/types/integer/views/utils.tsx @@ -24,11 +24,7 @@ export function useFormattedInput( // typeof value === 'string' implies the unparsed form // typeof value !== 'string' implies the parsed form if (typeof value === 'string' && typeof config.parse(value) !== 'string') { - throw new Error( - `Valid values must be passed in as a parsed value, not a raw value. The value you passed was \`${JSON.stringify( - value - )}\`, you should pass \`${JSON.stringify(config.parse(value))}\` instead` - ); + throw new Error(`Expected ${typeof config.parse(value)}, got ${typeof value}`); } let [internalValueState, setInternalValueState] = useState(() => typeof value === 'string' ? value : config.format(value) From 463f043174d5d83626c5e27ba46b0ddfd8956ca7 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 17 Oct 2022 16:09:20 +1100 Subject: [PATCH 4/6] yarn format --- examples/default-values/schema.ts | 4 ++-- packages/core/src/fields/types/bigInt/views/index.tsx | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/default-values/schema.ts b/examples/default-values/schema.ts index 6652996df91..0cd3b3dd84d 100644 --- a/examples/default-values/schema.ts +++ b/examples/default-values/schema.ts @@ -67,8 +67,8 @@ export const lists: Lists = { }), // Static default: When a task is first created, it has been viewed zero times viewCount: bigInt({ - defaultValue: 0n - }) + defaultValue: 0n, + }), }, }), Person: list({ diff --git a/packages/core/src/fields/types/bigInt/views/index.tsx b/packages/core/src/fields/types/bigInt/views/index.tsx index c051f11c484..bc1626439f7 100644 --- a/packages/core/src/fields/types/bigInt/views/index.tsx +++ b/packages/core/src/fields/types/bigInt/views/index.tsx @@ -22,7 +22,7 @@ type Validation = { type Value = | { kind: 'create'; value: string | bigint | null } - | { kind: 'update'; value: string | bigint | null; initial: bigint | null; }; + | { kind: 'update'; value: string | bigint | null; initial: bigint | null }; function BigIntInput({ value, @@ -214,7 +214,11 @@ export const controller = ( ? BigInt(config.fieldMeta.defaultValue) : null, }, - deserialize: data => ({ kind: 'update', value: BigInt(data[config.path]), initial: data[config.path] }), + deserialize: data => ({ + kind: 'update', + value: BigInt(data[config.path]), + initial: data[config.path], + }), serialize: value => ({ [config.path]: value.value === null ? null : value.value.toString() }), hasAutoIncrementDefault, validate: value => From 8a55258a22d2d6f73d778c9e2cbdb9f653fd9470 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 17 Oct 2022 16:25:04 +1100 Subject: [PATCH 5/6] tidy up initial value checks --- .../src/fields/types/bigInt/views/index.tsx | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/core/src/fields/types/bigInt/views/index.tsx b/packages/core/src/fields/types/bigInt/views/index.tsx index bc1626439f7..9193e69cf0a 100644 --- a/packages/core/src/fields/types/bigInt/views/index.tsx +++ b/packages/core/src/fields/types/bigInt/views/index.tsx @@ -22,7 +22,7 @@ type Validation = { type Value = | { kind: 'create'; value: string | bigint | null } - | { kind: 'update'; value: string | bigint | null; initial: bigint | null }; + | { kind: 'update'; value: string | bigint | null; initial: unknown | null }; function BigIntInput({ value, @@ -141,36 +141,36 @@ export const CardValue: CardValueComponent = ({ item, field }) => { }; function validate( - value: Value, + state: Value, validation: Validation, label: string, hasAutoIncrementDefault: boolean ): string | undefined { - const val = value.value; - if (typeof val === 'string') { + const { kind, value } = state; + if (typeof value === 'string') { return `${label} must be a BigInt`; } - // if we recieve null initially on the item view and the current value is null, + // if we receive null initially on the item view and the current value is null, // we should always allow saving it because: // - the value might be null in the database and we don't want to prevent saving the whole item because of that // - we might have null because of an access control error - if (value.kind === 'update' && value.initial === null && val === null) { + if (kind === 'update' && state.initial === null && value === null) { return undefined; } - if (value.kind === 'create' && value.value === null && hasAutoIncrementDefault) { + if (kind === 'create' && value === null && hasAutoIncrementDefault) { return undefined; } - if (validation.isRequired && val === null) { + if (validation.isRequired && value === null) { return `${label} is required`; } - if (typeof val === 'bigint') { - if (val < validation.min) { + if (typeof value === 'bigint') { + if (value < validation.min) { return `${label} must be greater than or equal to ${validation.min}`; } - if (val > validation.max) { + if (value > validation.max) { return `${label} must be less than or equal to ${validation.max}`; } } From 4da0159766720fc9e25cb39a5f04f0a1ab482ac2 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Mon, 17 Oct 2022 17:34:26 +1100 Subject: [PATCH 6/6] fix for null values --- .../core/src/fields/types/bigInt/views/index.tsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/core/src/fields/types/bigInt/views/index.tsx b/packages/core/src/fields/types/bigInt/views/index.tsx index 9193e69cf0a..76dbae0db50 100644 --- a/packages/core/src/fields/types/bigInt/views/index.tsx +++ b/packages/core/src/fields/types/bigInt/views/index.tsx @@ -214,11 +214,14 @@ export const controller = ( ? BigInt(config.fieldMeta.defaultValue) : null, }, - deserialize: data => ({ - kind: 'update', - value: BigInt(data[config.path]), - initial: data[config.path], - }), + deserialize: data => { + const raw = data[config.path]; + return { + kind: 'update', + value: raw === null ? null : BigInt(raw), + initial: raw, + }; + }, serialize: value => ({ [config.path]: value.value === null ? null : value.value.toString() }), hasAutoIncrementDefault, validate: value =>