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

     1  package service
     2  
     3  import (
     4  	"regexp"
     5  	"strconv"
     6  	"strings"
     7  
     8  	consts "github.com/easysoft/zendata/internal/pkg/const"
     9  	"github.com/easysoft/zendata/internal/pkg/domain"
    10  	"github.com/easysoft/zendata/pkg/utils/vari"
    11  )
    12  
    13  type FieldService struct {
    14  	ResService     *ResService     `inject:""`
    15  	TextService    *TextService    `inject:""`
    16  	ValueService   *ValueService   `inject:""`
    17  	ArticleService *ArticleService `inject:""`
    18  
    19  	FixService     *FixService     `inject:""`
    20  	LoopService    *LoopService    `inject:""`
    21  	ListService    *ListService    `inject:""`
    22  	RangeService   *RangeService   `inject:""`
    23  	RandomService  *RandomService  `inject:""`
    24  	CombineService *CombineService `inject:""`
    25  }
    26  
    27  func (s *FieldService) Generate(field *domain.DefField, parentJoin bool) {
    28  	field.Join = field.Join || parentJoin
    29  
    30  	s.RangeService.DealwithFixRange(field)
    31  
    32  	// iterate children
    33  	if len(field.Fields) > 0 {
    34  		for i := range field.Fields {
    35  			if field.Fields[i].From == "" {
    36  				field.Fields[i].From = field.From
    37  			}
    38  			field.Fields[i].FileDir = field.FileDir
    39  			//field.Fields[i].ParentItems = field.Items
    40  			//field.Fields[i].ParentJoin = field.Join
    41  
    42  			s.Generate(&field.Fields[i], field.Join)
    43  		}
    44  
    45  		s.CombineService.CombineChildrenIfNeeded(field, parentJoin)
    46  
    47  		return
    48  	}
    49  
    50  	// generate values
    51  	if len(field.Froms) > 0 { // refer to multi res
    52  		s.GenValuesForMultiRes(field, true)
    53  
    54  	} else if field.From != "" && field.Type != consts.FieldTypeArticle { // refer to res
    55  		s.GenValuesForSingleRes(field)
    56  
    57  	} else if field.Config != "" { // refer to config
    58  		s.GenValuesForConfig(field)
    59  
    60  	} else { // not a refer
    61  		s.GenerateValuesForNoReferField(field)
    62  	}
    63  
    64  	// random values
    65  	if field.Rand && field.Type != consts.FieldTypeArticle {
    66  		field.Values = s.RandomService.RandomValues(field.Values)
    67  	}
    68  
    69  	if field.Use != "" && field.From == "" {
    70  		field.From = vari.GlobalVars.DefData.From
    71  	}
    72  
    73  	//
    74  	vari.GlobalVars.FieldNameToValuesMap[field.Field] = field.Values
    75  	vari.GlobalVars.FieldNameToFieldMap[field.Field] = *field
    76  }
    77  
    78  func (s *FieldService) GenerateValuesForNoReferField(field *domain.DefField) {
    79  	s.CreateField(field)
    80  
    81  	s.LoopService.ComputerLoopTimes(field) // change LoopStart, LoopEnd for conf like loop:  1-10             # 循环1次,2次……
    82  
    83  	uniqueTotal := s.computerUniqueTotal(field) // computer total for array children(records: 3) OR range affixes (prefix: 1-3)
    84  
    85  	indexOfRow := 0
    86  	count := 0
    87  	values := make([]interface{}, 0)
    88  
    89  	for {
    90  		// 2. random replacement
    91  		isRandomAndLoopEnd := !vari.ResLoading && //  ignore rand in resource
    92  			!(*field).ReferToAnotherYaml &&
    93  			(*field).IsRand && (*field).LoopIndex > (*field).LoopEnd
    94  		// isNotRandomAndValOver := !(*field).IsRand && indexOfRow >= len(fieldWithValues.Values)
    95  		if count >= uniqueTotal || isRandomAndLoopEnd { // || count >= vari.GlobalVars.Total
    96  			for _, v := range field.Values {
    97  				v = s.FixService.AddFix(v, field, count, true)
    98  
    99  				values = append(values, v)
   100  			}
   101  			break
   102  		}
   103  
   104  		// 处理格式、前后缀、loop等
   105  		val := s.LoopService.LoopFieldValueToSingleStr(field, &indexOfRow, count, true)
   106  		values = append(values, val)
   107  
   108  		count++
   109  
   110  		if count >= uniqueTotal { // { || count >= vari.GlobalVars.Total{
   111  			break
   112  		}
   113  
   114  		(*field).LoopIndex = (*field).LoopIndex + 1
   115  		if (*field).LoopIndex > (*field).LoopEnd {
   116  			(*field).LoopIndex = (*field).LoopStart
   117  		}
   118  	}
   119  
   120  	field.Values = values
   121  
   122  	return
   123  }
   124  
   125  func (s *FieldService) CreateField(field *domain.DefField) {
   126  	if field.Type == "" { // set default
   127  		field.Type = consts.FieldTypeList
   128  	}
   129  	if field.Length > 0 {
   130  		// field.Length = field.Length - len(field.Prefix) - len(field.Postfix)
   131  		if field.Length < 0 {
   132  			field.Length = 0
   133  		}
   134  	}
   135  
   136  	if field.Type == consts.FieldTypeList {
   137  		s.ListService.CreateListFieldValues(field)
   138  	} else if field.Type == consts.FieldTypeArticle {
   139  		s.ArticleService.CreateArticleField(field)
   140  
   141  	} else if field.Type == consts.FieldTypeTimestamp {
   142  		s.ValueService.CreateTimestampField(field)
   143  	}
   144  
   145  	return
   146  }
   147  
   148  func (s *FieldService) GenValuesForConfig(field *domain.DefField) (values []interface{}) {
   149  	groupValues := vari.GlobalVars.ResData[field.Config]
   150  
   151  	field.Values = groupValues["all"]
   152  
   153  	s.LoopService.LoopAndFixFieldValues(field, true)
   154  
   155  	return
   156  }
   157  
   158  func (s *FieldService) GenValuesForSingleRes(field *domain.DefField) {
   159  	if field.Use != "" { // refer to ranges or instance
   160  		key := s.ResService.GetFromKey(field)
   161  		groupValues := vari.GlobalVars.ResData[key]
   162  
   163  		uses := strings.TrimSpace(field.Use) // like group{limit:repeat}
   164  		use, numLimit, repeat := s.getNum(uses)
   165  
   166  		if strings.Index(use, "all") == 0 {
   167  			valuesForAdd := s.getRepeatValuesFromAll(groupValues, numLimit, repeat)
   168  			field.Values = append(field.Values, valuesForAdd...)
   169  		} else {
   170  			infos := s.parseUse(uses)
   171  			valuesForAdd := s.getRepeatValuesFromGroups(groupValues, infos)
   172  			field.Values = append(field.Values, valuesForAdd...)
   173  		}
   174  
   175  	} else if field.Select != "" { // refer to excel
   176  		groupValues := vari.GlobalVars.ResData[s.ResService.GetFromKey(field)]
   177  		resKey := field.Select
   178  
   179  		// deal with the key
   180  		if vari.GlobalVars.DefData.Type == consts.DefTypeArticle {
   181  			resKey = resKey + "_" + field.Field
   182  		}
   183  
   184  		field.Values = append(field.Values, groupValues[resKey]...)
   185  	}
   186  
   187  	s.LoopService.LoopAndFixFieldValues(field, true)
   188  
   189  	return
   190  }
   191  
   192  func (s *FieldService) GenValuesForMultiRes(field *domain.DefField, withFix bool) {
   193  	unionValues := make([]interface{}, 0) // 2 dimension arr for from, [ [a,b,c], [1,2,3] ]
   194  
   195  	// multi froms 1.
   196  	for _, from := range field.Froms {
   197  		if from.From == "" {
   198  			from.From = field.From
   199  		}
   200  
   201  		from.FileDir = field.FileDir
   202  
   203  		s.Generate(&from, true)
   204  
   205  		unionValues = append(unionValues, from.Values...)
   206  	}
   207  
   208  	count := len(unionValues)
   209  	if count > vari.GlobalVars.Total {
   210  		count = vari.GlobalVars.Total
   211  	}
   212  
   213  	field.Values = unionValues
   214  
   215  	s.LoopService.LoopAndFixFieldValues(field, true)
   216  
   217  	return
   218  }
   219  
   220  func (s *FieldService) getRepeatValuesFromAll(groupValues map[string][]interface{}, numLimit, repeat int) (ret []interface{}) {
   221  	if repeat == 0 {
   222  		repeat = 1
   223  	}
   224  
   225  	count := 0
   226  exit:
   227  	for _, arr := range groupValues {
   228  		for _, item := range arr {
   229  			for i := 0; i < repeat; i++ {
   230  				ret = append(ret, item)
   231  				count++
   232  
   233  				if numLimit > 0 && count >= numLimit {
   234  					break exit
   235  				}
   236  			}
   237  		}
   238  	}
   239  
   240  	return
   241  }
   242  
   243  func (s *FieldService) getRepeatValuesFromGroups(groupValues map[string][]interface{}, info []retsInfo) (ret []interface{}) {
   244  	count := 0
   245  
   246  exit:
   247  	for _, v := range info {
   248  		if v.repeat == 0 {
   249  			v.repeat = 1
   250  		}
   251  
   252  		arr := groupValues[v.ret]
   253  		if len(arr) == 0 {
   254  			break exit
   255  		}
   256  		if v.numLimit != 0 { // privateB{n}
   257  			for i := 0; (v.numLimit > 0 && i < v.numLimit) && i < len(arr) && i < vari.GlobalVars.Total; i++ {
   258  				index := i / v.repeat
   259  				ret = append(ret, arr[index])
   260  				count++
   261  			}
   262  		} else { // privateA
   263  			for i := 0; i < len(arr) && i < vari.GlobalVars.Total; i++ {
   264  				index := i / v.repeat % len(arr)
   265  				ret = append(ret, arr[index])
   266  				count++
   267  			}
   268  		}
   269  
   270  		if count >= vari.GlobalVars.Total {
   271  			break exit
   272  		}
   273  
   274  	}
   275  	return
   276  }
   277  
   278  func (s *FieldService) computerUniqueTotal(field *domain.DefField) (ret int) {
   279  	ret = len(field.Values)
   280  
   281  	if field.PostfixRange != nil && len(field.PostfixRange.Values) > 0 {
   282  		ret *= len(field.PostfixRange.Values)
   283  	}
   284  
   285  	if field.PrefixRange != nil && len(field.PrefixRange.Values) > 0 {
   286  		ret *= len(field.PrefixRange.Values)
   287  	}
   288  
   289  	if ret < len(field.Values) {
   290  		ret = len(field.Values)
   291  	}
   292  
   293  	return
   294  }
   295  
   296  func (s *FieldService) getNum(group string) (ret string, numLimit, repeat int) {
   297  	regx := regexp.MustCompile(`\{([^:]*):?([^:]*)\}`)
   298  	arr := regx.FindStringSubmatch(group)
   299  	if len(arr) >= 2 {
   300  		numLimit, _ = strconv.Atoi(arr[1])
   301  	}
   302  	if len(arr) >= 3 {
   303  		repeat, _ = strconv.Atoi(arr[2])
   304  	}
   305  
   306  	ret = regx.ReplaceAllString(group, "")
   307  
   308  	return
   309  }
   310  
   311  // pars Uses
   312  type retsInfo struct {
   313  	ret      string
   314  	numLimit int
   315  	repeat   int
   316  }
   317  
   318  func (s *FieldService) parseUse(groups string) (results []retsInfo) {
   319  	rets := strings.Split(groups, ",")
   320  	results = make([]retsInfo, len(rets))
   321  	regx := regexp.MustCompile(`\{([^:]*):?([^:]*)\}`)
   322  	for k, v := range rets {
   323  		results[k].ret = regx.ReplaceAllString(v, "")
   324  		arr := regx.FindStringSubmatch(v)
   325  		if len(arr) >= 2 {
   326  			results[k].numLimit, _ = strconv.Atoi(arr[1])
   327  		}
   328  		if len(arr) >= 3 {
   329  			results[k].repeat, _ = strconv.Atoi(arr[2])
   330  			if results[k].repeat == 0 {
   331  				results[k].repeat = 1
   332  			}
   333  		}
   334  	}
   335  	return
   336  }