@@ -6,16 +6,47 @@ import (
6
6
"fmt"
7
7
)
8
8
9
- type OptionalNullable [T any ] struct {
9
+ /*
10
+
11
+ Usage of NullableOptional Type:
12
+
13
+ Consider a go type as below:
14
+ type Obj struct{
15
+ field NullableOptional[<any_go_type>]
16
+ }
17
+
18
+ 1. Check if value is explicitly provided null
19
+ if obj.field.IsNull() { // explicit null provided }
20
+
21
+ 2. Check if a value is explicitly provided which is not null
22
+ if obj.field.HasValue() { // some value provided which could be zero value but not null }
23
+
24
+ Caution:
25
+
26
+ A zero value should not be read before checking if it hasValue via `HasValue()`.
27
+ For example an empty json object `{}` Marshals to zero value even if it is not
28
+ explicitly provided in JSON.
29
+
30
+ Limitations:
31
+
32
+ The conversion of JSON date to NullableOptional type and then converting the
33
+ concrete golang NullableOptional type back to JSON does not result in the original
34
+ JSON for some of the cases meaning the operation is not idempotent.
35
+
36
+ Refer the test case TestNullableRequiredIdempotency
37
+ */
38
+
39
+ type NullableOptional [T any ] struct {
10
40
Value T
11
- // Set indicates whether the underlying Value was sent in the request TODO
41
+ // Set indicates whether the underlying Value was sent in the request.
12
42
Set bool
13
- // Null indicates whether the underlying Value was sent in the request as a literal `null` value. Should only be checked if Set==true TODO
43
+ // Null indicates whether the underlying Value was sent in the request as a literal `null` value.
44
+ // Should only be checked if Set==true.
14
45
Null bool
15
46
}
16
47
17
48
// UnmarshalJSON implements the Unmarshaler interface.
18
- func (t * OptionalNullable [T ]) UnmarshalJSON (data []byte ) error {
49
+ func (t * NullableOptional [T ]) UnmarshalJSON (data []byte ) error {
19
50
t .Set = true
20
51
if bytes .Equal (data , []byte ("null" )) {
21
52
t .Null = true
@@ -29,27 +60,58 @@ func (t *OptionalNullable[T]) UnmarshalJSON(data []byte) error {
29
60
}
30
61
31
62
// MarshalJSON implements the Marshaler interface.
32
- func (t OptionalNullable [T ]) MarshalJSON () ([]byte , error ) {
63
+ func (t NullableOptional [T ]) MarshalJSON () ([]byte , error ) {
33
64
if t .Set && t .Null {
34
65
return []byte ("null" ), nil
35
66
}
36
67
return json .Marshal (t .Value )
37
68
}
38
69
70
+ // IsNull returns true if the value is explicitly provided `null`
71
+ func (t * NullableOptional [T ]) IsNull () bool {
72
+ return t .Set && t .Null
73
+ }
74
+
75
+ // HasValue returns true if the value is explicitly provided and is not `null`
76
+ func (t * NullableOptional [T ]) HasValue () bool {
77
+ return t .Set && ! t .Null
78
+ }
79
+
80
+ /*
81
+
82
+ Usage of Nullable Type:
83
+
84
+ Consider a go type as below:
85
+ type Obj struct{
86
+ field Nullable[<any_go_type>]
87
+ }
88
+
89
+ 1. Check if value is explicitly provided null
90
+ if obj.field.IsNull() { // explicit null provided }
91
+
92
+ 2. Since Nullable type should be used with required fields, it does not have
93
+ the ability to answer if it was set, assuming it always provided.
94
+
95
+ Limitations:
96
+
97
+ The conversion of JSON date to NullableOptional type and then converting the
98
+ concrete golang NullableOptional type back to JSON does not result in the original
99
+ JSON for some of the cases meaning the operation is not idempotent.
100
+
101
+ Refer the test case TestNullableOptionalIdempotency
102
+
103
+ */
104
+
39
105
// Nullable type which can help distinguish between if a value was explicitly
40
106
// provided `null` in JSON or not
41
107
type Nullable [T any ] struct {
42
108
Value T
43
- // Set indicates whether the underlying Value was sent in the request TODO
44
- Set bool
45
- // Null indicates whether the underlying Value was sent in the request as a literal `null` value. Should only be checked if Set==true TODO
109
+ // Null indicates whether the underlying Value was sent in the request as a literal `null` value.
46
110
Null bool
47
111
}
48
112
49
113
// UnmarshalJSON implements the Unmarshaler interface.
50
114
func (t * Nullable [T ]) UnmarshalJSON (data []byte ) error {
51
- // fmt.Println("UnmarshalJSON")
52
- t .Set = true
53
115
if bytes .Equal (data , []byte ("null" )) {
54
116
t .Null = true
55
117
return nil
@@ -63,22 +125,13 @@ func (t *Nullable[T]) UnmarshalJSON(data []byte) error {
63
125
64
126
// MarshalJSON implements the Marshaler interface.
65
127
func (t Nullable [T ]) MarshalJSON () ([]byte , error ) {
66
- if t .Set && t . IsNull () {
128
+ if t .IsNull () {
67
129
return []byte ("null" ), nil
68
130
}
69
131
return json .Marshal (t .Value )
70
132
}
71
133
72
134
// IsNull returns true if the value is explicitly provided `null` in json
73
135
func (t * Nullable [T ]) IsNull () bool {
74
- return t .Set && t .Null
75
- }
76
-
77
- // HasValue returns true if the value is explicitly provided in json
78
- func (t * Nullable [T ]) HasValue () bool {
79
- return t .Set && t .Null
80
- }
81
-
82
- func (t * Nullable [T ]) Get () (value T , null bool ) {
83
- return t .Value , t .IsNull ()
136
+ return t .Null
84
137
}
0 commit comments