github.com/paweljw/pop@v4.13.1+incompatible/associations/association.go (about) 1 package associations 2 3 import ( 4 "reflect" 5 6 "github.com/gobuffalo/nulls" 7 "github.com/gobuffalo/pop/columns" 8 ) 9 10 // Association represents a definition of a model association 11 // field. It can represent a association of the type has_many 12 // belongs_to or has_one, and other customized types. 13 type Association interface { 14 Kind() reflect.Kind 15 Interface() interface{} 16 Constraint() (string, []interface{}) 17 InnerAssociations() InnerAssociations 18 Skipped() bool 19 } 20 21 // associationSkipable is a helper struct that helps 22 // to include skippable behavior in associations. 23 type associationSkipable struct { 24 skipped bool 25 } 26 27 func (a *associationSkipable) Skipped() bool { 28 return a.skipped 29 } 30 31 // associationComposite adds the ability for a Association to 32 // have nested associations. 33 type associationComposite struct { 34 innerAssociations InnerAssociations 35 } 36 37 func (a *associationComposite) InnerAssociations() InnerAssociations { 38 return a.innerAssociations 39 } 40 41 // InnerAssociation is a struct that represents a deep level 42 // association. per example Song.Composer, Composer is an inner 43 // association for Song. 44 type InnerAssociation struct { 45 Name string 46 Fields string 47 } 48 49 // InnerAssociations is a group of InnerAssociation. 50 type InnerAssociations []InnerAssociation 51 52 // AssociationSortable allows a type to be sortable. 53 type AssociationSortable interface { 54 OrderBy() string 55 Association 56 } 57 58 // AssociationBeforeCreatable allows an association to be created before 59 // the parent structure. 60 type AssociationBeforeCreatable interface { 61 BeforeInterface() interface{} 62 BeforeSetup() error 63 Association 64 } 65 66 // AssociationAfterCreatable allows an association to be created after 67 // the parent structure. 68 type AssociationAfterCreatable interface { 69 AfterInterface() interface{} 70 AfterSetup() error 71 AfterProcess() AssociationStatement 72 Association 73 } 74 75 // AssociationCreatableStatement a association that defines 76 // create statements on database. 77 type AssociationCreatableStatement interface { 78 Statements() []AssociationStatement 79 Association 80 } 81 82 // AssociationStatement a type that represents a statement to be 83 // executed. 84 type AssociationStatement struct { 85 Statement string 86 Args []interface{} 87 } 88 89 // Empty is true if the containing Statement is empty. 90 func (as AssociationStatement) Empty() bool { 91 return as.Statement == "" 92 } 93 94 // Associations a group of model associations. 95 type Associations []Association 96 97 // AssociationsBeforeCreatable returns all associations that implement AssociationBeforeCreatable 98 // interface. Belongs To association is an example of this implementation. 99 func (a Associations) AssociationsBeforeCreatable() []AssociationBeforeCreatable { 100 var before []AssociationBeforeCreatable 101 for i := range a { 102 if _, ok := a[i].(AssociationBeforeCreatable); ok { 103 before = append(before, a[i].(AssociationBeforeCreatable)) 104 } 105 } 106 return before 107 } 108 109 // AssociationsAfterCreatable returns all associations that implement AssociationAfterCreatable 110 // interface. Has Many and Has One associations are examples of this implementation. 111 func (a Associations) AssociationsAfterCreatable() []AssociationAfterCreatable { 112 var after []AssociationAfterCreatable 113 for i := range a { 114 if _, ok := a[i].(AssociationAfterCreatable); ok { 115 after = append(after, a[i].(AssociationAfterCreatable)) 116 } 117 } 118 return after 119 } 120 121 // AssociationsCreatableStatement returns all associations that implement AssociationCreatableStament 122 // interface. Many To Many association is an example of this implementation. 123 func (a Associations) AssociationsCreatableStatement() []AssociationCreatableStatement { 124 var stm []AssociationCreatableStatement 125 for i := range a { 126 if _, ok := a[i].(AssociationCreatableStatement); ok { 127 stm = append(stm, a[i].(AssociationCreatableStatement)) 128 } 129 } 130 return stm 131 } 132 133 // associationParams is a wrapper for associations definition 134 // and creation. 135 type associationParams struct { 136 field reflect.StructField // an association field defined in model. 137 modelType reflect.Type // the model type where this field is defined. 138 modelValue reflect.Value // the model value where this field is defined. 139 popTags columns.Tags // the tags defined in this association field. 140 model interface{} // the model, owner of the association. 141 innerAssociations InnerAssociations // the data for the deep level associations. 142 } 143 144 // associationBuilder is a type representing an association builder implementation. 145 // see the builder defined in ./has_many_association.go as a guide of how to use it. 146 type associationBuilder func(associationParams) (Association, error) 147 148 // fieldIsNil validates if a field has a nil reference. Also 149 // it validates if a field implements nullable interface and 150 // it has a nil value. 151 func fieldIsNil(f reflect.Value) bool { 152 if n := nulls.New(f.Interface()); n != nil { 153 return n.Interface() == nil 154 } 155 if f.Kind() == reflect.Interface || f.Kind() == reflect.Ptr { 156 return f.IsNil() 157 } 158 return f.Interface() == nil 159 } 160 161 // IsZeroOfUnderlyingType will check if the value of anything is the equal to the Zero value of that type. 162 func IsZeroOfUnderlyingType(x interface{}) bool { 163 return reflect.DeepEqual(x, reflect.Zero(reflect.TypeOf(x)).Interface()) 164 }