model.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. package orm
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "gitea.ckfah.com/go-script/logger"
  7. "gitea.ckfah.com/go-script/utils"
  8. _ "github.com/go-sql-driver/mysql"
  9. "github.com/go-xorm/xorm"
  10. "go/format"
  11. "strings"
  12. "text/template"
  13. )
  14. const (
  15. CreateTable = "Create Table"
  16. )
  17. const (
  18. specifiedTableNamesSql = `select table_name from information_schema.tables where table_schema = ? and table_name in ('%s') and table_type = 'base table';`
  19. tableColumnsSql = `select column_name as column_name,column_comment as column_comment,
  20. is_nullable as is_nullable, if(column_type = 'tinyint(1)', 'boolean', data_type) as file_type
  21. from information_schema.columns
  22. where table_schema = ? and table_name = ?
  23. order by ordinal_position;
  24. `
  25. )
  26. type FieldMeta struct {
  27. Name string
  28. FieldType string
  29. IsNullable string //OK YES
  30. ColumnComment string // 字段描述信息
  31. Tags []string
  32. }
  33. func (this *FieldMeta) GetDtoTag() string {
  34. return fmt.Sprintf("`json:\"%s\"`", this.Name)
  35. }
  36. func (this *FieldMeta) GetTag() string {
  37. var (
  38. tags = make([]string, 0)
  39. )
  40. for _, elem := range this.Tags {
  41. if strings.Compare(elem, "xorm") == 0 {
  42. if strings.Compare(this.Name, "id") == 0 {
  43. tags = append(tags, fmt.Sprintf("xorm:\"%s\"", "pk autoincr id"))
  44. continue
  45. }
  46. if strings.Compare(this.Name, "create_time") == 0 || strings.Compare(this.Name, "ctime") == 0 {
  47. tags = append(tags, fmt.Sprintf("xorm:\"%s %s\"", "created", this.Name))
  48. continue
  49. }
  50. if strings.Compare(this.Name, "update_time") == 0 || strings.Compare(this.Name, "utime") == 0 {
  51. tags = append(tags, fmt.Sprintf("xorm:\"%s %s\"", "updated", this.Name))
  52. continue
  53. }
  54. }
  55. tags = append(tags, fmt.Sprintf("%s:\"%s\"", elem, this.Name))
  56. }
  57. if len(tags) == 0 {
  58. return ""
  59. }
  60. var tagStr = ""
  61. for _, elem := range tags {
  62. tagStr += fmt.Sprintf("%s ", elem)
  63. }
  64. if len(tagStr) > 0 {
  65. tagStr = strings.TrimRight(tagStr, " ")
  66. }
  67. return fmt.Sprintf("`%s`", tagStr)
  68. }
  69. func (this *FieldMeta) GetGoField() string {
  70. return utils.Marshal(this.Name)
  71. }
  72. func (this *FieldMeta) GetGoDaoType() string {
  73. switch this.FieldType {
  74. case "bit", "tinyint", "boolean":
  75. return "uint8"
  76. case "smallint", "year":
  77. return "uint16"
  78. case "integer", "mediumint", "int":
  79. return "int"
  80. case "bigint":
  81. return "uint64"
  82. case "date", "timestamp without time zone", "timestamp with time zone", "time with time zone", "time without time zone",
  83. "timestamp", "datetime", "time":
  84. return "int64" // 时间全部是int64
  85. case "byte",
  86. "binary", "varbinary", "tinyblob", "blob", "mediumblob", "longblob":
  87. return "[]byte"
  88. case "text", "character", "character varying", "tsvector", "bit varying", "money", "json", "jsonb", "xml", "point", "interval", "line", "ARRAY",
  89. "char", "varchar", "tinytext", "mediumtext", "longtext":
  90. return "string"
  91. case "real":
  92. return "float32"
  93. case "numeric", "decimal", "double precision", "float", "double":
  94. return "float64"
  95. default:
  96. return "string"
  97. }
  98. }
  99. func (this *FieldMeta) GetGoType() string {
  100. switch this.FieldType {
  101. case "bit", "tinyint", "boolean":
  102. return "uint8"
  103. case "smallint", "year":
  104. return "uint16"
  105. case "integer", "mediumint", "int":
  106. return "int"
  107. case "bigint":
  108. return "uint64"
  109. case "date", "timestamp without time zone", "timestamp with time zone", "time with time zone", "time without time zone",
  110. "timestamp", "datetime", "time":
  111. return "time.Time"
  112. case "byte",
  113. "binary", "varbinary", "tinyblob", "blob", "mediumblob", "longblob":
  114. return "[]byte"
  115. case "text", "character", "character varying", "tsvector", "bit varying", "money", "json", "jsonb", "xml", "point", "interval", "line", "ARRAY",
  116. "char", "varchar", "tinytext", "mediumtext", "longtext":
  117. return "string"
  118. case "real":
  119. return "float32"
  120. case "numeric", "decimal", "double precision", "float", "double":
  121. return "float64"
  122. default:
  123. return "string"
  124. }
  125. }
  126. type ModelMeta struct {
  127. DbName string
  128. TableName string
  129. PackageName string
  130. Fields []FieldMeta
  131. Db *xorm.Engine
  132. Tags []string
  133. hasGetFieldInfo bool
  134. }
  135. func NewModelMeta(dbName string, tableName string, packageName string, db *xorm.Engine, tags []string) *ModelMeta {
  136. return &ModelMeta{
  137. DbName: dbName,
  138. TableName: tableName,
  139. PackageName: packageName,
  140. Db: db,
  141. Tags: tags,
  142. }
  143. }
  144. func (this *ModelMeta) ModelName() string {
  145. return utils.Marshal(this.TableName)
  146. }
  147. func (this *ModelMeta) Run(template *template.Template) ([]byte, error) {
  148. if this.Db == nil {
  149. return nil, errors.New("the db is nil")
  150. }
  151. err := this.FindField()
  152. if err != nil {
  153. return nil, err
  154. }
  155. var body = &bytes.Buffer{}
  156. err = template.Execute(body, this)
  157. if err != nil {
  158. return nil, err
  159. }
  160. source, err := format.Source(body.Bytes())
  161. if err != nil {
  162. logger.ErrorF("[Run] err,table=%v,err=%v,body=\n%s\n", this.TableName, err, body.Bytes())
  163. return body.Bytes(), nil
  164. }
  165. return source, nil
  166. }
  167. func (this *ModelMeta) FindField() error {
  168. if this.hasGetFieldInfo {
  169. return nil
  170. }
  171. queryString, err := this.Db.SQL(tableColumnsSql, this.DbName, this.TableName).QueryString()
  172. if err != nil {
  173. return err
  174. }
  175. metas := make([]FieldMeta, 0, len(queryString))
  176. for _, elem := range queryString {
  177. metas = append(metas, FieldMeta{
  178. Name: elem["column_name"],
  179. FieldType: elem["file_type"],
  180. IsNullable: elem["is_nullable"],
  181. ColumnComment: elem["column_comment"],
  182. Tags: this.Tags,
  183. })
  184. }
  185. this.Fields = metas
  186. this.hasGetFieldInfo = true
  187. return nil
  188. }
  189. func (this *ModelMeta) GetCreateSql() (string, error) {
  190. result, err := this.Db.SQL(fmt.Sprintf("SHOW CREATE TABLE %s", this.TableName)).QueryString()
  191. if err != nil {
  192. return "", err
  193. }
  194. var sql = ""
  195. for _, e := range result {
  196. str, isExist := e[CreateTable]
  197. if isExist {
  198. sql = str
  199. }
  200. }
  201. if sql == "" {
  202. return "", errors.New(fmt.Sprintf("can not fond %s create table sql", this.TableName))
  203. }
  204. return sql, nil
  205. }
  206. func (this *ModelMeta) HasTimeFiled() bool {
  207. for _, e := range this.Fields {
  208. if strings.Compare(e.GetGoType(), "time.Time") == 0 {
  209. return true
  210. }
  211. }
  212. return false
  213. }