init - add project files
This commit is contained in:
194
tools/jet-2.12.0/qrm/internal/null_types.go
Normal file
194
tools/jet-2.12.0/qrm/internal/null_types.go
Normal file
@@ -0,0 +1,194 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"github.com/go-jet/jet/v2/internal/utils/min"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
castOverFlowError = fmt.Errorf("cannot cast a negative value to an unsigned value, buffer overflow error")
|
||||
)
|
||||
|
||||
// NullBool struct
|
||||
type NullBool struct {
|
||||
sql.NullBool
|
||||
}
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (nb *NullBool) Scan(value interface{}) error {
|
||||
switch v := value.(type) {
|
||||
case bool:
|
||||
nb.Bool, nb.Valid = v, true
|
||||
case int8, int16, int32, int64, int:
|
||||
intVal := reflect.ValueOf(v).Int()
|
||||
|
||||
if intVal != 0 && intVal != 1 {
|
||||
return fmt.Errorf("can't assign %T(%d) to bool", value, value)
|
||||
}
|
||||
|
||||
nb.Bool = intVal == 1
|
||||
nb.Valid = true
|
||||
case uint8, uint16, uint32, uint64, uint:
|
||||
uintVal := reflect.ValueOf(v).Uint()
|
||||
|
||||
if uintVal != 0 && uintVal != 1 {
|
||||
return fmt.Errorf("can't assign %T(%d) to bool", value, value)
|
||||
}
|
||||
|
||||
nb.Bool = uintVal == 1
|
||||
nb.Valid = true
|
||||
default:
|
||||
return nb.NullBool.Scan(value)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NullTime struct
|
||||
type NullTime struct {
|
||||
sql.NullTime
|
||||
}
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (nt *NullTime) Scan(value interface{}) error {
|
||||
err := nt.NullTime.Scan(value)
|
||||
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Some of the drivers (pgx, mysql) are not parsing all of the time formats(date, time with time zone,...) and are just forwarding string value.
|
||||
// At this point we try to parse those values using some of the predefined formats
|
||||
nt.Time, nt.Valid = tryParseAsTime(value)
|
||||
|
||||
if !nt.Valid {
|
||||
return fmt.Errorf("can't scan time.Time from %q", value)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var formats = []string{
|
||||
"2006-01-02 15:04:05-07:00", // sqlite
|
||||
"2006-01-02 15:04:05.999999", // go-sql-driver/mysql
|
||||
"15:04:05-07", // pgx
|
||||
"15:04:05.999999", // pgx
|
||||
}
|
||||
|
||||
func tryParseAsTime(value interface{}) (time.Time, bool) {
|
||||
|
||||
var timeStr string
|
||||
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
timeStr = v
|
||||
case []byte:
|
||||
timeStr = string(v)
|
||||
case int64:
|
||||
return time.Unix(v, 0), true // sqlite
|
||||
default:
|
||||
return time.Time{}, false
|
||||
}
|
||||
|
||||
for _, format := range formats {
|
||||
formatLen := min.Int(len(format), len(timeStr))
|
||||
t, err := time.Parse(format[:formatLen], timeStr)
|
||||
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
return t, true
|
||||
}
|
||||
|
||||
return time.Time{}, false
|
||||
}
|
||||
|
||||
// NullUInt64 struct
|
||||
type NullUInt64 struct {
|
||||
UInt64 uint64
|
||||
Valid bool
|
||||
}
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (n *NullUInt64) Scan(value interface{}) error {
|
||||
var stringValue string
|
||||
switch v := value.(type) {
|
||||
case nil:
|
||||
n.Valid = false
|
||||
return nil
|
||||
case int64:
|
||||
if v < 0 {
|
||||
return castOverFlowError
|
||||
}
|
||||
n.UInt64, n.Valid = uint64(v), true
|
||||
return nil
|
||||
case int32:
|
||||
if v < 0 {
|
||||
return castOverFlowError
|
||||
}
|
||||
n.UInt64, n.Valid = uint64(v), true
|
||||
return nil
|
||||
case int16:
|
||||
if v < 0 {
|
||||
return castOverFlowError
|
||||
}
|
||||
n.UInt64, n.Valid = uint64(v), true
|
||||
return nil
|
||||
case int8:
|
||||
if v < 0 {
|
||||
return castOverFlowError
|
||||
}
|
||||
n.UInt64, n.Valid = uint64(v), true
|
||||
return nil
|
||||
case int:
|
||||
if v < 0 {
|
||||
return castOverFlowError
|
||||
}
|
||||
n.UInt64, n.Valid = uint64(v), true
|
||||
return nil
|
||||
case uint64:
|
||||
n.UInt64, n.Valid = v, true
|
||||
return nil
|
||||
case uint32:
|
||||
n.UInt64, n.Valid = uint64(v), true
|
||||
return nil
|
||||
case uint16:
|
||||
n.UInt64, n.Valid = uint64(v), true
|
||||
return nil
|
||||
case uint8:
|
||||
n.UInt64, n.Valid = uint64(v), true
|
||||
return nil
|
||||
case uint:
|
||||
n.UInt64, n.Valid = uint64(v), true
|
||||
return nil
|
||||
case []byte:
|
||||
stringValue = string(v)
|
||||
case string:
|
||||
stringValue = v
|
||||
default:
|
||||
return fmt.Errorf("can't scan uint64 from %v", value)
|
||||
}
|
||||
|
||||
uintV, err := strconv.ParseUint(stringValue, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n.UInt64 = uintV
|
||||
n.Valid = true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (n NullUInt64) Value() (driver.Value, error) {
|
||||
if !n.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return n.UInt64, nil
|
||||
}
|
||||
127
tools/jet-2.12.0/qrm/internal/null_types_test.go
Normal file
127
tools/jet-2.12.0/qrm/internal/null_types_test.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestNullBool(t *testing.T) {
|
||||
var nullBool NullBool
|
||||
|
||||
require.NoError(t, nullBool.Scan(nil))
|
||||
require.Equal(t, nullBool.Valid, false)
|
||||
|
||||
require.NoError(t, nullBool.Scan(int64(1)))
|
||||
require.Equal(t, nullBool.Valid, true)
|
||||
value, _ := nullBool.Value()
|
||||
require.Equal(t, value, true)
|
||||
|
||||
require.NoError(t, nullBool.Scan(uint32(0)))
|
||||
require.Equal(t, nullBool.Valid, true)
|
||||
value, _ = nullBool.Value()
|
||||
require.Equal(t, value, false)
|
||||
|
||||
require.EqualError(t, nullBool.Scan(uint16(22)), "can't assign uint16(22) to bool")
|
||||
}
|
||||
|
||||
func TestNullTime(t *testing.T) {
|
||||
var nullTime NullTime
|
||||
|
||||
require.NoError(t, nullTime.Scan(nil))
|
||||
require.Equal(t, nullTime.Valid, false)
|
||||
|
||||
time := time.Now()
|
||||
require.NoError(t, nullTime.Scan(time))
|
||||
require.Equal(t, nullTime.Valid, true)
|
||||
value, _ := nullTime.Value()
|
||||
require.Equal(t, value, time)
|
||||
|
||||
require.NoError(t, nullTime.Scan([]byte("13:10:11")))
|
||||
require.Equal(t, nullTime.Valid, true)
|
||||
value, _ = nullTime.Value()
|
||||
require.Equal(t, fmt.Sprintf("%v", value), "0000-01-01 13:10:11 +0000 UTC")
|
||||
|
||||
require.NoError(t, nullTime.Scan("13:10:11"))
|
||||
require.Equal(t, nullTime.Valid, true)
|
||||
value, _ = nullTime.Value()
|
||||
require.Equal(t, fmt.Sprintf("%v", value), "0000-01-01 13:10:11 +0000 UTC")
|
||||
|
||||
require.Error(t, nullTime.Scan(12), "can't scan time.Time from 12")
|
||||
}
|
||||
|
||||
func TestNullUInt64(t *testing.T) {
|
||||
var nullUInt64 NullUInt64
|
||||
|
||||
require.NoError(t, nullUInt64.Scan(nil))
|
||||
require.Equal(t, nullUInt64.Valid, false)
|
||||
|
||||
require.NoError(t, nullUInt64.Scan(int64(11)))
|
||||
require.Equal(t, nullUInt64.Valid, true)
|
||||
value, _ := nullUInt64.Value()
|
||||
require.Equal(t, value, uint64(11))
|
||||
|
||||
require.NoError(t, nullUInt64.Scan(uint64(11)))
|
||||
require.Equal(t, nullUInt64.Valid, true)
|
||||
value, _ = nullUInt64.Value()
|
||||
require.Equal(t, value, uint64(11))
|
||||
|
||||
require.NoError(t, nullUInt64.Scan(int32(32)))
|
||||
require.Equal(t, nullUInt64.Valid, true)
|
||||
value, _ = nullUInt64.Value()
|
||||
require.Equal(t, value, uint64(32))
|
||||
|
||||
require.NoError(t, nullUInt64.Scan(uint32(32)))
|
||||
require.Equal(t, nullUInt64.Valid, true)
|
||||
value, _ = nullUInt64.Value()
|
||||
require.Equal(t, value, uint64(32))
|
||||
|
||||
require.NoError(t, nullUInt64.Scan(int16(20)))
|
||||
require.Equal(t, nullUInt64.Valid, true)
|
||||
value, _ = nullUInt64.Value()
|
||||
require.Equal(t, value, uint64(20))
|
||||
|
||||
require.NoError(t, nullUInt64.Scan(uint16(16)))
|
||||
require.Equal(t, nullUInt64.Valid, true)
|
||||
value, _ = nullUInt64.Value()
|
||||
require.Equal(t, value, uint64(16))
|
||||
|
||||
require.NoError(t, nullUInt64.Scan(int8(30)))
|
||||
require.Equal(t, nullUInt64.Valid, true)
|
||||
value, _ = nullUInt64.Value()
|
||||
require.Equal(t, value, uint64(30))
|
||||
|
||||
require.NoError(t, nullUInt64.Scan(uint8(30)))
|
||||
require.Equal(t, nullUInt64.Valid, true)
|
||||
value, _ = nullUInt64.Value()
|
||||
require.Equal(t, value, uint64(30))
|
||||
|
||||
require.Error(t, nullUInt64.Scan("text"), "can't scan int32 from text")
|
||||
|
||||
//Validate negative use cases
|
||||
err := nullUInt64.Scan(int64(-5))
|
||||
assert.NotNil(t, err)
|
||||
assert.Error(t, err, castOverFlowError)
|
||||
|
||||
//Validate negative use cases
|
||||
err = nullUInt64.Scan(-5)
|
||||
assert.NotNil(t, err)
|
||||
assert.Error(t, err, castOverFlowError)
|
||||
|
||||
//Validate negative use cases
|
||||
err = nullUInt64.Scan(int32(-5))
|
||||
assert.NotNil(t, err)
|
||||
assert.Error(t, err, castOverFlowError)
|
||||
|
||||
//Validate negative use cases
|
||||
err = nullUInt64.Scan(int16(-5))
|
||||
assert.NotNil(t, err)
|
||||
assert.Error(t, err, castOverFlowError)
|
||||
|
||||
//Validate negative use cases
|
||||
err = nullUInt64.Scan(int8(-5))
|
||||
assert.NotNil(t, err)
|
||||
assert.Error(t, err, castOverFlowError)
|
||||
}
|
||||
Reference in New Issue
Block a user