Skip to content

Check uniqueness of resources is now opt-in #61

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ func init() {
type Marshaler struct {
meta any
includeJSONAPI bool
checkUniqueness bool
jsonAPImeta any
included []any
link *Link
Expand Down Expand Up @@ -50,6 +51,13 @@ func MarshalJSONAPI(meta any) MarshalOption {
}
}

// MarshallCheckUniqueness enables checking for unique resources during marshaling.
func MarshallCheckUniqueness() MarshalOption {
return func(m *Marshaler) {
m.checkUniqueness = true
}
}

// 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.
func MarshalInclude(v ...any) MarshalOption {
return func(m *Marshaler) {
Expand Down Expand Up @@ -204,9 +212,10 @@ func makeDocument(v any, m *Marshaler, isRelationship bool) (*document, error) {
}
d.Included = append(d.Included, ro)
}

if ok := d.verifyResourceUniqueness(); !ok {
return nil, ErrNonuniqueResource
if m.checkUniqueness {
if ok := d.verifyResourceUniqueness(); !ok {
return nil, ErrNonuniqueResource
}
}
// if we got any included data, verify full-linkage of this compound document.
if err := d.verifyFullLinkage(false); err != nil {
Expand Down
10 changes: 6 additions & 4 deletions marshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func TestMarshal(t *testing.T) {
given any
expect string
expectError error
opts []MarshalOption
}{
{
description: "nil",
Expand Down Expand Up @@ -86,6 +87,7 @@ func TestMarshal(t *testing.T) {
given: articlesAA,
expect: "",
expectError: ErrNonuniqueResource,
opts: []MarshalOption{MarshallCheckUniqueness()},
}, {
description: "[]*Article",
given: articlesABPtr,
Expand Down Expand Up @@ -285,11 +287,11 @@ func TestMarshal(t *testing.T) {

for i, tc := range tests {
tc := tc
t.Run(fmt.Sprintf("%02d", i), func(t *testing.T) {
t.Run(fmt.Sprintf("%02d - %s", i, tc.description), func(t *testing.T) {
t.Parallel()
t.Log(tc.description)

actual, err := Marshal(tc.given)
actual, err := Marshal(tc.given, tc.opts...)
if tc.expectError != nil {
is.EqualError(t, tc.expectError, err)
is.Nil(t, actual)
Expand Down Expand Up @@ -592,7 +594,7 @@ func TestMarshalRelationships(t *testing.T) {
}, {
description: "with related nonunique comments",
given: &articleRelatedNonuniqueComments,
marshalOptions: nil,
marshalOptions: []MarshalOption{MarshallCheckUniqueness()},
expect: "",
expectError: ErrNonuniqueResource,
}, {
Expand Down Expand Up @@ -641,7 +643,7 @@ func TestMarshalRelationships(t *testing.T) {

for i, tc := range tests {
tc := tc
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
t.Run(fmt.Sprintf("%d - %s", i, tc.description), func(t *testing.T) {
t.Parallel()
t.Log(tc.description)

Expand Down
14 changes: 12 additions & 2 deletions unmarshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
type Unmarshaler struct {
unmarshalMeta bool
unmarshalLinks bool
checkUniqueness bool
meta any
links *Link
memberNameValidationMode MemberNameValidationMode
Expand All @@ -35,6 +36,13 @@ func UnmarshalLinks(link *Link) UnmarshalOption {
}
}

// UnmarshalCheckUniqueness enables checking for unique resources during unmarshaling.
func UnmarshalCheckUniqueness() UnmarshalOption {
return func(m *Unmarshaler) {
m.checkUniqueness = true
}
}

// UnmarshalSetNameValidation enables a given level of document member name validation.
func UnmarshalSetNameValidation(mode MemberNameValidationMode) UnmarshalOption {
return func(m *Unmarshaler) {
Expand Down Expand Up @@ -88,8 +96,10 @@ func Unmarshal(data []byte, v any, opts ...UnmarshalOption) (err error) {
}

func (d *document) unmarshal(v any, m *Unmarshaler) (err error) {
if ok := d.verifyResourceUniqueness(); !ok {
return ErrNonuniqueResource
if m.checkUniqueness {
if ok := d.verifyResourceUniqueness(); !ok {
return ErrNonuniqueResource
}
}
// verify full-linkage in-case this is a compound document
if err = d.verifyFullLinkage(true); err != nil {
Expand Down
4 changes: 2 additions & 2 deletions unmarshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func TestUnmarshal(t *testing.T) {
given: articlesABNonuniqueData,
do: func(body []byte) (any, error) {
var a []Article
err := Unmarshal(body, &a)
err := Unmarshal(body, &a, UnmarshalCheckUniqueness())
return a, err
},
expect: ([]Article)(nil),
Expand Down Expand Up @@ -430,7 +430,7 @@ func TestUnmarshal(t *testing.T) {
given: articleRelatedNonuniqueLinkage,
do: func(body []byte) (any, error) {
var a ArticleRelated
err := Unmarshal(body, &a)
err := Unmarshal(body, &a, UnmarshalCheckUniqueness())
return a, err
},
expect: ArticleRelated{},
Expand Down
Loading