summaryrefslogtreecommitdiff
path: root/vendor/github.com/uptrace/bun/schema/field.go
blob: 283a3b99250227b625b2fbc1a2cd214916dec99f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package schema

import (
	"fmt"
	"reflect"

	"github.com/uptrace/bun/dialect"
	"github.com/uptrace/bun/internal/tagparser"
)

type Field struct {
	StructField reflect.StructField
	IsPtr       bool

	Tag          tagparser.Tag
	IndirectType reflect.Type
	Index        []int

	Name    string // SQL name, .e.g. id
	SQLName Safe   // escaped SQL name, e.g. "id"
	GoName  string // struct field name, e.g. Id

	DiscoveredSQLType  string
	UserSQLType        string
	CreateTableSQLType string
	SQLDefault         string

	OnDelete string
	OnUpdate string

	IsPK          bool
	NotNull       bool
	NullZero      bool
	AutoIncrement bool
	Identity      bool

	Append AppenderFunc
	Scan   ScannerFunc
	IsZero IsZeroerFunc
}

func (f *Field) String() string {
	return f.Name
}

func (f *Field) Clone() *Field {
	cp := *f
	cp.Index = cp.Index[:len(f.Index):len(f.Index)]
	return &cp
}

func (f *Field) Value(strct reflect.Value) reflect.Value {
	return fieldByIndexAlloc(strct, f.Index)
}

func (f *Field) HasNilValue(v reflect.Value) bool {
	if len(f.Index) == 1 {
		return v.Field(f.Index[0]).IsNil()
	}

	for _, index := range f.Index {
		if v.Kind() == reflect.Ptr {
			if v.IsNil() {
				return true
			}
			v = v.Elem()
		}
		v = v.Field(index)
	}
	return v.IsNil()
}

func (f *Field) HasZeroValue(v reflect.Value) bool {
	if len(f.Index) == 1 {
		return f.IsZero(v.Field(f.Index[0]))
	}

	for _, index := range f.Index {
		if v.Kind() == reflect.Ptr {
			if v.IsNil() {
				return true
			}
			v = v.Elem()
		}
		v = v.Field(index)
	}
	return f.IsZero(v)
}

func (f *Field) AppendValue(fmter Formatter, b []byte, strct reflect.Value) []byte {
	fv, ok := fieldByIndex(strct, f.Index)
	if !ok {
		return dialect.AppendNull(b)
	}

	if (f.IsPtr && fv.IsNil()) || (f.NullZero && f.IsZero(fv)) {
		return dialect.AppendNull(b)
	}
	if f.Append == nil {
		panic(fmt.Errorf("bun: AppendValue(unsupported %s)", fv.Type()))
	}
	return f.Append(fmter, b, fv)
}

func (f *Field) ScanWithCheck(fv reflect.Value, src interface{}) error {
	if f.Scan == nil {
		return fmt.Errorf("bun: Scan(unsupported %s)", f.IndirectType)
	}
	return f.Scan(fv, src)
}

func (f *Field) ScanValue(strct reflect.Value, src interface{}) error {
	if src == nil {
		if fv, ok := fieldByIndex(strct, f.Index); ok {
			return f.ScanWithCheck(fv, src)
		}
		return nil
	}

	fv := fieldByIndexAlloc(strct, f.Index)
	return f.ScanWithCheck(fv, src)
}

func (f *Field) SkipUpdate() bool {
	return f.Tag.HasOption("skipupdate")
}

func indexEqual(ind1, ind2 []int) bool {
	if len(ind1) != len(ind2) {
		return false
	}
	for i, ind := range ind1 {
		if ind != ind2[i] {
			return false
		}
	}
	return true
}