github.com/benoitkugler/goacve@v0.0.0-20201217100549-151ce6e55dc8/server/core/macros.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "go/ast" 6 "go/parser" 7 "go/token" 8 "html/template" 9 "io" 10 "log" 11 "os" 12 "os/exec" 13 "strings" 14 "unicode" 15 ) 16 17 var ( 18 templateAcces = template.Must(template.New("").Parse(` 19 // Acces{{ .Name }} est un pointeur sur l'objet {{ .Name }} 20 // d'id donné. 21 type Acces{{ .Name }} struct { 22 Base *BaseLocale 23 Id int64 24 } 25 26 func(b *BaseLocale) New{{ .Name }}(id int64) Acces{{ .Name }} { 27 return Acces{{ .Name }}{Base: b, Id: id} 28 } 29 30 // RawData renvoi les données sous-jacentes à l'accès. 31 func (ac Acces{{ .Name }}) RawData() rd.{{ .Name }} { 32 return ac.Base.{{ .Name }}s[ac.Id] 33 } 34 `)) 35 36 templateLoadBaseLocaleMain = ` 37 base.%ss, err = rd.SelectAll%ss(db) 38 if err != nil { 39 return nil, err 40 } 41 ` 42 43 templateLoadBaseLocalePartielMain = ` 44 base.%ss, err = rd.Select%ss(db, items["%ss"]...) 45 if err != nil { 46 return nil, err 47 } 48 ` 49 50 templateLoadBaseLocaleLink = ` 51 rl.%ss, err = rd.SelectAll%ss(db) 52 if err != nil { 53 return nil, err 54 } 55 ` 56 57 templateLoadBaseLocalePartielLink = ` 58 rl.%s, err = rd.Select%sById%s(db, items["%s"]...) 59 if err != nil { 60 return nil, err 61 } 62 ` 63 64 templateHashTable = ` 65 tmp = make(map[int64]uint32, len(base.%s)) 66 for id, v := range base.%s { 67 b, err := json.Marshal(v) 68 if err != nil { 69 return nil, err 70 } 71 tmp[id] = crc32.ChecksumIEEE(b) 72 } 73 baseHash["%s"] = tmp 74 ` 75 76 templateUpdateTable = ` 77 for id, v := range incomming.%s { 78 base.%s[id] = v 79 } 80 for _, id := range toDelete["%s"] { 81 delete(base.%s, id) 82 } 83 ` 84 85 templateTestMarshal = template.Must(template.New("").Parse(` 86 size, err = compressMesureSize(base.{{ .Name }}s) 87 if err != nil { 88 t.Fatal(err) 89 } 90 fmt.Println("{{ .Name }}s :", size / 1000, "KB") 91 92 `)) 93 ) 94 95 type templateArg struct { 96 Name string 97 } 98 99 func main() { 100 parse() 101 } 102 103 func isMainItem(name string) bool { 104 return len(strings.FieldsFunc(name, unicode.IsUpper)) == 1 105 } 106 107 var exclutedTables = []string{ 108 "User", "ContenuDocument", "Lettredirecteur", "Imageuploaded", "Inscription", 109 } 110 111 func isExcluded(s string) bool { 112 for _, table := range exclutedTables { 113 if s == table { 114 return true 115 } 116 } 117 return false 118 } 119 120 func parse() { 121 baseLinkTables := parseBaseLocaleLinks() 122 123 t := token.NewFileSet() 124 f, err := parser.ParseFile(t, "rawdata/models.go", nil, parser.ParseComments) 125 if err != nil { 126 log.Fatal(err) 127 } 128 129 fAcces, err := os.Create("datamodel/acces_def.go") 130 if err != nil { 131 log.Fatal(err) 132 } 133 fmt.Fprintln(fAcces, ` 134 // DO NOT EDIT -- auto-generated from rawadata.go 135 package datamodel 136 137 import ( 138 rd "github.com/benoitkugler/goACVE/server/core/rawdata" 139 ) 140 `) 141 142 var mainItems, linkItems []string 143 for _, decl := range f.Decls { 144 stm, ok := decl.(*ast.GenDecl) 145 if !ok { 146 continue 147 } 148 for _, spec := range stm.Specs { 149 s, ok := spec.(*ast.TypeSpec) 150 if !ok { 151 continue 152 } 153 name := s.Name.String() 154 if isExcluded(name) { 155 continue 156 } 157 if isMainItem(name) { 158 genereCode(fAcces, name) 159 mainItems = append(mainItems, name) 160 } else { 161 linkItems = append(linkItems, name) 162 } 163 } 164 } 165 fLoadDB, err := os.Create("datamodel/ioload.go") 166 if err != nil { 167 log.Fatal(err) 168 } 169 genereCodeBase(fLoadDB, mainItems, linkItems, baseLinkTables) 170 if err = fLoadDB.Close(); err != nil { 171 log.Fatal(err) 172 } 173 174 fTest, err := os.Create("datamodel/ioload_test.go") 175 if err != nil { 176 log.Fatal(err) 177 } 178 genereTestCode(fTest, mainItems) 179 if err = fTest.Close(); err != nil { 180 log.Fatal(err) 181 } 182 183 _ = exec.Command("goreturns", "-w", "datamodel/ioload.go").Run() 184 _ = exec.Command("goreturns", "-w", "datamodel/ioload_test.go").Run() 185 _ = exec.Command("goreturns", "-w", "datamodel/acces_def.go").Run() 186 } 187 188 func parseBaseLocaleLinks() []string { 189 var out []string 190 t := token.NewFileSet() 191 f, err := parser.ParseFile(t, "rawdata/properties.go", nil, parser.ParseComments) 192 if err != nil { 193 log.Fatal(err) 194 } 195 for _, decl := range f.Decls { 196 stm, ok := decl.(*ast.GenDecl) 197 if !ok { 198 continue 199 } 200 for _, spec := range stm.Specs { 201 s, ok := spec.(*ast.TypeSpec) 202 if !ok { 203 continue 204 } 205 if s.Name.String() != "Links" { 206 continue 207 } 208 for _, field := range s.Type.(*ast.StructType).Fields.List { 209 out = append(out, field.Names[0].String()) 210 } 211 } 212 } 213 return out 214 } 215 216 func genereCode(buffer io.Writer, name string) { 217 args := templateArg{Name: name} 218 219 if err := templateAcces.Execute(buffer, args); err != nil { 220 log.Fatal(err) 221 } 222 } 223 224 func genereCodeBase(w io.Writer, mainItems, linkItems, baseLinks []string) { 225 fmt.Fprintln(w, ` 226 // DO NOT EDIT -- auto-generated from rawadata.go 227 package datamodel 228 229 import ( 230 rd "github.com/benoitkugler/goACVE/server/core/rawdata" 231 ) 232 233 // BaseLocale stocke en mémoire vive toutes les informations nécessaires, 234 // sous forme brute. 235 type BaseLocale struct { 236 `) 237 for _, item := range mainItems { 238 fmt.Fprintf(w, " %ss rd.%ss\n", item, item) 239 } 240 fmt.Fprintln(w, ` 241 242 rd.Links 243 }`) 244 fmt.Fprintln(w, ` 245 type RawLinks struct { 246 `) 247 for _, item := range linkItems { 248 fmt.Fprintf(w, " %ss rd.%ss\n", item, item) 249 } 250 251 fmt.Fprintln(w, "}") 252 253 // chargement total de la base locale 254 fmt.Fprintln(w, ` 255 func LoadRemoteBaseLocale(db rd.DB) (base *BaseLocale, err error) { 256 base = new(BaseLocale) 257 var rl RawLinks 258 `) 259 for _, item := range mainItems { 260 fmt.Fprintf(w, templateLoadBaseLocaleMain, item, item) 261 } 262 for _, item := range linkItems { 263 fmt.Fprintf(w, templateLoadBaseLocaleLink, item, item) 264 } 265 fmt.Fprintln(w, ` 266 base.ProcessRawLinks(rl) 267 268 return base, nil 269 }`) 270 271 // chargment partiel 272 fmt.Fprintln(w, ` 273 func LoadRemoteBaseLocalePartiel(db rd.DB, items map[string][]int64) (base *BaseLocale, err error) { 274 base = new(BaseLocale) 275 `) 276 for _, item := range mainItems { 277 fmt.Fprintf(w, templateLoadBaseLocalePartielMain, item, item, item) 278 } 279 fmt.Fprintln(w, ` 280 rl, err := loadLinksById(db, items) 281 if err != nil { 282 return nil, err 283 } 284 base.ProcessRawLinks(rl) 285 286 return base, nil 287 }`) 288 289 // function de Hash 290 fmt.Fprintln(w, ` 291 func (base BaseLocale) Hash() (BaseHash, error) { 292 baseHash := make(BaseHash) 293 var tmp map[int64]uint32 294 `) 295 for _, item := range mainItems { 296 fmt.Fprintf(w, templateHashTable, item+"s", item+"s", item+"s") 297 } 298 for _, item := range baseLinks { 299 fmt.Fprintf(w, templateHashTable, item, item, item) 300 } 301 fmt.Fprintln(w, ` 302 return baseHash, nil 303 }`) 304 305 // function de fusion 306 fmt.Fprintln(w, ` 307 func (base *BaseLocale) MergeFrom(incomming BaseLocale, toDelete map[string][]int64) { 308 `) 309 for _, item := range mainItems { 310 fmt.Fprintf(w, templateUpdateTable, item+"s", item+"s", item+"s", item+"s") 311 } 312 for _, item := range baseLinks { 313 fmt.Fprintf(w, templateUpdateTable, item, item, item, item) 314 } 315 fmt.Fprintln(w, ` 316 }`) 317 318 } 319 320 func genereTestCode(w io.Writer, mainItems []string) { 321 fmt.Fprintln(w, ` 322 package datamodel 323 324 // DONT EDIT - autogenerated 325 326 func compressMesureSize(data interface{}) (int, error) { 327 var b bytes.Buffer 328 gzOut := gzip.NewWriter(&b) 329 enc := json.NewEncoder(gzOut) 330 enc.SetEscapeHTML(false) 331 332 if err := enc.Encode(data); err != nil { 333 return 0, err 334 } 335 if err := gzOut.Close(); err != nil { 336 return 0, err 337 } 338 return len(b.Bytes()), nil 339 } 340 341 func TestSizes(t *testing.T) { 342 var ( 343 size int 344 err error 345 ) 346 base := GetBase(true) 347 348 `) 349 350 for _, item := range mainItems { 351 if err := templateTestMarshal.Execute(w, templateArg{Name: item}); err != nil { 352 log.Fatal(err) 353 } 354 } 355 356 // links 357 if err := templateTestMarshal.Execute(w, templateArg{Name: "Link"}); err != nil { 358 log.Fatal(err) 359 } 360 361 fmt.Fprintln(w, "}") 362 }