github.com/mpontillo/pop@v4.13.1+incompatible/nulls/types_test.go (about) 1 package nulls_test 2 3 import ( 4 "database/sql" 5 "encoding/json" 6 "fmt" 7 "os" 8 "strings" 9 "testing" 10 "time" 11 12 "github.com/gobuffalo/nulls" 13 14 . "github.com/gobuffalo/pop/nulls" 15 "github.com/gofrs/uuid" 16 "github.com/jmoiron/sqlx" 17 _ "github.com/mattn/go-sqlite3" 18 "github.com/stretchr/testify/require" 19 ) 20 21 type Foo struct { 22 ID Int64 `json:"id" db:"id"` 23 Name String `json:"name" db:"name"` 24 Alive Bool `json:"alive" db:"alive"` 25 Price Float64 `json:"price" db:"price"` 26 Birth Time `json:"birth" db:"birth"` 27 Price32 Float32 `json:"price32" db:"price32"` 28 Bytes ByteSlice `json:"bytes" db:"bytes"` 29 IntType Int `json:"intType" db:"int_type"` 30 Int32Type Int32 `json:"int32Type" db:"int32_type"` 31 UInt32Type UInt32 `json:"uint32Type" db:"uint32_type"` 32 UID UUID `json:"uid" db:"uid"` 33 } 34 35 const schema = `CREATE TABLE "main"."foos" ( 36 "id" integer, 37 "name" text, 38 "alive" integer, 39 "price" float, 40 "birth" timestamp, 41 "price32" float, 42 "bytes" blob, 43 "int_type" integer, 44 "int32_type" integer, 45 "uint32_type" integer, 46 "uid" uuid 47 );` 48 49 // Ensure legacy package is still compatible with new package types. 50 var _ nulls.Bool = NewBool(true) 51 var uid, _ = uuid.NewV4() 52 var now = time.Now() 53 54 func newValidFoo() Foo { 55 return Foo{ 56 ID: NewInt64(1), 57 Name: NewString("Mark"), 58 Alive: NewBool(true), 59 Price: NewFloat64(9.99), 60 Birth: NewTime(now), 61 Price32: NewFloat32(3.33), 62 Bytes: NewByteSlice([]byte("Byte Slice")), 63 IntType: NewInt(2), 64 Int32Type: NewInt32(3), 65 UInt32Type: NewUInt32(5), 66 UID: NewUUID(uid), 67 } 68 } 69 70 func Test_TypesMarshalProperly(t *testing.T) { 71 t.Parallel() 72 73 a := require.New(t) 74 f := newValidFoo() 75 76 ti, _ := json.Marshal(now) 77 ba, _ := json.Marshal(f.Bytes) 78 jsonString := fmt.Sprintf(`{"id":1,"name":"Mark","alive":true,"price":9.99,"birth":%s,"price32":3.33,"bytes":%s,"intType":2,"int32Type":3,"uint32Type":5,"uid":"%s"}`, ti, ba, uid.String()) 79 80 // check marshalling to json works: 81 data, _ := json.Marshal(f) 82 a.Equal(string(data), jsonString) 83 84 // check unmarshalling from json works: 85 f = Foo{} 86 json.NewDecoder(strings.NewReader(jsonString)).Decode(&f) 87 a.Equal(f.ID.Int64, int64(1)) 88 a.Equal(f.Name.String, "Mark") 89 a.Equal(f.Alive.Bool, true) 90 a.Equal(f.Price.Float64, 9.99) 91 a.Equal(f.Birth.Time.Nanosecond(), now.Nanosecond()) 92 a.Equal(f.Price32.Float32, float32(3.33)) 93 a.Equal(f.Bytes.ByteSlice, ba) 94 a.Equal(f.IntType.Int, 2) 95 a.Equal(f.Int32Type.Int32, int32(3)) 96 a.Equal(f.UInt32Type.UInt32, uint32(5)) 97 a.Equal(uid.String(), f.UID.UUID.String()) 98 99 // check marshalling nulls works: 100 f = Foo{} 101 jsonString = `{"id":null,"name":null,"alive":null,"price":null,"birth":null,"price32":null,"bytes":null,"intType":null,"int32Type":null,"uint32Type":null,"uid":null}` 102 data, _ = json.Marshal(f) 103 a.Equal(string(data), jsonString) 104 105 f = Foo{} 106 json.NewDecoder(strings.NewReader(jsonString)).Decode(&f) 107 a.Equal(f.ID.Int64, int64(0)) 108 a.False(f.ID.Valid) 109 a.Equal(f.Name.String, "") 110 a.False(f.Name.Valid) 111 a.Equal(f.Alive.Bool, false) 112 a.False(f.Alive.Valid) 113 a.Equal(f.Price.Float64, float64(0)) 114 a.False(f.Price.Valid) 115 a.Equal(f.Birth.Time, time.Time{}) 116 a.False(f.Birth.Valid) 117 a.Equal(f.Price32.Float32, float32(0)) 118 a.False(f.Price32.Valid) 119 a.Equal(f.Bytes.ByteSlice, []byte(nil)) 120 a.False(f.Bytes.Valid) 121 a.Equal(f.IntType.Int, 0) 122 a.False(f.IntType.Valid) 123 a.Equal(f.Int32Type.Int32, int32(0)) 124 a.False(f.Int32Type.Valid) 125 a.Equal(f.UInt32Type.UInt32, uint32(0)) 126 a.False(f.UInt32Type.Valid) 127 a.Equal(f.UID.UUID, uuid.Nil) 128 a.False(f.UID.Valid) 129 } 130 131 func Test_TypeSaveAndRetrieveProperly(t *testing.T) { 132 t.Parallel() 133 134 a := require.New(t) 135 136 initDB(func(db *sqlx.DB) { 137 // Test with invalid INSERT query 138 tx, err := db.Beginx() 139 a.NoError(err) 140 _, err = tx.Exec("insert into foos") 141 a.Error(err) 142 143 f := Foo{} 144 a.Equal(sql.ErrNoRows, tx.Get(&f, "select * from foos")) 145 a.False(f.Alive.Valid) 146 a.False(f.Birth.Valid) 147 a.False(f.ID.Valid) 148 a.False(f.Name.Valid) 149 a.False(f.Price.Valid) 150 a.False(f.Alive.Bool) 151 a.False(f.Price32.Valid) 152 a.False(f.Bytes.Valid) 153 a.False(f.IntType.Valid) 154 a.False(f.Int32Type.Valid) 155 a.False(f.UInt32Type.Valid) 156 a.Equal(f.Birth.Time.UnixNano(), time.Time{}.UnixNano()) 157 a.Equal(f.ID.Int64, int64(0)) 158 a.Equal(f.Name.String, "") 159 a.Equal(f.Price.Float64, float64(0)) 160 a.Equal(f.Price32.Float32, float32(0)) 161 a.Equal(f.Bytes.ByteSlice, []byte(nil)) 162 a.Equal(f.IntType.Int, 0) 163 a.Equal(f.Int32Type.Int32, int32(0)) 164 a.Equal(f.UInt32Type.UInt32, uint32(0)) 165 a.NoError(tx.Rollback()) 166 167 // Test with valid INSERT query 168 tx, err = db.Beginx() 169 a.NoError(err) 170 171 f = newValidFoo() 172 _, err = tx.NamedExec("INSERT INTO foos (id, name, alive, price, birth, price32, bytes, int_type, int32_type, uint32_type, uid) VALUES (:id, :name, :alive, :price, :birth, :price32, :bytes, :int_type, :int32_type, :uint32_type, :uid)", &f) 173 a.NoError(err) 174 f = Foo{} 175 a.NoError(tx.Get(&f, "select * from foos")) 176 a.True(f.Alive.Valid) 177 a.True(f.Birth.Valid) 178 a.True(f.ID.Valid) 179 a.True(f.Name.Valid) 180 a.True(f.Price.Valid) 181 a.True(f.Alive.Bool) 182 a.True(f.Price32.Valid) 183 a.True(f.Bytes.Valid) 184 a.True(f.IntType.Valid) 185 a.True(f.Int32Type.Valid) 186 a.True(f.UInt32Type.Valid) 187 a.Equal(f.Birth.Time.UnixNano(), now.UnixNano()) 188 a.Equal(f.ID.Int64, int64(1)) 189 a.Equal(f.Name.String, "Mark") 190 a.Equal(f.Price.Float64, 9.99) 191 a.Equal(f.Price32.Float32, float32(3.33)) 192 a.Equal(f.Bytes.ByteSlice, []byte("Byte Slice")) 193 a.Equal(f.IntType.Int, 2) 194 a.Equal(f.Int32Type.Int32, int32(3)) 195 a.Equal(f.UInt32Type.UInt32, uint32(5)) 196 a.Equal(uid.String(), f.UID.UUID.String()) 197 198 a.NoError(tx.Rollback()) 199 }) 200 } 201 202 func initDB(f func(db *sqlx.DB)) { 203 os.Remove("./foo.db") 204 db, _ := sqlx.Open("sqlite3", "./foo.db") 205 db.MustExec(schema) 206 f(db) 207 os.Remove("./foo.db") 208 }