-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmptt.go
More file actions
135 lines (120 loc) · 3.13 KB
/
mptt.go
File metadata and controls
135 lines (120 loc) · 3.13 KB
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
package mptt
import (
"gorm.io/gorm"
)
type tree struct {
*gorm.DB
node interface{}
tableName string
fields *KeyFields
}
func (t *tree) GormDB() *gorm.DB {
return t.DB
}
func (t *tree) getTableName() string {
return t.Statement.Quote(t.tableName)
}
type treeOptions struct {
specialTableName string
keyColumns KeyColumnFields
}
// ModelBase default mptt base model for user to embedded
type ModelBase struct {
ID int `gorm:"primaryKey" json:"id"`
ParentID int `gorm:"default:0;index" json:"parent_id"`
TreeID int `gorm:"index" json:"tree_id"`
Lvl int `gorm:"index" json:"lvl"`
Lft int `gorm:"index" json:"lft"`
Rght int `gorm:"index" json:"rght"`
}
// Option ...
type Option func(options *treeOptions)
// KeyColumnFields for custom mptt model without embedded struct ModelBase
type KeyColumnFields struct {
IDFieldName string
ParentFieldName string
TreeIDFieldName string
LeftFieldName string
RightFieldName string
LevelFieldName string
}
// WithTableName custom table name
func WithTableName(name string) Option {
return func(options *treeOptions) {
options.specialTableName = name
}
}
// WithAttrs custom model without Embedded Struct ModelBase
func WithAttrs(fields KeyColumnFields) Option {
return func(options *treeOptions) {
options.keyColumns = fields
}
}
// NewTreeManager create mptt tree manager
func NewTreeManager(db *gorm.DB, modelPtr interface{}, opts ...Option) (TreeManager, error) {
t := tree{
DB: db,
node: modelPtr,
}
options := &treeOptions{
keyColumns: KeyColumnFields{
IDFieldName: DefaultIDColumn,
ParentFieldName: DefaultParentIDColumn,
TreeIDFieldName: DefaultTreeIDColumn,
LeftFieldName: DefaultLeftColumn,
RightFieldName: DefaultRightColumn,
LevelFieldName: DefaultLevelColumn,
},
}
for _, opt := range opts {
opt(options)
}
err := t.Statement.ParseWithSpecialTableName(t.node, options.specialTableName)
if err != nil {
return nil, err
}
t.fields = &KeyFields{
ID: KeyField{
Attr: ColumnIDAttr,
Field: t.Statement.Schema.FieldsByName[options.keyColumns.IDFieldName],
},
Parent: KeyField{
Attr: ColumnParentIDAttr,
Field: t.Statement.Schema.FieldsByName[options.keyColumns.ParentFieldName],
},
Tree: KeyField{
Attr: ColumnTreeIDAttr,
Field: t.Statement.Schema.FieldsByName[options.keyColumns.TreeIDFieldName],
},
Left: KeyField{
Attr: ColumnLeftAttr,
Field: t.Statement.Schema.FieldsByName[options.keyColumns.LeftFieldName],
},
Right: KeyField{
Attr: ColumnRightAttr,
Field: t.Statement.Schema.FieldsByName[options.keyColumns.RightFieldName],
},
Level: KeyField{
Attr: ColumnLevelAttr,
Field: t.Statement.Schema.FieldsByName[options.keyColumns.LevelFieldName],
},
}
t.tableName = t.Statement.Table
return &t, nil
}
type PositionEnum string
const (
LastChild PositionEnum = "last-child"
FirstChild PositionEnum = "first-child"
Left PositionEnum = "left"
Right PositionEnum = "right"
)
func (t *tree) Node(node interface{}) TreeNode {
newTree := &tree{
DB: t.DB,
node: node,
tableName: t.tableName,
fields: t.fields,
}
return newTree
}