Skip to content

Commit ded19ef

Browse files
ryclarkeRyan Clarke
andauthored
Implement BSON Marshaler support (#142)
Co-authored-by: Ryan Clarke <[email protected]>
1 parent 9480c3e commit ded19ef

File tree

6 files changed

+144
-3
lines changed

6 files changed

+144
-3
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
module github.com/deckarep/golang-set/v2
22

33
go 1.18
4+
5+
require go.mongodb.org/mongo-driver v1.17.4

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2+
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
3+
go.mongodb.org/mongo-driver v1.16.0 h1:tpRsfBJMROVHKpdGyc1BBEzzjDUWjItxbVSZ8Ls4BQ4=
4+
go.mongodb.org/mongo-driver v1.16.0/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw=
5+
go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFXVw=
6+
go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=

set.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ SOFTWARE.
3535
// that can enforce mutual exclusion through other means.
3636
package mapset
3737

38+
import "go.mongodb.org/mongo-driver/bson/bsontype"
39+
3840
// Set is the primary interface provided by the mapset package. It
3941
// represents an unordered set of data and a large number of
4042
// operations that can be applied to that set.
@@ -196,8 +198,15 @@ type Set[T comparable] interface {
196198
MarshalJSON() ([]byte, error)
197199

198200
// UnmarshalJSON will unmarshal a JSON-based byte slice into a full Set datastructure.
199-
// For this to work, set subtypes must implemented the Marshal/Unmarshal interface.
201+
// For this to work, set subtypes must implement the Marshal/Unmarshal interface.
200202
UnmarshalJSON(b []byte) error
203+
204+
// MarshalBSONValue will marshal the set into a BSON-based representation.
205+
MarshalBSONValue() (bsontype.Type, []byte, error)
206+
207+
// UnmarshalBSONValue will unmarshal a BSON-based byte slice into a full Set datastructure.
208+
// For this to work, set subtypes must implement the Marshal/Unmarshal interface.
209+
UnmarshalBSONValue(bt bsontype.Type, b []byte) error
201210
}
202211

203212
// NewSet creates and returns a new set with the given elements.

threadsafe.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@ SOFTWARE.
2525

2626
package mapset
2727

28-
import "sync"
28+
import (
29+
"sync"
30+
31+
"go.mongodb.org/mongo-driver/bson/bsontype"
32+
)
2933

3034
type threadSafeSet[T comparable] struct {
3135
sync.RWMutex
@@ -305,9 +309,25 @@ func (t *threadSafeSet[T]) MarshalJSON() ([]byte, error) {
305309
}
306310

307311
func (t *threadSafeSet[T]) UnmarshalJSON(p []byte) error {
308-
t.RLock()
312+
t.Lock()
309313
err := t.uss.UnmarshalJSON(p)
314+
t.Unlock()
315+
316+
return err
317+
}
318+
319+
func (t *threadSafeSet[T]) MarshalBSONValue() (bsontype.Type, []byte, error) {
320+
t.RLock()
321+
bt, b, err := t.uss.MarshalBSONValue()
310322
t.RUnlock()
311323

324+
return bt, b, err
325+
}
326+
327+
func (t *threadSafeSet[T]) UnmarshalBSONValue(bt bsontype.Type, p []byte) error {
328+
t.Lock()
329+
err := t.uss.UnmarshalBSONValue(bt, p)
330+
t.Unlock()
331+
312332
return err
313333
}

threadsafe_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ import (
3333
"sync"
3434
"sync/atomic"
3535
"testing"
36+
37+
"go.mongodb.org/mongo-driver/bson"
3638
)
3739

3840
const N = 1000
@@ -683,3 +685,81 @@ func Test_DeadlockOnEachCallbackWhenPanic(t *testing.T) {
683685
t.Errorf("Expected widgets to have 5 elements, but has %d", card)
684686
}
685687
}
688+
689+
func Test_UnmarshalBSONValue(t *testing.T) {
690+
tp, s, initErr := bson.MarshalValue(
691+
bson.A{"1", "2", "3", "test"},
692+
)
693+
694+
if initErr != nil {
695+
t.Errorf("Init Error should be nil: %v", initErr)
696+
697+
return
698+
}
699+
700+
if tp != bson.TypeArray {
701+
t.Errorf("Encoded Type should be bson.Array, got: %v", tp)
702+
703+
return
704+
}
705+
706+
expected := NewSet("1", "2", "3", "test")
707+
actual := NewSet[string]()
708+
err := bson.UnmarshalValue(bson.TypeArray, s, actual)
709+
if err != nil {
710+
t.Errorf("Error should be nil: %v", err)
711+
}
712+
713+
if !expected.Equal(actual) {
714+
t.Errorf("Expected no difference, got: %v", expected.Difference(actual))
715+
}
716+
}
717+
718+
func TestThreadUnsafeSet_UnmarshalBSONValue(t *testing.T) {
719+
tp, s, initErr := bson.MarshalValue(
720+
bson.A{int64(1), int64(2), int64(3)},
721+
)
722+
723+
if initErr != nil {
724+
t.Errorf("Init Error should be nil: %v", initErr)
725+
726+
return
727+
}
728+
729+
if tp != bson.TypeArray {
730+
t.Errorf("Encoded Type should be bson.Array, got: %v", tp)
731+
732+
return
733+
}
734+
735+
expected := NewThreadUnsafeSet[int64](1, 2, 3)
736+
actual := NewThreadUnsafeSet[int64]()
737+
err := actual.UnmarshalBSONValue(bson.TypeArray, []byte(s))
738+
if err != nil {
739+
t.Errorf("Error should be nil: %v", err)
740+
}
741+
if !expected.Equal(actual) {
742+
t.Errorf("Expected no difference, got: %v", expected.Difference(actual))
743+
}
744+
}
745+
746+
func Test_MarshalBSONValue(t *testing.T) {
747+
expected := NewSet("1", "test")
748+
749+
_, b, err := bson.MarshalValue(
750+
NewSet("1", "test"),
751+
)
752+
if err != nil {
753+
t.Errorf("Error should be nil: %v", err)
754+
}
755+
756+
actual := NewSet[string]()
757+
err = bson.UnmarshalValue(bson.TypeArray, b, actual)
758+
if err != nil {
759+
t.Errorf("Error should be nil: %v", err)
760+
}
761+
762+
if !expected.Equal(actual) {
763+
t.Errorf("Expected no difference, got: %v", expected.Difference(actual))
764+
}
765+
}

threadunsafe.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ import (
2929
"encoding/json"
3030
"fmt"
3131
"strings"
32+
33+
"go.mongodb.org/mongo-driver/bson"
34+
"go.mongodb.org/mongo-driver/bson/bsontype"
3235
)
3336

3437
type threadUnsafeSet[T comparable] map[T]struct{}
@@ -350,3 +353,24 @@ func (s *threadUnsafeSet[T]) UnmarshalJSON(b []byte) error {
350353

351354
return nil
352355
}
356+
357+
// MarshalBSON creates a BSON array from the set.
358+
func (s threadUnsafeSet[T]) MarshalBSONValue() (bsontype.Type, []byte, error) {
359+
return bson.MarshalValue(s.ToSlice())
360+
}
361+
362+
// UnmarshalBSON recreates a set from a BSON array.
363+
func (s threadUnsafeSet[T]) UnmarshalBSONValue(bt bsontype.Type, b []byte) error {
364+
if bt != bson.TypeArray {
365+
return fmt.Errorf("must use BSON Array to unmarshal Set")
366+
}
367+
368+
var i []T
369+
err := bson.UnmarshalValue(bt, b, &i)
370+
if err != nil {
371+
return err
372+
}
373+
s.Append(i...)
374+
375+
return nil
376+
}

0 commit comments

Comments
 (0)