Closed coopbri closed 1 year ago
Hi @coopbri. Thanks for using and your words, I'm really glad to see it helping others.
Once that every input type in Graphql must be defined, you cant freely update like objects, you need to define a new...
You can create a input type with a property linked to the original input, and set extra freely. ✔ Keeps the expressiveness of the args ✔ Auto sync with database ❌ But breaks the original shape of the data arg...
export const UserUpdateInput = builder.inputRef<{
original: Prisma.UserUpdateInput,
customArg: string;
}>('UserUpdateInputCustom').implement({
fields: (t) => ({
original: t.field({ "required": false, "type": Inputs.UserUpdateInput }),
customArg: t.field({ "required": true, "type": "String" }), // Custom
}),
});
export default builder.mutationFields((t) => {
const field = updateOneUserMutationObject(t);
return {
updateOneUserCustom: t.prismaField({
...field,
args: {
...field.args,
data: t.arg({ type: UserUpdateInput, required: true }),
},
resolve: async (...args) => {
const [include, root, { data }, { response, db }, info] = args;
if (data.customArg === "123") throw new Error("Invalid");
return field.resolve(...args);
},
}),
};
});
If you need the data.arg original shape (ie: for a auto generated admin panel) i think the easiest way its copy original input definition and set the custom fields. Neither pothos nor this lib also offer a function to easily create derived args. So it won't automatically stay in sync with the database... @saphewilliam any idea on this?
✔ Keeps the expressiveness of the args ❌ Auto sync with database ✔ Original shape of the data arg...
export const UserUpdateInput = builder.inputRef<Prisma.UserUpdateInput & { customArg?: string }>('UserUpdateInputCustom').implement({
fields: (t) => ({
email: t.field({ "required": false, "type": Inputs.StringFieldUpdateOperationsInput }),
name: t.field({ "required": false, "type": Inputs.NullableStringFieldUpdateOperationsInput }),
Address: t.field({ "required": false, "type": Inputs.AddressNullableUpdateEnvelopeInput }),
Posts: t.field({ "required": false, "type": Inputs.PostUpdateManyWithoutAuthorNestedInput }),
customArg: t.field({ "required": false, "type": "String" }), // Custom
}),
});
...
args: {
...field.args,
data: t.arg({ type: UserUpdateInput, required: true }),
},
...
Do any of the approaches helps you?
Great use case! I hadn't considered it before.
I think I would go for option 2, creating a custom UserUpdateInput
and supplying that to your resolver. Since this custom arg does not come from the Prisma schema, we cannot auto-generate it in any way, but we could make it as easy as possible to create these custom input types from the auto generated ones.
I can't check this right now, but does something along these lines work?
import { UserCreateInput } from './inputs.ts';
const CustomUserCreateInput = builder.inputRef<Prisma.UserUpdateInput & { customArg?: string }>('CustomUserCreateInput').implement({
fields: (t) => ({
...UserCreateInput.fields(t)
customArg: t.field({ "required": false, "type": "String" }), // Custom
}),
});
If this works, we should probably add this use case to the docs. If it doesn't work, we should probably figure out a way to make it work to support this use case.
@saphewilliam This doesn't work
I think we could export 2 variables for each input, like this:
// __generated__/inputs.ts
export const UserUpdateInputFields = (t: any) => ({
email: t.field({ "required": false, "type": Inputs.StringFieldUpdateOperationsInput }),
name: t.field({ "required": false, "type": Inputs.NullableStringFieldUpdateOperationsInput }),
Address: t.field({ "required": false, "type": Inputs.AddressNullableUpdateEnvelopeInput }),
Posts: t.field({ "required": false, "type": Inputs.PostUpdateManyWithoutAuthorNestedInput }),
})
export const UserUpdateInput = builder.inputRef<Prisma.UserUpdateInput>('UserUpdateInputCustom3').implement({
fields: (t) => UserUpdateInputFields(t),
});
// User/inputs.ts
export const UserUpdateInputCustom = builder.inputRef<Prisma.UserUpdateInput & { customArg: string }>('UserUpdateInputCustom').implement({
fields: (t) => ({
...UserUpdateInputFields(t),
customArg: t.field({ "required": true, "type": "String" }), // custom
}),
});
Even with (t: any)
, its typesafe because types are linked to the input itself, but i dont know if im confortable with it XD
What do you think?
Yeah this would be a great solution imo! We could put any
there for now and we'll see later if we can do something more fancy if that's even necessary.
@coopbri We update with a new feature to augment inputs. Version: 0.5.3 version
Please update and try :D
@Cauen @saphewilliam you guys are amazing! I was planning on helping implement a solution but you knocked it out super fast. I just tested 0.5.3 and it works great. All I did was:
0.5.3
...and it worked like a charm. I really appreciate your time and effort, seriously. This solution is super clean, consistent with the rest of the API, and works flawlessly.
Hey, thank you so much for this library, this is exactly what I was trying to do with Pothos + Prisma and the key feature I was missing from Nexus. I have a question about augmenting the generated
data
argument in generated input types.I am able to add a custom arg like so:
That works great. However, I would like to augment the
data
arg with that field. Is there an easy way to do this? For example, instead of the input beingI'd like to have the custom arg stored inside of data like:
I tried adjusting the
data
arg a couple ways:data: { ...field.args.data }
(doesn't work because of how the data arg is generated)data: field.args.data
(not sure how to adjust it from here)