GraphQLのType別gqlgen自動生成結果一覧

# お題
表題の通り。備忘録として。

# 開発環境
## # OS - Linux(Ubuntu)
```
$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="18.04.4 LTS (Bionic Beaver)"
```

## # 言語 - Golang
```
$ go version
go version go1.13.9 linux/amd64
```

## # ツール - gqlgen
```
$ gqlgen version
v0.11.3-dev
```

# 結果
今回のソースは下記。
https://github.com/sky0621/study-gqlgen/tree/v0.1/types

## Null"不可"のケース

| 型名 | GraphQLスキーマ上の定義 | gqlgen自動生成後の型 | 備考 |
|:----|:---------------------|:-------------------|:----|
| ID型 | ID! | string | Uniqueであることが前提 |
| UTF8文字列型 | String! | string | - |
| 符号付き32bit整数型 | Int! | int | - |
| 符号付き倍精度浮動小数点数型 | Float! | float64 | - |
| 真偽値型 | Boolean! | bool | - |
| 日付型 | Date! | string | Date型で定義しても自動的に言語依存の日付型にはマッピングされない |
| 列挙型 | Signal! | Signal | enumはGolangではstring型の定数となる |
| 時刻型(gqlgenビルトイン) | Time! | time.Time | - |
| マップ型(gqlgenビルトイン) | Map! | map[string]interface{} | GraphQLスキーマ上はNull"不可"の定義だが、map なので nil が入りうる |
| アップロード型(gqlgenビルトイン) | Upload! | graphql.Upload | - |
| なんでもあり型(gqlgenビルトイン) | Any! | interface{} | GraphQLスキーマ上はNull"不可"の定義だが、interface なので nil が入りうる |
| カスタムScalar型 | YesNo! | YesNo | 事前定義した型にマッピングされる |
| Object構造型 | SomeType! | *Object | GraphQLスキーマ上はNull"不可"の定義だが、参照型で自動生成されるので nil が入りうる |
| 文字列型配列 | [String!]! | []string | GraphQLスキーマ上はNull"不可"の定義だが、Slice なので nil が入りうる |
| マップ型配列 | [Map!]! | []map[string]interface{} | GraphQLスキーマ上はNull"不可"の定義だが、Slice なので nil が入りうる<br>内部の要素も map なので nil が入りうる |
| なんでもあり型配列 | [Any!]! | []interface{} | GraphQLスキーマ上はNull"不可"の定義だが、Slice なので nil が入りうる<br>内部の要素も interface なので nil が入りうる |
| Object構造型配列 | [SomeType!]! | []*Object | GraphQLスキーマ上はNull"不可"の定義だが、Slice なので nil が入りうる<br>内部の要素も参照型なので nil が入りうる |

## Null"可"のケース

| 型名 | GraphQLスキーマ上の定義 | gqlgen自動生成後の型 | 備考 |
|:----|:---------------------|:-------------------|:----|
| UTF8文字列型 | String | *string | - |
| 符号付き32bit整数型 | Int | *int | - |
| 符号付き倍精度浮動小数点数型 | Float | *float64 | - |
| 真偽値型 | Boolean | *bool | - |
| 日付型 | Date | *string | Date型で定義しても自動的に言語依存の日付型にはマッピングされない |
| 列挙型 | Signal | *Signal | enumはGolangではstring型の定数となる |
| 時刻型(gqlgenビルトイン) | Time | *time.Time | - |
| マップ型(gqlgenビルトイン) | Map | map[string]interface{} | - |
| アップロード型(gqlgenビルトイン) | Upload | *graphql.Upload | - |
| なんでもあり型(gqlgenビルトイン) | Any | interface{} | - |
| カスタムScalar型 | YesNo | *YesNo | 事前定義した型にマッピングされる |
| Object構造型 | SomeType | *Object | - |
| 文字列型配列 | [String] | []*string | - |
| 文字列型配列 | [String]! | []*string | - |
| 文字列型配列 | [String!] | []string | - |
| マップ型配列 | [Map] | []map[string]interface{} | - |
| マップ型配列 | [Map]! | []map[string]interface{} | - |
| マップ型配列 | [Map!] | []map[string]interface{} | - |
| なんでもあり型配列 | [Any] | []interface{} | - |
| なんでもあり型配列 | [Any]! | []interface{} | - |
| なんでもあり型配列 | [Any!] | []interface{} | - |
| Object構造型配列 | [SomeType] | []*Object | - |
| Object構造型配列 | [SomeType]! | []*Object | - |
| Object構造型配列 | [SomeType!] | []*Object | - |

