Skip to content

Commit 8cf4f78

Browse files
authored
feat: support encode zero values (#5)
* support encode zero values * remove auto fail of test fix linting.
1 parent a9dd514 commit 8cf4f78

File tree

5 files changed

+57
-16
lines changed

5 files changed

+57
-16
lines changed

insert.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func BuildInsert(tableName string, values []any, options ...InsertOption) (strin
3737
}
3838
encodedValues := make([]map[string]SQLValuer, len(values))
3939
for i, value := range values {
40-
encodedValues[i] = encodeValues(value, skipInsert)
40+
encodedValues[i] = encodeValues(value, skipInsert, false)
4141
}
4242
return q.Rows(encodedValues).ToSQL()
4343
}

struct.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,25 @@ const (
2424
defaultNowUtc = "now_utc"
2525
)
2626

27-
func encodeValues(v any, skipType string) map[string]SQLValuer {
27+
func encodeValues(v any, skipType string, skipZeroValues bool) map[string]SQLValuer {
2828
t := reflect.ValueOf(v)
2929
fields := reflect.VisibleFields(t.Type())
3030
values := make(map[string]SQLValuer)
3131
for _, f := range fields {
3232
if !f.IsExported() || strings.Contains(f.Tag.Get(tagName), skipType) {
3333
continue
3434
}
35+
value := t.FieldByName(f.Name)
36+
if skipZeroValues && reflect.Zero(f.Type).Equal(value) {
37+
continue
38+
}
3539
switch {
3640
case strings.Contains(f.Tag.Get(tagName), defaultNowUtc):
3741
values[strcase.ToSnake(f.Name)] = SQLValuer{time.Now().UTC()}
3842
case strings.Contains(f.Tag.Get(tagName), defaultNow):
3943
values[strcase.ToSnake(f.Name)] = SQLValuer{time.Now()}
4044
default:
41-
values[strcase.ToSnake(f.Name)] = SQLValuer{t.FieldByName(f.Name).Interface()}
45+
values[strcase.ToSnake(f.Name)] = SQLValuer{value.Interface()}
4246
}
4347
}
4448
return values

struct_test.go

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ import (
1111

1212
func TestEncodeValues(t *testing.T) {
1313
tableTests := []struct {
14-
name string
15-
model interface{}
16-
values map[string]SQLValuer
17-
skipFlag string
14+
name string
15+
model interface{}
16+
values map[string]SQLValuer
17+
skipFlag string
18+
skipZeroValues bool
1819
}{
1920
{
2021
name: "encode_insert",
@@ -23,21 +24,44 @@ func TestEncodeValues(t *testing.T) {
2324
unexported bool
2425
FieldToSkip int `goqux:"skip_insert"`
2526
}{IntField: 1},
26-
values: map[string]SQLValuer{"int_field": {1}},
27-
skipFlag: skipInsert,
27+
values: map[string]SQLValuer{"int_field": {1}},
28+
skipFlag: skipInsert,
29+
skipZeroValues: false,
2830
},
2931
{
3032
name: "encode_array",
3133
model: struct {
3234
IntField []int
3335
}{IntField: []int{1, 2}},
34-
values: map[string]SQLValuer{"int_field": {[]int{1, 2}}},
35-
skipFlag: skipInsert,
36+
values: map[string]SQLValuer{"int_field": {[]int{1, 2}}},
37+
skipFlag: skipInsert,
38+
skipZeroValues: false,
39+
},
40+
{
41+
name: "encode_array_with_zero_values",
42+
model: struct {
43+
IntField []int
44+
}{IntField: []int{1, 0}},
45+
values: map[string]SQLValuer{"int_field": {[]int{1, 0}}},
46+
skipFlag: skipInsert,
47+
skipZeroValues: false,
48+
},
49+
{
50+
name: "encode_zero_values",
51+
model: struct {
52+
IntField int
53+
FloatField float64
54+
unexported bool
55+
FieldToSkip int `goqux:"skip_insert"`
56+
}{IntField: 0},
57+
values: map[string]SQLValuer{},
58+
skipFlag: skipInsert,
59+
skipZeroValues: true,
3660
},
3761
}
3862
for _, tt := range tableTests {
3963
t.Run(tt.name, func(t *testing.T) {
40-
values := encodeValues(tt.model, tt.skipFlag)
64+
values := encodeValues(tt.model, tt.skipFlag, tt.skipZeroValues)
4165
assert.Equal(t, tt.values, values)
4266
})
4367
}
@@ -50,12 +74,11 @@ func TestEncodeTimeValue(t *testing.T) {
5074
FieldToSkip int `goqux:"skip_insert"`
5175
}{
5276
FieldToSkip: 5,
53-
}, skipInsert)
77+
}, skipInsert, true)
5478
if tf, ok := values["time_field"]; ok {
5579
require.NotNil(t, tf)
5680
return
5781
}
58-
t.Fail()
5982
}
6083

6184
func TestGetColumnsFromStruct(t *testing.T) {

update.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package goqux
22

33
import (
4+
"errors"
5+
46
"github.com/doug-martin/goqu/v9"
57
"github.com/doug-martin/goqu/v9/exp"
68
)
@@ -31,6 +33,10 @@ func BuildUpdate(tableName string, value any, options ...UpdateOption) (string,
3133
for _, o := range options {
3234
q = o(table, q)
3335
}
34-
q = q.Set(encodeValues(value, skipUpdate))
36+
values := encodeValues(value, skipUpdate, true)
37+
if len(values) == 0 {
38+
return "", nil, errors.New("no values to update")
39+
}
40+
q = q.Set(values)
3541
return q.ToSQL()
3642
}

update_test.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package goqux_test
22

33
import (
4+
"errors"
45
"testing"
56

67
"github.com/roneli/goqux"
@@ -41,12 +42,19 @@ func TestBuildUpdate(t *testing.T) {
4142
expectedQuery: `UPDATE "update_models" SET "int_field"=$1 RETURNING *`,
4243
expectedArgs: []interface{}{int64(5)},
4344
},
45+
{
46+
name: "update_with_zero_values",
47+
dst: updateModel{IntField: 0},
48+
expectedQuery: ``,
49+
expectedArgs: nil,
50+
expectedError: errors.New("no values to update"),
51+
},
4452
}
4553
for _, tt := range tableTests {
4654
t.Run(tt.name, func(t *testing.T) {
4755
query, args, err := goqux.BuildUpdate("update_models", tt.dst, tt.options...)
4856
if tt.expectedError != nil {
49-
assert.ErrorIs(t, tt.expectedError, err)
57+
assert.Equal(t, tt.expectedError, err)
5058
}
5159
assert.Equal(t, tt.expectedQuery, query)
5260
assert.Equal(t, tt.expectedArgs, args)

0 commit comments

Comments
 (0)