@@ -28,6 +28,7 @@ import (
2828 "xorm.io/xorm/log"
2929 "xorm.io/xorm/names"
3030 "xorm.io/xorm/schemas"
31+ "xorm.io/xorm/tags"
3132)
3233
3334// Engine is the major struct of xorm, it means a database manager.
@@ -36,10 +37,7 @@ type Engine struct {
3637 db * core.DB
3738 dialect dialects.Dialect
3839
39- ColumnMapper names.Mapper
40- TableMapper names.Mapper
41- TagIdentifier string
42- Tables map [reflect.Type ]* schemas.Table
40+ Tables map [reflect.Type ]* schemas.Table
4341
4442 mutex * sync.RWMutex
4543
@@ -50,12 +48,12 @@ type Engine struct {
5048 TZLocation * time.Location // The timezone of the application
5149 DatabaseTZ * time.Location // The timezone of the database
5250
53- tagHandlers map [string ]tagHandler
54-
5551 engineGroup * EngineGroup
56- cacherMgr * caches.Manager
5752
5853 defaultContext context.Context
54+
55+ tagParser * tags.Parser
56+ cacherMgr * caches.Manager
5957}
6058
6159func (engine * Engine ) SetCacher (tableName string , cacher caches.Cacher ) {
@@ -151,12 +149,12 @@ func (engine *Engine) SetMapper(mapper names.Mapper) {
151149
152150// SetTableMapper set the table name mapping rule
153151func (engine * Engine ) SetTableMapper (mapper names.Mapper ) {
154- engine .TableMapper = mapper
152+ engine .tagParser . TableMapper = mapper
155153}
156154
157155// SetColumnMapper set the column name mapping rule
158156func (engine * Engine ) SetColumnMapper (mapper names.Mapper ) {
159- engine .ColumnMapper = mapper
157+ engine .tagParser . ColumnMapper = mapper
160158}
161159
162160// SupportInsertMany If engine's database support batch insert records like
@@ -769,7 +767,7 @@ func (engine *Engine) autoMapType(v reflect.Value) (*schemas.Table, error) {
769767 table , ok := engine .Tables [t ]
770768 if ! ok {
771769 var err error
772- table , err = engine .mapType (v )
770+ table , err = engine .tagParser . MapType (v )
773771 if err != nil {
774772 return nil , err
775773 }
@@ -813,215 +811,6 @@ func (engine *Engine) TableInfo(bean interface{}) *Table {
813811 return & Table {tb , engine .TableName (bean )}
814812}
815813
816- func addIndex (indexName string , table * schemas.Table , col * schemas.Column , indexType int ) {
817- if index , ok := table .Indexes [indexName ]; ok {
818- index .AddColumn (col .Name )
819- col .Indexes [index .Name ] = indexType
820- } else {
821- index := schemas .NewIndex (indexName , indexType )
822- index .AddColumn (col .Name )
823- table .AddIndex (index )
824- col .Indexes [index .Name ] = indexType
825- }
826- }
827-
828- // TableName table name interface to define customerize table name
829- type TableName interface {
830- TableName () string
831- }
832-
833- var (
834- tpTableName = reflect .TypeOf ((* TableName )(nil )).Elem ()
835- )
836-
837- func (engine * Engine ) mapType (v reflect.Value ) (* schemas.Table , error ) {
838- t := v .Type ()
839- table := schemas .NewEmptyTable ()
840- table .Type = t
841- table .Name = names .GetTableName (engine .TableMapper , v )
842-
843- var idFieldColName string
844- var hasCacheTag , hasNoCacheTag bool
845-
846- for i := 0 ; i < t .NumField (); i ++ {
847- tag := t .Field (i ).Tag
848-
849- ormTagStr := tag .Get (engine .TagIdentifier )
850- var col * schemas.Column
851- fieldValue := v .Field (i )
852- fieldType := fieldValue .Type ()
853-
854- if ormTagStr != "" {
855- col = & schemas.Column {
856- FieldName : t .Field (i ).Name ,
857- Nullable : true ,
858- IsPrimaryKey : false ,
859- IsAutoIncrement : false ,
860- MapType : schemas .TWOSIDES ,
861- Indexes : make (map [string ]int ),
862- DefaultIsEmpty : true ,
863- }
864- tags := splitTag (ormTagStr )
865-
866- if len (tags ) > 0 {
867- if tags [0 ] == "-" {
868- continue
869- }
870-
871- var ctx = tagContext {
872- table : table ,
873- col : col ,
874- fieldValue : fieldValue ,
875- indexNames : make (map [string ]int ),
876- engine : engine ,
877- }
878-
879- if strings .HasPrefix (strings .ToUpper (tags [0 ]), "EXTENDS" ) {
880- pStart := strings .Index (tags [0 ], "(" )
881- if pStart > - 1 && strings .HasSuffix (tags [0 ], ")" ) {
882- var tagPrefix = strings .TrimFunc (tags [0 ][pStart + 1 :len (tags [0 ])- 1 ], func (r rune ) bool {
883- return r == '\'' || r == '"'
884- })
885-
886- ctx .params = []string {tagPrefix }
887- }
888-
889- if err := ExtendsTagHandler (& ctx ); err != nil {
890- return nil , err
891- }
892- continue
893- }
894-
895- for j , key := range tags {
896- if ctx .ignoreNext {
897- ctx .ignoreNext = false
898- continue
899- }
900-
901- k := strings .ToUpper (key )
902- ctx .tagName = k
903- ctx .params = []string {}
904-
905- pStart := strings .Index (k , "(" )
906- if pStart == 0 {
907- return nil , errors .New ("( could not be the first character" )
908- }
909- if pStart > - 1 {
910- if ! strings .HasSuffix (k , ")" ) {
911- return nil , fmt .Errorf ("field %s tag %s cannot match ) character" , col .FieldName , key )
912- }
913-
914- ctx .tagName = k [:pStart ]
915- ctx .params = strings .Split (key [pStart + 1 :len (k )- 1 ], "," )
916- }
917-
918- if j > 0 {
919- ctx .preTag = strings .ToUpper (tags [j - 1 ])
920- }
921- if j < len (tags )- 1 {
922- ctx .nextTag = tags [j + 1 ]
923- } else {
924- ctx .nextTag = ""
925- }
926-
927- if h , ok := engine .tagHandlers [ctx .tagName ]; ok {
928- if err := h (& ctx ); err != nil {
929- return nil , err
930- }
931- } else {
932- if strings .HasPrefix (key , "'" ) && strings .HasSuffix (key , "'" ) {
933- col .Name = key [1 : len (key )- 1 ]
934- } else {
935- col .Name = key
936- }
937- }
938-
939- if ctx .hasCacheTag {
940- hasCacheTag = true
941- }
942- if ctx .hasNoCacheTag {
943- hasNoCacheTag = true
944- }
945- }
946-
947- if col .SQLType .Name == "" {
948- col .SQLType = schemas .Type2SQLType (fieldType )
949- }
950- engine .dialect .SQLType (col )
951- if col .Length == 0 {
952- col .Length = col .SQLType .DefaultLength
953- }
954- if col .Length2 == 0 {
955- col .Length2 = col .SQLType .DefaultLength2
956- }
957- if col .Name == "" {
958- col .Name = engine .ColumnMapper .Obj2Table (t .Field (i ).Name )
959- }
960-
961- if ctx .isUnique {
962- ctx .indexNames [col .Name ] = schemas .UniqueType
963- } else if ctx .isIndex {
964- ctx .indexNames [col .Name ] = schemas .IndexType
965- }
966-
967- for indexName , indexType := range ctx .indexNames {
968- addIndex (indexName , table , col , indexType )
969- }
970- }
971- } else {
972- var sqlType schemas.SQLType
973- if fieldValue .CanAddr () {
974- if _ , ok := fieldValue .Addr ().Interface ().(Conversion ); ok {
975- sqlType = schemas.SQLType {Name : schemas .Text }
976- }
977- }
978- if _ , ok := fieldValue .Interface ().(Conversion ); ok {
979- sqlType = schemas.SQLType {Name : schemas .Text }
980- } else {
981- sqlType = schemas .Type2SQLType (fieldType )
982- }
983- col = schemas .NewColumn (engine .ColumnMapper .Obj2Table (t .Field (i ).Name ),
984- t .Field (i ).Name , sqlType , sqlType .DefaultLength ,
985- sqlType .DefaultLength2 , true )
986-
987- if fieldType .Kind () == reflect .Int64 && (strings .ToUpper (col .FieldName ) == "ID" || strings .HasSuffix (strings .ToUpper (col .FieldName ), ".ID" )) {
988- idFieldColName = col .Name
989- }
990- }
991- if col .IsAutoIncrement {
992- col .Nullable = false
993- }
994-
995- table .AddColumn (col )
996-
997- } // end for
998-
999- if idFieldColName != "" && len (table .PrimaryKeys ) == 0 {
1000- col := table .GetColumn (idFieldColName )
1001- col .IsPrimaryKey = true
1002- col .IsAutoIncrement = true
1003- col .Nullable = false
1004- table .PrimaryKeys = append (table .PrimaryKeys , col .Name )
1005- table .AutoIncrement = col .Name
1006- }
1007-
1008- if hasCacheTag {
1009- if engine .GetDefaultCacher () != nil { // !nash! use engine's cacher if provided
1010- engine .logger .Info ("enable cache on table:" , table .Name )
1011- engine .SetCacher (table .Name , engine .GetDefaultCacher ())
1012- } else {
1013- engine .logger .Info ("enable LRU cache on table:" , table .Name )
1014- engine .SetCacher (table .Name , caches .NewLRUCacher2 (caches .NewMemoryStore (), time .Hour , 10000 ))
1015- }
1016- }
1017- if hasNoCacheTag {
1018- engine .logger .Info ("disable cache on table:" , table .Name )
1019- engine .SetCacher (table .Name , nil )
1020- }
1021-
1022- return table , nil
1023- }
1024-
1025814// IsTableEmpty if a table has any reocrd
1026815func (engine * Engine ) IsTableEmpty (bean interface {}) (bool , error ) {
1027816 session := engine .NewSession ()
@@ -1542,12 +1331,12 @@ func (engine *Engine) formatTime(sqlTypeName string, t time.Time) (v interface{}
15421331
15431332// GetColumnMapper returns the column name mapper
15441333func (engine * Engine ) GetColumnMapper () names.Mapper {
1545- return engine .ColumnMapper
1334+ return engine .tagParser . ColumnMapper
15461335}
15471336
15481337// GetTableMapper returns the table name mapper
15491338func (engine * Engine ) GetTableMapper () names.Mapper {
1550- return engine .TableMapper
1339+ return engine .tagParser . TableMapper
15511340}
15521341
15531342// GetTZLocation returns time zone of the application
0 commit comments