Skip to content

Commit 1a1613d

Browse files
committed
merge
2 parents 9c9517b + 89682f5 commit 1a1613d

File tree

4 files changed

+418
-0
lines changed

4 files changed

+418
-0
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,16 @@ Methods:
127127
- `.Map()` [doc](https://pkg.go.dev/github.com/samber/mo#Option.Map)
128128
- `.MapNone()` [doc](https://pkg.go.dev/github.com/samber/mo#Option.MapNone)
129129
- `.FlatMap()` [doc](https://pkg.go.dev/github.com/samber/mo#Option.FlatMap)
130+
- `.MarshalJSON()` [doc](https://pkg.go.dev/github.com/samber/mo#Option.MarshalJSON)
131+
- `.UnmarshalJSON()` [doc](https://pkg.go.dev/github.com/samber/mo#Option.UnmarshalJSON)
132+
- `.MarshalText()` [doc](https://pkg.go.dev/github.com/samber/mo#Option.MarshalText)
133+
- `.UnmarshalText()` [doc](https://pkg.go.dev/github.com/samber/mo#Option.UnmarshalText)
134+
- `.MarshalBinary()` [doc](https://pkg.go.dev/github.com/samber/mo#Option.MarshalBinary)
135+
- `.UnmarshalBinary()` [doc](https://pkg.go.dev/github.com/samber/mo#Option.UnmarshalBinary)
136+
- `.GobEncode()` [doc](https://pkg.go.dev/github.com/samber/mo#Option.GobEncode)
137+
- `.GobDecode()` [doc](https://pkg.go.dev/github.com/samber/mo#Option.GobDecode)
138+
- `.Scan()` [doc](https://pkg.go.dev/github.com/samber/mo#Option.Scan)
139+
- `.Value()` [doc](https://pkg.go.dev/github.com/samber/mo#Option.Value)
130140

131141
### Result[T any]
132142

option.go

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
package mo
22

33
import (
4+
"bytes"
5+
"database/sql/driver"
6+
"encoding/gob"
7+
"encoding/json"
8+
"errors"
49
"fmt"
510
"reflect"
11+
"time"
612
)
713

814
var optionNoSuchElement = fmt.Errorf("no such element")
@@ -141,3 +147,115 @@ func (o Option[T]) FlatMap(mapper func(value T) Option[T]) Option[T] {
141147

142148
return None[T]()
143149
}
150+
151+
// MarshalJSON encodes Option into json.
152+
func (o Option[T]) MarshalJSON() ([]byte, error) {
153+
if o.isPresent {
154+
return json.Marshal(o.value)
155+
}
156+
return json.Marshal(nil)
157+
}
158+
159+
// UnmarshalJSON decodes Option from json.
160+
func (o *Option[T]) UnmarshalJSON(b []byte) error {
161+
if bytes.Equal(b, []byte("null")) {
162+
o.isPresent = false
163+
return nil
164+
}
165+
166+
err := json.Unmarshal(b, &o.value)
167+
if err != nil {
168+
return err
169+
}
170+
171+
o.isPresent = true
172+
time.Now()
173+
return nil
174+
}
175+
176+
// MarshalText implements the encoding.TextMarshaler interface.
177+
func (o Option[T]) MarshalText() ([]byte, error) {
178+
return json.Marshal(o)
179+
}
180+
181+
// UnmarshalText implements the encoding.TextUnmarshaler interface.
182+
func (o *Option[T]) UnmarshalText(data []byte) error {
183+
return json.Unmarshal(data, o)
184+
}
185+
186+
// BinaryMarshaler is the interface implemented by an object that can marshal itself into a binary form.
187+
func (o Option[T]) MarshalBinary() ([]byte, error) {
188+
if !o.isPresent {
189+
return []byte{0}, nil
190+
}
191+
192+
var buf bytes.Buffer
193+
194+
enc := gob.NewEncoder(&buf)
195+
if err := enc.Encode(o.value); err != nil {
196+
return []byte{}, err
197+
}
198+
199+
return append([]byte{1}, buf.Bytes()...), nil
200+
}
201+
202+
// BinaryUnmarshaler is the interface implemented by an object that can unmarshal a binary representation of itself.
203+
func (o *Option[T]) UnmarshalBinary(data []byte) error {
204+
if len(data) == 0 {
205+
return errors.New("Option[T].UnmarshalBinary: no data")
206+
}
207+
208+
if data[0] == 0 {
209+
o.isPresent = false
210+
o.value = empty[T]()
211+
return nil
212+
}
213+
214+
buf := bytes.NewBuffer(data[1:])
215+
dec := gob.NewDecoder(buf)
216+
err := dec.Decode(&o.value)
217+
if err != nil {
218+
return err
219+
}
220+
221+
o.isPresent = true
222+
return nil
223+
}
224+
225+
// GobEncode implements the gob.GobEncoder interface.
226+
func (o Option[T]) GobEncode() ([]byte, error) {
227+
return o.MarshalBinary()
228+
}
229+
230+
// GobDecode implements the gob.GobDecoder interface.
231+
func (o *Option[T]) GobDecode(data []byte) error {
232+
return o.UnmarshalBinary(data)
233+
}
234+
235+
// Scan implements the SQL driver.Scanner interface.
236+
func (o *Option[T]) Scan(src any) error {
237+
if src == nil {
238+
o.isPresent = false
239+
o.value = empty[T]()
240+
return nil
241+
}
242+
243+
if av, err := driver.DefaultParameterConverter.ConvertValue(src); err == nil {
244+
if v, ok := av.(T); ok {
245+
o.isPresent = true
246+
o.value = v
247+
return nil
248+
}
249+
}
250+
251+
return fmt.Errorf("failed to scan Option[T]")
252+
}
253+
254+
// Value implements the driver Valuer interface.
255+
func (o Option[T]) Value() (driver.Value, error) {
256+
if !o.isPresent {
257+
return nil, nil
258+
}
259+
260+
return o.value, nil
261+
}

option_example_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package mo
22

33
import (
4+
"encoding/json"
45
"fmt"
56
)
67

@@ -280,3 +281,67 @@ func ExampleOption_FlatMap_none() {
280281
fmt.Println(result.IsPresent(), result.OrEmpty())
281282
// Output: false 0
282283
}
284+
285+
func ExampleOption_MarshalJSON_some() {
286+
type test struct {
287+
Email Option[string] `json:"email"`
288+
}
289+
290+
value := test{Email: Some("samuel@example.com")}
291+
result, err := json.Marshal(value)
292+
293+
fmt.Println(string(result))
294+
fmt.Println(err)
295+
// Output:
296+
// {"email":"samuel@example.com"}
297+
// <nil>
298+
}
299+
300+
func ExampleOption_MarshalJSON_none() {
301+
type test struct {
302+
Email Option[string] `json:"email"`
303+
}
304+
305+
value := test{Email: None[string]()}
306+
result, err := json.Marshal(value)
307+
308+
fmt.Println(string(result))
309+
fmt.Println(err)
310+
// Output:
311+
// {"email":null}
312+
// <nil>
313+
}
314+
315+
func ExampleOption_UnmarshalJSON_some() {
316+
type test struct {
317+
Email Option[string] `json:"email"`
318+
}
319+
320+
value := []byte(`{"email":"samuel@example.com"}`)
321+
322+
var result test
323+
err := json.Unmarshal(value, &result)
324+
325+
fmt.Println(result.Email.Get())
326+
fmt.Println(err)
327+
// Output:
328+
// samuel@example.com true
329+
// <nil>
330+
}
331+
332+
func ExampleOption_UnmarshalJSON_none() {
333+
type test struct {
334+
Email Option[string] `json:"email"`
335+
}
336+
337+
value := []byte(`{"email":null}`)
338+
339+
var result test
340+
err := json.Unmarshal(value, &result)
341+
342+
fmt.Println(result.Email.Get())
343+
fmt.Println(err)
344+
// Output:
345+
// false
346+
// <nil>
347+
}

0 commit comments

Comments
 (0)