214 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			214 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package schema
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"fmt"
 | |
| 	"reflect"
 | |
| 	"regexp"
 | |
| 	"strings"
 | |
| 
 | |
| 	"gorm.io/gorm/clause"
 | |
| 	"gorm.io/gorm/utils"
 | |
| )
 | |
| 
 | |
| var embeddedCacheKey = "embedded_cache_store"
 | |
| 
 | |
| func ParseTagSetting(str string, sep string) map[string]string {
 | |
| 	settings := map[string]string{}
 | |
| 	names := strings.Split(str, sep)
 | |
| 
 | |
| 	for i := 0; i < len(names); i++ {
 | |
| 		j := i
 | |
| 		if len(names[j]) > 0 {
 | |
| 			for {
 | |
| 				if names[j][len(names[j])-1] == '\\' {
 | |
| 					i++
 | |
| 					names[j] = names[j][0:len(names[j])-1] + sep + names[i]
 | |
| 					names[i] = ""
 | |
| 				} else {
 | |
| 					break
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		values := strings.Split(names[j], ":")
 | |
| 		k := strings.TrimSpace(strings.ToUpper(values[0]))
 | |
| 
 | |
| 		if len(values) >= 2 {
 | |
| 			settings[k] = strings.Join(values[1:], ":")
 | |
| 		} else if k != "" {
 | |
| 			settings[k] = k
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return settings
 | |
| }
 | |
| 
 | |
| func toColumns(val string) (results []string) {
 | |
| 	if val != "" {
 | |
| 		for _, v := range strings.Split(val, ",") {
 | |
| 			results = append(results, strings.TrimSpace(v))
 | |
| 		}
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func removeSettingFromTag(tag reflect.StructTag, names ...string) reflect.StructTag {
 | |
| 	for _, name := range names {
 | |
| 		tag = reflect.StructTag(regexp.MustCompile(`(?i)(gorm:.*?)(`+name+`(:.*?)?)(;|("))`).ReplaceAllString(string(tag), "${1}${5}"))
 | |
| 	}
 | |
| 	return tag
 | |
| }
 | |
| 
 | |
| func appendSettingFromTag(tag reflect.StructTag, value string) reflect.StructTag {
 | |
| 	t := tag.Get("gorm")
 | |
| 	if strings.Contains(t, value) {
 | |
| 		return tag
 | |
| 	}
 | |
| 	return reflect.StructTag(fmt.Sprintf(`gorm:"%s;%s"`, value, t))
 | |
| }
 | |
| 
 | |
| // GetRelationsValues get relations's values from a reflect value
 | |
| func GetRelationsValues(ctx context.Context, reflectValue reflect.Value, rels []*Relationship) (reflectResults reflect.Value) {
 | |
| 	for _, rel := range rels {
 | |
| 		reflectResults = reflect.MakeSlice(reflect.SliceOf(reflect.PtrTo(rel.FieldSchema.ModelType)), 0, 1)
 | |
| 
 | |
| 		appendToResults := func(value reflect.Value) {
 | |
| 			if _, isZero := rel.Field.ValueOf(ctx, value); !isZero {
 | |
| 				result := reflect.Indirect(rel.Field.ReflectValueOf(ctx, value))
 | |
| 				switch result.Kind() {
 | |
| 				case reflect.Struct:
 | |
| 					reflectResults = reflect.Append(reflectResults, result.Addr())
 | |
| 				case reflect.Slice, reflect.Array:
 | |
| 					for i := 0; i < result.Len(); i++ {
 | |
| 						if elem := result.Index(i); elem.Kind() == reflect.Ptr {
 | |
| 							reflectResults = reflect.Append(reflectResults, elem)
 | |
| 						} else {
 | |
| 							reflectResults = reflect.Append(reflectResults, elem.Addr())
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		switch reflectValue.Kind() {
 | |
| 		case reflect.Struct:
 | |
| 			appendToResults(reflectValue)
 | |
| 		case reflect.Slice:
 | |
| 			for i := 0; i < reflectValue.Len(); i++ {
 | |
| 				appendToResults(reflectValue.Index(i))
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		reflectValue = reflectResults
 | |
| 	}
 | |
| 
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // GetIdentityFieldValuesMap get identity map from fields
 | |
| func GetIdentityFieldValuesMap(ctx context.Context, reflectValue reflect.Value, fields []*Field) (map[string][]reflect.Value, [][]interface{}) {
 | |
| 	var (
 | |
| 		results       = [][]interface{}{}
 | |
| 		dataResults   = map[string][]reflect.Value{}
 | |
| 		loaded        = map[interface{}]bool{}
 | |
| 		notZero, zero bool
 | |
| 	)
 | |
| 
 | |
| 	if reflectValue.Kind() == reflect.Ptr ||
 | |
| 		reflectValue.Kind() == reflect.Interface {
 | |
| 		reflectValue = reflectValue.Elem()
 | |
| 	}
 | |
| 
 | |
| 	switch reflectValue.Kind() {
 | |
| 	case reflect.Struct:
 | |
| 		results = [][]interface{}{make([]interface{}, len(fields))}
 | |
| 
 | |
| 		for idx, field := range fields {
 | |
| 			results[0][idx], zero = field.ValueOf(ctx, reflectValue)
 | |
| 			notZero = notZero || !zero
 | |
| 		}
 | |
| 
 | |
| 		if !notZero {
 | |
| 			return nil, nil
 | |
| 		}
 | |
| 
 | |
| 		dataResults[utils.ToStringKey(results[0]...)] = []reflect.Value{reflectValue}
 | |
| 	case reflect.Slice, reflect.Array:
 | |
| 		for i := 0; i < reflectValue.Len(); i++ {
 | |
| 			elem := reflectValue.Index(i)
 | |
| 			elemKey := elem.Interface()
 | |
| 			if elem.Kind() != reflect.Ptr && elem.CanAddr() {
 | |
| 				elemKey = elem.Addr().Interface()
 | |
| 			}
 | |
| 
 | |
| 			if _, ok := loaded[elemKey]; ok {
 | |
| 				continue
 | |
| 			}
 | |
| 			loaded[elemKey] = true
 | |
| 
 | |
| 			fieldValues := make([]interface{}, len(fields))
 | |
| 			notZero = false
 | |
| 			for idx, field := range fields {
 | |
| 				fieldValues[idx], zero = field.ValueOf(ctx, elem)
 | |
| 				notZero = notZero || !zero
 | |
| 			}
 | |
| 
 | |
| 			if notZero {
 | |
| 				dataKey := utils.ToStringKey(fieldValues...)
 | |
| 				if _, ok := dataResults[dataKey]; !ok {
 | |
| 					results = append(results, fieldValues)
 | |
| 					dataResults[dataKey] = []reflect.Value{elem}
 | |
| 				} else {
 | |
| 					dataResults[dataKey] = append(dataResults[dataKey], elem)
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return dataResults, results
 | |
| }
 | |
| 
 | |
| // GetIdentityFieldValuesMapFromValues get identity map from fields
 | |
| func GetIdentityFieldValuesMapFromValues(ctx context.Context, values []interface{}, fields []*Field) (map[string][]reflect.Value, [][]interface{}) {
 | |
| 	resultsMap := map[string][]reflect.Value{}
 | |
| 	results := [][]interface{}{}
 | |
| 
 | |
| 	for _, v := range values {
 | |
| 		rm, rs := GetIdentityFieldValuesMap(ctx, reflect.Indirect(reflect.ValueOf(v)), fields)
 | |
| 		for k, v := range rm {
 | |
| 			resultsMap[k] = append(resultsMap[k], v...)
 | |
| 		}
 | |
| 		results = append(results, rs...)
 | |
| 	}
 | |
| 	return resultsMap, results
 | |
| }
 | |
| 
 | |
| // ToQueryValues to query values
 | |
| func ToQueryValues(table string, foreignKeys []string, foreignValues [][]interface{}) (interface{}, []interface{}) {
 | |
| 	queryValues := make([]interface{}, len(foreignValues))
 | |
| 	if len(foreignKeys) == 1 {
 | |
| 		for idx, r := range foreignValues {
 | |
| 			queryValues[idx] = r[0]
 | |
| 		}
 | |
| 
 | |
| 		return clause.Column{Table: table, Name: foreignKeys[0]}, queryValues
 | |
| 	}
 | |
| 
 | |
| 	columns := make([]clause.Column, len(foreignKeys))
 | |
| 	for idx, key := range foreignKeys {
 | |
| 		columns[idx] = clause.Column{Table: table, Name: key}
 | |
| 	}
 | |
| 
 | |
| 	for idx, r := range foreignValues {
 | |
| 		queryValues[idx] = r
 | |
| 	}
 | |
| 
 | |
| 	return columns, queryValues
 | |
| }
 | |
| 
 | |
| type embeddedNamer struct {
 | |
| 	Table string
 | |
| 	Namer
 | |
| }
 |