OSDN Git Service

feat: init cross_tx keepers (#146)
[bytom/vapor.git] / vendor / github.com / jinzhu / gorm / dialect.go
1 package gorm
2
3 import (
4         "database/sql"
5         "fmt"
6         "reflect"
7         "strconv"
8         "strings"
9 )
10
11 // Dialect interface contains behaviors that differ across SQL database
12 type Dialect interface {
13         // GetName get dialect's name
14         GetName() string
15
16         // SetDB set db for dialect
17         SetDB(db SQLCommon)
18
19         // BindVar return the placeholder for actual values in SQL statements, in many dbs it is "?", Postgres using $1
20         BindVar(i int) string
21         // Quote quotes field name to avoid SQL parsing exceptions by using a reserved word as a field name
22         Quote(key string) string
23         // DataTypeOf return data's sql type
24         DataTypeOf(field *StructField) string
25
26         // HasIndex check has index or not
27         HasIndex(tableName string, indexName string) bool
28         // HasForeignKey check has foreign key or not
29         HasForeignKey(tableName string, foreignKeyName string) bool
30         // RemoveIndex remove index
31         RemoveIndex(tableName string, indexName string) error
32         // HasTable check has table or not
33         HasTable(tableName string) bool
34         // HasColumn check has column or not
35         HasColumn(tableName string, columnName string) bool
36         // ModifyColumn modify column's type
37         ModifyColumn(tableName string, columnName string, typ string) error
38
39         // LimitAndOffsetSQL return generated SQL with Limit and Offset, as mssql has special case
40         LimitAndOffsetSQL(limit, offset interface{}) string
41         // SelectFromDummyTable return select values, for most dbs, `SELECT values` just works, mysql needs `SELECT value FROM DUAL`
42         SelectFromDummyTable() string
43         // LastInsertIdReturningSuffix most dbs support LastInsertId, but postgres needs to use `RETURNING`
44         LastInsertIDReturningSuffix(tableName, columnName string) string
45         // DefaultValueStr
46         DefaultValueStr() string
47
48         // BuildKeyName returns a valid key name (foreign key, index key) for the given table, field and reference
49         BuildKeyName(kind, tableName string, fields ...string) string
50
51         // CurrentDatabase return current database name
52         CurrentDatabase() string
53 }
54
55 var dialectsMap = map[string]Dialect{}
56
57 func newDialect(name string, db SQLCommon) Dialect {
58         if value, ok := dialectsMap[name]; ok {
59                 dialect := reflect.New(reflect.TypeOf(value).Elem()).Interface().(Dialect)
60                 dialect.SetDB(db)
61                 return dialect
62         }
63
64         fmt.Printf("`%v` is not officially supported, running under compatibility mode.\n", name)
65         commontDialect := &commonDialect{}
66         commontDialect.SetDB(db)
67         return commontDialect
68 }
69
70 // RegisterDialect register new dialect
71 func RegisterDialect(name string, dialect Dialect) {
72         dialectsMap[name] = dialect
73 }
74
75 // GetDialect gets the dialect for the specified dialect name
76 func GetDialect(name string) (dialect Dialect, ok bool) {
77         dialect, ok = dialectsMap[name]
78         return
79 }
80
81 // ParseFieldStructForDialect get field's sql data type
82 var ParseFieldStructForDialect = func(field *StructField, dialect Dialect) (fieldValue reflect.Value, sqlType string, size int, additionalType string) {
83         // Get redirected field type
84         var (
85                 reflectType = field.Struct.Type
86                 dataType, _ = field.TagSettingsGet("TYPE")
87         )
88
89         for reflectType.Kind() == reflect.Ptr {
90                 reflectType = reflectType.Elem()
91         }
92
93         // Get redirected field value
94         fieldValue = reflect.Indirect(reflect.New(reflectType))
95
96         if gormDataType, ok := fieldValue.Interface().(interface {
97                 GormDataType(Dialect) string
98         }); ok {
99                 dataType = gormDataType.GormDataType(dialect)
100         }
101
102         // Get scanner's real value
103         if dataType == "" {
104                 var getScannerValue func(reflect.Value)
105                 getScannerValue = func(value reflect.Value) {
106                         fieldValue = value
107                         if _, isScanner := reflect.New(fieldValue.Type()).Interface().(sql.Scanner); isScanner && fieldValue.Kind() == reflect.Struct {
108                                 getScannerValue(fieldValue.Field(0))
109                         }
110                 }
111                 getScannerValue(fieldValue)
112         }
113
114         // Default Size
115         if num, ok := field.TagSettingsGet("SIZE"); ok {
116                 size, _ = strconv.Atoi(num)
117         } else {
118                 size = 255
119         }
120
121         // Default type from tag setting
122         notNull, _ := field.TagSettingsGet("NOT NULL")
123         unique, _ := field.TagSettingsGet("UNIQUE")
124         additionalType = notNull + " " + unique
125         if value, ok := field.TagSettingsGet("DEFAULT"); ok {
126                 additionalType = additionalType + " DEFAULT " + value
127         }
128
129         return fieldValue, dataType, size, strings.TrimSpace(additionalType)
130 }
131
132 func currentDatabaseAndTable(dialect Dialect, tableName string) (string, string) {
133         if strings.Contains(tableName, ".") {
134                 splitStrings := strings.SplitN(tableName, ".", 2)
135                 return splitStrings[0], splitStrings[1]
136         }
137         return dialect.CurrentDatabase(), tableName
138 }