From eb43b539f906dd45acad7c388bf803627cd33905 Mon Sep 17 00:00:00 2001 From: Jinzhu Date: Fri, 16 Mar 2018 11:16:22 +0800 Subject: [PATCH] Build query SQL --- dialects/common/sqlbuilder/conditions.go | 4 +- dialects/common/sqlbuilder/fields.go | 36 ++++++++++--- dialects/common/sqlbuilder/group.go | 1 + dialects/sqlite/sqlite.go | 64 +++++++++++++++++++++++- 4 files changed, 94 insertions(+), 11 deletions(-) diff --git a/dialects/common/sqlbuilder/conditions.go b/dialects/common/sqlbuilder/conditions.go index d213b637..34b908e7 100644 --- a/dialects/common/sqlbuilder/conditions.go +++ b/dialects/common/sqlbuilder/conditions.go @@ -12,13 +12,13 @@ type ConditionInterface interface { } // BuildConditions build conditions -func BuildConditions(tx *gorm.DB) chan *Builder { +func BuildConditions(tx *gorm.DB, conds []gorm.ConditionInterface) chan *Builder { queryChan := make(chan *Builder) go func() { builder := &Builder{} - for i, c := range tx.Statement.Conditions { + for i, c := range conds { if i > 0 { builder.SQL.WriteString(" AND ") } diff --git a/dialects/common/sqlbuilder/fields.go b/dialects/common/sqlbuilder/fields.go index 35f47e8f..eb3bc332 100644 --- a/dialects/common/sqlbuilder/fields.go +++ b/dialects/common/sqlbuilder/fields.go @@ -50,13 +50,35 @@ func GetAssignmentFields(tx *gorm.DB) chan [][]*model.Field { return fieldChan } -func mapToFields(value map[string]interface{}, s *schema.Schema, assignableChecker func(*model.Field) bool) (fields []*model.Field) { +// GetSelectableFields get selectable fields +func GetSelectableFields(tx *gorm.DB) chan []string { + fieldChan := make(chan []string) + + go func() { + assignableChecker := generateAssignableChecker(selectAttrs(tx.Statement), omitAttrs(tx.Statement)) + if s := schema.Parse(tx.Statement.Dest); s != nil { + columns := []string{} + for _, field := range s.Fields { + if assignableChecker(field) { + columns = append(columns, field.DBName) + } + } + fieldChan <- columns + return + } + fieldChan <- []string{"*"} + }() + + return fieldChan +} + +func mapToFields(value map[string]interface{}, s *schema.Schema, assignableChecker func(*schema.Field) bool) (fields []*model.Field) { // TODO assign those value to dest for k, v := range value { if s != nil { if f := s.FieldByName(k); f != nil { field := &model.Field{Field: f, Value: reflect.ValueOf(v)} - if assignableChecker(field) { + if assignableChecker(field.Field) { fields = append(fields, field) } continue @@ -64,7 +86,7 @@ func mapToFields(value map[string]interface{}, s *schema.Schema, assignableCheck } field := &model.Field{Field: &schema.Field{DBName: k}, Value: reflect.ValueOf(v)} - if assignableChecker(field) { + if assignableChecker(field.Field) { fields = append(fields, field) } } @@ -75,7 +97,7 @@ func mapToFields(value map[string]interface{}, s *schema.Schema, assignableCheck return } -func structToField(value reflect.Value, s *schema.Schema, assignableChecker func(*model.Field) bool) (fields []*model.Field) { +func structToField(value reflect.Value, s *schema.Schema, assignableChecker func(*schema.Field) bool) (fields []*model.Field) { // TODO use Offset to replace FieldByName? for _, sf := range s.Fields { obj := value @@ -83,7 +105,7 @@ func structToField(value reflect.Value, s *schema.Schema, assignableChecker func obj = value.FieldByName(bn) } field := &model.Field{Field: sf, Value: obj, IsBlank: model.IsBlank(obj)} - if assignableChecker(field) { + if assignableChecker(field.Field) { fields = append(fields, field) } } @@ -91,8 +113,8 @@ func structToField(value reflect.Value, s *schema.Schema, assignableChecker func } // generateAssignableChecker generate checker to check if field is assignable or not -func generateAssignableChecker(selectAttrs []string, omitAttrs []string) func(*model.Field) bool { - return func(field *model.Field) bool { +func generateAssignableChecker(selectAttrs []string, omitAttrs []string) func(*schema.Field) bool { + return func(field *schema.Field) bool { if len(selectAttrs) > 0 { for _, attr := range selectAttrs { if field.Name == attr || field.DBName == attr { diff --git a/dialects/common/sqlbuilder/group.go b/dialects/common/sqlbuilder/group.go index c1ff4d40..165dd9e2 100644 --- a/dialects/common/sqlbuilder/group.go +++ b/dialects/common/sqlbuilder/group.go @@ -13,6 +13,7 @@ func BuildGroupCondition(tx *gorm.DB) chan *Builder { go func() { builder := &Builder{} if groupBy := tx.Statement.GroupBy; len(groupBy.Columns) > 0 { + builder.SQL.WriteString(" GROUP BY ") builder.SQL.WriteString(strings.Join(tx.Statement.GroupBy.Columns, ", ")) if len(groupBy.Having) > 0 { diff --git a/dialects/sqlite/sqlite.go b/dialects/sqlite/sqlite.go index dd3d2149..fc6c0763 100644 --- a/dialects/sqlite/sqlite.go +++ b/dialects/sqlite/sqlite.go @@ -100,8 +100,68 @@ func (dialect *Dialect) Insert(tx *gorm.DB) (err error) { } // Query query -func (*Dialect) Query(tx *gorm.DB) error { - return nil +func (dialect *Dialect) Query(tx *gorm.DB) (err error) { + var ( + args []interface{} + tableNameChan = sqlbuilder.GetTable(tx) + conditionsChan = sqlbuilder.BuildConditions(tx, tx.Statement.Conditions) + groupChan = sqlbuilder.BuildGroupCondition(tx) + orderChan = sqlbuilder.BuildOrderCondition(tx) + limitChan = sqlbuilder.BuildLimitCondition(tx) + ) + + s := bytes.NewBufferString("SELECT ") + + // FIXME quote, add table + columns := tx.Statement.Select.Columns + if len(columns) > 0 { + args = append(args, tx.Statement.Select.Args...) + } else { + columns = []string{"*"} + } + + for idx, column := range columns { + if idx != 0 { + s.WriteString(",") + } + s.WriteString(column) + } + + s.WriteString(" FROM ") + s.WriteString(dialect.Quote(<-tableNameChan)) + + // Join SQL + for _, join := range tx.Statement.Joins { + if join.Table == "" { + builder := <-sqlbuilder.BuildConditions(tx, join.Conditions) + _, err = builder.SQL.WriteTo(s) + args = append(args, builder.Args...) + } + // FIXME + } + + if len(tx.Statement.Conditions) > 0 { + s.WriteString(" WHERE ") + builder := <-conditionsChan + _, err = builder.SQL.WriteTo(s) + args = append(args, builder.Args...) + } + + if builder := <-groupChan; builder != nil { + _, err = builder.SQL.WriteTo(s) + args = append(args, builder.Args) + } + + if builder := <-orderChan; builder != nil { + _, err = builder.SQL.WriteTo(s) + args = append(args, builder.Args) + } + + if builder := <-limitChan; builder != nil { + _, err = builder.SQL.WriteTo(s) + args = append(args, builder.Args) + } + return } // Update update