This PR adds support for a new copier.Valuer interface. This interface lets custom types implement a function returning the actual value to copy.
For example if your type is a wrapper, or if it doesn't have to implement sql/driver.Valuer, you can implement this interface so the returned value will be used instead. It can also be used to format your type or convert it to another one before being copied.
It differs from TypeConverter in several ways:
It can work with generics (see example use-case below). With TypeConverter, you would have to define a type pair for every different generic type you are going to use. This is inconvenient.
You don't know the destination type, and you don't need to.
It can be used in addition to TypeConverter, where TypeConverter handles the concrete simple types and Valuer allows more complex types to be handled gracefully.
It works in a very simple way: at the start of copier() and set() functions, if the from value implements Valuer,it is replaced with the one returned by CopyValue(), and the usual process continues.
Example use-case:
The Undefined type allows to know if a field in a structure is undefined (which is different from nil, in the case of nullable values). This is useful for PATCH updates so we just omit the fields that are not present.
type Undefined[T any] struct {
Val T
Present bool
}
func (u Undefined[T]) CopyValue() any {
if !u.Present {
return nil
}
if valuer, ok := any(&u.Val).(copier.Valuer); ok {
return valuer.CopyValue()
}
return u.Val
}
If the field is not present, the struct has its zero-value, which is handy so it can be ignored with the option IgnoreEmpty.
This PR adds support for a new
copier.Valuer
interface. This interface lets custom types implement a function returning the actual value to copy.For example if your type is a wrapper, or if it doesn't have to implement
sql/driver.Valuer
, you can implement this interface so the returned value will be used instead. It can also be used to format your type or convert it to another one before being copied.It differs from
TypeConverter
in several ways:TypeConverter
, you would have to define a type pair for every different generic type you are going to use. This is inconvenient.TypeConverter
, whereTypeConverter
handles the concrete simple types andValuer
allows more complex types to be handled gracefully.It works in a very simple way: at the start of
copier()
andset()
functions, if the from value implementsValuer
,it is replaced with the one returned byCopyValue()
, and the usual process continues.Example use-case:
The
Undefined
type allows to know if a field in a structure is undefined (which is different fromnil
, in the case of nullable values). This is useful for PATCH updates so we just omit the fields that are not present.If the field is not present, the struct has its zero-value, which is handy so it can be ignored with the option
IgnoreEmpty
.