Skip to content

Commit

Permalink
fix: slices package NULL handling
Browse files Browse the repository at this point in the history
  • Loading branch information
alnr committed Mar 31, 2023
1 parent 4b8d6dc commit b7e2752
Show file tree
Hide file tree
Showing 9 changed files with 37 additions and 10 deletions.
9 changes: 1 addition & 8 deletions SHOULDERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,9 @@ Thank you to the following **GIANTS**:
* [github.com/inconshreveable/mousetrap](https://godoc.org/github.com/inconshreveable/mousetrap)
* [github.com/jackc/chunkreader](https://godoc.org/github.com/jackc/chunkreader)
* [github.com/jackc/chunkreader/v2](https://godoc.org/github.com/jackc/chunkreader/v2)
* [github.com/jackc/pgconn](https://godoc.org/github.com/jackc/pgconn)
* [github.com/jackc/pgio](https://godoc.org/github.com/jackc/pgio)
* [github.com/jackc/pgmock](https://godoc.org/github.com/jackc/pgmock)
* [github.com/jackc/pgpassfile](https://godoc.org/github.com/jackc/pgpassfile)
* [github.com/jackc/pgproto3](https://godoc.org/github.com/jackc/pgproto3)
* [github.com/jackc/pgproto3/v2](https://godoc.org/github.com/jackc/pgproto3/v2)
* [github.com/jackc/pgservicefile](https://godoc.org/github.com/jackc/pgservicefile)
* [github.com/jackc/pgtype](https://godoc.org/github.com/jackc/pgtype)
* [github.com/jackc/pgx/v4](https://godoc.org/github.com/jackc/pgx/v4)
* [github.com/jackc/puddle](https://godoc.org/github.com/jackc/puddle)
* [github.com/jackc/pgx/v5](https://godoc.org/github.com/jackc/pgx/v5)
* [github.com/jmoiron/sqlx](https://godoc.org/github.com/jmoiron/sqlx)
* [github.com/joho/godotenv](https://godoc.org/github.com/joho/godotenv)
* [github.com/kballard/go-shellquote](https://godoc.org/github.com/kballard/go-shellquote)
Expand Down
4 changes: 3 additions & 1 deletion executors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1605,6 +1605,8 @@ func Test_UpdateQuery(t *testing.T) {

// ID is ignored
count, err = tx.Where("true").UpdateQuery(&User{ID: 123, Name: nulls.NewString("Bar")}, "id", "name")
r.NoError(err)
r.Equal(int64(3), count)
r.NoError(tx.Find(u1b, u1.ID))
r.NoError(tx.Find(u2b, u2.ID))
r.NoError(tx.Find(u3b, u3.ID))
Expand All @@ -1613,7 +1615,7 @@ func Test_UpdateQuery(t *testing.T) {
r.Equal(u3b.Name.String, "Bar")

// Invalid column yields an error
count, err = tx.Where("name = ?", "Foo").UpdateQuery(&User{Name: nulls.NewString("Bar")}, "mistake")
_, err = tx.Where("name = ?", "Foo").UpdateQuery(&User{Name: nulls.NewString("Bar")}, "mistake")
r.Contains(err.Error(), "could not find name mistake")

tx.Where("true").Delete(&User{})
Expand Down
3 changes: 3 additions & 0 deletions slices/float.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ func (f Float) Interface() interface{} {
func (f *Float) Scan(src interface{}) error {
var str string
switch t := src.(type) {
case nil:
*f = make([]float64, 0)
return nil
case []byte:
str = string(t)
case string:
Expand Down
3 changes: 3 additions & 0 deletions slices/int.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ func (i Int) Interface() interface{} {
func (i *Int) Scan(src interface{}) error {
var str string
switch t := src.(type) {
case nil:
*i = make([]int, 0)
return nil
case []byte:
str = string(t)
case string:
Expand Down
4 changes: 4 additions & 0 deletions slices/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ func (s String) Interface() interface{} {
// Scan implements the sql.Scanner interface.
// It allows to read the string slice from the database value.
func (s *String) Scan(src interface{}) error {
if src == nil {
*s = make([]string, 0)
return nil
}
// Still relying on pq driver to help with string arrays.
ss := pq.StringArray(*s)
err := ss.Scan(src)
Expand Down
8 changes: 8 additions & 0 deletions slices/string_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ import (
)

func Test_String_Scan(t *testing.T) {
t.Run("empty slice", func(t *testing.T) {
r := require.New(t)
in := "{}"
v := &String{}
r.NoError(v.Scan(in))
r.Len(*v, 0)
})

r := require.New(t)
in := `{"This has a comma,","This has a double quote\"","Also a single'"}`
s := &String{}
Expand Down
3 changes: 3 additions & 0 deletions slices/uuid.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ func (s UUID) Interface() interface{} {
func (s *UUID) Scan(src interface{}) error {
var b []byte
switch t := src.(type) {
case nil:
*s = make([]uuid.UUID, 0)
return nil
case []byte:
b = t
case string:
Expand Down
9 changes: 9 additions & 0 deletions slices_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ type Cake struct {
Int slices.Int `db:"int_slice"`
Float slices.Float `db:"float_slice"`
String slices.String `db:"string_slice"`
UUID slices.UUID `db:"uuid_slice"`
Map slices.Map `db:"map"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
}
Expand All @@ -27,7 +29,10 @@ func (s *PostgreSQLSuite) Test_String() {

err = tx.Reload(c)
r.NoError(err)
r.Equal(slices.Int{}, c.Int)
r.Equal(slices.Float{}, c.Float)
r.Equal(slices.String{"a", "b", "c"}, c.String)
r.Equal(slices.UUID{}, c.UUID)
})
}

Expand All @@ -45,6 +50,8 @@ func (s *PostgreSQLSuite) Test_Int() {
r.NoError(err)
r.Equal(slices.Int{1, 2, 3}, c.Int)
r.Equal(slices.Float{}, c.Float)
r.Equal(slices.String{}, c.String)
r.Equal(slices.UUID{}, c.UUID)
})
}

Expand All @@ -62,5 +69,7 @@ func (s *PostgreSQLSuite) Test_Float() {
r.NoError(err)
r.Equal(slices.Int{}, c.Int)
r.Equal(slices.Float{1.0, 2.1, 3.2}, c.Float)
r.Equal(slices.String{}, c.String)
r.Equal(slices.UUID{}, c.UUID)
})
}
4 changes: 3 additions & 1 deletion testdata/migrations/20181104140743_cakes.up.fizz
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
t.Column("int_slice", "int[]", {"null": true})
t.Column("float_slice", "numeric[]", {"null": true})
t.Column("string_slice", "varchar[]", {"null": true})
t.Column("uuid_slice", "uuid[]", {"null": true})
t.Column("map", "json", {"null": true})
t.Timestamps()
}
{{ end -}}
{{ end -}}

0 comments on commit b7e2752

Please sign in to comment.