-
Notifications
You must be signed in to change notification settings - Fork 12
/
sorting.go
139 lines (117 loc) · 3.79 KB
/
sorting.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package sorting
import (
"encoding/json"
"fmt"
"reflect"
"github.com/jinzhu/gorm"
"github.com/qor/admin"
"github.com/qor/publish"
)
type sortingInterface interface {
GetPosition() int
SetPosition(int)
}
type sortingDescInterface interface {
GetPosition() int
SetPosition(int)
SortingDesc()
}
// Sorting ascending mode
type Sorting struct {
Position int `sql:"DEFAULT:NULL"`
}
// GetPosition get current position
func (position Sorting) GetPosition() int {
return position.Position
}
// SetPosition set position, only set field value, won't save
func (position *Sorting) SetPosition(pos int) {
position.Position = pos
}
// SortingDESC descending mode
type SortingDESC struct {
Sorting
}
// SortingDesc make your model sorting desc by default
func (SortingDESC) SortingDesc() {}
func init() {
admin.RegisterViewPath("github.com/qor/sorting/views")
}
func newModel(value interface{}) interface{} {
return reflect.New(reflect.Indirect(reflect.ValueOf(value)).Type()).Interface()
}
func move(db *gorm.DB, value sortingInterface, pos int) (err error) {
var startedTransaction bool
var tx = db.Set("publish:publish_event", true)
if t := tx.Begin(); t.Error == nil {
startedTransaction = true
tx = t
}
scope := db.NewScope(value)
for _, field := range scope.PrimaryFields() {
// "version_name" is a "reserved" primary key, we always update all versions postion at the same time.
// so don't count version name as a condition.
if field.DBName != "id" && field.DBName != "version_name" {
tx = tx.Where(fmt.Sprintf("%s = ?", field.DBName), field.Field.Interface())
}
}
currentPos := value.GetPosition()
var results *gorm.DB
if pos > 0 {
results = tx.Table(scope.TableName()).Where("position > ? AND position <= ?", currentPos, currentPos+pos).
UpdateColumn("position", gorm.Expr("position - ?", 1))
} else {
results = tx.Table(scope.TableName()).Where("position < ? AND position >= ?", currentPos, currentPos+pos).
UpdateColumn("position", gorm.Expr("position + ?", 1))
}
if err = results.Error; err == nil && results.RowsAffected > 0 {
// Use ID as the ONLY condition, so that we can update all version of one record's position.
modelObj := reflect.Indirect(reflect.ValueOf(value))
err = tx.Table(scope.TableName()).Where("id = ?", modelObj.FieldByName("ID").Interface().(uint)).UpdateColumn("position", currentPos+pos).Error
}
// Create Publish Event
createPublishEvent(tx, value)
if startedTransaction {
if err == nil {
tx.Commit()
} else {
tx.Rollback()
}
}
return err
}
func createPublishEvent(db *gorm.DB, value interface{}) (err error) {
// Create Publish Event in Draft Mode
if publish.IsDraftMode(db) && publish.IsPublishableModel(value) {
scope := db.NewScope(value)
var sortingPublishEvent = changedSortingPublishEvent{
Table: scope.TableName(),
}
for _, field := range scope.PrimaryFields() {
sortingPublishEvent.PrimaryKeys = append(sortingPublishEvent.PrimaryKeys, field.DBName)
}
var result []byte
if result, err = json.Marshal(sortingPublishEvent); err == nil {
err = db.New().Where("publish_status = ?", publish.DIRTY).Where(map[string]interface{}{
"name": "changed_sorting",
"argument": string(result),
}).Attrs(map[string]interface{}{
"publish_status": publish.DIRTY,
"description": "Changed sort order for " + scope.GetModelStruct().ModelType.Name(),
}).FirstOrCreate(&publish.PublishEvent{}).Error
}
}
return
}
// MoveUp move position up
func MoveUp(db *gorm.DB, value sortingInterface, pos int) error {
return move(db, value, -pos)
}
// MoveDown move position down
func MoveDown(db *gorm.DB, value sortingInterface, pos int) error {
return move(db, value, pos)
}
// MoveTo move position to
func MoveTo(db *gorm.DB, value sortingInterface, pos int) error {
return move(db, value, pos-value.GetPosition())
}