Skip to content
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

Add ForceSendFields and a custom Marshaller #615

Merged
merged 26 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
4b0ed4e
Create custom marshaller
hectorcast-db Sep 7, 2023
f6377d9
Delete file commited by mistake
hectorcast-db Sep 13, 2023
7594c7a
Remove slices package usage for compatiblity with older golang versions
hectorcast-db Sep 13, 2023
20732bd
Implement non omit empty fields
hectorcast-db Sep 13, 2023
4840554
Remove useless log
hectorcast-db Sep 13, 2023
3aa4e5b
Fix PR comments
hectorcast-db Sep 14, 2023
ea0abcc
Remove unnecesary retype
hectorcast-db Sep 14, 2023
a2d31f0
Update template
hectorcast-db Sep 14, 2023
421092b
Address PR comments
hectorcast-db Sep 15, 2023
d2cec31
Add ForceSendFields only to structs with fields which the omitempty j…
hectorcast-db Sep 15, 2023
e705c43
More PR comments
hectorcast-db Sep 22, 2023
eb90608
Merge remote-tracking branch 'origin/main' into custom-marshaller-test
hectorcast-db Sep 22, 2023
37407aa
Fix comments
hectorcast-db Sep 22, 2023
084272a
Cache reflect values
hectorcast-db Sep 22, 2023
611178a
Cache tag parsing
hectorcast-db Sep 22, 2023
e8d4dbd
Simplify tag caching
hectorcast-db Sep 25, 2023
49150a8
Use thread lock on reads
hectorcast-db Sep 25, 2023
22d5c4f
Unlock by defer to ensure unlocking
hectorcast-db Sep 25, 2023
e9a35c2
Merge remote-tracking branch 'origin/main' into custom-marshaller-test
hectorcast-db Sep 29, 2023
72e9718
Update openapi sha
hectorcast-db Sep 29, 2023
168f324
Missing file
hectorcast-db Sep 29, 2023
c4b5b3f
Merge remote-tracking branch 'origin/main' into custom-marshaller-test
hectorcast-db Oct 4, 2023
9480c80
Fmt
hectorcast-db Oct 4, 2023
d55c909
Improve tests
hectorcast-db Oct 11, 2023
30f09af
Merge branch 'main' into custom-marshaller-test
hectorcast-db Oct 11, 2023
baffd4d
Update comment in marshal/marshal.go
hectorcast-db Oct 11, 2023
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
13 changes: 13 additions & 0 deletions .codegen/model.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
{{range .ImportedPackages}}
"github.com/databricks/databricks-sdk-go/service/{{.}}"{{end}}
"io"
"github.com/databricks/databricks-sdk-go/marshal"
)

// all definitions in this file are in alphabetical order
Expand All @@ -15,7 +16,19 @@ type {{.PascalName}} struct {
{{- range .Fields}}
{{.Comment " // " 80}}
{{.PascalName}} {{if .IsOptionalObject}}*{{end}}{{template "type" .Entity}} `{{template "field-tag" . }}`{{end}}

{{if .ShouldIncludeForceSendFields}} ForceSendFields []string `json:"-"` {{end}}
}

{{if .ShouldIncludeForceSendFields}}
func (s *{{.PascalName}}) UnmarshalJSON(b []byte) error {
return marshal.Unmarshal(b, s)
}

func (s {{.PascalName}}) MarshalJSON() ([]byte, error) {
hectorcast-db marked this conversation as resolved.
Show resolved Hide resolved
return marshal.Marshal(s)
}
{{end}}
{{else if .MapValue}}{{.Comment "// " 80}}
type {{.PascalName}} {{template "type" .}}
{{else if .Enum}}{{.Comment "// " 80}}
Expand Down
190 changes: 190 additions & 0 deletions marshal/composite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
package marshal

import (
"encoding/json"
"testing"

"github.com/stretchr/testify/assert"
)

type CompositeParent struct {
Field1 int `json:"field1,omitempty"`

ForceSendFields []string `json:"-"`
}

type CompositeSecondParent struct {
Field3 int `json:"field3,omitempty"`

ForceSendFields []string `json:"-"`
}

func (s *CompositeSecondParent) UnmarshalJSON(b []byte) error {
return Unmarshal(b, s)
}

func (s CompositeSecondParent) MarshalJSON() ([]byte, error) {
return Marshal(s)
}

