package exql import ( "errors" "reflect" "strings" "git.hexq.cn/tiglog/mydb/internal/cache" ) var errUnknownTemplateType = errors.New("Unknown template type") // represents different kinds of SQL statements. type Statement struct { Type Table Fragment Database Fragment Columns Fragment Values Fragment Distinct bool ColumnValues Fragment OrderBy Fragment GroupBy Fragment Joins Fragment Where Fragment Returning Fragment Limit Offset SQL string amendFn func(string) string } func (layout *Template) doCompile(c Fragment) (string, error) { if c != nil && !reflect.ValueOf(c).IsNil() { return c.Compile(layout) } return "", nil } // Hash returns a unique identifier for the struct. func (s *Statement) Hash() uint64 { if s == nil { return cache.NewHash(FragmentType_Statement, nil) } return cache.NewHash( FragmentType_Statement, s.Type, s.Table, s.Database, s.Columns, s.Values, s.Distinct, s.ColumnValues, s.OrderBy, s.GroupBy, s.Joins, s.Where, s.Returning, s.Limit, s.Offset, s.SQL, ) } func (s *Statement) SetAmendment(amendFn func(string) string) { s.amendFn = amendFn } func (s *Statement) Amend(in string) string { if s.amendFn == nil { return in } return s.amendFn(in) } func (s *Statement) template(layout *Template) (string, error) { switch s.Type { case Truncate: return layout.TruncateLayout, nil case DropTable: return layout.DropTableLayout, nil case DropDatabase: return layout.DropDatabaseLayout, nil case Count: return layout.CountLayout, nil case Select: return layout.SelectLayout, nil case Delete: return layout.DeleteLayout, nil case Update: return layout.UpdateLayout, nil case Insert: return layout.InsertLayout, nil default: return "", errUnknownTemplateType } } // Compile transforms the Statement into an equivalent SQL query. func (s *Statement) Compile(layout *Template) (compiled string, err error) { if s.Type == SQL { // No need to hit the cache. return s.SQL, nil } if z, ok := layout.Read(s); ok { return s.Amend(z), nil } tpl, err := s.template(layout) if err != nil { return "", err } compiled = layout.MustCompile(tpl, s) compiled = strings.TrimSpace(compiled) layout.Write(s, compiled) return s.Amend(compiled), nil } // RawSQL represents a raw SQL statement. func RawSQL(s string) *Statement { return &Statement{ Type: SQL, SQL: s, } }