Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

Add BSON struct tag to generated models #865

Closed
jamesabbottsmith opened this issue Sep 18, 2019 · 16 comments
Closed

Add BSON struct tag to generated models #865

jamesabbottsmith opened this issue Sep 18, 2019 · 16 comments
Labels
enhancement New feature or request

Comments

@jamesabbottsmith
Copy link

jamesabbottsmith commented Sep 18, 2019

What happened?

Generated models (with multi-part member names) cannot be used with MongoDB

What did you expect?

The ability to directly parse the resulting BSON from MongoDB queries into the models generated by gqlgen.
This is handy when the graphql schema exactly matches the models stored in MongoDB

Minimal graphql.schema and models to reproduce

type WithMultiPartMember {
  multi_part_member: String
}

Would currently generate...

type WithMultiPartMember struct {
    MultiPartMember *string `json:"multi_part_member"`
}

Would like it to generate...

type WithMultiPartMember struct {
    MultiPartMember *string `json:"multi_part_member"` `bson:"multi_part_member"` 
}

Possible fix

Replace plugin/modelgen/models.go:181

Tag: `json:"` + field.Name + `"`,

with

Tag:  `json:"` + field.Name + `" bson:"` + field.Name + `"`,

versions

  • gqlgen version v0.9.3-dev
  • go version 1.13
  • dep or go modules?

Can generate PR if you are happy with it

@domsn
Copy link

domsn commented Sep 20, 2019

i need this feature

@pascoual
Copy link

pascoual commented Sep 27, 2019

What about the possibility to add options in graphql schema file like this:

input WithMultiPartMember {
  multi_part_member: String #`json:"multi_part_member" bson:"multi_part_member,omitempty"` 
}

I need to add bson omitempty for mongo-go updates with optional fields.

Another use case is this:

type Car {
  id: ID! # `json:"id" bson:"_id"`
  ...
}

Like this the _id in MongoDB is automatically well Marshaled and UnMarshaled

@stale
Copy link

stale bot commented Nov 26, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Nov 26, 2019
@jamesabbottsmith
Copy link
Author

@vektah - should I make a PR for this?

@stale stale bot removed the stale label Nov 26, 2019
@vvakame vvakame added the enhancement New feature or request label Dec 25, 2019
@vvakame
Copy link
Collaborator

vvakame commented Dec 25, 2019

https://gqlgen.com/recipes/modelgen-hook/
models generated by modelgen plugin. and it has a hooks.
You can inject bson tag by yourself.

I think it seems convenient to write plugin settings in gqlgen.yml.

@kurtsson
Copy link

Following the tips from @vvakame, I created a file called runner.go inside an otherwise empty folder with the following code:

package main

import (
	"fmt"
	"os"

	"github.com/99designs/gqlgen/api"
	"github.com/99designs/gqlgen/codegen/config"
	"github.com/99designs/gqlgen/plugin/modelgen"
)

func mutateHook(b *modelgen.ModelBuild) *modelgen.ModelBuild {
	for _, model := range b.Models {
		for _, field := range model.Fields {
			name := field.Name
			if name == "id" {
				name = "_id"
			}
			field.Tag += ` bson:"` + name + `"`
		}
	}
	return b
}

func main() {
	cfg, err := config.LoadConfigFromDefaultLocations()
	if err != nil {
		fmt.Fprintln(os.Stderr, "failed to load config", err.Error())
		os.Exit(2)
	}

	p := modelgen.Plugin{
		MutateHook: mutateHook,
	}

	err = api.Generate(cfg,
		api.NoPlugins(),
		api.AddPlugin(&p),
	)
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(3)
	}
}

I then call it with go run runner\runner.go and it will generate my models with mongo friendly bson tags.

@kockok
Copy link

kockok commented Jun 29, 2020

Following the tips from @vvakame, I created a file called runner.go inside an otherwise empty folder with the following code:

package main

import (
	"fmt"
	"os"

	"github.com/99designs/gqlgen/api"
	"github.com/99designs/gqlgen/codegen/config"
	"github.com/99designs/gqlgen/plugin/modelgen"
)

func mutateHook(b *modelgen.ModelBuild) *modelgen.ModelBuild {
	for _, model := range b.Models {
		for _, field := range model.Fields {
			name := field.Name
			if name == "id" {
				name = "_id"
			}
			field.Tag += ` bson:"` + name + `"`
		}
	}
	return b
}

func main() {
	cfg, err := config.LoadConfigFromDefaultLocations()
	if err != nil {
		fmt.Fprintln(os.Stderr, "failed to load config", err.Error())
		os.Exit(2)
	}

	p := modelgen.Plugin{
		MutateHook: mutateHook,
	}

	err = api.Generate(cfg,
		api.NoPlugins(),
		api.AddPlugin(&p),
	)
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(3)
	}
}

I then call it with go run runner\runner.go and it will generate my models with mongo friendly bson tags.

You demonstrated how to mannually run the hook, the thing is, how could the mutate hook run alongside with the normal gqlgen generate procedure?

This recipe here doesn't show whether we should run the code separately, as what you did. Or we could incorporate the hook into gqlgen generate.

@vvakame Please advise.

@SergeyYakubov
Copy link

It seems the plugin runs the gqlgen generate procedure automatically along with hook.
So I just changed //go:generate go run github.com/99designs/gqlgen to //go:generate go run hooks/bson.go and go generate ./... works as expected.

@jlamb1
Copy link

jlamb1 commented Jul 3, 2020

@SergeyYakubov this works, thanks!

@kockok
Copy link

kockok commented Jul 4, 2020

It seems the plugin runs the gqlgen generate procedure automatically along with hook.
So I just changed //go:generate go run github.com/99designs/gqlgen to //go:generate go run hooks/bson.go and go generate ./... works as expected.

I got go generate exited with an error, check gopls logs error when running go generate ./...

Can you provide your bson.go?

Thanks.

@SergeyYakubov
Copy link

@kockok - it is exactly the same example showed above #865 (comment), which itself a slight modification of a gqlgen recipe, so your errors must be somewhere else.

@kockok
Copy link

kockok commented Jul 5, 2020

@SergeyYakubov Wondering if package main matters.
The recipe didn't indicate which package to implement, or ANY package, e.g. package graph is ok.

@RobertoOrtis
Copy link

This should be implemented as default. It is a must!

@rijine
Copy link

rijine commented Aug 15, 2020

This should be a parameter in gqlgen.yml file

@martinfriedel
Copy link

We had the same problem and adapted and expanded the code example above by @kockok a bit further and are now happily generating the models with mongodb specific tags so _id is properly marshalled. Here it is: https://github.com/qubidu/gqlgen-add-bson-mappings

@sebpaj
Copy link

sebpaj commented Jun 9, 2021

Does anyone face issue when using federated services?
I have User from different microservice with key directives

extend type UserType @key(fields: "id") {
  id: ID!
}

Then during running hook I have following error: failed to load schema: graph/schema.graphqls:48: Undefined directive key.
Following code part provides this error

	err = api.Generate(cfg,
		api.NoPlugins(),
		api.AddPlugin(&p),
	)

@frederikhors frederikhors converted this issue into discussion #1943 Feb 4, 2022

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests