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
 | 
						|
}
 |