[BUG] Cannot accept/send array using input type / input plugin
I don't know why, but if you make an inputType that is an array (list) the input plugin just ignores it, expecting a keyless object :)
Even if you specify array literals directly in the mutation, it still, converts that to an object, for some unknown reason
Even when trying to do a validation scheme, it doesn't like it. Below is the full code.
And yes, I can choose not to send an array, and the input plugin is fine with that, although it's very strange.
Mutation:
mutation MyMutation {
createProject(
input: {name: "", rootDirectory: "", url: "", environmentVariables: {createMany: {skipDuplicates: false, data: [{key: "ss", value: "ss", environments: [PRODUCTION]}]}}, preset: {connect: {id: 1}}}
) {
... on ValidationError {
__typename
code
errors {
codeDescription
code
isFatal
path
systemCode
}
message
timestamp
}
}
}
const EnvironmentVariable = builder.prismaObject("EnvironmentVariable", {
fields: (t) => ({
id: t.exposeID("id"),
key: t.exposeString("key"),
value: t.exposeString("value"),
isSensitive: t.exposeBoolean("isSensitive"),
environments: t.exposeStringList("environments"),
}),
});
const EnvironmentManyVariableCreateInput = builder.prismaCreateMany("EnvironmentVariable", {
name: "EnvironmentManyVariableCreateInput",
fields: (t) => ({
key: t.string({ required: true }),
value: t.string({ required: true }),
isSensitive: t.boolean(),
environments: t.field({
type: [EnvironmentEnum],
}),
}),
});
const EnvironmentManyVariableCreateInputData = builder.inputType("EnvironmentManyVariableCreateInputData", {
fields: (t) => ({
data: t.field({ type: [EnvironmentManyVariableCreateInput], required: true }),
skipDuplicates: t.boolean(),
}),
});
const EnvironmentManyVariableCreate = builder.inputType("EnvironmentManyVariableCreate", {
fields: (t) => ({
createMany: t.field({ type: EnvironmentManyVariableCreateInputData }),
}),
});
Invalid `prisma.project.create()` invocation in
E:\project\Project.initialization.ts:356:44
353
354 console.log(environmentVariables);
355
→ 356 const project = await prisma.project.create({
data: {
preset: {
connect: {
id: 1
}
},
environmentVariables: {
createMany: {
data: {
0: {
key: "ss",
value: "ss",
environments: {
0: "PRODUCTION"
}
},
+ key: String
}
}
},
name: "",
rootDirectory: "",
url: "",
customPreset: undefined,
ownerTeam: undefined,
ownerUser: {
connect: {
id: 1
}
}
}
})
Argument `key` is missing.
builder.mutationField("createProject", (t) =>
t.prismaFieldWithInput({
type: Project,
errors: {},
authScopes: {
isAuthorised: true,
},
input: {
name: t.input.string({ required: true }),
url: t.input.string({ required: true }),
rootDirectory: t.input.string({ required: true }),
preset: t.input.field({
type: PresetConnect,
required: true,
}),
customPreset: t.input.field({ type: CustomPresetCreate }),
ownerTeam: t.input.field({ type: TeamConnect }),
environmentVariables: t.input.field({
type: EnvironmentManyVariableCreate,
validate: {
schema: z.object({
createMany: z.object({
data: z.array(
z.object({
key: z.string(),
value: z.string(),
isSensitive: z.boolean().optional(),
environments: z.array(z.nativeEnum(Environment)), // ERROR, see below
}),
),
removeDuplicates: z.boolean().optional(),
}),
}),
},
}),
},
Type "{ schema: z.ZodObject<{ createMany: z.ZodObject<{ data: z.ZodArray<z.ZodObject<{ key: z.ZodString; value: z.ZodString; isSensitive: z.ZodOptional<z.ZodBoolean>; environments: z.ZodArray<z. ZodNativeEnum<{ DEVELOPMENT: "DEVELOPMENT"; PRODUCTION: "PRODUCTION"; PREVIEW: "PREVIEW"; }>, "many">; }, "strip", z.ZodTypeAny, ..." cannot be assigned to type "ValidationOptions<{ createMany? { skipDuplicates?: boolean | null | undefined; data: { value: string; id: number; teamId: number | null; projectId: number | null; projectId: number | null; key: string; isSensitive: boolean; environments: environment[]; }[]; } | null | undefined; }> | undefined".
The types "schema._type.createMany.data" are incompatible between these types.
The type "{ value: string; key: string; environments: ("DEVELOPMENT" | "PRODUCTION" | "PREVIEW")[]; isSensitive?: boolean | undefined; }[]" cannot be assigned to the type "{ value: string; id: number; teamId: number | null; projectId: number | null; key: string; isSensitive: boolean; environments: Environment[]; }[]".
The following properties from the type "{ value: string; key: string; environments: ("DEVELOPMENT" | "PRODUCTION" | "PREVIEW")[]; isSensitive?: boolean | undefined; }" are missing from the type "{ value: string; id: number; teamId: number | null; projectId: number | null; key: string; isSensitive: boolean; environments: Environment[]; }": id, teamId, projectIdts(2322).
global-types.d.ts(27, 13): The expected type comes from the "validate" property declared here in type "InputObjectFieldOptions<ExtendDefaultTypes<SchemaBuilderTypes>, InputObjectRef<ExtendDefaultTypes<SchemaBuilderTypes>, { ...; }>, FieldRequiredness<...>>"
Not sure whats going on here, can you share the generated GraphQL schema.
Part of the issue with types is that the prisma utils plugin claims to return the full create input with the required relation properties, but the validation schema can't validate that (since they aren't actually part of the input). Working around this would require significantly better type inference for the prisma input fields, which isn't likely to be added soon.
I am not clear on whats happening with the runtime error.
Is the issue that the input is being converted from an array to an object, or is the prisma error just rendering it that way?
the input plugin just ignores it, expecting a keyless object :)
I don't know what this means, what is the input plugin, and where is it "expecting" and keyless object?
having the GraphQL schema output, and the JSON version of the input args received in the resolver might help clarify what the issue is here
UP
The problem is partially solved, and it was my mistake.
- Changing type from array to object [SOLVED]
- You can send an object instead of an array and it will not be considered an error. Although it is specifically described in inputType that only an array is expected.
- It is impossible to validate such an input without an error using zod, because it writes that wrong fields/incorrect types .
As I understand point 3 is difficult to fix now, because of the complexity of type casting.
Changing type from array to object [SOLVED]
Glad you got this figured out
You can send an object instead of an array and it will not be considered an error. Although it is specifically described in inputType that only an array is expected.
If I am understanding this correctly, I think it might be a GraphQL issue, GraphQL automatically allows list inputs to be passed as an object, which it will treat as an list with 1 item, but it also shouldn't cause any issues
It is impossible to validate such an input without an error using zod, because it writes that wrong fields/incorrect types .
I think impossible might be an exaggeration here, I think if you do validate: { schema: { ... } as {} } it will avoid the type errors, but getting complete type-safety would be challenging.
createMany is tricky to use correctly. I think you are better of using create which can create multiple relations:
const CreateUserInput = builder.prismaCreate('User', {
fields: () => ({
email: 'String',
name: 'String',
posts: CreateUserPostsInput,
}),
});
const CreateUserPostsInput = builder.prismaCreateRelation('User', 'posts', {
fields: () => ({
create: CreateUserPostInput,
}),
});
const CreateUserPostInput = builder.prismaCreate('Post', {
name: 'CreateUserPostsInput',
fields: () => ({
title: 'String',
}),
});
builder.mutationType({
fields: (t) => ({
createUser: t.prismaField({
type: 'User',
args: {
data: t.arg({ type: CreateUserInput, required: true }),
},
resolve: (query, _, args) => prisma.user.create({ ...query, data: args.data }),
}),
}
})
mutation {
createUser(data: {
name: "test"
email: "[email protected]"
posts: {
create: [{
title: "post 1"
}, {
title: "post 2"
}]
}
}) {
id
posts {
title
}
}
}