Browse Source

Allow adding prefix for fields with `extends` tag

Added new syntax like `extends('Prefix')` to enable matching all
extended fields as 'PrefixFieldName'.
xormplus 6 years ago
parent
commit
0ccebe2d25
3 changed files with 150 additions and 1 deletions
  1. 10 1
      engine.go
  2. 20 0
      tag.go
  3. 120 0
      tag_extends_test.go

+ 10 - 1
engine.go

@@ -932,7 +932,16 @@ func (engine *Engine) mapType(v reflect.Value) (*core.Table, error) {
 					engine:     engine,
 				}
 
-				if strings.ToUpper(tags[0]) == "EXTENDS" {
+				if strings.HasPrefix(strings.ToUpper(tags[0]), "EXTENDS") {
+					pStart := strings.Index(tags[0], "(")
+					if pStart > -1 && strings.HasSuffix(tags[0], ")") {
+						var tagPrefix = strings.TrimFunc(tags[0][pStart+1:len(tags[0])-1], func(r rune) bool {
+							return r == '\'' || r == '"'
+						})
+
+						ctx.params = []string{tagPrefix}
+					}
+
 					if err := ExtendsTagHandler(&ctx); err != nil {
 						return nil, err
 					}

+ 20 - 0
tag.go

@@ -244,6 +244,7 @@ func SQLTypeTagHandler(ctx *tagContext) error {
 // ExtendsTagHandler describes extends tag handler
 func ExtendsTagHandler(ctx *tagContext) error {
 	var fieldValue = ctx.fieldValue
+	var isPtr = false
 	switch fieldValue.Kind() {
 	case reflect.Ptr:
 		f := fieldValue.Type().Elem()
@@ -254,6 +255,7 @@ func ExtendsTagHandler(ctx *tagContext) error {
 				fieldValue = reflect.New(f).Elem()
 			}
 		}
+		isPtr = true
 		fallthrough
 	case reflect.Struct:
 		parentTable, err := ctx.engine.mapType(fieldValue)
@@ -262,6 +264,24 @@ func ExtendsTagHandler(ctx *tagContext) error {
 		}
 		for _, col := range parentTable.Columns() {
 			col.FieldName = fmt.Sprintf("%v.%v", ctx.col.FieldName, col.FieldName)
+
+			var tagPrefix = ctx.col.FieldName
+			if len(ctx.params) > 0 {
+				col.Nullable = isPtr
+				tagPrefix = ctx.params[0]
+				if col.IsPrimaryKey {
+					col.Name = ctx.col.FieldName
+					col.IsPrimaryKey = false
+				} else {
+					col.Name = fmt.Sprintf("%v%v", tagPrefix, col.Name)
+				}
+			}
+
+			if col.Nullable {
+				col.IsAutoIncrement = false
+				col.IsPrimaryKey = false
+			}
+
 			ctx.table.AddColumn(col)
 			for indexName, indexType := range col.Indexes {
 				addIndex(indexName, ctx.table, col, indexType)

+ 120 - 0
tag_extends_test.go

@@ -486,3 +486,123 @@ func TestExtends4(t *testing.T) {
 		panic(err)
 	}
 }
+
+type Size struct {
+	ID     int64   `xorm:"int(4) 'id' pk autoincr"`
+	Width  float32 `json:"width" xorm:"float 'Width'"`
+	Height float32 `json:"height" xorm:"float 'Height'"`
+}
+
+type Book struct {
+	ID         int64 `xorm:"int(4) 'id' pk autoincr"`
+	SizeOpen   *Size `xorm:"extends('Open')"`
+	SizeClosed *Size `xorm:"extends('Closed')"`
+	Size       *Size `xorm:"extends('')"`
+}
+
+func TestExtends5(t *testing.T) {
+	assert.NoError(t, prepareEngine())
+	err := testEngine.DropTables(&Book{}, &Size{})
+	if err != nil {
+		t.Error(err)
+		panic(err)
+	}
+
+	err = testEngine.CreateTables(&Size{}, &Book{})
+	if err != nil {
+		t.Error(err)
+		panic(err)
+	}
+
+	var sc = Size{Width: 0.2, Height: 0.4}
+	var so = Size{Width: 0.2, Height: 0.8}
+	var s = Size{Width: 0.15, Height: 1.5}
+	var bk1 = Book{
+		SizeOpen:   &so,
+		SizeClosed: &sc,
+		Size:       &s,
+	}
+	var bk2 = Book{
+		SizeOpen: &so,
+	}
+	var bk3 = Book{
+		SizeClosed: &sc,
+		Size:       &s,
+	}
+	var bk4 = Book{}
+	var bk5 = Book{Size: &s}
+	_, err = testEngine.Insert(&sc, &so, &s, &bk1, &bk2, &bk3, &bk4, &bk5)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var books = map[int64]Book{
+		bk1.ID: bk1,
+		bk2.ID: bk2,
+		bk3.ID: bk3,
+		bk4.ID: bk4,
+		bk5.ID: bk5,
+	}
+
+	session := testEngine.NewSession()
+	defer session.Close()
+
+	var mapper = testEngine.GetTableMapper().Obj2Table
+	var quote = testEngine.Quote
+	bookTableName := quote(testEngine.TableName(mapper("Book"), true))
+	sizeTableName := quote(testEngine.TableName(mapper("Size"), true))
+
+	list := make([]Book, 0)
+	err = session.
+		Select(fmt.Sprintf(
+			"%s.%s, sc.%s AS %s, sc.%s AS %s, s.%s, s.%s",
+			quote(bookTableName),
+			quote("id"),
+			quote("Width"),
+			quote("ClosedWidth"),
+			quote("Height"),
+			quote("ClosedHeight"),
+			quote("Width"),
+			quote("Height"),
+		)).
+		Table(bookTableName).
+		Join(
+			"LEFT",
+			sizeTableName+" AS `sc`",
+			bookTableName+".`SizeClosed`=sc.`id`",
+		).
+		Join(
+			"LEFT",
+			sizeTableName+" AS `s`",
+			bookTableName+".`Size`=s.`id`",
+		).
+		Find(&list)
+	if err != nil {
+		t.Error(err)
+		panic(err)
+	}
+
+	for _, book := range list {
+		if ok := assert.Equal(t, books[book.ID].SizeClosed.Width, book.SizeClosed.Width); !ok {
+			t.Error("Not bounded size closed")
+			panic("Not bounded size closed")
+		}
+
+		if ok := assert.Equal(t, books[book.ID].SizeClosed.Height, book.SizeClosed.Height); !ok {
+			t.Error("Not bounded size closed")
+			panic("Not bounded size closed")
+		}
+
+		if books[book.ID].Size != nil || book.Size != nil {
+			if ok := assert.Equal(t, books[book.ID].Size.Width, book.Size.Width); !ok {
+				t.Error("Not bounded size")
+				panic("Not bounded size")
+			}
+
+			if ok := assert.Equal(t, books[book.ID].Size.Height, book.Size.Height); !ok {
+				t.Error("Not bounded size")
+				panic("Not bounded size")
+			}
+		}
+	}
+}