# 補足

## GraphQLスキーマ

```graphql:types/graph/schema.graphqls
# Global Object Identification ... 全データを共通のIDでユニーク化
interface Node {
  id: ID!
}

schema {
  query: Query
  mutation: Mutation
}

type Query {
  node(id: ID!): Node
}

type Mutation {
  noop(input: NoopInput): NoopPayload
}

input NoopInput {
  clientMutationId: String
}

type NoopPayload {
  clientMutationId: String
}

type MutationResponse {
  id: ID
}

scalar Date
scalar Time
scalar Map
scalar Upload
scalar Any
scalar YesNo

enum Signal {
  RED
  YELLOW
  GREEN
}
```

```graphql:types/graph/various.graphqls

extend type Query {
    nonNullTypes: [NonNullType!]!
    nullableTypes: [NullableType!]!
}

"""
https://graphql.org/learn/schema/#scalar-types
https://github.com/99designs/gqlgen/blob/master/docs/content/reference/scalars.md
"""
type NonNullType implements Node {
    "ID型 - ID!"
    id: ID!

    "UTF8文字列型 - String!"
    stringNonNull: String!

    "符号付き32bit整数型 - Int!"
    intNonNull: Int!

    "符号付き倍精度浮動小数点数型 - Float!"
    floatNonNull: Float!

    "真偽値型 - Boolean!"
    booleanNonNull: Boolean!

    "日付型 - Date!"
    dateNonNull: Date!

    "列挙型 - Signal!"
    signalNonNull: Signal!

    "時刻型(gqlgenビルトイン) - Time!"
    timeNonNull: Time!

    "マップ型(gqlgenビルトイン) - Map!"
    mapNonNull: Map!

    "アップロード型(gqlgenビルトイン) - Upload!"
    uploadNonNull: Upload!

    "なんでもあり型(gqlgenビルトイン) - Any!"
    anyNonNull: Any!

    "カスタムScalar型 - YesNo!"
    yesNoNonNull: YesNo!

    "Object構造型 - SomeType!"
    objectNonNull: Object!

    "文字列型配列 - [String!]!"
    stringsNonNull: [String!]!

    "マップ型配列 - [Map!]!"
    mapsNonNull: [Map!]!

    "なんでもあり型配列 - [Any!]!"
    anyTypesNonNull: [Any!]!

    "Object構造型配列 - [SomeType!]!"
    objectsNonNull: [Object!]!
}

type NullableType implements Node {
    "ID型 - ID!"
    id: ID!

    "UTF8文字列型 - String"
    stringNullable: String

    "符号付き32bit整数型 - Int"
    intNullable: Int

    "符号付き倍精度浮動小数点数型 - Float"
    floatNullable: Float

    "真偽値型 - Boolean"
    booleanNullable: Boolean

    "日付型 - Date"
    dateNullable: Date

    "列挙型 - Signal"
    signalNullable: Signal

    "時刻型(gqlgenビルトイン) - Time"
    timeNullable: Time

    "マップ型(gqlgenビルトイン) - Map"
    mapNullable: Map

    "アップロード型(gqlgenビルトイン) - Upload"
    uploadNullable: Upload

    "なんでもあり型(gqlgenビルトイン) - Any"
    anyNullable: Any

    "カスタムScalar型 - YesNo"
    yesNoNullable: YesNo

    "Object構造型 - SomeType"
    objectNullable: Object

    "文字列型配列 - [String]"
    stringsNullable: [String]
    "文字列型配列 - [String]!"
    stringsObjectNullable: [String]!
    "文字列型配列 - [String!]"
    stringsArrayNullable: [String!]

    "マップ型配列 - [Map]"
    mapsNullable: [Map]
    "マップ型配列 - [Map]!"
    mapsObjectNullable: [Map]!
    "マップ型配列 - [Map!]"
    mapsArrayNullable: [Map!]

    "なんでもあり型配列 - [Any]"
    anyTypesNullable: [Any]
    "なんでもあり型配列 - [Any]!"
    anyTypesObjectNullable: [Any]!
    "なんでもあり型配列 - [Any!]"
    anyTypesArrayNullable: [Any!]

    "Object構造型配列 - [SomeType]"
    objectsNullable: [Object]
    "Object構造型配列 - [SomeType]!"
    objectsObjectNullable: [Object]!
    "Object構造型配列 - [SomeType!]"
    objectsArrayNullable: [Object!]
}

type Object implements Node {
    id: ID!
```

## 自動生成モデル

```go:types/graph/model/models_gen.go
// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.

package model

import (
	"fmt"
	"io"
	"strconv"
	"time"

	"github.com/99designs/gqlgen/graphql"
)

type Node interface {
	IsNode()
}

type MutationResponse struct {
	ID *string `json:"id"`
}

// https://graphql.org/learn/schema/#scalar-types
// https://github.com/99designs/gqlgen/blob/master/docs/content/reference/scalars.md
type NonNullType struct {
	// ID型 - ID!
	ID string `json:"id"`
	// UTF8文字列型 - String!
	StringNonNull string `json:"stringNonNull"`
	// 符号付き32bit整数型 - Int!
	IntNonNull int `json:"intNonNull"`
	// 符号付き倍精度浮動小数点数型 - Float!
	FloatNonNull float64 `json:"floatNonNull"`
	// 真偽値型 - Boolean!
	BooleanNonNull bool `json:"booleanNonNull"`
	// 日付型 - Date!
	DateNonNull string `json:"dateNonNull"`
	// 列挙型 - Signal!
	SignalNonNull Signal `json:"signalNonNull"`
	// 時刻型(gqlgenビルトイン) - Time!
	TimeNonNull time.Time `json:"timeNonNull"`
	// マップ型(gqlgenビルトイン) - Map!
	MapNonNull map[string]interface{} `json:"mapNonNull"`
	// アップロード型(gqlgenビルトイン) - Upload!
	UploadNonNull graphql.Upload `json:"uploadNonNull"`
	// なんでもあり型(gqlgenビルトイン) - Any!
	AnyNonNull interface{} `json:"anyNonNull"`
	// カスタムScalar型 - YesNo!
	YesNoNonNull YesNo `json:"yesNoNonNull"`
	// Object構造型 - SomeType!
	ObjectNonNull *Object `json:"objectNonNull"`
	// 文字列型配列 - [String!]!
	StringsNonNull []string `json:"stringsNonNull"`
	// マップ型配列 - [Map!]!
	MapsNonNull []map[string]interface{} `json:"mapsNonNull"`
	// なんでもあり型配列 - [Any!]!
	AnyTypesNonNull []interface{} `json:"anyTypesNonNull"`
	// Object構造型配列 - [SomeType!]!
	ObjectsNonNull []*Object `json:"objectsNonNull"`
}

func (NonNullType) IsNode() {}

type NoopInput struct {
	ClientMutationID *string `json:"clientMutationId"`
}

type NoopPayload struct {
	ClientMutationID *string `json:"clientMutationId"`
}

type NullableType struct {
	// ID型 - ID!
	ID string `json:"id"`
	// UTF8文字列型 - String
	StringNullable *string `json:"stringNullable"`
	// 符号付き32bit整数型 - Int
	IntNullable *int `json:"intNullable"`
	// 符号付き倍精度浮動小数点数型 - Float
	FloatNullable *float64 `json:"floatNullable"`
	// 真偽値型 - Boolean
	BooleanNullable *bool `json:"booleanNullable"`
	// 日付型 - Date
	DateNullable *string `json:"dateNullable"`
	// 列挙型 - Signal
	SignalNullable *Signal `json:"signalNullable"`
	// 時刻型(gqlgenビルトイン) - Time
	TimeNullable *time.Time `json:"timeNullable"`
	// マップ型(gqlgenビルトイン) - Map
	MapNullable map[string]interface{} `json:"mapNullable"`
	// アップロード型(gqlgenビルトイン) - Upload
	UploadNullable *graphql.Upload `json:"uploadNullable"`
	// なんでもあり型(gqlgenビルトイン) - Any
	AnyNullable interface{} `json:"anyNullable"`
	// カスタムScalar型 - YesNo
	YesNoNullable *YesNo `json:"yesNoNullable"`
	// Object構造型 - SomeType
	ObjectNullable *Object `json:"objectNullable"`
	// 文字列型配列 - [String]
	StringsNullable []*string `json:"stringsNullable"`
	// 文字列型配列 - [String]!
	StringsObjectNullable []*string `json:"stringsObjectNullable"`
	// 文字列型配列 - [String!]
	StringsArrayNullable []string `json:"stringsArrayNullable"`
	// マップ型配列 - [Map]
	MapsNullable []map[string]interface{} `json:"mapsNullable"`
	// マップ型配列 - [Map]!
	MapsObjectNullable []map[string]interface{} `json:"mapsObjectNullable"`
	// マップ型配列 - [Map!]
	MapsArrayNullable []map[string]interface{} `json:"mapsArrayNullable"`
	// なんでもあり型配列 - [Any]
	AnyTypesNullable []interface{} `json:"anyTypesNullable"`
	// なんでもあり型配列 - [Any]!
	AnyTypesObjectNullable []interface{} `json:"anyTypesObjectNullable"`
	// なんでもあり型配列 - [Any!]
	AnyTypesArrayNullable []interface{} `json:"anyTypesArrayNullable"`
	// Object構造型配列 - [SomeType]
	ObjectsNullable []*Object `json:"objectsNullable"`
	// Object構造型配列 - [SomeType]!
	ObjectsObjectNullable []*Object `json:"objectsObjectNullable"`
	// Object構造型配列 - [SomeType!]
	ObjectsArrayNullable []*Object `json:"objectsArrayNullable"`
}

func (NullableType) IsNode() {}

type Object struct {
	ID string `json:"id"`
}

func (Object) IsNode() {}

type Signal string

const (
	SignalRed    Signal = "RED"
	SignalYellow Signal = "YELLOW"
	SignalGreen  Signal = "GREEN"
)

var AllSignal = []Signal{
	SignalRed,
	SignalYellow,
	SignalGreen,
}

func (e Signal) IsValid() bool {
	switch e {
	case SignalRed, SignalYellow, SignalGreen:
		return true
	}
	return false
}

func (e Signal) String() string {
	return string(e)
}

func (e *Signal) UnmarshalGQL(v interface{}) error {
	str, ok := v.(string)
	if !ok {
		return fmt.Errorf("enums must be strings")
	}

	*e = Signal(str)
	if !e.IsValid() {
		return fmt.Errorf("%s is not a valid Signal", str)
	}
	return nil
}

func (e Signal) MarshalGQL(w io.Writer) {
	fmt.Fprint(w, strconv.Quote(e.String()))
}
```

