// Copyright 2019 The Xorm Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package core import ( "fmt" "reflect" "strings" "time" ) const ( TWOSIDES = iota + 1 ONLYTODB ONLYFROMDB ) // Column defines database column type Column struct { Name string TableName string FieldName string SQLType SQLType IsJSON bool Length int Length2 int Nullable bool Default string Indexes map[string]int IsPrimaryKey bool IsAutoIncrement bool MapType int IsCreated bool IsUpdated bool IsDeleted bool IsCascade bool IsVersion bool DefaultIsEmpty bool EnumOptions map[string]int SetOptions map[string]int DisableTimeZone bool TimeZone *time.Location // column specified time zone Comment string } // NewColumn creates a new column func NewColumn(name, fieldName string, sqlType SQLType, len1, len2 int, nullable bool) *Column { return &Column{ Name: name, TableName: "", FieldName: fieldName, SQLType: sqlType, Length: len1, Length2: len2, Nullable: nullable, Default: "", Indexes: make(map[string]int), IsPrimaryKey: false, IsAutoIncrement: false, MapType: TWOSIDES, IsCreated: false, IsUpdated: false, IsDeleted: false, IsCascade: false, IsVersion: false, DefaultIsEmpty: false, EnumOptions: make(map[string]int), Comment: "", } } // String generate column description string according dialect func (col *Column) String(d Dialect) string { sql := d.Quote(col.Name) + " " sql += d.SqlType(col) + " " if col.IsPrimaryKey { sql += "PRIMARY KEY " if col.IsAutoIncrement { sql += d.AutoIncrStr() + " " } } if col.Default != "" { sql += "DEFAULT " + col.Default + " " } if d.ShowCreateNull() { if col.Nullable { sql += "NULL " } else { sql += "NOT NULL " } } return sql } // StringNoPk generate column description string according dialect without primary keys func (col *Column) StringNoPk(d Dialect) string { sql := d.Quote(col.Name) + " " sql += d.SqlType(col) + " " if col.Default != "" { sql += "DEFAULT " + col.Default + " " } if d.ShowCreateNull() { if col.Nullable { sql += "NULL " } else { sql += "NOT NULL " } } return sql } // ValueOf returns column's filed of struct's value func (col *Column) ValueOf(bean interface{}) (*reflect.Value, error) { dataStruct := reflect.Indirect(reflect.ValueOf(bean)) return col.ValueOfV(&dataStruct) } // ValueOfV returns column's filed of struct's value accept reflevt value func (col *Column) ValueOfV(dataStruct *reflect.Value) (*reflect.Value, error) { var fieldValue reflect.Value fieldPath := strings.Split(col.FieldName, ".") if dataStruct.Type().Kind() == reflect.Map { keyValue := reflect.ValueOf(fieldPath[len(fieldPath)-1]) fieldValue = dataStruct.MapIndex(keyValue) return &fieldValue, nil } else if dataStruct.Type().Kind() == reflect.Interface { structValue := reflect.ValueOf(dataStruct.Interface()) dataStruct = &structValue } level := len(fieldPath) fieldValue = dataStruct.FieldByName(fieldPath[0]) for i := 0; i < level-1; i++ { if !fieldValue.IsValid() { break } if fieldValue.Kind() == reflect.Struct { fieldValue = fieldValue.FieldByName(fieldPath[i+1]) } else if fieldValue.Kind() == reflect.Ptr { if fieldValue.IsNil() { fieldValue.Set(reflect.New(fieldValue.Type().Elem())) } fieldValue = fieldValue.Elem().FieldByName(fieldPath[i+1]) } else { return nil, fmt.Errorf("field %v is not valid", col.FieldName) } } if !fieldValue.IsValid() { return nil, fmt.Errorf("field %v is not valid", col.FieldName) } return &fieldValue, nil }