1package exql 2 3import ( 4 "errors" 5 "reflect" 6 "strings" 7) 8 9var errUnknownTemplateType = errors.New("Unknown template type") 10 11// represents different kinds of SQL statements. 12type Statement struct { 13 Type 14 Table Fragment 15 Database Fragment 16 Columns Fragment 17 Values Fragment 18 Distinct bool 19 ColumnValues Fragment 20 OrderBy Fragment 21 GroupBy Fragment 22 Joins Fragment 23 Where Fragment 24 Returning Fragment 25 26 Limit 27 Offset 28 29 SQL string 30 31 hash hash 32 amendFn func(string) string 33} 34 35func (layout *Template) doCompile(c Fragment) (string, error) { 36 if c != nil && !reflect.ValueOf(c).IsNil() { 37 return c.Compile(layout) 38 } 39 return "", nil 40} 41 42// Hash returns a unique identifier for the struct. 43func (s *Statement) Hash() string { 44 return s.hash.Hash(s) 45} 46 47func (s *Statement) SetAmendment(amendFn func(string) string) { 48 s.amendFn = amendFn 49} 50 51func (s *Statement) Amend(in string) string { 52 if s.amendFn == nil { 53 return in 54 } 55 return s.amendFn(in) 56} 57 58func (s *Statement) template(layout *Template) (string, error) { 59 switch s.Type { 60 case Truncate: 61 return layout.TruncateLayout, nil 62 case DropTable: 63 return layout.DropTableLayout, nil 64 case DropDatabase: 65 return layout.DropDatabaseLayout, nil 66 case Count: 67 return layout.CountLayout, nil 68 case Select: 69 return layout.SelectLayout, nil 70 case Delete: 71 return layout.DeleteLayout, nil 72 case Update: 73 return layout.UpdateLayout, nil 74 case Insert: 75 return layout.InsertLayout, nil 76 default: 77 return "", errUnknownTemplateType 78 } 79} 80 81// Compile transforms the Statement into an equivalent SQL query. 82func (s *Statement) Compile(layout *Template) (compiled string, err error) { 83 if s.Type == SQL { 84 // No need to hit the cache. 85 return s.SQL, nil 86 } 87 88 if z, ok := layout.Read(s); ok { 89 return s.Amend(z), nil 90 } 91 92 tpl, err := s.template(layout) 93 if err != nil { 94 return "", err 95 } 96 97 compiled = layout.MustCompile(tpl, s) 98 99 compiled = strings.TrimSpace(compiled) 100 layout.Write(s, compiled) 101 102 return s.Amend(compiled), nil 103} 104 105// RawSQL represents a raw SQL statement. 106func RawSQL(s string) *Statement { 107 return &Statement{ 108 Type: SQL, 109 SQL: s, 110 } 111} 112