Skip to content

Commit 3e39971

Browse files
chore(internal): support default value struct tag
1 parent 7721cb4 commit 3e39971

File tree

4 files changed

+67
-10
lines changed

4 files changed

+67
-10
lines changed

internal/apiform/tag.go

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ const apiStructTag = "api"
99
const jsonStructTag = "json"
1010
const formStructTag = "form"
1111
const formatStructTag = "format"
12+
const defaultStructTag = "default"
1213

1314
type parsedStructTag struct {
14-
name string
15-
required bool
16-
extras bool
17-
metadata bool
18-
omitzero bool
15+
name string
16+
required bool
17+
extras bool
18+
metadata bool
19+
omitzero bool
20+
defaultValue any
1921
}
2022

2123
func parseFormStructTag(field reflect.StructField) (tag parsedStructTag, ok bool) {
@@ -45,9 +47,23 @@ func parseFormStructTag(field reflect.StructField) (tag parsedStructTag, ok bool
4547
}
4648

4749
parseApiStructTag(field, &tag)
50+
parseDefaultStructTag(field, &tag)
4851
return tag, ok
4952
}
5053

54+
func parseDefaultStructTag(field reflect.StructField, tag *parsedStructTag) {
55+
if field.Type.Kind() != reflect.String {
56+
// Only strings are currently supported
57+
return
58+
}
59+
60+
raw, ok := field.Tag.Lookup(defaultStructTag)
61+
if !ok {
62+
return
63+
}
64+
tag.defaultValue = raw
65+
}
66+
5167
func parseApiStructTag(field reflect.StructField, tag *parsedStructTag) {
5268
raw, ok := field.Tag.Lookup(apiStructTag)
5369
if !ok {

internal/apijson/encoder.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import (
1212
"time"
1313

1414
"github.com/tidwall/sjson"
15+
16+
shimjson "github.com/beeper/desktop-api-go/internal/encoding/json"
1517
)
1618

1719
var encoders sync.Map // map[encoderEntry]encoderFunc
@@ -271,6 +273,12 @@ func (e *encoder) newStructTypeEncoder(t reflect.Type) encoderFunc {
271273
if err != nil {
272274
return nil, err
273275
}
276+
if ef.tag.defaultValue != nil && (!field.IsValid() || field.IsZero()) {
277+
encoded, err = shimjson.Marshal(ef.tag.defaultValue)
278+
if err != nil {
279+
return nil, err
280+
}
281+
}
274282
if encoded == nil {
275283
continue
276284
}

internal/apijson/json_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,3 +614,20 @@ func TestEncode(t *testing.T) {
614614
})
615615
}
616616
}
617+
618+
type StructWithDefault struct {
619+
Type string `json:"type" default:"foo"`
620+
}
621+
622+
func TestDefault(t *testing.T) {
623+
value := StructWithDefault{}
624+
expected := `{"type":"foo"}`
625+
626+
raw, err := Marshal(value)
627+
if err != nil {
628+
t.Fatalf("serialization of %v failed with error %v", value, err)
629+
}
630+
if string(raw) != expected {
631+
t.Fatalf("expected %+#v to serialize to %s but got %s", value, expected, string(raw))
632+
}
633+
}

internal/apijson/tag.go

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ import (
88
const apiStructTag = "api"
99
const jsonStructTag = "json"
1010
const formatStructTag = "format"
11+
const defaultStructTag = "default"
1112

1213
type parsedStructTag struct {
13-
name string
14-
required bool
15-
extras bool
16-
metadata bool
17-
inline bool
14+
name string
15+
required bool
16+
extras bool
17+
metadata bool
18+
inline bool
19+
defaultValue any
1820
}
1921

2022
func parseJSONStructTag(field reflect.StructField) (tag parsedStructTag, ok bool) {
@@ -42,9 +44,23 @@ func parseJSONStructTag(field reflect.StructField) (tag parsedStructTag, ok bool
4244

4345
// the `api` struct tag is only used alongside `json` for custom behaviour
4446
parseApiStructTag(field, &tag)
47+
parseDefaultStructTag(field, &tag)
4548
return tag, ok
4649
}
4750

51+
func parseDefaultStructTag(field reflect.StructField, tag *parsedStructTag) {
52+
if field.Type.Kind() != reflect.String {
53+
// Only strings are currently supported
54+
return
55+
}
56+
57+
raw, ok := field.Tag.Lookup(defaultStructTag)
58+
if !ok {
59+
return
60+
}
61+
tag.defaultValue = raw
62+
}
63+
4864
func parseApiStructTag(field reflect.StructField, tag *parsedStructTag) {
4965
raw, ok := field.Tag.Lookup(apiStructTag)
5066
if !ok {

0 commit comments

Comments
 (0)