package dbx import ( "reflect" "github.com/go-jet/jet/v2/mysql" "golang.org/x/exp/constraints" ) type ApplyInterface[T any] interface { Equal(T) bool IsZero() bool } // ApplyPtr compares the existing value with a new value and returns the updated value if they differ. // If the new value is nil, the existing value is retained. If the new value is a zero-value, the // existing value is NOT retained, it will be set to nil. If the value is changed, targetColumn is pushed // to updatedColumns. func ApplyPtr[T constraints.Float | constraints.Integer | string | bool]( existing *T, newVal *T, updatedColumns *mysql.ColumnList, targetColumn mysql.Column, ) *T { if newVal == nil { return existing } if reflect.ValueOf(*newVal).IsZero() { newVal = nil } if newVal == nil && existing == nil || newVal != nil && existing != nil && *existing == *newVal { return existing } *updatedColumns = append(*updatedColumns, targetColumn) return newVal } // ApplyComplexPtr compares the existing value with a new value and returns the updated value if they differ. // The new value may be of a different type (e.g. existing is uint16 and new is uint64), but it will be // converted to match the current type resulting in potential loss of data. If the new value is nil, the // existing value is retained. If the new value is a zero-value, the existing value is NOT retained, it // will be set to nil. If the value is changed, targetColumn is pushed to updatedColumns. func ApplyComplexPtr[ Existing constraints.Float | constraints.Integer, New constraints.Float | constraints.Integer, ]( existing *Existing, newVal *New, updatedColumns *mysql.ColumnList, targetColumn mysql.Column, ) *Existing { if newVal == nil { return existing } cast := Existing(*newVal) if existing != nil && *existing == cast { return existing } if reflect.ValueOf(cast).IsZero() { if existing != nil { *updatedColumns = append(*updatedColumns, targetColumn) } return nil } *updatedColumns = append(*updatedColumns, targetColumn) return &cast } // ApplyInterfacePtr compares the existing value with a new value and returns the updated value if // they differ. Comparable types must have IsZero and Equal methods. If the new value is nil, the // existing value is retained. If the new value is a zero-value, the existing value is NOT retained, // it will be set to nil. If the value is changed, targetColumn is pushed to updatedColumns. func ApplyInterfacePtr[T ApplyInterface[T]]( existing *T, newVal *T, updatedColumns *mysql.ColumnList, targetColumn mysql.Column, ) *T { if newVal == nil { return existing } if existing != nil && (*existing).Equal(*newVal) { return existing } if (*newVal).IsZero() { if existing != nil { *updatedColumns = append(*updatedColumns, targetColumn) } return nil } *updatedColumns = append(*updatedColumns, targetColumn) return newVal } // ApplyVal compares the existing value with a pointer to a new value and returns the updated value if they // differ. If the new value is nil, the existing value is retained. If the value is changed, targetColumn // is pushed to updatedColumns func ApplyVal[T constraints.Float | constraints.Integer | string | bool]( existing T, newVal *T, updatedColumns *mysql.ColumnList, targetColumn mysql.Column, ) T { if newVal == nil { return existing } if existing == *newVal { return existing } *updatedColumns = append(*updatedColumns, targetColumn) return *newVal }