func (s *CompositeParent) UnmarshalJSON(b []byte) error {
return Unmarshal(b, s)
}

func (s CompositeParent) MarshalJSON() ([]byte, error) {
return Marshal(s)
}

type compositeChild struct {
CompositeParent
*CompositeSecondParent
Field2 int `json:"field2,omitempty"`
}

func (s compositeChild) MarshalJSON() ([]byte, error) {
return Marshal(s)
}

func (s *compositeChild) UnmarshalJSON(b []byte) error {
return Unmarshal(b, s)
}

func TestComposite(t *testing.T) {
executeCompositeMarshalTest(
t, compositeTest{
st: compositeChild{
Field2: 2,
CompositeParent: CompositeParent{
Field1: 1,
ForceSendFields: []string{"Field1"},
},
CompositeSecondParent: &CompositeSecondParent{
Field3: 3,
ForceSendFields: []string{"Field3"},
},
},
jsonString: `{"field1":1, "field2":2, "field3":3}`,
matchClassic: true,
},
)

}

func TestCompositeNil(t *testing.T) {
element := compositeChild{
Field2: 2,
CompositeParent: CompositeParent{
Field1: 1,
ForceSendFields: []string{"Field1"},
},
}
expected := compositeChild{
Field2: 2,
CompositeParent: CompositeParent{
Field1: 1,
},
//CompositeSecondParent will be present due to limitations of the unmarshalling
CompositeSecondParent: &CompositeSecondParent{},
}
executeCompositeMarshalTest(
t, compositeTest{
st: element,
jsonString: `{"field1":1, "field2":2}`,
matchClassic: true,
unmarshalResult: &expected,
},
)
element.CompositeSecondParent = &CompositeSecondParent{}

}

func TestCompositeDefault(t *testing.T) {
executeCompositeMarshalTest(
t, compositeTest{
st: compositeChild{
Field2: 0,
CompositeParent: CompositeParent{
Field1: 0,
ForceSendFields: []string{"Field1"},
},
CompositeSecondParent: &CompositeSecondParent{
Field3: 0,
ForceSendFields: []string{"Field3"},
},
},
jsonString: `{"field1":0, "field3":0}`,
matchClassic: true,
},
)
}

type compositeTest struct {
st compositeChild
jsonString string
// Compare marshal results with normal marshal
matchClassic bool
// Unmarshal may not match, since ForceSendFields will be populated during
// custom unmarshal process
unmarshalResult *compositeChild
}

func executeCompositeMarshalTest(t *testing.T, tc compositeTest) compositeChild {
// Convert to JSON
res, err := json.Marshal(tc.st)
assert.NoError(t, err, "error while executing custom marshal")
compareJSON(t, tc.jsonString, string(res))

var reconstruct compositeChild
err = json.Unmarshal(res, &reconstruct)
assert.NoError(t, err, "error while unmarshaling")

expected := tc.st
if tc.unmarshalResult != nil {
expected = *tc.unmarshalResult
}
// We don't expect the ForceSendFields to match. Removing to compare the results
expected.CompositeParent.ForceSendFields = nil
if expected.CompositeSecondParent != nil {
expected.CompositeSecondParent.ForceSendFields = nil
}
reconstruct.CompositeParent.ForceSendFields = nil
if reconstruct.CompositeSecondParent != nil {
reconstruct.CompositeSecondParent.ForceSendFields = nil
}

assert.Equal(t, expected, reconstruct)

return reconstruct
}

type noSendFieldChild struct {
*CompositeSecondParent
Field2 int `json:"field2"`
}

func (s *noSendFieldChild) UnmarshalJSON(b []byte) error {
return Unmarshal(b, s)
}

func (s noSendFieldChild) MarshalJSON() ([]byte, error) {
return Marshal(s)
}

// Similar to TestCompositeNil, but this struct has a single anonymous field.
// In such case, GoLang will surface ForceSendFields.
func TestNoSendFieldChild(t *testing.T) {
st := noSendFieldChild{
Field2: 2,
}

res, err := json.Marshal(st)
assert.NoError(t, err, "error while executing custom marshal")
compareJSON(t, `{"field2":2}`, string(res))

var reconstruct noSendFieldChild
err = json.Unmarshal(res, &reconstruct)
assert.NoError(t, err, "error while unmarshaling")
st.CompositeSecondParent = &CompositeSecondParent{}
assert.Equal(t, st, reconstruct)

}
Loading
Loading