You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
116 lines
3.6 KiB
116 lines
3.6 KiB
package gorm |
|
|
|
import ( |
|
"database/sql" |
|
"fmt" |
|
"reflect" |
|
"strconv" |
|
"strings" |
|
) |
|
|
|
// Dialect interface contains behaviors that differ across SQL database |
|
type Dialect interface { |
|
// GetName get dialect's name |
|
GetName() string |
|
|
|
// SetDB set db for dialect |
|
SetDB(db SQLCommon) |
|
|
|
// BindVar return the placeholder for actual values in SQL statements, in many dbs it is "?", Postgres using $1 |
|
BindVar(i int) string |
|
// Quote quotes field name to avoid SQL parsing exceptions by using a reserved word as a field name |
|
Quote(key string) string |
|
// DataTypeOf return data's sql type |
|
DataTypeOf(field *StructField) string |
|
|
|
// HasIndex check has index or not |
|
HasIndex(tableName string, indexName string) bool |
|
// HasForeignKey check has foreign key or not |
|
HasForeignKey(tableName string, foreignKeyName string) bool |
|
// RemoveIndex remove index |
|
RemoveIndex(tableName string, indexName string) error |
|
// HasTable check has table or not |
|
HasTable(tableName string) bool |
|
// HasColumn check has column or not |
|
HasColumn(tableName string, columnName string) bool |
|
|
|
// LimitAndOffsetSQL return generated SQL with Limit and Offset, as mssql has special case |
|
LimitAndOffsetSQL(limit, offset interface{}) string |
|
// SelectFromDummyTable return select values, for most dbs, `SELECT values` just works, mysql needs `SELECT value FROM DUAL` |
|
SelectFromDummyTable() string |
|
// LastInsertIdReturningSuffix most dbs support LastInsertId, but postgres needs to use `RETURNING` |
|
LastInsertIDReturningSuffix(tableName, columnName string) string |
|
|
|
// BuildForeignKeyName returns a foreign key name for the given table, field and reference |
|
BuildForeignKeyName(tableName, field, dest string) string |
|
|
|
// CurrentDatabase return current database name |
|
CurrentDatabase() string |
|
} |
|
|
|
var dialectsMap = map[string]Dialect{} |
|
|
|
func newDialect(name string, db SQLCommon) Dialect { |
|
if value, ok := dialectsMap[name]; ok { |
|
dialect := reflect.New(reflect.TypeOf(value).Elem()).Interface().(Dialect) |
|
dialect.SetDB(db) |
|
return dialect |
|
} |
|
|
|
fmt.Printf("`%v` is not officially supported, running under compatibility mode.\n", name) |
|
commontDialect := &commonDialect{} |
|
commontDialect.SetDB(db) |
|
return commontDialect |
|
} |
|
|
|
// RegisterDialect register new dialect |
|
func RegisterDialect(name string, dialect Dialect) { |
|
dialectsMap[name] = dialect |
|
} |
|
|
|
// ParseFieldStructForDialect get field's sql data type |
|
var ParseFieldStructForDialect = func(field *StructField, dialect Dialect) (fieldValue reflect.Value, sqlType string, size int, additionalType string) { |
|
// Get redirected field type |
|
var ( |
|
reflectType = field.Struct.Type |
|
dataType = field.TagSettings["TYPE"] |
|
) |
|
|
|
for reflectType.Kind() == reflect.Ptr { |
|
reflectType = reflectType.Elem() |
|
} |
|
|
|
// Get redirected field value |
|
fieldValue = reflect.Indirect(reflect.New(reflectType)) |
|
|
|
if gormDataType, ok := fieldValue.Interface().(interface { |
|
GormDataType(Dialect) string |
|
}); ok { |
|
dataType = gormDataType.GormDataType(dialect) |
|
} |
|
|
|
// Get scanner's real value |
|
var getScannerValue func(reflect.Value) |
|
getScannerValue = func(value reflect.Value) { |
|
fieldValue = value |
|
if _, isScanner := reflect.New(fieldValue.Type()).Interface().(sql.Scanner); isScanner && fieldValue.Kind() == reflect.Struct { |
|
getScannerValue(fieldValue.Field(0)) |
|
} |
|
} |
|
getScannerValue(fieldValue) |
|
|
|
// Default Size |
|
if num, ok := field.TagSettings["SIZE"]; ok { |
|
size, _ = strconv.Atoi(num) |
|
} else { |
|
size = 255 |
|
} |
|
|
|
// Default type from tag setting |
|
additionalType = field.TagSettings["NOT NULL"] + " " + field.TagSettings["UNIQUE"] |
|
if value, ok := field.TagSettings["DEFAULT"]; ok { |
|
additionalType = additionalType + " DEFAULT " + value |
|
} |
|
|
|
return fieldValue, dataType, size, strings.TrimSpace(additionalType) |
|
}
|
|
|