package database import ( "fmt" "strings" ) // Trackable interface for models that can track field changes type Trackable interface { GetTableName() string GetID() int GetDirtyFields() map[string]any SetDirty(field string, value any) ClearDirty() IsDirty() bool } // FieldTracker provides dirty field tracking functionality type FieldTracker struct { dirty map[string]any } // SetDirty marks a field as dirty with its new value func (ft *FieldTracker) SetDirty(field string, value any) { if ft.dirty == nil { ft.dirty = make(map[string]any) } ft.dirty[field] = value } // GetDirtyFields returns map of dirty fields and their values func (ft *FieldTracker) GetDirtyFields() map[string]any { if ft.dirty == nil { return make(map[string]any) } return ft.dirty } // ClearDirty clears all dirty field tracking func (ft *FieldTracker) ClearDirty() { ft.dirty = nil } // IsDirty returns true if any fields have been modified func (ft *FieldTracker) IsDirty() bool { return len(ft.dirty) > 0 } // UpdateDirty updates only dirty fields in the database func UpdateDirty(model Trackable) error { if !model.IsDirty() { return nil // No changes to save } dirty := model.GetDirtyFields() if len(dirty) == 0 { return nil } // Build dynamic UPDATE query var setParts []string var args []any for field, value := range dirty { setParts = append(setParts, field+" = ?") args = append(args, value) } args = append(args, model.GetID()) // Add ID for WHERE clause query := fmt.Sprintf("UPDATE %s SET %s WHERE id = ?", model.GetTableName(), strings.Join(setParts, ", ")) err := Exec(query, args...) if err != nil { return fmt.Errorf("failed to update %s: %w", model.GetTableName(), err) } model.ClearDirty() return nil }