github.com/maeglindeveloper/gqlgen@v0.13.1-0.20210413081235-57808b12a0a0/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  	Modified *time.Time // direct binding to builtin types with external Marshal/Unmarshal methods
    43  	ValPrefs Prefs      // external un/marshal that act on pointers
    44  	PtrPrefs *Prefs
    45  	IsBanned Banned
    46  	Address  Address
    47  	Tier     Tier
    48  }
    49  
    50  // Point is serialized as a simple array, eg [1, 2]
    51  type Point struct {
    52  	X int
    53  	Y int
    54  }
    55  
    56  func (p *Point) UnmarshalGQL(v interface{}) error {
    57  	pointStr, ok := v.(string)
    58  	if !ok {
    59  		return fmt.Errorf("points must be strings")
    60  	}
    61  
    62  	parts := strings.Split(pointStr, ",")
    63  
    64  	if len(parts) != 2 {
    65  		return fmt.Errorf("points must have 2 parts")
    66  	}
    67  
    68  	var err error
    69  	if p.X, err = strconv.Atoi(parts[0]); err != nil {
    70  		return err
    71  	}
    72  	if p.Y, err = strconv.Atoi(parts[1]); err != nil {
    73  		return err
    74  	}
    75  	return nil
    76  }
    77  
    78  // MarshalGQL implements the graphql.Marshaler interface
    79  func (p Point) MarshalGQL(w io.Writer) {
    80  	fmt.Fprintf(w, `"%d,%d"`, p.X, p.Y)
    81  }
    82  
    83  // if the type referenced in .gqlgen.yml is a function that returns a marshaller we can use it to encode and decode
    84  // onto any existing go type.
    85  func MarshalTimestamp(t time.Time) graphql.Marshaler {
    86  	return graphql.WriterFunc(func(w io.Writer) {
    87  		io.WriteString(w, strconv.FormatInt(t.Unix(), 10))
    88  	})
    89  }
    90  
    91  // Unmarshal{Typename} is only required if the scalar appears as an input. The raw values have already been decoded
    92  // from json into int/float64/bool/nil/map[string]interface/[]interface
    93  func UnmarshalTimestamp(v interface{}) (time.Time, error) {
    94  	if tmpStr, ok := v.(int64); ok {
    95  		return time.Unix(tmpStr, 0), nil
    96  	}
    97  	return time.Time{}, errors.New("time should be a unix timestamp")
    98  }
    99  
   100  // Lets redefine the base ID type to use an id from an external library
   101  func MarshalID(id external.ObjectID) graphql.Marshaler {
   102  	return graphql.WriterFunc(func(w io.Writer) {
   103  		io.WriteString(w, strconv.Quote(fmt.Sprintf("=%d=", id)))
   104  	})
   105  }
   106  
   107  // And the same for the unmarshaler
   108  func UnmarshalID(v interface{}) (external.ObjectID, error) {
   109  	str, ok := v.(string)
   110  	if !ok {
   111  		return 0, fmt.Errorf("ids must be strings")
   112  	}
   113  	i, err := strconv.Atoi(str[1 : len(str)-1])
   114  	return external.ObjectID(i), err
   115  }
   116  
   117  type SearchArgs struct {
   118  	Location     *Point
   119  	CreatedAfter *time.Time
   120  	IsBanned     Banned
   121  }
   122  
   123  // A custom enum that uses integers to represent the values in memory but serialize as string for graphql
   124  type Tier uint
   125  
   126  const (
   127  	TierA Tier = iota
   128  	TierB Tier = iota
   129  	TierC Tier = iota
   130  )
   131  
   132  func TierForStr(str string) (Tier, error) {
   133  	switch str {
   134  	case "A":
   135  		return TierA, nil
   136  	case "B":
   137  		return TierB, nil
   138  	case "C":
   139  		return TierC, nil
   140  	default:
   141  		return 0, fmt.Errorf("%s is not a valid Tier", str)
   142  	}
   143  }
   144  
   145  func (e Tier) IsValid() bool {
   146  	switch e {
   147  	case TierA, TierB, TierC:
   148  		return true
   149  	}
   150  	return false
   151  }
   152  
   153  func (e Tier) String() string {
   154  	switch e {
   155  	case TierA:
   156  		return "A"
   157  	case TierB:
   158  		return "B"
   159  	case TierC:
   160  		return "C"
   161  	default:
   162  		panic("invalid enum value")
   163  	}
   164  }
   165  
   166  func (e *Tier) UnmarshalGQL(v interface{}) error {
   167  	str, ok := v.(string)
   168  	if !ok {
   169  		return fmt.Errorf("enums must be strings")
   170  	}
   171  
   172  	var err error
   173  	*e, err = TierForStr(str)
   174  	return err
   175  }
   176  
   177  func (e Tier) MarshalGQL(w io.Writer) {
   178  	fmt.Fprint(w, strconv.Quote(e.String()))
   179  }
   180  
   181  type Prefs struct {
   182  	DarkMode bool
   183  }
   184  
   185  func MarshalPreferences(p *Prefs) graphql.Marshaler {
   186  	return graphql.MarshalBoolean(p.DarkMode)
   187  }
   188  
   189  func UnmarshalPreferences(v interface{}) (*Prefs, error) {
   190  	tmp, err := graphql.UnmarshalBoolean(v)
   191  	if err != nil {
   192  		return nil, err
   193  	}
   194  	return &Prefs{DarkMode: tmp}, nil
   195  }