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  }