package schema

import (
	
	
	
	
	
	

	
	
	
)

var (
	bunNullTimeType = reflect.TypeOf((*NullTime)(nil)).Elem()
	nullTimeType    = reflect.TypeOf((*sql.NullTime)(nil)).Elem()
	nullBoolType    = reflect.TypeOf((*sql.NullBool)(nil)).Elem()
	nullFloatType   = reflect.TypeOf((*sql.NullFloat64)(nil)).Elem()
	nullIntType     = reflect.TypeOf((*sql.NullInt64)(nil)).Elem()
	nullStringType  = reflect.TypeOf((*sql.NullString)(nil)).Elem()
)

var sqlTypes = []string{
	reflect.Bool:       sqltype.Boolean,
	reflect.Int:        sqltype.BigInt,
	reflect.Int8:       sqltype.SmallInt,
	reflect.Int16:      sqltype.SmallInt,
	reflect.Int32:      sqltype.Integer,
	reflect.Int64:      sqltype.BigInt,
	reflect.Uint:       sqltype.BigInt,
	reflect.Uint8:      sqltype.SmallInt,
	reflect.Uint16:     sqltype.SmallInt,
	reflect.Uint32:     sqltype.Integer,
	reflect.Uint64:     sqltype.BigInt,
	reflect.Uintptr:    sqltype.BigInt,
	reflect.Float32:    sqltype.Real,
	reflect.Float64:    sqltype.DoublePrecision,
	reflect.Complex64:  "",
	reflect.Complex128: "",
	reflect.Array:      "",
	reflect.Interface:  "",
	reflect.Map:        sqltype.VarChar,
	reflect.Ptr:        "",
	reflect.Slice:      sqltype.VarChar,
	reflect.String:     sqltype.VarChar,
	reflect.Struct:     sqltype.VarChar,
}

func ( reflect.Type) string {
	switch  {
	case timeType, nullTimeType, bunNullTimeType:
		return sqltype.Timestamp
	case nullBoolType:
		return sqltype.Boolean
	case nullFloatType:
		return sqltype.DoublePrecision
	case nullIntType:
		return sqltype.BigInt
	case nullStringType:
		return sqltype.VarChar
	}
	return sqlTypes[.Kind()]
}

//------------------------------------------------------------------------------

var jsonNull = []byte("null")

// NullTime is a time.Time wrapper that marshals zero time as JSON null and SQL NULL.
type NullTime struct {
	time.Time
}

var (
	_ json.Marshaler   = (*NullTime)(nil)
	_ json.Unmarshaler = (*NullTime)(nil)
	_ sql.Scanner      = (*NullTime)(nil)
	_ QueryAppender    = (*NullTime)(nil)
)

func ( NullTime) () ([]byte, error) {
	if .IsZero() {
		return jsonNull, nil
	}
	return .Time.MarshalJSON()
}

func ( *NullTime) ( []byte) error {
	if bytes.Equal(, jsonNull) {
		.Time = time.Time{}
		return nil
	}
	return .Time.UnmarshalJSON()
}

func ( NullTime) ( Formatter,  []byte) ([]byte, error) {
	if .IsZero() {
		return dialect.AppendNull(), nil
	}
	return dialect.AppendTime(, .Time), nil
}

func ( *NullTime) ( interface{}) error {
	if  == nil {
		.Time = time.Time{}
		return nil
	}

	switch src := .(type) {
	case time.Time:
		.Time = 
		return nil
	case string:
		,  := internal.ParseTime()
		if  != nil {
			return 
		}
		.Time = 
		return nil
	case []byte:
		,  := internal.ParseTime(internal.String())
		if  != nil {
			return 
		}
		.Time = 
		return nil
	default:
		return fmt.Errorf("bun: can't scan %#v into NullTime", )
	}
}