From e91e47865a21400d6918d2693d9c46a4b7c1cd32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Carlos=20Nieto?= <xiam@menteslibres.org> Date: Mon, 17 Sep 2012 07:14:07 -0500 Subject: [PATCH] Testing SQLite3 with new datatypes. --- db.go | 5 +- mysql/mysql.go | 2 +- sqlite/dumps/gotest.sqlite3.db | Bin 5120 -> 6144 bytes sqlite/sqlite.go | 82 ++++++++++----- sqlite/sqlite_test.go | 175 ++++++++++++++++++++++++++++++++- 5 files changed, 237 insertions(+), 27 deletions(-) diff --git a/db.go b/db.go index 6ad6a8ab..22422b5f 100644 --- a/db.go +++ b/db.go @@ -303,7 +303,10 @@ func (item Item) GetBool(name string) bool { if item[name] == nil { return false - } else { + } + + switch item[name].(type) { + default: b := strings.ToLower(fmt.Sprintf("%v", item[name])) if b == "" || b == "0" || b == "false" { return false diff --git a/mysql/mysql.go b/mysql/mysql.go index 98169668..32acb62e 100644 --- a/mysql/mysql.go +++ b/mysql/mysql.go @@ -159,7 +159,7 @@ func toInternal(val interface{}) string { return val.(time.Time).Format(dateFormat) case time.Duration: t := val.(time.Duration) - return fmt.Sprintf(timeFormat, int(t.Hours()), int(t.Minutes())%60, int(t.Seconds())%60, int(t.Nanoseconds())%1e9) + return fmt.Sprintf(timeFormat, int(t.Hours()), int(t.Minutes())%60, int(t.Seconds())%60) case bool: if val.(bool) == true { return "1" diff --git a/sqlite/dumps/gotest.sqlite3.db b/sqlite/dumps/gotest.sqlite3.db index ca9d13e8bbac02b5a7ef62946a1424ab5192be0e..d2277f0e3d8399fa4f70f07b13decca884fa5582 100644 GIT binary patch delta 559 zcmZqBXfT){CB(Lvfq{Vyh+%+xqK=USP*nGk8ZS_cmEjTtb04!j(^e)=hD#G0V=S9W zSlPuD6&YKNOA?cEQd1I365~rM3sQ>_EH>vLSH}=ng%C$4A6EsK_~eI7GWGGLnRz7& zK%APMTBM@@<`$F`p@~?a@eR#D0#N0~Mo1hp6DSAOSRfDC3?LU`L_O46pa8@e1Rr7& zl%JN9p9oS>l$w|Wv=+<-Du8m6Doaw4Tv$|^hs;gN&(A@UEiNg_%u81&Nv!~SKqVd+ z8mUlDJjk3x7^fsN7b2m#*^_CzAP*??nV4G`m=7_xY*yr`V6L%Y5@X;514a-4vxJR> sW&eXfVp6h^fuWJEfw``cg@S>hm4T6!fiY0j(A>(%z{<eDhLIB80OixC82|tP delta 61 zcmZoLXwaA-CB$-{fq{V)h+%+jqK=UmP*nGkDlbrsg~^kFxsO?%X)BZGW<`#xjGH}~ HwhICPKu8Oy diff --git a/sqlite/sqlite.go b/sqlite/sqlite.go index d0f00019..95f8e15f 100644 --- a/sqlite/sqlite.go +++ b/sqlite/sqlite.go @@ -31,10 +31,14 @@ import ( _ "github.com/xiam/gosqlite3" "reflect" "regexp" + "time" "strconv" "strings" ) +const dateFormat = "2006-01-02 15:04:05" +const timeFormat = "%d:%02d:%02d" + type slQuery struct { Query []string SqlArgs []string @@ -144,7 +148,7 @@ func (t *SqliteTable) slFetchAll(rows sql.Rows) []db.Item { return items } -func (sl *SqliteDataSource) slExec(method string, terms ...interface{}) sql.Rows { +func (sl *SqliteDataSource) slExec(method string, terms ...interface{}) (sql.Rows, error) { var rows sql.Rows @@ -169,7 +173,7 @@ func (sl *SqliteDataSource) slExec(method string, terms ...interface{}) sql.Rows res := fn.Call(args) if res[1].IsNil() == false { - panic(res[1].Elem().Interface().(error)) + return rows, res[1].Elem().Interface().(error) } switch res[0].Elem().Interface().(type) { @@ -177,10 +181,7 @@ func (sl *SqliteDataSource) slExec(method string, terms ...interface{}) sql.Rows rows = res[0].Elem().Interface().(sql.Rows) } - return rows - - //return res[0].Elem().Interface().(sql.Rows) - + return rows, nil } // Represents a SQLite table. @@ -366,18 +367,18 @@ func (t *SqliteTable) marshal(where db.Cond) (string, []string) { } // Deletes all the rows in the table. -func (t *SqliteTable) Truncate() bool { +func (t *SqliteTable) Truncate() error { - t.parent.slExec( + _, err := t.parent.slExec( "Exec", fmt.Sprintf("DELETE FROM %s", slTable(t.name)), ) - return false + return err } // Deletes all the rows in the table that match certain conditions. -func (t *SqliteTable) Remove(terms ...interface{}) bool { +func (t *SqliteTable) Remove(terms ...interface{}) error { conditions, cargs := t.compileConditions(terms) @@ -385,17 +386,17 @@ func (t *SqliteTable) Remove(terms ...interface{}) bool { conditions = "1 = 1" } - t.parent.slExec( + _, err := t.parent.slExec( "Exec", fmt.Sprintf("DELETE FROM %s", slTable(t.name)), fmt.Sprintf("WHERE %s", conditions), cargs, ) - return true + return err } // Modifies all the rows in the table that match certain conditions. -func (t *SqliteTable) Update(terms ...interface{}) bool { +func (t *SqliteTable) Update(terms ...interface{}) error { var fields string var fargs db.SqlArgs @@ -412,13 +413,13 @@ func (t *SqliteTable) Update(terms ...interface{}) bool { conditions = "1 = 1" } - t.parent.slExec( + _, err := t.parent.slExec( "Exec", fmt.Sprintf("UPDATE %s SET %s", slTable(t.name), fields), fargs, fmt.Sprintf("WHERE %s", conditions), cargs, ) - return true + return err } // Returns all the rows in the table that match certain conditions. @@ -459,7 +460,7 @@ func (t *SqliteTable) FindAll(terms ...interface{}) []db.Item { conditions = "1 = 1" } - rows := t.parent.slExec( + rows, _ := t.parent.slExec( "Query", fmt.Sprintf("SELECT %s FROM %s", fields, slTable(t.name)), fmt.Sprintf("WHERE %s", conditions), args, @@ -583,7 +584,7 @@ func (t *SqliteTable) FindAll(terms ...interface{}) []db.Item { } // Returns the number of rows in the current table that match certain conditions. -func (t *SqliteTable) Count(terms ...interface{}) int { +func (t *SqliteTable) Count(terms ...interface{}) (int, error) { terms = append(terms, db.Fields{"COUNT(1) AS _total"}) @@ -593,11 +594,11 @@ func (t *SqliteTable) Count(terms ...interface{}) int { response := result[0].Interface().([]db.Item) if len(response) > 0 { val, _ := strconv.Atoi(response[0]["_total"].(string)) - return val + return val, nil } } - return 0 + return 0, nil } // Returns the first row in the table that matches certain conditions. @@ -619,8 +620,39 @@ func (t *SqliteTable) Find(terms ...interface{}) db.Item { return item } +func toInternal(val interface{}) string { + + switch val.(type) { + case []byte: + return fmt.Sprintf("%s", string(val.([]byte))) + case time.Time: + return val.(time.Time).Format(dateFormat) + case time.Duration: + t := val.(time.Duration) + //return fmt.Sprintf(timeFormat, int(t.Hours()), int(t.Minutes())%60, int(t.Seconds())%60, int(t.Nanoseconds())%1e9) + return fmt.Sprintf(timeFormat, int(t.Hours()), int(t.Minutes())%60, int(t.Seconds())%60) + case bool: + if val.(bool) == true { + return "1" + } else { + return "0" + } + } + + return fmt.Sprintf("%v", val) +} + +func toNative(val interface{}) interface{} { + + switch val.(type) { + } + + return val + +} + // Inserts rows into the currently active table. -func (t *SqliteTable) Append(items ...interface{}) bool { +func (t *SqliteTable) Append(items ...interface{}) error { itop := len(items) @@ -633,10 +665,10 @@ func (t *SqliteTable) Append(items ...interface{}) bool { for field, value := range item.(db.Item) { fields = append(fields, field) - values = append(values, fmt.Sprintf("%v", value)) + values = append(values, toInternal(value)) } - t.parent.slExec( + _, err := t.parent.slExec( "Exec", "INSERT INTO", slTable(t.name), @@ -645,9 +677,13 @@ func (t *SqliteTable) Append(items ...interface{}) bool { slValues(values), ) + if err != nil { + return err + } + } - return true + return nil } // Returns a SQLite table structure by name. diff --git a/sqlite/sqlite_test.go b/sqlite/sqlite_test.go index ac22d4cc..da42755c 100644 --- a/sqlite/sqlite_test.go +++ b/sqlite/sqlite_test.go @@ -4,12 +4,57 @@ import ( "fmt" "github.com/gosexy/db" "github.com/kr/pretty" + "github.com/gosexy/sugar" "math/rand" "testing" + "time" ) const sqDatabase = "./dumps/gotest.sqlite3.db" +func getTestData() db.Item { + + _time, _ := time.ParseDuration("17h20m") + + data := db.Item{ + "_uint": uint(1), + "_uintptr": uintptr(1), + + "_uint8": uint8(1), + "_uint16": uint16(1), + "_uint32": uint32(1), + "_uint64": uint64(1), + + "_int": int(-1), + "_int8": int8(-1), + "_int16": int16(-1), + "_int32": int32(-1), + "_int64": int64(-1), + + "_float32": float32(1.0), + "_float64": float64(1.0), + + //"_complex64": complex64(1), + //"_complex128": complex128(1), + + "_byte": byte(1), + "_rune": rune(1), + + "_bool": bool(true), + "_string": string("abc"), + "_bytea": []byte{'a', 'b', 'c'}, + + //"_list": sugar.List{1, 2, 3}, + //"_map": sugar.Tuple{"a": 1, "b": 2, "c": 3}, + + "_date": time.Date(2012, 7, 28, 1, 2, 3, 0, time.UTC), + "_time": _time, + } + + return data +} + + func TestSqTruncate(t *testing.T) { sess := SqliteSession(db.DataSource{Database: sqDatabase}) @@ -26,7 +71,8 @@ func TestSqTruncate(t *testing.T) { for _, name := range collections { col := sess.Collection(name) col.Truncate() - if col.Count() != 0 { + total, _ := col.Count() + if total != 0 { t.Errorf("Could not truncate '%s'.", name) } } @@ -54,7 +100,9 @@ func TestSqAppend(t *testing.T) { col.Append(db.Item{"name": names[i]}) } - if col.Count() != len(names) { + total, _ := col.Count() + + if total != len(names) { panic(fmt.Errorf("Could not append all items")) } @@ -220,3 +268,126 @@ func TestSqRelation(t *testing.T) { fmt.Printf("%# v\n", pretty.Formatter(result)) } + +func TestDataTypes(t *testing.T) { + + sess := SqliteSession(db.DataSource{Database: sqDatabase}) + + err := sess.Open() + + if err == nil { + defer sess.Close() + } + + col := sess.Collection("data_types") + + col.Truncate() + + data := getTestData() + + err = col.Append(data) + + if err != nil { + t.Errorf("Could not append test data.") + } + + // Getting and reinserting. + item := col.Find() + + err = col.Append(item) + + if err == nil { + t.Errorf("Expecting duplicated-key error.") + } + + delete(item, "id") + + err = col.Append(item) + + if err != nil { + t.Errorf("Could not append second element.") + } + + // Testing rows + items := col.FindAll() + + for i := 0; i < len(items); i++ { + + item := items[i] + + for key, _ := range item { + + switch key { + + // Signed integers. + case + "_int", + "_int8", + "_int16", + "_int32", + "_int64": + if item.GetInt(key) != int64(data["_int"].(int)) { + t.Errorf("Wrong datatype %v.", key) + } + + // Unsigned integers. + case + "_uint", + "_uintptr", + "_uint8", + "_uint16", + "_uint32", + "_uint64", + "_byte", + "_rune": + if item.GetInt(key) != int64(data["_uint"].(uint)) { + t.Errorf("Wrong datatype %v.", key) + } + + // Floating point. + case "_float32": + case "_float64": + if item.GetFloat(key) != data["_float64"].(float64) { + t.Errorf("Wrong datatype %v.", key) + } + + // Boolean + case "_bool": + if item.GetBool(key) != data["_bool"].(bool) { + t.Errorf("Wrong datatype %v.", key) + } + + // String + case "_string": + if item.GetString(key) != data["_string"].(string) { + t.Errorf("Wrong datatype %v.", key) + } + + // Map + case "_map": + if item.GetTuple(key)["a"] != data["_map"].(sugar.Tuple)["a"] { + t.Errorf("Wrong datatype %v.", key) + } + + // Array + case "_list": + if item.GetList(key)[0] != data["_list"].(sugar.List)[0] { + t.Errorf("Wrong datatype %v.", key) + } + + // Time + case "_time": + if item.GetDuration(key).String() != data["_time"].(time.Duration).String() { + t.Errorf("Wrong datatype %v.", key) + } + + // Date + case "_date": + if item.GetDate(key).Equal(data["_date"].(time.Time)) == false { + t.Errorf("Wrong datatype %v.", key) + } + } + } + } + +} -- GitLab