diff --git a/.github/workflows/ci-code-approval.yml b/.github/workflows/ci-code-approval.yml index daf3caf..46d3b8e 100644 --- a/.github/workflows/ci-code-approval.yml +++ b/.github/workflows/ci-code-approval.yml @@ -100,3 +100,6 @@ jobs: # Do not run this is the PR is created by dependabot - name: "Check for changes" run: git diff --exit-code + + - name: "Check for new files" + run: git diff --exit-code --name-status diff --git a/examples/basic_ignores/main.go b/examples/basic_ignores/main.go new file mode 100644 index 0000000..5f93f24 --- /dev/null +++ b/examples/basic_ignores/main.go @@ -0,0 +1,51 @@ +package main + +import ( + "encoding/json" + "fmt" + + "github.com/jacobbrewer1/patcher" +) + +type Person struct { + ID *int `json:"id" db:"id"` + Name *string `json:"name" db:"name"` + IgnoredField *string `json:"ignored_field" patcher:"-"` +} + +type PersonWhere struct { + ID *int `db:"id"` +} + +func NewPersonWhere(id int) *PersonWhere { + return &PersonWhere{ + ID: &id, + } +} + +func (p *PersonWhere) Where() (string, []any) { + return "id = ?", []any{*p.ID} +} + +func main() { + const jsonStr = `{"id": 1, "name": "john", "ignored_field": "ignored"}` + + person := new(Person) + if err := json.Unmarshal([]byte(jsonStr), person); err != nil { + panic(err) + } + + condition := NewPersonWhere(*person.ID) + + sqlStr, args, err := patcher.GenerateSQL( + person, + patcher.WithTable("people"), + patcher.WithWhere(condition), + ) + if err != nil { + panic(err) + } + + fmt.Println(sqlStr) + fmt.Println(args) +} diff --git a/examples/loader_with_opts/main.go b/examples/loader_with_opts/main.go index fb8a2da..56fb22f 100644 --- a/examples/loader_with_opts/main.go +++ b/examples/loader_with_opts/main.go @@ -2,6 +2,8 @@ package main import ( "fmt" + "reflect" + "strings" "github.com/jacobbrewer1/patcher" ) @@ -16,6 +18,7 @@ type Something struct { IgnoredField string IgnoredFieldTwo string IgnoredFieldByFunc string + IgnoredByTag string `patcher:"-"` } func main() { @@ -30,6 +33,7 @@ func main() { IgnoredField: "Ignored", IgnoredFieldTwo: "Ignored Two", IgnoredFieldByFunc: "Ignored By Func", + IgnoredByTag: "Ignored By Tag", } n := Something{ @@ -41,6 +45,7 @@ func main() { IgnoredField: "Diff Ignored", IgnoredFieldTwo: "Diff Ignored Two", IgnoredFieldByFunc: "Diff Ignored By Func", + IgnoredByTag: "Diff Ignored By Tag", } // The patcher.LoadDiff function will apply the changes from n to s. @@ -48,8 +53,8 @@ func main() { patcher.WithIncludeZeroValues(), patcher.WithIncludeNilValues(), patcher.WithIgnoredFields("ignoredField", "IgNoReDfIeLdTwO"), - patcher.WithIgnoredFieldsFunc(func(fieldName string, oldValue, newValue interface{}) bool { - return fieldName == "ignoredfieldbyfunc" + patcher.WithIgnoredFieldsFunc(func(field reflect.StructField, oldValue, newValue interface{}) bool { + return strings.ToLower(field.Name) == "ignoredfieldbyfunc" }), ); err != nil { panic(err) @@ -65,6 +70,7 @@ func main() { // Ignored // Ignored Two // Ignored By Func + // Ignored By Tag fmt.Println(s.Number) fmt.Println(s.Text) fmt.Println(s.PrePopulated) @@ -74,4 +80,5 @@ func main() { fmt.Println(s.IgnoredField) fmt.Println(s.IgnoredFieldTwo) fmt.Println(s.IgnoredFieldByFunc) + fmt.Println(s.IgnoredByTag) } diff --git a/loader.go b/loader.go index e699fe0..b24a91f 100644 --- a/loader.go +++ b/loader.go @@ -12,6 +12,8 @@ var ( ErrInvalidType = errors.New("invalid type: must pointer to struct") ) +type IgnoreFieldsFunc func(field reflect.StructField, oldValue, newValue any) bool + type loader struct { // includeZeroValues determines whether zero values should be included in the patch includeZeroValues bool @@ -25,7 +27,7 @@ type loader struct { // ignoreFieldsFunc is a function that determines whether a field should be ignored // // This func should return true is the field is to be ignored - ignoreFieldsFunc func(fieldName string, oldValue, newValue any) bool + ignoreFieldsFunc IgnoreFieldsFunc } func newLoader(opts ...LoaderOption) *loader { @@ -124,7 +126,7 @@ func (l *loader) checkSkipField(field reflect.StructField, oldValue, newValue an return true } - return l.ignoredFieldsCheck(strings.ToLower(field.Name), oldValue, newValue) + return l.ignoredFieldsCheck(field, oldValue, newValue) } func (l *loader) checkSkipTag(field reflect.StructField) bool { @@ -137,12 +139,12 @@ func (l *loader) checkSkipTag(field reflect.StructField) bool { return slices.Contains(tags, TagOptSkip) } -func (l *loader) ignoredFieldsCheck(field string, oldValue, newValue any) bool { - return l.checkIgnoredFields(field) || l.checkIgnoreFunc(field, oldValue, newValue) +func (l *loader) ignoredFieldsCheck(field reflect.StructField, oldValue, newValue any) bool { + return l.checkIgnoredFields(strings.ToLower(field.Name)) || l.checkIgnoreFunc(field, oldValue, newValue) } -func (l *loader) checkIgnoreFunc(field string, oldValue, newValue any) bool { - return l.ignoreFieldsFunc != nil && l.ignoreFieldsFunc(strings.ToLower(field), oldValue, newValue) +func (l *loader) checkIgnoreFunc(field reflect.StructField, oldValue, newValue any) bool { + return l.ignoreFieldsFunc != nil && l.ignoreFieldsFunc(field, oldValue, newValue) } func (l *loader) checkIgnoredFields(field string) bool { diff --git a/loader_opts.go b/loader_opts.go index 169ec00..50a1fec 100644 --- a/loader_opts.go +++ b/loader_opts.go @@ -1,6 +1,8 @@ package patcher -import "strings" +import ( + "strings" +) type LoaderOption func(*loader) @@ -43,10 +45,7 @@ func WithIgnoredFields(fields ...string) func(*loader) { } // WithIgnoredFieldsFunc sets a function that determines whether a field should be ignored when patching. -// -// Note. The field name is wrapped with `strings.ToLower` before being passed to this function, so please ensure that -// the field name is in lowercase if you are comparing it with this function. -func WithIgnoredFieldsFunc(f func(fieldName string, oldValue, newValue any) bool) func(*loader) { +func WithIgnoredFieldsFunc(f IgnoreFieldsFunc) func(*loader) { return func(l *loader) { if f == nil { return diff --git a/loader_test.go b/loader_test.go index 25c6613..f62b536 100644 --- a/loader_test.go +++ b/loader_test.go @@ -1,6 +1,8 @@ package patcher import ( + "reflect" + "strings" "testing" "github.com/stretchr/testify/suite" @@ -606,8 +608,8 @@ func (s *loadDiffSuite) TestLoadDiff_Success_IgnoreFields() { func (s *loadDiffSuite) TestLoadDiff_Success_IgnoreFieldsFunc() { l := s.l - l.ignoreFieldsFunc = func(fieldName string, oldValue, newValue any) bool { - return fieldName == "name" + l.ignoreFieldsFunc = func(field reflect.StructField, oldValue, newValue any) bool { + return strings.ToLower(field.Name) == "name" } type testStruct struct { @@ -634,8 +636,8 @@ func (s *loadDiffSuite) TestLoadDiff_Success_IgnoreFieldsFunc() { func (s *loadDiffSuite) TestLoadDiff_Success_IgnoreFieldsFuncAndIgnoreFields() { l := s.l l.ignoreFields = []string{"name"} - l.ignoreFieldsFunc = func(fieldName string, oldValue, newValue any) bool { - return fieldName == "name" + l.ignoreFieldsFunc = func(field reflect.StructField, oldValue, newValue any) bool { + return strings.ToLower(field.Name) == "name" } type testStruct struct {