## カスタムScalar:「`YesNo`」型

```go:types/graph/model/custom_scalar.go
package model

import (
	"fmt"
	"io"
)

type YesNo bool

// UnmarshalGQL implements the graphql.Unmarshaler interface
func (y *YesNo) UnmarshalGQL(v interface{}) error {
	yes, ok := v.(string)
	if !ok {
		return fmt.Errorf("points must be strings")
	}

	if yes == "yes" {
		*y = true
	} else {
		*y = false
	}
	return nil
}

// MarshalGQL implements the graphql.Marshaler interface
func (y YesNo) MarshalGQL(w io.Writer) {
	if y {
		if _, err := w.Write([]byte(`"yes"`)); err != nil {
			fmt.Println(err)
		}
	} else {
		if _, err := w.Write([]byte(`"no"`)); err != nil {
			fmt.Println(err)
		}
	}
}
```

## gqlgen.yml

```yaml:types/gqlgen.yml
# Where are all the schema files located? globs are supported eg  src/**/*.graphqls
schema:
  - graph/*.graphqls

　　〜〜省略〜〜

models:
  ID:
    model:
      - github.com/99designs/gqlgen/graphql.ID
      - github.com/99designs/gqlgen/graphql.Int
      - github.com/99designs/gqlgen/graphql.Int64
      - github.com/99designs/gqlgen/graphql.Int32
  Int:
    model:
      - github.com/99designs/gqlgen/graphql.Int
      - github.com/99designs/gqlgen/graphql.Int64
      - github.com/99designs/gqlgen/graphql.Int32
  YesNo:
    model:
      - github.com/sky0621/study-gqlgen/types/graph/model.YesNo
```