-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathscalars.go
129 lines (121 loc) · 2.98 KB
/
scalars.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package apifu
import (
"math"
"strconv"
"time"
"github.com/ccbrown/api-fu/graphql"
"github.com/ccbrown/api-fu/graphql/ast"
)
func parseDateTime(v interface{}) interface{} {
switch v := v.(type) {
case []byte:
t := time.Time{}
if err := t.UnmarshalText(v); err == nil {
return t
}
return nil
case string:
return parseDateTime([]byte(v))
}
return nil
}
// DateTimeType provides a DateTime implementation that serializing to and from RFC-3339 datetimes.
var DateTimeType = &graphql.ScalarType{
Name: "DateTime",
Description: "DateTime represents an RFC-3339 datetime.",
LiteralCoercion: func(v ast.Value) interface{} {
switch v := v.(type) {
case *ast.StringValue:
return parseDateTime(v.Value)
}
return nil
},
VariableValueCoercion: parseDateTime,
ResultCoercion: func(v interface{}) interface{} {
switch v := v.(type) {
case time.Time:
if b, err := v.MarshalText(); err == nil {
return string(b)
}
}
return nil
},
}
// NonZeroDateTime returns a field definition that resolves to the value of the field with the given
// name. If the field's value is the zero time, the field resolves to nil instead.
func NonZeroDateTime(fieldName string) *graphql.FieldDefinition {
return &graphql.FieldDefinition{
Type: DateTimeType,
Resolve: func(ctx graphql.FieldContext) (interface{}, error) {
if t := fieldValue(ctx.Object, fieldName).(time.Time); !t.IsZero() {
return t, nil
}
return nil, nil
},
}
}
const (
maxSafeInteger = 9007199254740991
minSafeInteger = -9007199254740991
)
func coerceLongInt(v interface{}) interface{} {
switch v := v.(type) {
case bool:
if v {
return int64(1)
}
return int64(0)
case int8:
return int64(v)
case uint8:
return int64(v)
case int16:
return int64(v)
case uint16:
return int64(v)
case int32:
return int64(v)
case uint32:
return int64(v)
case int64:
if v >= minSafeInteger && v <= maxSafeInteger {
return int64(v)
}
case uint64:
if v <= maxSafeInteger {
return int64(v)
}
case int:
if v >= minSafeInteger && v <= maxSafeInteger {
return int64(v)
}
case uint:
if v <= maxSafeInteger {
return int64(v)
}
case float32:
return coerceLongInt(float64(v))
case float64:
if n := math.Trunc(v); n == v && n >= minSafeInteger && n <= maxSafeInteger {
return int64(n)
}
}
return nil
}
// LongIntType provides a scalar implementation for integers that may be larger than 32 bits, but
// can still be represented by JavaScript numbers.
var LongIntType = &graphql.ScalarType{
Name: "LongInt",
Description: "LongInt represents a signed integer that may be longer than 32 bits, but still within JavaScript / IEEE-654's \"safe\" range.",
LiteralCoercion: func(v ast.Value) interface{} {
switch v := v.(type) {
case *ast.IntValue:
if n, err := strconv.ParseInt(v.Value, 10, 64); err == nil && n >= minSafeInteger && n <= maxSafeInteger {
return n
}
}
return nil
},
VariableValueCoercion: coerceLongInt,
ResultCoercion: coerceLongInt,
}