-
-
Notifications
You must be signed in to change notification settings - Fork 241
/
association.go
168 lines (144 loc) · 5.17 KB
/
association.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package associations
import (
"reflect"
"github.com/gobuffalo/nulls"
"github.com/gobuffalo/pop/v6/columns"
)
// Association represents a definition of a model association
// field. It can represent a association of the type has_many
// belongs_to or has_one, and other customized types.
type Association interface {
Kind() reflect.Kind
Interface() interface{}
Constraint() (string, []interface{})
InnerAssociations() InnerAssociations
Skipped() bool
}
// associationSkipable is a helper struct that helps
// to include skippable behavior in associations.
type associationSkipable struct {
skipped bool
}
func (a *associationSkipable) Skipped() bool {
return a.skipped
}
// associationComposite adds the ability for a Association to
// have nested associations.
type associationComposite struct {
innerAssociations InnerAssociations
}
func (a *associationComposite) InnerAssociations() InnerAssociations {
return a.innerAssociations
}
// InnerAssociation is a struct that represents a deep level
// association. per example Song.Composer, Composer is an inner
// association for Song.
type InnerAssociation struct {
Name string
Fields []string
}
// InnerAssociations is a group of InnerAssociation.
type InnerAssociations []InnerAssociation
// AssociationSortable allows a type to be sortable.
type AssociationSortable interface {
OrderBy() string
Association
}
// AssociationBeforeCreatable allows an association to be created before
// the parent structure.
type AssociationBeforeCreatable interface {
BeforeInterface() interface{}
BeforeSetup() error
Association
}
// AssociationAfterCreatable allows an association to be created after
// the parent structure.
type AssociationAfterCreatable interface {
AfterInterface() interface{}
AfterSetup() error
AfterProcess() AssociationStatement
Association
}
// AssociationCreatableStatement a association that defines
// create statements on database.
type AssociationCreatableStatement interface {
Statements() []AssociationStatement
Association
}
// AssociationStatement a type that represents a statement to be
// executed.
type AssociationStatement struct {
Statement string
Args []interface{}
}
// Empty is true if the containing Statement is empty.
func (as AssociationStatement) Empty() bool {
return as.Statement == ""
}
// Associations a group of model associations.
type Associations []Association
// AssociationsBeforeCreatable returns all associations that implement AssociationBeforeCreatable
// interface. Belongs To association is an example of this implementation.
func (a Associations) AssociationsBeforeCreatable() []AssociationBeforeCreatable {
var before []AssociationBeforeCreatable
for i := range a {
if _, ok := a[i].(AssociationBeforeCreatable); ok {
before = append(before, a[i].(AssociationBeforeCreatable))
}
}
return before
}
// AssociationsAfterCreatable returns all associations that implement AssociationAfterCreatable
// interface. Has Many and Has One associations are examples of this implementation.
func (a Associations) AssociationsAfterCreatable() []AssociationAfterCreatable {
var after []AssociationAfterCreatable
for i := range a {
if _, ok := a[i].(AssociationAfterCreatable); ok {
after = append(after, a[i].(AssociationAfterCreatable))
}
}
return after
}
// AssociationsCreatableStatement returns all associations that implement AssociationCreatableStament
// interface. Many To Many association is an example of this implementation.
func (a Associations) AssociationsCreatableStatement() []AssociationCreatableStatement {
var stm []AssociationCreatableStatement
for i := range a {
if _, ok := a[i].(AssociationCreatableStatement); ok {
stm = append(stm, a[i].(AssociationCreatableStatement))
}
}
return stm
}
// associationParams is a wrapper for associations definition
// and creation.
type associationParams struct {
field reflect.StructField // an association field defined in model.
modelType reflect.Type // the model type where this field is defined.
modelValue reflect.Value // the model value where this field is defined.
popTags columns.Tags // the tags defined in this association field.
model interface{} // the model, owner of the association.
innerAssociations InnerAssociations // the data for the deep level associations.
}
// associationBuilder is a type representing an association builder implementation.
// see the builder defined in ./has_many_association.go as a guide of how to use it.
type associationBuilder func(associationParams) (Association, error)
// fieldIsNil validates if a field has a nil reference. Also
// it validates if a field implements nullable interface and
// it has a nil value.
func fieldIsNil(f reflect.Value) bool {
if n := nulls.New(f.Interface()); n != nil {
return n.Interface() == nil
}
if f.Kind() == reflect.Interface || f.Kind() == reflect.Ptr {
return f.IsNil()
}
return f.Interface() == nil
}
// IsZeroOfUnderlyingType will check if the value of anything is the equal to the Zero value of that type.
func IsZeroOfUnderlyingType(x interface{}) bool {
if x == nil {
return true
}
return reflect.DeepEqual(x, reflect.Zero(reflect.TypeOf(x)).Interface())
}