-
Notifications
You must be signed in to change notification settings - Fork 11
Description
Problem Description:
We are encountering an issue when parsing a nullable typeid from the database and then using it in another query. When we parse a NULL value, we expect to get NULL back, but instead, we get prefix_00000000000000000000000000, which disrupts our query.
Currently, scanning nils/empty strings results in a zero-initialized typeid:
Lines 13 to 18 in dd4ff4b
| case nil: | |
| return nil | |
| case string: | |
| if src == "" { | |
| return nil | |
| } |
However, when encoding it back, we get prefix_00000000000000000000000000, which is neither NULL nor an empty string:
Lines 31 to 33 in dd4ff4b
| func (tid TypeID[P]) Value() (driver.Value, error) { | |
| return tid.String(), nil | |
| } |
The discussion in #11 mainly focuses on parsing but does not address putting the ID back into the database.
Question:
How should we handle NULL values?
Option 1: Wrapping typeid in a Parent Struct to Handle NULL Explicitly
Example wrapping code:
type NullableTypeID[P typeid.PrefixType] struct {
Valid bool
TypeID typeid.TypeID[P]
}
func (ntid *NullableTypeID[P]) Scan(src any) error {
switch obj := src.(type) {
case nil:
return nil
case string:
if err := ntid.TypeID.Scan(src); err != nil {
return err
}
ntid.Valid = true
return nil
default:
return fmt.Errorf("unsupported scan type %T", obj)
}
}
func (ntid NullableTypeID[P]) Value() (driver.Value, error) {
if !ntid.Valid {
return nil, nil
}
return ntid.TypeID.String(), nil
}This approach has some disadvantages like the fact that NullableTypeID.TypeID is not comparable to a regular TypeID.
In this case, I would either like to get some documentation that recommends this approach or even include the wrapper in the package directly.
Option 2: typeid.Value() Returns NULL Based on isZero
The Value() method is updated to:
func (tid TypeID[P]) Value() (driver.Value, error) {
if tid.IsZero() {
return nil, nil
}
return tid.String(), nil
}This could cause an issue if someone was relying on "" being converted to "prefix_00000000000000000000000000" if the column wasn't nullable.
Just an extra note:
From the description of sql.Scanner the current Scan() implementation is invalid as we are losing the distinction between NULL and "".
// An error should be returned if the value cannot be stored
// without loss of information.