camli/db: more type conversion work

Change-Id: Icbbf4a084017478ba74df85f4c31be6541d7b44e
This commit is contained in:
Brad Fitzpatrick 2011-08-25 18:25:12 +04:00
parent 2f1527a71d
commit 3a29e1c245
5 changed files with 139 additions and 8 deletions

View File

@ -0,0 +1,57 @@
/*
Copyright 2011 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package db
import (
"fmt"
"os"
"reflect"
)
// valueToImpl converts v to one of the restricted subset types that
// dbimpl drivers need to support: int64, float64, bool, nil, []byte
func valueToImpl(v interface{}) (interface{}, os.Error) {
if v == nil {
return nil, nil
}
if _, ok := v.([]byte); ok {
return v, nil
}
if _, ok := v.(bool); ok {
return v, nil
}
if s, ok := v.(string); ok {
return []byte(s), nil
}
rv := reflect.ValueOf(v)
switch rv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return rv.Int(), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
return int64(rv.Uint()), nil
case reflect.Uint64:
u64 := rv.Uint()
if u64 >= 1 << 63 {
return nil, fmt.Errorf("uint64 values with high bit set are not supported")
}
return int64(u64), nil
case reflect.Float32, reflect.Float64:
return rv.Float(), nil
}
return nil, fmt.Errorf("unsupported type %s", rv.Kind())
}

View File

@ -244,7 +244,13 @@ func (s *Stmt) Exec(args ...interface{}) os.Error {
// Then convert everything into the restricted subset
// of types that the dbimpl package needs to know about.
// all integers -> int64, etc
// TODO(bradfitz): ^that
for n, arg := range args {
var err os.Error
args[n], err = valueToImpl(arg)
if err != nil {
return fmt.Errorf("db: error converting index %d: %v", n, err)
}
}
resi, err := si.Exec(args)
if err != nil {

View File

@ -31,8 +31,8 @@ func newTestDB(t *testing.T, name string) *DB {
return db
}
func exec(t *testing.T, db *DB, query string) {
err := db.Exec(query)
func exec(t *testing.T, db *DB, query string, args ...interface{}) {
err := db.Exec(query, args...)
if err != nil {
t.Fatalf("Exec of %q: %v", query, err)
}
@ -41,6 +41,7 @@ func exec(t *testing.T, db *DB, query string) {
func TestQuery(t *testing.T) {
db := newTestDB(t, "foo")
exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
exec(t, db, "INSERT|t1|name=Brad,age=?", 31)
}

View File

@ -0,0 +1,72 @@
/*
Copyright 2011 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package dbimpl
import (
"fmt"
"os"
"reflect"
"strconv"
)
type boolType struct{}
var Bool = boolType{}
func (boolType) ConvertValue(v interface{}) (interface{}, os.Error) {
return nil, fmt.Errorf("TODO(bradfitz): bool conversions")
}
type int32Type struct{}
var Int32 = int32Type{}
func (int32Type) ConvertValue(v interface{}) (interface{}, os.Error) {
rv := reflect.ValueOf(v)
switch rv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
i64 := rv.Int()
if i64 > (1<<31)-1 || i64 < -(1<<31) {
return nil, fmt.Errorf("value %d overflows int32", v)
}
return int32(i64), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
u64 := rv.Uint()
if u64 > (1<<31)-1 {
return nil, fmt.Errorf("value %d overflows int32", v)
}
return int32(u64), nil
case reflect.String:
i, err := strconv.Atoi(rv.String())
if err != nil {
return nil, fmt.Errorf("value %q can't be converted to int32", v)
}
return int32(i), nil
}
return nil, fmt.Errorf("unsupported value %v (type %T) converting to int32", v, v)
}
type stringType struct{}
var String = stringType{}
func (stringType) ConvertValue(v interface{}) (interface{}, os.Error) {
if s, ok := v.(string); ok {
return s, nil
}
return fmt.Sprintf("%v", v), nil
}

View File

@ -312,11 +312,6 @@ func (s *fakeStmt) execInsert(args []interface{}) (dbimpl.Result, os.Error) {
} else {
val = s.colValue[n]
}
valType := fmt.Sprintf("%T", val)
if colType := t.coltype[colidx]; valType != colType {
return nil, fmt.Errorf("fakedb: column %q value of %v (%v) doesn't match column type of %q",
colname, val, valType, colType)
}
cols[colidx] = val
}