github.com/easysoft/zendata@v0.0.0-20240513203326-705bd5a7fd67/internal/pkg/helper/column.go (about)

     1  package helper
     2  
     3  import (
     4  	"fmt"
     5  	"math/rand"
     6  	"regexp"
     7  	"strconv"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/asaskevich/govalidator"
    12  	consts "github.com/easysoft/zendata/internal/pkg/const"
    13  )
    14  
    15  func GenerateFieldDefByMetadata(metadata string, param string, name string, records []interface{}) (info FieldTypeInfo) {
    16  	GetColumnType(metadata, name, records, &info)
    17  
    18  	if info.ColumnType == consts.Varchar && info.VarcharType != "" {
    19  		generateDefByVarcharType(param, &info)
    20  		return
    21  	}
    22  	if info.ColumnType == consts.Json {
    23  		generateDefForJson(records, &info)
    24  		return
    25  	}
    26  
    27  	GenDefByColumnType(param, &info)
    28  
    29  	return
    30  }
    31  
    32  func generateDefForJson(records []interface{}, info *FieldTypeInfo) {
    33  	rang := Json
    34  	if len(records) > 0 {
    35  		rang = fmt.Sprintf("%v", records[0])
    36  	}
    37  
    38  	info.Rang = rang
    39  	info.Format = "json"
    40  }
    41  
    42  func generateDefByVarcharType(param string, info *FieldTypeInfo) {
    43  	if info.Rang != "" || info.VarcharType == "" {
    44  		return
    45  	}
    46  
    47  	if info.VarcharType == consts.Username {
    48  		info.From = "name.enaccount.v1.yaml"
    49  		info.Use = "common_underline"
    50  
    51  	} else if info.VarcharType == consts.Email {
    52  		info.From = "email.v1.yaml"
    53  		info.Use = "western_with_esp"
    54  
    55  	} else if info.VarcharType == consts.Url {
    56  		info.From = "domain.domain.v1.yaml"
    57  		info.Use = "letters_at_cn"
    58  		info.Prefix = "https://"
    59  
    60  	} else if info.VarcharType == consts.Ip {
    61  		info.From = "ip.v1.yaml"
    62  		info.Use = "privateB"
    63  
    64  	} else if info.VarcharType == consts.Mac {
    65  		info.Format = "mac()"
    66  
    67  	} else if info.VarcharType == consts.CreditCard {
    68  		info.Format = "credit_card('amex')"
    69  
    70  	} else if info.VarcharType == consts.IdCard {
    71  		info.Format = "id_card()"
    72  
    73  	} else if info.VarcharType == consts.MobileNumber {
    74  		info.From = "phone.v1.yaml"
    75  		info.Use = "cellphone"
    76  
    77  	} else if info.VarcharType == consts.TelNumber {
    78  		info.From = "phone.v1.yaml"
    79  		info.Use = "telephone_china"
    80  
    81  	} else if info.VarcharType == consts.Token {
    82  		info.Format = "token()"
    83  
    84  	} else if info.VarcharType == consts.Uuid {
    85  		info.From = "uuid.v1.yaml"
    86  		info.Use = "length32_random"
    87  
    88  	} else if info.VarcharType == consts.JsonStr {
    89  		info.Format = "json()"
    90  
    91  	} else if info.VarcharType == consts.Md5 {
    92  		info.Rang = "1-100"
    93  		info.Format = "md5"
    94  	}
    95  
    96  	return
    97  }
    98  
    99  func GetColumnType(metaType string, name string, records []interface{}, info *FieldTypeInfo) {
   100  	metaType = strings.ToLower(metaType)
   101  
   102  	if metaType == "integer" {
   103  		metaType = "int"
   104  	}
   105  
   106  	info.ColumnType = consts.ColumnType(metaType)
   107  
   108  	if info.ColumnType == consts.Varchar {
   109  		info.VarcharType = GetVarcharTypeByName(name)
   110  	}
   111  
   112  	if info.ColumnType == consts.Varchar && info.VarcharType == "" && len(records) > 0 {
   113  		info.VarcharType = GetVarcharTypeByRecords(records)
   114  	}
   115  
   116  	if info.ColumnType == consts.Float || info.ColumnType == consts.Double {
   117  		GetPrecisionByRecords(records, info)
   118  	}
   119  
   120  	SetIsNum(info)
   121  	if info.IsNum {
   122  		GetSignByRecords(records, info)
   123  	}
   124  
   125  	return
   126  }
   127  
   128  func SetIsNum(info *FieldTypeInfo) {
   129  	info.IsNum = info.ColumnType == consts.Tinyint || info.ColumnType == consts.Smallint ||
   130  		info.ColumnType == consts.Mediumint || info.ColumnType == consts.Int || info.ColumnType == consts.Bigint ||
   131  		info.ColumnType == consts.Float || info.ColumnType == consts.Double
   132  }
   133  
   134  func GetSignByRecords(records []interface{}, info *FieldTypeInfo) {
   135  	if len(records) == 0 {
   136  		return
   137  	}
   138  	num := getRandNum(len(records))
   139  	computerPrecision(records[num], info)
   140  
   141  	num = getRandNum(len(records))
   142  	computerPrecision(records[num], info)
   143  
   144  	num = getRandNum(len(records))
   145  	computerPrecision(records[num], info)
   146  }
   147  func GetPrecisionByRecords(records []interface{}, info *FieldTypeInfo) {
   148  	if len(records) == 0 {
   149  		return
   150  	}
   151  
   152  	num := getRandNum(len(records))
   153  	computerSign(records[num], info)
   154  
   155  	num = getRandNum(len(records))
   156  	computerSign(records[num], info)
   157  
   158  	num = getRandNum(len(records))
   159  	computerSign(records[num], info)
   160  }
   161  func computerPrecision(val interface{}, info *FieldTypeInfo) {
   162  	str := fmt.Sprintf("%v", val)
   163  
   164  	index := strings.LastIndex(str, ".")
   165  	subStr := str[index+1:]
   166  
   167  	info.Precision = len(subStr)
   168  }
   169  func computerSign(val interface{}, info *FieldTypeInfo) {
   170  	str := fmt.Sprintf("%v", val)
   171  	float, _ := strconv.ParseFloat(str, 64)
   172  
   173  	info.HasSign = info.HasSign || float < 0
   174  }
   175  
   176  func GetVarcharTypeByName(name string) (ret consts.VarcharType) {
   177  	ret = consts.Empty
   178  
   179  	if regexp.MustCompile(`(user).*(name)`).MatchString(name) {
   180  		ret = consts.Username
   181  	} else if regexp.MustCompile(`(phone|number)`).MatchString(name) {
   182  		if regexp.MustCompile(`(tel)`).MatchString(name) {
   183  			ret = consts.TelNumber
   184  		} else { // default use mobile phone
   185  			ret = consts.MobileNumber
   186  		}
   187  	} else if regexp.MustCompile(`(email)`).MatchString(name) {
   188  		ret = consts.Email
   189  	} else if regexp.MustCompile(`(url)`).MatchString(name) {
   190  		ret = consts.Url
   191  	} else if regexp.MustCompile(`(ip)`).MatchString(name) {
   192  		ret = consts.Ip
   193  	} else if regexp.MustCompile(`(mac).*(address)`).MatchString(name) {
   194  		ret = consts.Mac
   195  	} else if regexp.MustCompile(`(creditcard)`).MatchString(name) {
   196  		ret = consts.CreditCard
   197  	} else if regexp.MustCompile(`(idcard)`).MatchString(name) {
   198  		ret = consts.IdCard
   199  	} else if regexp.MustCompile(`(token)`).MatchString(name) {
   200  		ret = consts.Token
   201  	}
   202  
   203  	return
   204  }
   205  
   206  func GetVarcharTypeByRecords(records []interface{}) (ret consts.VarcharType) {
   207  	ret = consts.Empty
   208  
   209  	if len(records) == 0 {
   210  		return
   211  	}
   212  
   213  	val := fmt.Sprintf("%v", records[0])
   214  
   215  	if govalidator.IsEmail(val) {
   216  		ret = consts.Email
   217  
   218  	} else if govalidator.IsCreditCard(val) {
   219  		ret = consts.CreditCard
   220  
   221  	} else if govalidator.IsMAC(val) {
   222  		ret = consts.Mac
   223  
   224  	} else if govalidator.IsUUID(val) {
   225  		ret = consts.Uuid
   226  
   227  	} else if govalidator.IsMD5(val) {
   228  		ret = consts.Md5
   229  
   230  	} else if IsIDCard(val) {
   231  		ret = consts.IdCard
   232  
   233  	} else if IsMobilePhone(val) {
   234  		ret = consts.MobileNumber
   235  
   236  	} else if IsTelPhone(val) {
   237  		ret = consts.TelNumber
   238  
   239  	} else if govalidator.IsURL(val) {
   240  		ret = consts.Url
   241  
   242  	} else if govalidator.IsJSON(val) {
   243  		ret = consts.JsonStr
   244  	}
   245  
   246  	return
   247  }
   248  
   249  type FieldTypeInfo struct {
   250  	ColumnType  consts.ColumnType
   251  	VarcharType consts.VarcharType
   252  
   253  	IsNum     bool
   254  	Precision int
   255  	HasSign   bool
   256  
   257  	Note    string
   258  	Rang    string
   259  	Loop    string
   260  	Loopfix string
   261  	Type    string
   262  	Format  string
   263  	From    string
   264  	Use     string
   265  	Select  string
   266  	Prefix  string
   267  }
   268  
   269  func GenDefByColumnType(param string, ret *FieldTypeInfo) {
   270  	switch ret.ColumnType {
   271  	// int
   272  	case "bit":
   273  		ret.Rang, ret.Note = GenBit()
   274  	case "tinyint":
   275  		ret.Rang, ret.Note = GenTinyint(ret.HasSign)
   276  	case "smallint":
   277  		ret.Rang, ret.Note = GenSmallint(ret.HasSign)
   278  	case "mediumint":
   279  		ret.Rang, ret.Note = GenMediumint(ret.HasSign)
   280  	case "int":
   281  		ret.Rang, ret.Note = GenInt(ret.HasSign)
   282  	case "bigint":
   283  		ret.Rang, ret.Note = GenBigint(ret.HasSign)
   284  
   285  	// float
   286  	case "float":
   287  		ret.Rang, ret.Note = GenFloat(ret.HasSign)
   288  	case "double":
   289  		ret.Rang, ret.Note = GenDouble(ret.HasSign)
   290  	// fixed-point
   291  	case "decimal":
   292  		ret.Rang, ret.Note = GenDecimal(ret.HasSign)
   293  
   294  	// string
   295  	case "char":
   296  		ret.Rang, ret.Loop = GenChar(param)
   297  
   298  	case "tinytext":
   299  		ret.From = "idiom.v1.idiom"
   300  		ret.Select = "word"
   301  	case "text":
   302  		ret.From = "xiehouyu.v1.xiehouyu"
   303  		ret.Select = "riddle"
   304  	case "mediumtext":
   305  		ret.From = "joke.v1.joke"
   306  		ret.Select = "content"
   307  	case "longtext":
   308  		ret.From = "song.v1.song"
   309  		ret.Select = "lyric"
   310  
   311  	// binary data
   312  	case "tinyblob":
   313  		ret.From, ret.Format = GenBin()
   314  	case "blob":
   315  		ret.From, ret.Format = GenBin()
   316  	case "mediumblob":
   317  		ret.From, ret.Format = GenBin()
   318  	case "longblob":
   319  		ret.From, ret.Format = GenBin()
   320  	case "binary":
   321  		ret.From, ret.Format = GenBin()
   322  	case "varbinary":
   323  		ret.From, ret.Format = GenBin()
   324  
   325  	// date and time type
   326  	case "date":
   327  		ret.Rang, ret.Type, ret.Format = GenDate()
   328  	case "time":
   329  		ret.Rang, ret.Type, ret.Format = GenTime()
   330  	case "year":
   331  		ret.Rang, ret.Type, ret.Format = GenYear()
   332  	case "datetime":
   333  		ret.Rang, ret.Type, ret.Format = GenDatetime()
   334  	case "timestamp":
   335  		ret.Rang, ret.Type, ret.Format = GenTimestamp()
   336  
   337  	// other type
   338  	case "enum":
   339  		ret.Rang = getEnumValue(param)
   340  	case "set":
   341  		ret.Rang, ret.Loop, ret.Loopfix = getSetValue(param)
   342  
   343  	//case "geometry":
   344  	//	ret.Rang = `"geometry"`
   345  	//case "point":
   346  	//	ret.Rang = `"point"`
   347  	//case "linestring":
   348  	//	ret.Rang = `"linestring"`
   349  	//case "polygon":
   350  	//	ret.Rang = `"polygon"`
   351  	//case "multipoint":
   352  	//	ret.Rang = `"multipoint"`
   353  	//case "multilinestring":
   354  	//	ret.Rang = `"multilinestring"`
   355  	//case "multipolygon":
   356  	//	ret.Rang = `"multipolygon"`
   357  	//case "geometrycollection":
   358  	//	ret.Rang = `"geometrycollection"`
   359  
   360  	default:
   361  	}
   362  
   363  	return
   364  }
   365  
   366  func getEnumValue(param string) (ret string) {
   367  	ret = strings.ReplaceAll(param, "'", "")
   368  
   369  	return
   370  }
   371  
   372  func getSetValue(param string) (ret, loop, loopfix string) {
   373  	ret = strings.ReplaceAll(param, "'", "")
   374  
   375  	arr := strings.Split(param, ",")
   376  
   377  	start := 1
   378  	if len(arr) > 2 {
   379  		start = 2
   380  	}
   381  	loop = fmt.Sprintf("%d-%d", start, len(arr))
   382  
   383  	return
   384  }
   385  
   386  func getRandNum(num int) (ret int) {
   387  	ret = rand.New(rand.NewSource(time.Now().UnixNano())).Intn(num)
   388  
   389  	return
   390  }