...

Source file src/github.com/doug-martin/goqu/v9/internal/util/column_map.go

Documentation: github.com/doug-martin/goqu/v9/internal/util

     1  package util
     2  
     3  import (
     4  	"reflect"
     5  	"sort"
     6  	"strings"
     7  
     8  	"github.com/doug-martin/goqu/v9/internal/tag"
     9  )
    10  
    11  type (
    12  	ColumnData struct {
    13  		ColumnName     string
    14  		FieldIndex     []int
    15  		ShouldInsert   bool
    16  		ShouldUpdate   bool
    17  		DefaultIfEmpty bool
    18  		GoType         reflect.Type
    19  	}
    20  	ColumnMap map[string]ColumnData
    21  )
    22  
    23  func newColumnMap(t reflect.Type, fieldIndex []int, prefixes []string) ColumnMap {
    24  	cm, n := ColumnMap{}, t.NumField()
    25  	var subColMaps []ColumnMap
    26  	for i := 0; i < n; i++ {
    27  		f := t.Field(i)
    28  		if f.Anonymous && (f.Type.Kind() == reflect.Struct || f.Type.Kind() == reflect.Ptr) {
    29  			goquTag := tag.New("db", f.Tag)
    30  			if !goquTag.Contains("-") {
    31  				subColMaps = append(subColMaps, getStructColumnMap(&f, fieldIndex, goquTag.Values(), prefixes))
    32  			}
    33  		} else if f.PkgPath == "" {
    34  			dbTag := tag.New("db", f.Tag)
    35  			// if PkgPath is empty then it is an exported field
    36  			columnName := getColumnName(&f, dbTag)
    37  			if !shouldIgnoreField(dbTag) {
    38  				if !implementsScanner(f.Type) {
    39  					subCm := getStructColumnMap(&f, fieldIndex, []string{columnName}, prefixes)
    40  					if len(subCm) != 0 {
    41  						subColMaps = append(subColMaps, subCm)
    42  						continue
    43  					}
    44  				}
    45  				goquTag := tag.New("goqu", f.Tag)
    46  				columnName = strings.Join(append(prefixes, columnName), ".")
    47  				cm[columnName] = newColumnData(&f, columnName, fieldIndex, goquTag)
    48  			}
    49  		}
    50  	}
    51  	return cm.Merge(subColMaps)
    52  }
    53  
    54  func (cm ColumnMap) Cols() []string {
    55  	structCols := make([]string, 0, len(cm))
    56  	for key := range cm {
    57  		structCols = append(structCols, key)
    58  	}
    59  	sort.Strings(structCols)
    60  	return structCols
    61  }
    62  
    63  func (cm ColumnMap) Merge(colMaps []ColumnMap) ColumnMap {
    64  	for _, subCm := range colMaps {
    65  		for key, val := range subCm {
    66  			if _, ok := cm[key]; !ok {
    67  				cm[key] = val
    68  			}
    69  		}
    70  	}
    71  	return cm
    72  }
    73  
    74  func implementsScanner(t reflect.Type) bool {
    75  	if IsPointer(t.Kind()) {
    76  		t = t.Elem()
    77  	}
    78  	if reflect.PtrTo(t).Implements(scannerType) {
    79  		return true
    80  	}
    81  	if !IsStruct(t.Kind()) {
    82  		return true
    83  	}
    84  
    85  	return false
    86  }
    87  
    88  func newColumnData(f *reflect.StructField, columnName string, fieldIndex []int, goquTag tag.Options) ColumnData {
    89  	return ColumnData{
    90  		ColumnName:     columnName,
    91  		ShouldInsert:   !goquTag.Contains(skipInsertTagName),
    92  		ShouldUpdate:   !goquTag.Contains(skipUpdateTagName),
    93  		DefaultIfEmpty: goquTag.Contains(defaultIfEmptyTagName),
    94  		FieldIndex:     concatFieldIndexes(fieldIndex, f.Index),
    95  		GoType:         f.Type,
    96  	}
    97  }
    98  
    99  func getStructColumnMap(f *reflect.StructField, fieldIndex []int, fieldNames, prefixes []string) ColumnMap {
   100  	subFieldIndexes := concatFieldIndexes(fieldIndex, f.Index)
   101  	subPrefixes := append(prefixes, fieldNames...)
   102  	if f.Type.Kind() == reflect.Ptr {
   103  		return newColumnMap(f.Type.Elem(), subFieldIndexes, subPrefixes)
   104  	}
   105  	return newColumnMap(f.Type, subFieldIndexes, subPrefixes)
   106  }
   107  
   108  func getColumnName(f *reflect.StructField, dbTag tag.Options) string {
   109  	if dbTag.IsEmpty() {
   110  		return columnRenameFunction(f.Name)
   111  	}
   112  	return dbTag.Values()[0]
   113  }
   114  
   115  func shouldIgnoreField(dbTag tag.Options) bool {
   116  	if dbTag.Equals("-") {
   117  		return true
   118  	} else if dbTag.IsEmpty() && ignoreUntaggedFields {
   119  		return true
   120  	}
   121  
   122  	return false
   123  }
   124  
   125  // safely concat two fieldIndex slices into one.
   126  func concatFieldIndexes(fieldIndexPath, fieldIndex []int) []int {
   127  	fieldIndexes := make([]int, 0, len(fieldIndexPath)+len(fieldIndex))
   128  	fieldIndexes = append(fieldIndexes, fieldIndexPath...)
   129  	return append(fieldIndexes, fieldIndex...)
   130  }
   131  

View as plain text