github.com/easysoft/zendata@v0.0.0-20240513203326-705bd5a7fd67/internal/server/service/def.go (about) 1 package serverService 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 "strconv" 8 "strings" 9 10 "github.com/easysoft/zendata/internal/pkg/domain" 11 "github.com/easysoft/zendata/internal/pkg/service" 12 13 consts "github.com/easysoft/zendata/internal/pkg/const" 14 "github.com/easysoft/zendata/internal/pkg/helper" 15 "github.com/easysoft/zendata/internal/pkg/model" 16 serverRepo "github.com/easysoft/zendata/internal/server/repo" 17 serverUtils "github.com/easysoft/zendata/internal/server/utils" 18 fileUtils "github.com/easysoft/zendata/pkg/utils/file" 19 "github.com/easysoft/zendata/pkg/utils/vari" 20 "gopkg.in/yaml.v3" 21 "gorm.io/gorm" 22 ) 23 24 type DefService struct { 25 DefRepo *serverRepo.DefRepo `inject:""` 26 FieldRepo *serverRepo.FieldRepo `inject:""` 27 ReferRepo *serverRepo.ReferRepo `inject:""` 28 SectionRepo *serverRepo.SectionRepo `inject:""` 29 MockRepo *serverRepo.MockRepo `inject:""` 30 31 ResService *ResService `inject:""` 32 SectionService *SectionService `inject:""` 33 34 RangeService *service.RangeService `inject:""` 35 } 36 37 func (s *DefService) List(keywords string, page int) (list []*model.ZdDef, total int) { 38 list, total, _ = s.DefRepo.List(strings.TrimSpace(keywords), page) 39 return 40 } 41 42 func (s *DefService) Get(id int) (def model.ZdDef, dirs []domain.Dir) { 43 if id > 0 { 44 def, _ = s.DefRepo.Get(uint(id)) 45 } else { 46 def.Folder = "users" + consts.PthSep 47 def.Type = "text" 48 } 49 50 serverUtils.GetDirs(consts.ResDirUsers, &dirs) 51 52 return 53 } 54 55 func (s *DefService) Save(def *model.ZdDef) (err error) { 56 def.Folder = serverUtils.DealWithPathSepRight(def.Folder) 57 58 def.Path = vari.WorkDir + def.Folder + 59 serverUtils.AddExt(strings.TrimSuffix(def.FileName, ".yaml"), ".yaml") 60 61 if def.ID == 0 { 62 err = s.Create(def) 63 } else { 64 err = s.Update(def) 65 } 66 s.updateYaml(def.ID) 67 68 return 69 } 70 71 func (s *DefService) Create(def *model.ZdDef) (err error) { 72 def.ReferName = helper.PathToName(def.Path, consts.ResDirUsers, def.Type) 73 err = s.DefRepo.Create(def) 74 75 // add root field node 76 rootField, err := s.FieldRepo.CreateTreeNode(def.ID, 0, "字段", "root") 77 s.ReferRepo.CreateDefault(rootField.ID, consts.ResTypeDef) 78 err = s.DefRepo.Update(def) 79 80 return 81 } 82 83 func (s *DefService) Update(def *model.ZdDef) (err error) { 84 var old model.ZdDef 85 old, err = s.DefRepo.Get(def.ID) 86 if err == gorm.ErrRecordNotFound { 87 return 88 } 89 if def.Path != old.Path { 90 fileUtils.RemoveExist(old.Path) 91 } 92 93 def.ReferName = helper.PathToName(def.Path, consts.ResDirUsers, def.Type) 94 err = s.DefRepo.Update(def) 95 96 return 97 } 98 99 func (s *DefService) Remove(id int) (err error) { 100 var old model.ZdDef 101 old, err = s.DefRepo.Get(uint(id)) 102 if err == gorm.ErrRecordNotFound { 103 return 104 } 105 fileUtils.RemoveExist(old.Path) 106 107 err = s.DefRepo.Remove(uint(id)) 108 return 109 } 110 111 func (s *DefService) updateYamlByField(fieldId uint) (err error) { 112 field, _ := s.FieldRepo.Get(fieldId) 113 return s.updateYaml(field.DefID) 114 } 115 116 func (s *DefService) updateYaml(id uint) (err error) { 117 var po model.ZdDef 118 po, _ = s.DefRepo.Get(id) 119 120 s.genYaml(&po) 121 err = s.DefRepo.UpdateYaml(po) 122 //update mock content 123 mockData := s.MockRepo.GetByDefID(id) 124 if mockData.ID > 0 { 125 mockData.DataContent = po.Yaml 126 s.MockRepo.Save(&mockData) 127 } 128 fileUtils.WriteFile(po.Path, po.Yaml) 129 130 return 131 } 132 133 func (s *DefService) genYaml(def *model.ZdDef) (str string) { 134 root, err := s.FieldRepo.GetDefFieldTree(def.ID) 135 if err != nil { 136 return 137 } 138 139 yamlObj := domain.DefData{} 140 s.DefRepo.GenDef(*def, &yamlObj) 141 142 for _, child := range root.Fields { // ignore the root 143 defField := domain.DefField{} 144 145 refer, _ := s.ReferRepo.GetByOwnerIdAndType(child.ID, consts.ResTypeDef) 146 s.zdFieldToFieldForExport(*child, refer, &defField) 147 148 yamlObj.Fields = append(yamlObj.Fields, defField) 149 } 150 151 bytes, err := yaml.Marshal(yamlObj) 152 def.Yaml = helper.ConvertYamlStringToMapFormat(bytes) 153 154 return 155 } 156 157 func (s *DefService) zdFieldToFieldForExport(treeNode model.ZdField, refer model.ZdRefer, field *domain.DefField) { 158 genFieldFromZdField(treeNode, refer, field) 159 160 for _, child := range treeNode.Fields { 161 childField := domain.DefField{} 162 163 childRefer, _ := s.ReferRepo.GetByOwnerId(child.ID) 164 s.zdFieldToFieldForExport(*child, childRefer, &childField) 165 166 field.Fields = append(field.Fields, childField) 167 } 168 169 //for _, from := range treeNode.Froms { // only one level 170 // childField := model.DefField{} 171 // genFieldFromZdField(*from, &childField) 172 // 173 // field.Froms = append(field.Froms, childField) 174 //} 175 176 if len(field.Fields) == 0 { 177 field.Fields = nil 178 } 179 if len(field.Froms) == 0 { 180 field.Froms = nil 181 } 182 183 return 184 } 185 186 func (s *DefService) Sync(files []domain.ResFile) (err error) { 187 list := s.DefRepo.ListAll() 188 189 mp := map[string]*model.ZdDef{} 190 for _, item := range list { 191 mp[item.Path] = item 192 } 193 194 for _, fi := range files { 195 // for yaml "res", "data" type should be default value text 196 if fi.ResType == "" || fi.ResType == consts.ResTypeYaml { 197 fi.ResType = consts.ResTypeText 198 } 199 200 _, found := mp[fi.Path] 201 if !found { // no record 202 s.SyncToDB(fi, false) 203 } else if fi.UpdatedAt.Unix() > mp[fi.Path].UpdatedAt.Unix() { // db is old 204 s.DefRepo.Remove(mp[fi.Path].ID) 205 s.SyncToDB(fi, false) 206 } 207 } 208 209 return 210 } 211 func (s *DefService) SyncToDB(fi domain.ResFile, isMock bool) (err error, id uint) { 212 content, _ := os.ReadFile(fi.Path) 213 yamlContent := helper.ReplaceSpecialChars(content) 214 po := model.ZdDef{} 215 err = yaml.Unmarshal(yamlContent, &po) 216 po.Title = fi.Title 217 po.Type = fi.ResType 218 po.Desc = fi.Desc 219 po.Path = fi.Path 220 po.IsMock = isMock 221 po.Folder = serverUtils.GetRelativePath(po.Path) 222 223 po.ReferName = helper.PathToName(po.Path, consts.ResDirUsers, po.Type) 224 po.FileName = fileUtils.GetFileName(po.Path) 225 226 po.Yaml = string(content) 227 228 s.DefRepo.Create(&po) 229 id = po.ID 230 231 rootField, _ := s.FieldRepo.CreateTreeNode(po.ID, 0, "字段", "root") 232 s.ReferRepo.CreateDefault(rootField.ID, consts.ResTypeDef) 233 fmt.Println(rootField.ID, po.Type, po, rootField) 234 for i, field := range po.Fields { 235 field.Ord = i + 1 236 s.saveFieldToDB(&field, po, fi.Path, rootField.ID, po.ID) 237 } 238 239 return 240 } 241 func (s *DefService) saveFieldToDB(field *model.ZdField, def model.ZdDef, currPath string, parentID, defID uint) { 242 if field.Froms != nil && len(field.Froms) > 0 { 243 for idx, from := range field.Froms { 244 if from.Field == "" { 245 from.Field = "from" + strconv.Itoa(idx+1) 246 } 247 s.saveFieldToDB(from, def, currPath, parentID, defID) 248 } 249 250 return 251 } 252 253 // update field 254 field.DefID = defID 255 field.ParentID = parentID 256 if field.From == "" && def.From != "" { 257 field.From = def.From 258 } 259 if field.Type == "" { 260 field.Type = consts.FieldTypeList 261 } 262 if field.Mode == "" { 263 field.Mode = consts.ModeParallel 264 } 265 266 field.Range = strings.TrimSpace(field.Range) 267 268 // save field 269 s.FieldRepo.Save(field) 270 271 // create refer 272 refer := model.ZdRefer{OwnerType: "def", OwnerID: field.ID} 273 274 needToCreateSections := false 275 if field.Select != "" { // refer to excel 276 refer.Type = consts.ResTypeExcel 277 278 refer.ColName = field.Select 279 refer.Condition = field.Where 280 refer.Rand = field.Rand 281 282 _, sheet := fileUtils.ConvertResExcelPath(field.From, currPath) 283 refer.File = field.From 284 refer.Sheet = sheet 285 286 } else if field.Use != "" { // refer to ranges or instances, need to read yaml to get the type 287 rangeSections := s.RangeService.ParseRangeProperty(field.Use) 288 if len(rangeSections) > 0 { // only get the first one 289 rangeSection := rangeSections[0] 290 desc, _, count, countTag := s.RangeService.ParseRangeSection(rangeSection) // medium{2!} 291 refer.ColName = desc 292 refer.Count = count 293 refer.CountTag = countTag 294 } 295 296 path := fileUtils.ConvertReferRangeToPath(field.From, currPath) 297 _, _, refer.Type = helper.ReadYamlInfo(path) 298 refer.File = field.From 299 300 } else if field.Config != "" { // refer to config 301 refer.Type = consts.ResTypeConfig 302 303 rangeSections := s.RangeService.ParseRangeProperty(field.Config) // dir/config.yaml 304 if len(rangeSections) > 0 { // only get the first one 305 rangeSection := rangeSections[0] 306 desc, _, count, countTag := s.RangeService.ParseRangeSection(rangeSection) 307 refer.Count = count 308 refer.CountTag = countTag 309 310 path := fileUtils.ConvertReferRangeToPath(desc, currPath) 311 refer.File = GetRelatedPathWithResDir(path) 312 } 313 314 } else if field.Range != "" { 315 rangeSections := s.RangeService.ParseRangeProperty(field.Range) 316 if len(rangeSections) > 0 { 317 rangeSection := rangeSections[0] // deal with yaml and text refer using range prop 318 desc, step, count, countTag := s.RangeService.ParseRangeSection(rangeSection) // dir/users.txt:R{3} 319 if filepath.Ext(desc) == ".txt" || filepath.Ext(desc) == ".yaml" { 320 if filepath.Ext(desc) == ".txt" { // dir/users.txt:2 321 refer.Type = consts.ResTypeText 322 323 if strings.ToLower(step) == "r" { 324 refer.Rand = true 325 } else { 326 refer.Step, _ = strconv.Atoi(step) 327 } 328 329 } else if filepath.Ext(desc) == ".yaml" { // dir/content.yaml{3} 330 refer.Type = consts.ResTypeYaml 331 332 refer.Count = count 333 refer.CountTag = countTag 334 } 335 336 path := fileUtils.ConvertReferRangeToPath(desc, currPath) 337 refer.File = GetRelatedPathWithResDir(path) 338 } else { // like 1-9,a-z 339 needToCreateSections = true 340 } 341 } 342 } 343 344 // save refer 345 refer.OwnerID = field.ID 346 s.ReferRepo.Save(&refer) 347 348 // gen sections if needed 349 if needToCreateSections { 350 rangeSections := s.RangeService.ParseRangeProperty(field.Range) 351 352 for i, rangeSection := range rangeSections { 353 s.SectionService.SaveFieldSectionToDB(rangeSection, i, field.ID, "def") 354 } 355 } 356 357 // deal with field's children 358 for _, child := range field.Fields { 359 s.saveFieldToDB(child, def, currPath, field.ID, defID) 360 } 361 }