1// Copyright 2019 The Xorm Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package schemas
6
7import (
8	"errors"
9	"reflect"
10	"strconv"
11	"time"
12)
13
14// enumerates all database mapping way
15const (
16	TWOSIDES = iota + 1
17	ONLYTODB
18	ONLYFROMDB
19)
20
21// Column defines database column
22type Column struct {
23	Name            string
24	TableName       string
25	FieldName       string // Available only when parsed from a struct
26	FieldIndex      []int  // Available only when parsed from a struct
27	SQLType         SQLType
28	IsJSON          bool
29	Length          int
30	Length2         int
31	Nullable        bool
32	Default         string
33	Indexes         map[string]int
34	IsPrimaryKey    bool
35	IsAutoIncrement bool
36	MapType         int
37	IsCreated       bool
38	IsUpdated       bool
39	IsDeleted       bool
40	IsCascade       bool
41	IsVersion       bool
42	DefaultIsEmpty  bool // false means column has no default set, but not default value is empty
43	EnumOptions     map[string]int
44	SetOptions      map[string]int
45	DisableTimeZone bool
46	TimeZone        *time.Location // column specified time zone
47	Comment         string
48}
49
50// NewColumn creates a new column
51func NewColumn(name, fieldName string, sqlType SQLType, len1, len2 int, nullable bool) *Column {
52	return &Column{
53		Name:            name,
54		IsJSON:          sqlType.IsJson(),
55		TableName:       "",
56		FieldName:       fieldName,
57		SQLType:         sqlType,
58		Length:          len1,
59		Length2:         len2,
60		Nullable:        nullable,
61		Default:         "",
62		Indexes:         make(map[string]int),
63		IsPrimaryKey:    false,
64		IsAutoIncrement: false,
65		MapType:         TWOSIDES,
66		IsCreated:       false,
67		IsUpdated:       false,
68		IsDeleted:       false,
69		IsCascade:       false,
70		IsVersion:       false,
71		DefaultIsEmpty:  true, // default should be no default
72		EnumOptions:     make(map[string]int),
73		Comment:         "",
74	}
75}
76
77// ValueOf returns column's filed of struct's value
78func (col *Column) ValueOf(bean interface{}) (*reflect.Value, error) {
79	dataStruct := reflect.Indirect(reflect.ValueOf(bean))
80	return col.ValueOfV(&dataStruct)
81}
82
83// ValueOfV returns column's filed of struct's value accept reflevt value
84func (col *Column) ValueOfV(dataStruct *reflect.Value) (*reflect.Value, error) {
85	var v = *dataStruct
86	for _, i := range col.FieldIndex {
87		if v.Kind() == reflect.Ptr {
88			if v.IsNil() {
89				v.Set(reflect.New(v.Type().Elem()))
90			}
91			v = v.Elem()
92		}
93		v = v.FieldByIndex([]int{i})
94	}
95	return &v, nil
96}
97
98// ConvertID converts id content to suitable type according column type
99func (col *Column) ConvertID(sid string) (interface{}, error) {
100	if col.SQLType.IsNumeric() {
101		n, err := strconv.ParseInt(sid, 10, 64)
102		if err != nil {
103			return nil, err
104		}
105		return n, nil
106	} else if col.SQLType.IsText() {
107		return sid, nil
108	}
109	return nil, errors.New("not supported")
110}
111