Skip to content

Commit 6daad4d

Browse files
authored
Check uniqueness of resources is now opt-in (#61)
* Set optional the check uniqueness * Include unique option * Inject marshal options
1 parent 326e1d5 commit 6daad4d

File tree

4 files changed

+32
-11
lines changed

4 files changed

+32
-11
lines changed

marshal.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ func init() {
2121
type Marshaler struct {
2222
meta any
2323
includeJSONAPI bool
24+
checkUniqueness bool
2425
jsonAPImeta any
2526
included []any
2627
link *Link
@@ -50,6 +51,13 @@ func MarshalJSONAPI(meta any) MarshalOption {
5051
}
5152
}
5253

54+
// MarshallCheckUniqueness enables checking for unique resources during marshaling.
55+
func MarshallCheckUniqueness() MarshalOption {
56+
return func(m *Marshaler) {
57+
m.checkUniqueness = true
58+
}
59+
}
60+
5361
// MarshalInclude includes the json:api encoding of v within Document.Included creating a compound document as defined by https://jsonapi.org/format/#document-compound-documents.
5462
func MarshalInclude(v ...any) MarshalOption {
5563
return func(m *Marshaler) {
@@ -204,9 +212,10 @@ func makeDocument(v any, m *Marshaler, isRelationship bool) (*document, error) {
204212
}
205213
d.Included = append(d.Included, ro)
206214
}
207-
208-
if ok := d.verifyResourceUniqueness(); !ok {
209-
return nil, ErrNonuniqueResource
215+
if m.checkUniqueness {
216+
if ok := d.verifyResourceUniqueness(); !ok {
217+
return nil, ErrNonuniqueResource
218+
}
210219
}
211220
// if we got any included data, verify full-linkage of this compound document.
212221
if err := d.verifyFullLinkage(false); err != nil {

marshal_test.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ func TestMarshal(t *testing.T) {
2020
given any
2121
expect string
2222
expectError error
23+
opts []MarshalOption
2324
}{
2425
{
2526
description: "nil",
@@ -86,6 +87,7 @@ func TestMarshal(t *testing.T) {
8687
given: articlesAA,
8788
expect: "",
8889
expectError: ErrNonuniqueResource,
90+
opts: []MarshalOption{MarshallCheckUniqueness()},
8991
}, {
9092
description: "[]*Article",
9193
given: articlesABPtr,
@@ -285,11 +287,11 @@ func TestMarshal(t *testing.T) {
285287

286288
for i, tc := range tests {
287289
tc := tc
288-
t.Run(fmt.Sprintf("%02d", i), func(t *testing.T) {
290+
t.Run(fmt.Sprintf("%02d - %s", i, tc.description), func(t *testing.T) {
289291
t.Parallel()
290292
t.Log(tc.description)
291293

292-
actual, err := Marshal(tc.given)
294+
actual, err := Marshal(tc.given, tc.opts...)
293295
if tc.expectError != nil {
294296
is.EqualError(t, tc.expectError, err)
295297
is.Nil(t, actual)
@@ -592,7 +594,7 @@ func TestMarshalRelationships(t *testing.T) {
592594
}, {
593595
description: "with related nonunique comments",
594596
given: &articleRelatedNonuniqueComments,
595-
marshalOptions: nil,
597+
marshalOptions: []MarshalOption{MarshallCheckUniqueness()},
596598
expect: "",
597599
expectError: ErrNonuniqueResource,
598600
}, {
@@ -641,7 +643,7 @@ func TestMarshalRelationships(t *testing.T) {
641643

642644
for i, tc := range tests {
643645
tc := tc
644-
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
646+
t.Run(fmt.Sprintf("%d - %s", i, tc.description), func(t *testing.T) {
645647
t.Parallel()
646648
t.Log(tc.description)
647649

unmarshal.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
type Unmarshaler struct {
1212
unmarshalMeta bool
1313
unmarshalLinks bool
14+
checkUniqueness bool
1415
meta any
1516
links *Link
1617
memberNameValidationMode MemberNameValidationMode
@@ -35,6 +36,13 @@ func UnmarshalLinks(link *Link) UnmarshalOption {
3536
}
3637
}
3738

39+
// UnmarshalCheckUniqueness enables checking for unique resources during unmarshaling.
40+
func UnmarshalCheckUniqueness() UnmarshalOption {
41+
return func(m *Unmarshaler) {
42+
m.checkUniqueness = true
43+
}
44+
}
45+
3846
// UnmarshalSetNameValidation enables a given level of document member name validation.
3947
func UnmarshalSetNameValidation(mode MemberNameValidationMode) UnmarshalOption {
4048
return func(m *Unmarshaler) {
@@ -88,8 +96,10 @@ func Unmarshal(data []byte, v any, opts ...UnmarshalOption) (err error) {
8896
}
8997

9098
func (d *document) unmarshal(v any, m *Unmarshaler) (err error) {
91-
if ok := d.verifyResourceUniqueness(); !ok {
92-
return ErrNonuniqueResource
99+
if m.checkUniqueness {
100+
if ok := d.verifyResourceUniqueness(); !ok {
101+
return ErrNonuniqueResource
102+
}
93103
}
94104
// verify full-linkage in-case this is a compound document
95105
if err = d.verifyFullLinkage(true); err != nil {

unmarshal_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func TestUnmarshal(t *testing.T) {
7474
given: articlesABNonuniqueData,
7575
do: func(body []byte) (any, error) {
7676
var a []Article
77-
err := Unmarshal(body, &a)
77+
err := Unmarshal(body, &a, UnmarshalCheckUniqueness())
7878
return a, err
7979
},
8080
expect: ([]Article)(nil),
@@ -430,7 +430,7 @@ func TestUnmarshal(t *testing.T) {
430430
given: articleRelatedNonuniqueLinkage,
431431
do: func(body []byte) (any, error) {
432432
var a ArticleRelated
433-
err := Unmarshal(body, &a)
433+
err := Unmarshal(body, &a, UnmarshalCheckUniqueness())
434434
return a, err
435435
},
436436
expect: ArticleRelated{},

0 commit comments

Comments
 (0)