github.com/unionj-cloud/go-doudou/v2@v2.3.5/toolkit/gormgen/internal/parser/method.go (about) 1 package parser 2 3 import ( 4 "fmt" 5 "go/ast" 6 "go/parser" 7 "go/token" 8 "io/ioutil" 9 "strings" 10 ) 11 12 func DefaultMethodTableName(structName string) *Method { 13 return &Method{ 14 Receiver: Param{IsPointer: true, Type: structName}, 15 MethodName: "TableName", 16 Doc: fmt.Sprint("TableName ", structName, "'s table name "), 17 Result: []Param{{Type: "string"}}, 18 Body: fmt.Sprintf("{\n\treturn TableName%s\n} ", structName), 19 } 20 } 21 22 // Method Apply to query struct and base struct custom method 23 type Method struct { 24 Receiver Param 25 MethodName string 26 Doc string 27 Params []Param 28 Result []Param 29 Body string 30 } 31 32 // FuncSign function signature 33 func (m Method) FuncSign() string { 34 return fmt.Sprintf("%s(%s) (%s)", m.MethodName, m.GetParamInTmpl(), m.GetResultParamInTmpl()) 35 } 36 37 // GetBaseStructTmpl return method bind info string 38 func (m *Method) GetBaseStructTmpl() string { 39 return m.Receiver.TmplString() 40 } 41 42 // GetParamInTmpl return param list 43 func (m *Method) GetParamInTmpl() string { 44 return paramToString(m.Params) 45 } 46 47 // GetResultParamInTmpl return result list 48 func (m *Method) GetResultParamInTmpl() string { 49 return paramToString(m.Result) 50 } 51 52 // paramToString param list to string used in tmpl 53 func paramToString(params []Param) string { 54 res := make([]string, len(params)) 55 for i, param := range params { 56 res[i] = param.TmplString() 57 } 58 return strings.Join(res, ",") 59 } 60 61 // DocComment return comment sql add "//" every line 62 func (m *Method) DocComment() string { 63 return strings.Replace(strings.TrimSpace(m.Doc), "\n", "\n//", -1) 64 } 65 66 // DIYMethods user Custom methods bind to db base struct 67 type DIYMethods struct { 68 BaseStructType string 69 MethodName string 70 pkgPath string 71 currentFile string 72 pkgFiles []string 73 Methods []*Method 74 } 75 76 func (m *DIYMethods) parserPath(path string) error { 77 pathList := strings.Split(path, ".") 78 if len(pathList) < 3 { 79 return fmt.Errorf("parser diy method error") 80 } 81 82 m.pkgPath = strings.Join(pathList[:len(pathList)-2], ".") 83 methodName := pathList[len(pathList)-1] 84 m.MethodName = methodName[:len(methodName)-3] 85 86 structName := pathList[len(pathList)-2] 87 m.BaseStructType = strings.Trim(structName, "()*") 88 return nil 89 } 90 91 // Visit ast visit function 92 func (m *DIYMethods) Visit(n ast.Node) (w ast.Visitor) { 93 switch t := n.(type) { 94 case *ast.FuncDecl: 95 // check base struct and method name is expect 96 structMeta := getParamList(t.Recv) 97 if len(structMeta) != 1 { 98 return 99 } 100 if structMeta[0].Type != m.BaseStructType { 101 return 102 } 103 // if m.MethodName is null will generate all methods 104 if m.MethodName != "" && m.MethodName != t.Name.Name { 105 return 106 } 107 108 // use ast read bind start package is UNDEFINED ,set it null string 109 structMeta[0].Package = "" 110 m.Methods = append(m.Methods, &Method{ 111 Receiver: structMeta[0], 112 MethodName: t.Name.String(), 113 Doc: t.Doc.Text(), 114 Body: getBody(m.currentFile, int(t.Body.Pos()), int(t.Body.End())), 115 Params: getParamList(t.Type.Params), 116 Result: getParamList(t.Type.Results), 117 }) 118 } 119 120 return m 121 } 122 123 // read old file get method body 124 func getBody(fileName string, start, end int) string { 125 f1, err := ioutil.ReadFile(fileName) 126 if err != nil { 127 return "{}" 128 } 129 130 return string(f1[start-1 : end-1]) 131 } 132 133 // LoadMethods ast read file get diy method 134 func (m *DIYMethods) LoadMethods() error { 135 for _, filename := range m.pkgFiles { 136 f, err := parser.ParseFile(token.NewFileSet(), filename, nil, parser.ParseComments) 137 if err != nil { 138 return fmt.Errorf("can't parse file %q: %s", filename, err) 139 } 140 m.currentFile = filename 141 ast.Walk(m, f) 142 } 143 144 return nil 145 }