github.com/fortexxx/gqlgen@v0.10.3-0.20191216030626-ca5ea8b21ead/example/scalars/model/model.go (about)

     1  package model
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io"
     7  	"strconv"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/99designs/gqlgen/example/scalars/external"
    12  	"github.com/99designs/gqlgen/graphql"
    13  )
    14  
    15  type Banned bool
    16  
    17  func (b Banned) MarshalGQL(w io.Writer) {
    18  	if b {
    19  		w.Write([]byte("true"))
    20  	} else {
    21  		w.Write([]byte("false"))
    22  	}
    23  }
    24  
    25  func (b *Banned) UnmarshalGQL(v interface{}) error {
    26  	switch v := v.(type) {
    27  	case string:
    28  		*b = strings.ToLower(v) == "true"
    29  		return nil
    30  	case bool:
    31  		*b = Banned(v)
    32  		return nil
    33  	default:
    34  		return fmt.Errorf("%T is not a bool", v)
    35  	}
    36  }
    37  
    38  type User struct {
    39  	ID       external.ObjectID
    40  	Name     string
    41  	Created  time.Time // direct binding to builtin types with external Marshal/Unmarshal methods
    42  	IsBanned Banned
    43  	Address  Address
    44  	Tier     Tier
    45  }
    46  
    47  // Point is serialized as a simple array, eg [1, 2]
    48  type Point struct {
    49  	X int
    50  	Y int
    51  }
    52  
    53  func (p *Point) UnmarshalGQL(v interface{}) error {
    54  	pointStr, ok := v.(string)
    55  	if !ok {
    56  		return fmt.Errorf("points must be strings")
    57  	}
    58  
    59  	parts := strings.Split(pointStr, ",")
    60  
    61  	if len(parts) != 2 {
    62  		return fmt.Errorf("points must have 2 parts")
    63  	}
    64  
    65  	var err error
    66  	if p.X, err = strconv.Atoi(parts[0]); err != nil {
    67  		return err
    68  	}
    69  	if p.Y, err = strconv.Atoi(parts[1]); err != nil {
    70  		return err
    71  	}
    72  	return nil
    73  }
    74  
    75  // MarshalGQL implements the graphql.Marshaler interface
    76  func (p Point) MarshalGQL(w io.Writer) {
    77  	fmt.Fprintf(w, `"%d,%d"`, p.X, p.Y)
    78  }
    79  
    80  // if the type referenced in .gqlgen.yml is a function that returns a marshaller we can use it to encode and decode
    81  // onto any existing go type.
    82  func MarshalTimestamp(t time.Time) graphql.Marshaler {
    83  	return graphql.WriterFunc(func(w io.Writer) {
    84  		io.WriteString(w, strconv.FormatInt(t.Unix(), 10))
    85  	})
    86  }
    87  
    88  // Unmarshal{Typename} is only required if the scalar appears as an input. The raw values have already been decoded
    89  // from json into int/float64/bool/nil/map[string]interface/[]interface
    90  func UnmarshalTimestamp(v interface{}) (time.Time, error) {
    91  	if tmpStr, ok := v.(int64); ok {
    92  		return time.Unix(tmpStr, 0), nil
    93  	}
    94  	return time.Time{}, errors.New("time should be a unix timestamp")
    95  }
    96  
    97  // Lets redefine the base ID type to use an id from an external library
    98  func MarshalID(id external.ObjectID) graphql.Marshaler {
    99  	return graphql.WriterFunc(func(w io.Writer) {
   100  		io.WriteString(w, strconv.Quote(fmt.Sprintf("=%d=", id)))
   101  	})
   102  }
   103  
   104  // And the same for the unmarshaler
   105  func UnmarshalID(v interface{}) (external.ObjectID, error) {
   106  	str, ok := v.(string)
   107  	if !ok {
   108  		return 0, fmt.Errorf("ids must be strings")
   109  	}
   110  	i, err := strconv.Atoi(str[1 : len(str)-1])
   111  	return external.ObjectID(i), err
   112  }
   113  
   114  type SearchArgs struct {
   115  	Location     *Point
   116  	CreatedAfter *time.Time
   117  	IsBanned     Banned
   118  }
   119  
   120  // A custom enum that uses integers to represent the values in memory but serialize as string for graphql
   121  type Tier uint
   122  
   123  const (
   124  	TierA Tier = iota
   125  	TierB Tier = iota
   126  	TierC Tier = iota
   127  )
   128  
   129  func TierForStr(str string) (Tier, error) {
   130  	switch str {
   131  	case "A":
   132  		return TierA, nil
   133  	case "B":
   134  		return TierB, nil
   135  	case "C":
   136  		return TierC, nil
   137  	default:
   138  		return 0, fmt.Errorf("%s is not a valid Tier", str)
   139  	}
   140  }
   141  
   142  func (e Tier) IsValid() bool {
   143  	switch e {
   144  	case TierA, TierB, TierC:
   145  		return true
   146  	}
   147  	return false
   148  }
   149  
   150  func (e Tier) String() string {
   151  	switch e {
   152  	case TierA:
   153  		return "A"
   154  	case TierB:
   155  		return "B"
   156  	case TierC:
   157  		return "C"
   158  	default:
   159  		panic("invalid enum value")
   160  	}
   161  }
   162  
   163  func (e *Tier) UnmarshalGQL(v interface{}) error {
   164  	str, ok := v.(string)
   165  	if !ok {
   166  		return fmt.Errorf("enums must be strings")
   167  	}
   168  
   169  	var err error
   170  	*e, err = TierForStr(str)
   171  	return err
   172  }
   173  
   174  func (e Tier) MarshalGQL(w io.Writer) {
   175  	fmt.Fprint(w, strconv.Quote(e.String()))
   176  }