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  }