Skip to content

proposal: database/sql: add a common method to unwrap value of sql.Null* types #63633

Open
@dolmen

Description

@dolmen

Proposal

Add an interface to database/sql implemented by sql.Null* types to unwrap the NULL or the value:

// NullUnwrap allows to unwrap sql.Null* types.
type NullUnwrap interface {
	UnwrapNull() (value any, valid bool)
}

(names to be debatted)

Extend sql.Null* types to implement it:

func (n Null[T]) UnwrapNull() (value any, valid bool) {                                                                                                                                                     
	if !n.Valid {
		return nil, false
	}
	return n.V, true
}

Why?

There is currently no builtin generic way to unwrap the value of types sql.Null* (sql.NullBool,sql.NullByte, sql.NullInt16, sql.NullInt32sql.NullInt64, sql.NullFloat64, sql.NullString, sql.NullTime).

But at least the list of types was known, so it was possible to use a type switch.

With the addition of sql.Null[T] (#60370) for Go 1.22 the type switch solution will not be enough.

The only ways to unwrap an sql.Null[T] are just hacks using either the driver.Valuer interface or reflect:

(full example: https://go.dev/play/p/DnStyHLekX1?v=gotip)

func UnwrapNullable(val driver.Valuer) (value any, valid bool) {
	v := reflect.ValueOf(val)
	if v.Field(1).Bool() {
		return v.Field(0).Interface(), true
	}
	return nil, false
}

func UnwrapNullable2(val driver.Valuer) (value any, valid bool) {
	value, err := val.Value()
	if err != nil {
		panic(err)
	}
	if value != nil {
		return value, true
	}
	return nil, false
}

A common method available on sql.Null* types would allow to have an efficient unwrapping and be type safe as unwrapping could be done after an interface check.

That interface could also help to distinguish types that are able to represent a NULL value (types that never return valid == false should not implement it).

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    Incoming

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions