gqlgen에서 생성된 구조에 사용자 정의 디렉터리에 지정한 임의의 태그를 설정합니다

16249 단어 GraphQLgolangtech
이런 패턴 파일에서
directive @tag(
    validate: String
) on INPUT_FIELD_DEFINITION

input NewUser {
  email: String! @tag(validate: "required,email")
  password: String! @tag(validate: "required,max=50")
  name: String! @tag(validate: "required,max=50")
}
이런 모형을 만들고 싶어요.
type NewUser struct {
	Email    string `json:"email" validate:"required,email"`
	Password string `json:"password" validate:"required,max=50"`
	Name     string `json:"name" validate:"required,max=50"`
}
modelgen.Plugin의 MutaateHook을 사용해 해시태그를 설정한 레시피가 기재돼 있기 때문에 이를 바탕으로 맞춤 제작이 이뤄진다.
https://gqlgen.com/recipes/modelgen-hook/
원본 코드에서는 모델의 필드 정보만 참조할 수 있기 때문에 패턴 파일에 정의된 정보를 얻어야 한다
fd *ast.FieldDefinition = cfg.Schema.Types[model.Name].Fields[i]
이 정보를 얻을 수 있으면 필드 정의에서 지시를 받고 식단과 같은 방식field.Tag으로 보충한다.
//go:build ignore

package main

import (
	"fmt"
	"os"

	"github.com/99designs/gqlgen/api"
	"github.com/99designs/gqlgen/codegen/config"
	"github.com/99designs/gqlgen/plugin"
	"github.com/99designs/gqlgen/plugin/modelgen"
	"github.com/vektah/gqlparser/v2/ast"
)

func fieldHook(f *modelgen.Field, fd *ast.FieldDefinition) {
	// @tagディレクティブ
	directive := fd.Directives.ForName("tag")
	if directive != nil {
		// validateタグを追加
		validateTag := directive.Arguments.ForName("validate")
		if validateTag != nil {
			f.Tag += fmt.Sprintf(` validate:"%s"`, validateTag.Value.Raw)
		}
	}
}

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

	// Attaching the mutation function onto modelgen plugin
	p := modelgen.Plugin{
		MutateHook: func(b *modelgen.ModelBuild) *modelgen.ModelBuild {
			for _, model := range b.Models {
				for i, field := range model.Fields {
					fieldHook(field, cfg.Schema.Types[model.Name].Fields[i])
				}
			}

			return b
		},
	}

	// ディレクティブとしては使用しないのでコードに出力されないように設定
	// https://github.com/99designs/gqlgen/blob/v0.14.0/codegen/config/config.go#L231
	cfg.Directives["tag"] = config.DirectiveConfig{
		SkipRuntime: true,
	}

	err = api.Generate(cfg,
		func(cfg *config.Config, plugins *[]plugin.Plugin) {
			for i, plugin := range *plugins {
				if _, ok := plugin.(*modelgen.Plugin); ok {
					// modelgen.Pluginを置き換える
					(*plugins)[i] = &p
				}
			}
		},
	)
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(3)
	}
}
이 동작을 적당한 곳에서 실행하면 라벨이 설정된 모델을 생성합니다.
go run cmd/gqlgen/gen.go
를 점으로 하고 원형을 유지하면 지시 코드로 생성하기 때문에 @goField와 같이 코드를 생성하지 않아야 한다.
cfg.Directives["tag"] = config.DirectiveConfig{
	SkipRuntime: true,
}
또한 원시 코드를 유지한다
err = api.Generate(cfg,
	api.NoPlugins(),
	api.AddPlugin(&p),
)
라면 모델만 생성하기 때문에 잘 바꿀 수 있는 방법을 찾아보았으나 찾을 수 없어 이미 유형 변환이 진행된 모델을 교체해 봤다.
이 예에서는 validate에만 대응하지만 아래 부분과 같은 방식으로 진행하면 임의의 형식으로 진행할 수 있다.
// validateタグを追加
validateTag := directive.Arguments.ForName("validate")
if validateTag != nil {
	f.Tag += fmt.Sprintf(` validate:"%s"`, validateTag.Value.Raw)
}

좋은 웹페이지 즐겨찾기