Skip to content

Commit

Permalink
Merge pull request #29 from kaleido-io/map-omit
Browse files Browse the repository at this point in the history
Do not include the ",omitempty" in the JSON field name
  • Loading branch information
nguyer authored Aug 8, 2022
2 parents 5a2539a + ff559e4 commit 133c038
Show file tree
Hide file tree
Showing 10 changed files with 233 additions and 6 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ lint: ${LINT}
${MOCKERY}:
$(VGO) install github.com/vektra/mockery/cmd/mockery@latest
${LINT}:
$(VGO) install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
$(VGO) install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.47.0


define makemock
Expand Down
4 changes: 4 additions & 0 deletions pkg/fftypes/bigint.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,7 @@ func (i *FFBigInt) Equals(i2 *FFBigInt) bool {
return (*big.Int)(i).Cmp((*big.Int)(i2)) == 0
}
}

func (i *FFBigInt) String() string {
return (*big.Int)(i).String()
}
3 changes: 2 additions & 1 deletion pkg/fftypes/bigint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func TestBigIntJSONBadJSON(t *testing.T) {

}

func TestLagePositiveBigIntValue(t *testing.T) {
func TestLargePositiveBigIntValue(t *testing.T) {

var iMax FFBigInt
_ = iMax.Int().Exp(big.NewInt(2), big.NewInt(256), nil)
Expand Down Expand Up @@ -165,6 +165,7 @@ func TestScanString(t *testing.T) {
err := i.Scan("-feedbeef")
assert.NoError(t, err)
assert.Equal(t, int64(-4276993775), i.Int().Int64())
assert.Equal(t, "-4276993775", i.String())

}

Expand Down
100 changes: 100 additions & 0 deletions pkg/fftypes/int.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright © 2022 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package fftypes

import (
"context"
"encoding/json"
"math/big"
"strconv"

"github.com/hyperledger/firefly-common/pkg/i18n"
)

// FFuint64 on the API are serialized as Base10 strings, and can be parsed from multiple bases
// (very similar to fftypes.FFBigInt, but limited to a 64bit unsigned integer)
type FFuint64 uint64

func (i FFuint64) MarshalText() ([]byte, error) {
// Represent as base 10 string in Marshalled JSON
return []byte(strconv.FormatUint(uint64(i), 10)), nil
}

func (i *FFuint64) UnmarshalJSON(b []byte) error {
var val interface{}
if err := json.Unmarshal(b, &val); err != nil {
return i18n.WrapError(context.Background(), err, i18n.MsgBigIntParseFailed, b)
}
switch val := val.(type) {
case string:
bi, ok := new(big.Int).SetString(val, 0)
if !ok {
return i18n.NewError(context.Background(), i18n.MsgBigIntParseFailed, b)
}
*i = FFuint64(bi.Int64())
return nil
case float64:
*i = FFuint64(val)
return nil
default:
return i18n.NewError(context.Background(), i18n.MsgBigIntParseFailed, b)
}
}

func (i *FFuint64) Uint64() uint64 {
if i == nil {
return 0
}
return uint64(*i)
}

// FFint64 on the API are serialized as Base10 strings, and can be parsed from multiple bases
// (very similar to fftypes.FFBigInt, but limited to a 64bit signed integer)
type FFint64 int64

func (i FFint64) MarshalText() ([]byte, error) {
// Represent as base 10 string in Marshalled JSON
return []byte(strconv.FormatInt(int64(i), 10)), nil
}

func (i *FFint64) UnmarshalJSON(b []byte) error {
var val interface{}
if err := json.Unmarshal(b, &val); err != nil {
return i18n.WrapError(context.Background(), err, i18n.MsgBigIntParseFailed, b)
}
switch val := val.(type) {
case string:
bi, ok := new(big.Int).SetString(val, 0)
if !ok {
return i18n.NewError(context.Background(), i18n.MsgBigIntParseFailed, b)
}
*i = FFint64(bi.Int64())
return nil
case float64:
*i = FFint64(val)
return nil
default:
return i18n.NewError(context.Background(), i18n.MsgBigIntParseFailed, b)
}
}

func (i *FFint64) Int64() int64 {
if i == nil {
return 0
}
return int64(*i)
}
110 changes: 110 additions & 0 deletions pkg/fftypes/int_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Copyright © 2022 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package fftypes

import (
"encoding/json"
"testing"

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

func TestFFInt64JSON(t *testing.T) {

var myStruct struct {
Field1 FFint64 `json:"field1"`
Field2 *FFint64 `json:"field2"`
Field3 *FFint64 `json:"field3"`
Field4 *FFint64 `json:"field4"`
}

jsonVal := []byte(`{
"field1": -111111,
"field2": 2222.22,
"field3": "333333",
"field4": "0xfeedBEEF"
}`)

err := json.Unmarshal(jsonVal, &myStruct)
assert.NoError(t, err)
assert.Equal(t, int64(-111111), myStruct.Field1.Int64())
assert.Equal(t, int64(2222), myStruct.Field2.Int64())
assert.Equal(t, int64(333333), myStruct.Field3.Int64())
assert.Equal(t, int64(4276993775), myStruct.Field4.Int64())

jsonValSerialized, err := json.Marshal(&myStruct)

assert.NoError(t, err)
assert.JSONEq(t, `{
"field1": "-111111",
"field2": "2222",
"field3": "333333",
"field4": "4276993775"
}`, string(jsonValSerialized))

var ffi *FFuint64
assert.Equal(t, uint64(0), ffi.Uint64())
err = ffi.UnmarshalJSON([]byte(`"bad string`))
assert.Regexp(t, "FF00104", err)
err = ffi.UnmarshalJSON([]byte(`"!!! not a number"`))
assert.Regexp(t, "FF00104", err)
err = ffi.UnmarshalJSON([]byte(`{}`))
assert.Regexp(t, "FF00104", err)
}

func TestFFUint64JSON(t *testing.T) {

var myStruct struct {
Field1 FFuint64 `json:"field1"`
Field2 *FFuint64 `json:"field2"`
Field3 *FFuint64 `json:"field3"`
Field4 *FFuint64 `json:"field4"`
}

jsonVal := []byte(`{
"field1": 111111,
"field2": 2222.22,
"field3": "333333",
"field4": "0xfeedBEEF"
}`)

err := json.Unmarshal(jsonVal, &myStruct)
assert.NoError(t, err)
assert.Equal(t, uint64(111111), myStruct.Field1.Uint64())
assert.Equal(t, uint64(2222), myStruct.Field2.Uint64())
assert.Equal(t, uint64(333333), myStruct.Field3.Uint64())
assert.Equal(t, uint64(4276993775), myStruct.Field4.Uint64())

jsonValSerialized, err := json.Marshal(&myStruct)

assert.NoError(t, err)
assert.JSONEq(t, `{
"field1": "111111",
"field2": "2222",
"field3": "333333",
"field4": "4276993775"
}`, string(jsonValSerialized))

var ffi *FFint64
assert.Equal(t, int64(0), ffi.Int64())
err = ffi.UnmarshalJSON([]byte(`"bad string`))
assert.Regexp(t, "FF00104", err)
err = ffi.UnmarshalJSON([]byte(`"!!! not a number"`))
assert.Regexp(t, "FF00104", err)
err = ffi.UnmarshalJSON([]byte(`{}`))
assert.Regexp(t, "FF00104", err)
}
4 changes: 4 additions & 0 deletions pkg/fftypes/jsonobject.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ func (jd JSONObject) GetString(key string) string {

func (jd JSONObject) GetInteger(key string) *big.Int {
s := jd.GetString(key)
if s == "" {
log.L(context.Background()).Debugf("Int value unset for key '%s'", key)
return big.NewInt(0)
}
i, ok := big.NewInt(0).SetString(s, 0)
if !ok {
log.L(context.Background()).Errorf("Invalid int value '%+v' for key '%s'", s, key)
Expand Down
5 changes: 4 additions & 1 deletion pkg/fftypes/jsonobject_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ func TestJSONNestedSafeGet(t *testing.T) {
"string_array": ["str1","str2"],
"wrong": null,
"int1": "0xfeedbeef",
"int2": "12345"
"int2": "12345",
"bad": "!!!!!!!not an integer"
}
`), &jd)
assert.NoError(t, err)
Expand Down Expand Up @@ -186,6 +187,8 @@ func TestJSONNestedSafeGet(t *testing.T) {
assert.Equal(t, int64(0xfeedbeef), jd.GetInt64("int1"))
assert.Equal(t, int64(12345), jd.GetInt64("int2"))
assert.Equal(t, int64(0), jd.GetInt64("wrong"))
assert.Equal(t, int64(0), jd.GetInteger("string_array").Int64())
assert.Equal(t, int64(0), jd.GetInteger("bad").Int64())

sa, ok := jd.GetStringArrayOk("wrong")
assert.False(t, ok)
Expand Down
3 changes: 3 additions & 0 deletions pkg/fftypes/uuid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ func TestDatabaseSerialization(t *testing.T) {
assert.Nil(t, v)
assert.Equal(t, "", u.String())

err = u.UnmarshalText([]byte(""))
assert.NoError(t, err)

u, err = ParseUUID(context.Background(), "!not an id")
assert.Regexp(t, "FF00138", err)
u, err = ParseUUID(context.Background(), "03D31DFB-9DBB-43F2-9E0B-84DD3D293499")
Expand Down
6 changes: 4 additions & 2 deletions pkg/jsonmap/jsonmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,12 @@ func AddJSONFieldsToMap(val reflect.Value, data map[string]interface{}) {
tag, ok := varType.Field(i).Tag.Lookup(`json`)
var fieldName string
if ok && len(tag) > 0 {
if tag == "-" || strings.Contains(tag, ",omitempty") && isEmptyValue(f) {
tagValues := strings.Split(tag, ",")
tagName := tagValues[0]
if tagName == "-" || len(tagValues) > 1 && tagValues[1] == "omitempty" && isEmptyValue(f) {
continue
}
fieldName = tag
fieldName = tagName
} else {
fieldName = fType.Name
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/jsonmap/jsonmap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func TestAddJSONFieldsToMap(t *testing.T) {

type testType2 struct {
testType1
Field3 string `json:"f3"`
Field3 string `json:"f3,omitempty"`
IgnoreMe string `json:"-"`
DefaultName string
internalField string
Expand Down

0 comments on commit 133c038

Please sign in to comment.