github.com/profzone/eden-framework@v1.0.10/pkg/sqlx/generator/utils.go (about)

     1  package generator
     2  
     3  import (
     4  	"fmt"
     5  	"go/types"
     6  	"reflect"
     7  	"regexp"
     8  	"strings"
     9  
    10  	"github.com/profzone/eden-framework/pkg/codegen"
    11  	"github.com/profzone/eden-framework/pkg/sqlx/builder"
    12  )
    13  
    14  var (
    15  	defRegexp = regexp.MustCompile(`@def ([^\n]+)`)
    16  	relRegexp = regexp.MustCompile(`@rel ([^\n]+)`)
    17  )
    18  
    19  type Keys struct {
    20  	Primary       []string
    21  	Indexes       builder.Indexes
    22  	UniqueIndexes builder.Indexes
    23  }
    24  
    25  func (ks *Keys) PatchUniqueIndexesWithSoftDelete(softDeleteField string) {
    26  	if len(ks.UniqueIndexes) > 0 {
    27  		for name, fieldNames := range ks.UniqueIndexes {
    28  			ks.UniqueIndexes[name] = stringUniq(append(fieldNames, softDeleteField))
    29  		}
    30  	}
    31  }
    32  
    33  func (ks *Keys) Bind(table *builder.Table) {
    34  	if len(ks.Primary) > 0 {
    35  		cols, err := table.Fields(ks.Primary...)
    36  		if err != nil {
    37  			panic(fmt.Errorf("%s, please check primary def", err))
    38  		}
    39  		ks.Primary = cols.FieldNames()
    40  		table.AddKey(builder.PrimaryKey(cols))
    41  	}
    42  
    43  	if len(ks.UniqueIndexes) > 0 {
    44  		for indexNameAndMethod, fieldNames := range ks.UniqueIndexes {
    45  			indexName, method := builder.ResolveIndexNameAndMethod(indexNameAndMethod)
    46  			cols, err := table.Fields(fieldNames...)
    47  			if err != nil {
    48  				panic(fmt.Errorf("%s, please check unique_index def", err))
    49  			}
    50  			ks.UniqueIndexes[indexNameAndMethod] = cols.FieldNames()
    51  			table.AddKey(builder.UniqueIndex(indexName, cols).Using(method))
    52  		}
    53  	}
    54  
    55  	if len(ks.Indexes) > 0 {
    56  		for indexNameAndMethod, fieldNames := range ks.Indexes {
    57  			indexName, method := builder.ResolveIndexNameAndMethod(indexNameAndMethod)
    58  			cols, err := table.Fields(fieldNames...)
    59  			if err != nil {
    60  				panic(fmt.Errorf("%s, please check index def", err))
    61  			}
    62  			ks.Indexes[indexNameAndMethod] = cols.FieldNames()
    63  			table.AddKey(builder.Index(indexName, cols).Using(method))
    64  		}
    65  	}
    66  }
    67  
    68  func parseColRelFromComment(doc string) (string, []string) {
    69  	others := make([]string, 0)
    70  
    71  	rel := ""
    72  
    73  	for _, line := range strings.Split(doc, "\n") {
    74  		if len(line) == 0 {
    75  			continue
    76  		}
    77  
    78  		matches := relRegexp.FindAllStringSubmatch(line, 1)
    79  
    80  		if matches == nil {
    81  			others = append(others, line)
    82  			continue
    83  		}
    84  
    85  		if len(matches) == 1 {
    86  			rel = matches[0][1]
    87  		}
    88  	}
    89  
    90  	return rel, others
    91  }
    92  
    93  func parseKeysFromDoc(doc string) (*Keys, []string) {
    94  	ks := &Keys{}
    95  
    96  	others := make([]string, 0)
    97  
    98  	for _, line := range strings.Split(doc, "\n") {
    99  		if len(line) == 0 {
   100  			continue
   101  		}
   102  
   103  		matches := defRegexp.FindAllStringSubmatch(line, -1)
   104  
   105  		if matches == nil {
   106  			others = append(others, line)
   107  			continue
   108  		}
   109  
   110  		for _, subMatch := range matches {
   111  			if len(subMatch) == 2 {
   112  				defs := defSplit(subMatch[1])
   113  
   114  				switch strings.ToLower(defs[0]) {
   115  				case "primary":
   116  					if len(defs) < 2 {
   117  						panic(fmt.Errorf("primary at lease 1 Field"))
   118  					}
   119  					ks.Primary = defs[1:]
   120  				case "unique_index":
   121  					if len(defs) < 3 {
   122  						panic(fmt.Errorf("unique indexes at lease 1 Field"))
   123  					}
   124  					if ks.UniqueIndexes == nil {
   125  						ks.UniqueIndexes = builder.Indexes{}
   126  					}
   127  					ks.UniqueIndexes[defs[1]] = defs[2:]
   128  				case "index":
   129  					if len(defs) < 3 {
   130  						panic(fmt.Errorf("index at lease 1 Field"))
   131  					}
   132  					if ks.Indexes == nil {
   133  						ks.Indexes = builder.Indexes{}
   134  					}
   135  					ks.Indexes[defs[1]] = defs[2:]
   136  				}
   137  			}
   138  		}
   139  	}
   140  
   141  	return ks, others
   142  }
   143  
   144  func defSplit(def string) (defs []string) {
   145  	vs := strings.Split(def, " ")
   146  	for _, s := range vs {
   147  		if s != "" {
   148  			defs = append(defs, s)
   149  		}
   150  	}
   151  	return
   152  }
   153  
   154  func toDefaultTableName(name string) string {
   155  	return codegen.LowerSnakeCase("t_" + name)
   156  }
   157  
   158  func forEachStructField(structType *types.Struct, fn func(fieldVar *types.Var, columnName string, tagValue string)) {
   159  	for i := 0; i < structType.NumFields(); i++ {
   160  		field := structType.Field(i)
   161  		tag := structType.Tag(i)
   162  		if field.Exported() {
   163  			structTag := reflect.StructTag(tag)
   164  			tagValue, exists := structTag.Lookup("db")
   165  			if exists {
   166  				if tagValue != "-" {
   167  					fn(field, builder.GetColumnName(field.Name(), tagValue), tagValue)
   168  				}
   169  			} else if field.Anonymous() {
   170  				if nextStructType, ok := field.Type().Underlying().(*types.Struct); ok {
   171  					forEachStructField(nextStructType, fn)
   172  				}
   173  				continue
   174  			}
   175  		}
   176  	}
   177  }
   178  
   179  func stringPartition(list []string, checker func(item string, i int) bool) ([]string, []string) {
   180  	newLeftList := make([]string, 0)
   181  	newRightList := make([]string, 0)
   182  	for i, item := range list {
   183  		if checker(item, i) {
   184  			newLeftList = append(newLeftList, item)
   185  		} else {
   186  			newRightList = append(newRightList, item)
   187  		}
   188  	}
   189  	return newLeftList, newRightList
   190  }
   191  
   192  func stringFilter(list []string, checker func(item string, i int) bool) []string {
   193  	newList, _ := stringPartition(list, checker)
   194  	return newList
   195  }
   196  
   197  func stringUniq(list []string) (result []string) {
   198  	strMap := make(map[string]bool)
   199  	for _, str := range list {
   200  		strMap[str] = true
   201  	}
   202  
   203  	for i := range list {
   204  		str := list[i]
   205  		if _, ok := strMap[str]; ok {
   206  			delete(strMap, str)
   207  			result = append(result, str)
   208  		}
   209  	}
   210  	return
   211  }