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 }