Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Valuer interface #191

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

System-Glitch
Copy link

@System-Glitch System-Glitch commented Aug 10, 2023

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.


  • Tests
  • Documentation

@System-Glitch
Copy link
Author

For those wanting this feature, I decided to maintain a fork: https://github.com/go-goyave/copier

Contributions are also welcome there.

It also includes a few other bug fixes, including #182 #185

@@ -118,6 +127,11 @@ func CopyWithOption(toValue interface{}, fromValue interface{}, opt Option) (err
}

func copier(toValue interface{}, fromValue interface{}, opt Option) (err error) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: unnecessary break line

}

func TestCopyValuer(t *testing.T) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: unnecessary break line

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants