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

Generate input object helpers #635

Open
gampleman opened this issue Sep 22, 2023 · 1 comment
Open

Generate input object helpers #635

gampleman opened this issue Sep 22, 2023 · 1 comment

Comments

@gampleman
Copy link
Contributor

At work we have an InputObject.Extra module, that looks like this:

withTags : List String -> { a | tags : OptionalArgument (List String) } -> { a | tags : OptionalArgument (List String) }
withTags tags inp =
    { inp | tags = Present tags }


withName : String -> { a | name : OptionalArgument String } -> { a | name : OptionalArgument String }
withName name inp =
    { inp | name = Present name }


withVisibility : List Visibility -> { a | withVisibility : OptionalArgument (List Visibility) } -> { a | withVisibility : OptionalArgument (List Visibility) }
withVisibility vis inp =
    { inp | withVisibility = Present vis }


withSetData : (SetDataInAnalysisInput -> SetDataInAnalysisInput) -> { a | setData : OptionalArgument SetDataInAnalysisInput } -> { a | setData : OptionalArgument SetDataInAnalysisInput }
withSetData fn inp =
    { inp | setData = Present (InputObject.buildSetDataInAnalysisInput fn) }

and so on. This makes simple queries nicer:

Mutation.updateProject projectId (InputObject.withTags ["some-tag"]) Project.projectId

-- vs

Mutation.updateProject projectId (\inp -> { inp | tags = Present ["some-tag" }) Project.projectId

More complex queries are quite nice also with function composition:

InputObject.buildProjectsInput (InputObject.withVisibility [ Public ] >> InputObject.withTags [ "tag" ])

-- vs 

InputObject.buildProjectsInput (\inp -> { inp | visibility = Present [ Public ], tags = Public [ "tag" ] })

Complex nested queries can also be simplified:

InputObject.buildAnalysisInput (InputObject.withSetData (InputObject.withTags ["tag"]))

-- vs 

InputObject.buildAnalysisInput (\inp -> 
   {inp | 
       setData = Present (InputObject.buildSetDataInAnalysisInput (\sdiaInp -> 
            { sdiaInp | tags = Present ["tag"] } 
        ) 
   } 
)

The idea here is to generate these helpers automatically, so this more compact form of input can be used by anyone.

@dillonkearns
Copy link
Owner

I'm definitely open to a pull request for some functionality like this if you're interested in working on it. It seems like a good idea overall.

One thing to consider is that I think it would need to be more flexible to allow for name collisions:

withVisibility : List Visibility -> { a | withVisibility : OptionalArgument (List Visibility) } -> { a | withVisibility : OptionalArgument (List Visibility) }

So something like this instead, since you could have fields in different types of Input Objects that have the same name but different types of values:

withVisibility : visibility -> { a | withVisibility : OptionalArgument visibility } -> { a | withVisibility : OptionalArgument visibility }

Also, I think Matt Griffith and Ryan Haskell-Glatz explored some different approaches to building input object values at some point, so it might be worth comparing notes with them. Ryan wrote a post about a few ideas: https://rhg.dev/blog/exploring-graphql-input/. And I think Matt ended up with a slightly different approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants