Merge pull request #436 from jaytaylor/master

FoundationDB dialect integration
This commit is contained in:
Jinzhu 2015-03-30 14:55:50 +08:00
commit 03966a1e20
8 changed files with 110 additions and 12 deletions

View File

@ -96,6 +96,7 @@ import (
) )
db, err := gorm.Open("postgres", "user=gorm dbname=gorm sslmode=disable") db, err := gorm.Open("postgres", "user=gorm dbname=gorm sslmode=disable")
// db, err := gorm.Open("foundation", "dbname=gorm") // FoundationDB.
// db, err := gorm.Open("mysql", "user:password@/dbname?charset=utf8&parseTime=True&loc=Local") // db, err := gorm.Open("mysql", "user:password@/dbname?charset=utf8&parseTime=True&loc=Local")
// db, err := gorm.Open("sqlite3", "/tmp/gorm.db") // db, err := gorm.Open("sqlite3", "/tmp/gorm.db")

View File

@ -24,6 +24,8 @@ func NewDialect(driver string) Dialect {
switch driver { switch driver {
case "postgres": case "postgres":
d = &postgres{} d = &postgres{}
case "foundation":
d = &foundation{}
case "mysql": case "mysql":
d = &mysql{} d = &mysql{}
case "sqlite3": case "sqlite3":

78
foundation.go Normal file
View File

@ -0,0 +1,78 @@
package gorm
import (
"fmt"
"reflect"
"time"
)
type foundation struct {
commonDialect
}
func (foundation) BinVar(i int) string {
return fmt.Sprintf("$%v", i)
}
func (foundation) SupportLastInsertId() bool {
return false
}
func (foundation) SqlTag(value reflect.Value, size int, autoIncrease bool) string {
switch value.Kind() {
case reflect.Bool:
return "boolean"
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
if autoIncrease {
return "serial"
}
return "int"
case reflect.Int64, reflect.Uint64:
if autoIncrease {
return "bigserial"
}
return "bigint"
case reflect.Float32, reflect.Float64:
return "double"
case reflect.String:
if size > 0 && size < 65532 {
return fmt.Sprintf("varchar(%d)", size)
}
return "clob"
case reflect.Struct:
if _, ok := value.Interface().(time.Time); ok {
return "datetime"
}
default:
if _, ok := value.Interface().([]byte); ok {
return "blob"
}
}
panic(fmt.Sprintf("invalid sql type %s (%s) for foundation", value.Type().Name(), value.Kind().String()))
}
func (f foundation) ReturningStr(tableName, key string) string {
return fmt.Sprintf("RETURNING %v.%v", f.Quote(tableName), key)
}
func (foundation) HasTable(scope *Scope, tableName string) bool {
var count int
scope.NewDB().Raw("SELECT count(*) FROM INFORMATION_SCHEMA.tables WHERE table_schema = current_schema AND table_type = 'TABLE' AND table_name = ?", tableName).Row().Scan(&count)
return count > 0
}
func (foundation) HasColumn(scope *Scope, tableName string, columnName string) bool {
var count int
scope.NewDB().Raw("SELECT count(*) FROM INFORMATION_SCHEMA.columns WHERE table_schema = current_schema AND table_name = ? AND column_name = ?", tableName, columnName).Row().Scan(&count)
return count > 0
}
func (f foundation) RemoveIndex(scope *Scope, indexName string) {
scope.NewDB().Exec(fmt.Sprintf("DROP INDEX %v", f.Quote(indexName)))
}
func (foundation) HasIndex(scope *Scope, tableName string, indexName string) bool {
var count int
scope.NewDB().Raw("SELECT count(*) FROM INFORMATION_SCHEMA.indexes WHERE table_schema = current_schema AND table_name = ? AND index_name = ?", tableName, indexName).Row().Scan(&count)
return count > 0
}

View File

@ -104,7 +104,7 @@ func (s JoinTableHandler) Add(db *DB, source1 interface{}, source2 interface{})
quotedTable := s.Table(db) quotedTable := s.Table(db)
sql := fmt.Sprintf( sql := fmt.Sprintf(
"INSERT INTO %v (%v) SELECT %v %v WHERE NOT EXISTS (SELECT * FROM %v WHERE %v);", "INSERT INTO %v (%v) SELECT %v %v WHERE NOT EXISTS (SELECT * FROM %v WHERE %v)",
quotedTable, quotedTable,
strings.Join(assignColumns, ","), strings.Join(assignColumns, ","),
strings.Join(binVars, ","), strings.Join(binVars, ","),

View File

@ -55,6 +55,9 @@ func Open(dialect string, args ...interface{}) (DB, error) {
driver = value driver = value
source = args[1].(string) source = args[1].(string)
} }
if driver == "foundation" {
driver = "postgres" // FoundationDB speaks a postgres-compatible protocol.
}
dbSql, err = sql.Open(driver, source) dbSql, err = sql.Open(driver, source)
case sqlCommon: case sqlCommon:
source = reflect.Indirect(reflect.ValueOf(value)).FieldByName("dsn").String() source = reflect.Indirect(reflect.ValueOf(value)).FieldByName("dsn").String()

View File

@ -36,6 +36,9 @@ func init() {
case "postgres": case "postgres":
fmt.Println("testing postgres...") fmt.Println("testing postgres...")
DB, err = gorm.Open("postgres", "user=gorm DB.name=gorm sslmode=disable") DB, err = gorm.Open("postgres", "user=gorm DB.name=gorm sslmode=disable")
case "foundation":
fmt.Println("testing foundation...")
DB, err = gorm.Open("foundation", "dbname=gorm port=15432 sslmode=disable")
case "mssql": case "mssql":
fmt.Println("testing mssql...") fmt.Println("testing mssql...")
DB, err = gorm.Open("mssql", "server=SERVER_HERE;database=rogue;user id=USER_HERE;password=PW_HERE;port=1433") DB, err = gorm.Open("mssql", "server=SERVER_HERE;database=rogue;user id=USER_HERE;password=PW_HERE;port=1433")
@ -445,6 +448,14 @@ func TestHaving(t *testing.T) {
} }
} }
func DialectHasTzSupport() bool {
// NB: mssql and FoundationDB do not support time zones.
if dialect := os.Getenv("GORM_DIALECT"); dialect == "mssql" || dialect == "foundation" {
return false
}
return true
}
func TestTimeWithZone(t *testing.T) { func TestTimeWithZone(t *testing.T) {
var format = "2006-01-02 15:04:05 -0700" var format = "2006-01-02 15:04:05 -0700"
var times []time.Time var times []time.Time
@ -456,26 +467,30 @@ func TestTimeWithZone(t *testing.T) {
name := "time_with_zone_" + strconv.Itoa(index) name := "time_with_zone_" + strconv.Itoa(index)
user := User{Name: name, Birthday: vtime} user := User{Name: name, Birthday: vtime}
// TODO mssql does not support time zones if !DialectHasTzSupport() {
if dialect := os.Getenv("GORM_DIALECT"); dialect == "mssql" { // If our driver dialect doesn't support TZ's, just use UTC for everything here.
user.Birthday = vtime.UTC() user.Birthday = vtime.UTC()
} }
DB.Save(&user) DB.Save(&user)
if user.Birthday.UTC().Format(format) != "2013-02-18 17:51:49 +0000" { expectedBirthday := "2013-02-18 17:51:49 +0000"
t.Errorf("User's birthday should not be changed after save") foundBirthday := user.Birthday.UTC().Format(format)
if foundBirthday != expectedBirthday {
t.Errorf("User's birthday should not be changed after save for name=%s, expected bday=%+v but actual value=%+v", name, expectedBirthday, foundBirthday)
} }
var findUser, findUser2, findUser3 User var findUser, findUser2, findUser3 User
DB.First(&findUser, "name = ?", name) DB.First(&findUser, "name = ?", name)
if findUser.Birthday.UTC().Format(format) != "2013-02-18 17:51:49 +0000" { foundBirthday = findUser.Birthday.UTC().Format(format)
t.Errorf("User's birthday should not be changed after find") if foundBirthday != expectedBirthday {
t.Errorf("User's birthday should not be changed after find for name=%s, expected bday=%+v but actual value=%+v or %+v", name, expectedBirthday, foundBirthday)
} }
if DB.Where("id = ? AND birthday >= ?", findUser.Id, vtime.Add(-time.Minute)).First(&findUser2).RecordNotFound() { if DB.Where("id = ? AND birthday >= ?", findUser.Id, user.Birthday.Add(-time.Minute)).First(&findUser2).RecordNotFound() {
t.Errorf("User should be found") t.Errorf("User should be found")
} }
if !DB.Where("id = ? AND birthday >= ?", findUser.Id, vtime.Add(time.Minute)).First(&findUser3).RecordNotFound() { if !DB.Where("id = ? AND birthday >= ?", findUser.Id, user.Birthday.Add(time.Minute)).First(&findUser3).RecordNotFound() {
t.Errorf("User should not be found") t.Errorf("User should not be found")
} }
} }

View File

@ -3,7 +3,6 @@ package gorm
import ( import (
"database/sql" "database/sql"
"database/sql/driver" "database/sql/driver"
"errors"
"fmt" "fmt"
"reflect" "reflect"
"regexp" "regexp"
@ -360,7 +359,7 @@ func (scope *Scope) pluck(column string, value interface{}) *Scope {
dest := reflect.Indirect(reflect.ValueOf(value)) dest := reflect.Indirect(reflect.ValueOf(value))
scope.Search.Select(column) scope.Search.Select(column)
if dest.Kind() != reflect.Slice { if dest.Kind() != reflect.Slice {
scope.Err(errors.New("results should be a slice")) scope.Err(fmt.Errorf("results should be a slice, not %s", dest.Kind()))
return scope return scope
} }

View File

@ -1,4 +1,4 @@
dialects=("postgres" "mysql" "sqlite") dialects=("postgres" "foundation" "mysql" "sqlite")
for dialect in "${dialects[@]}" ; do for dialect in "${dialects[@]}" ; do
GORM_DIALECT=${dialect} go test GORM_DIALECT=${dialect} go test