diff --git a/main_test.go b/main_test.go index d9ecb547378d27874b2aaee23b666b630d7dfca7..62eaf311ea139ca0cd2bd0ea696b4ab3b25c2fd1 100644 --- a/main_test.go +++ b/main_test.go @@ -38,7 +38,7 @@ import ( _ "upper.io/db/postgresql" // Temporary removing QL. It includes a _solaris.go file that produces // compile time errors on < go1.3. - //_ "upper.io/db/ql" + _ "upper.io/db/ql" _ "upper.io/db/sqlite" ) @@ -47,7 +47,7 @@ var wrappers = []string{ `mysql`, `postgresql`, `mongo`, - //`ql`, + `ql`, } const ( @@ -116,6 +116,9 @@ var setupFn = map[string]func(driver interface{}) error{ col = mgod.DB("upperio_tests").C("is_even") col.DropCollection() + + col = mgod.DB("upperio_tests").C("CaSe_TesT") + col.DropCollection() return nil } return errDriverErr @@ -162,6 +165,18 @@ var setupFn = map[string]func(driver interface{}) error{ return err } + _, err = sqld.Exec(`DROP TABLE IF EXISTS "CaSe_TesT"`) + if err != nil { + return err + } + _, err = sqld.Exec(`CREATE TABLE "CaSe_TesT" ( + "ID" SERIAL PRIMARY KEY, + "Case_Test" VARCHAR(60) + )`) + if err != nil { + return err + } + return nil } return errDriverErr @@ -169,6 +184,7 @@ var setupFn = map[string]func(driver interface{}) error{ `mysql`: func(driver interface{}) error { if sqld, ok := driver.(*sql.DB); ok == true { var err error + _, err = sqld.Exec(`DROP TABLE IF EXISTS birthdays`) if err != nil { return err @@ -181,6 +197,7 @@ var setupFn = map[string]func(driver interface{}) error{ if err != nil { return err } + _, err = sqld.Exec(`DROP TABLE IF EXISTS fibonacci`) if err != nil { return err @@ -193,6 +210,7 @@ var setupFn = map[string]func(driver interface{}) error{ if err != nil { return err } + _, err = sqld.Exec(`DROP TABLE IF EXISTS is_even`) if err != nil { return err @@ -204,6 +222,19 @@ var setupFn = map[string]func(driver interface{}) error{ if err != nil { return err } + + _, err = sqld.Exec(`DROP TABLE IF EXISTS CaSe_TesT`) + if err != nil { + return err + } + _, err = sqld.Exec(`CREATE TABLE CaSe_TesT ( + ID BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY(ID), + Case_Test VARCHAR(60) + ) CHARSET=utf8`) + if err != nil { + return err + } + return nil } return errDriverErr @@ -211,6 +242,7 @@ var setupFn = map[string]func(driver interface{}) error{ `sqlite`: func(driver interface{}) error { if sqld, ok := driver.(*sql.DB); ok == true { var err error + _, err = sqld.Exec(`DROP TABLE IF EXISTS "birthdays"`) if err != nil { return err @@ -223,6 +255,7 @@ var setupFn = map[string]func(driver interface{}) error{ if err != nil { return err } + _, err = sqld.Exec(`DROP TABLE IF EXISTS "fibonacci"`) if err != nil { return err @@ -235,6 +268,7 @@ var setupFn = map[string]func(driver interface{}) error{ if err != nil { return err } + _, err = sqld.Exec(`DROP TABLE IF EXISTS "is_even"`) if err != nil { return err @@ -246,6 +280,19 @@ var setupFn = map[string]func(driver interface{}) error{ if err != nil { return err } + + _, err = sqld.Exec(`DROP TABLE IF EXISTS "CaSe_TesT"`) + if err != nil { + return err + } + _, err = sqld.Exec(`CREATE TABLE "CaSe_TesT" ( + "ID" INTEGER PRIMARY KEY, + "Case_Test" VARCHAR + )`) + if err != nil { + return err + } + return nil } return errDriverErr @@ -298,6 +345,18 @@ var setupFn = map[string]func(driver interface{}) error{ return err } + _, err = tx.Exec(`DROP TABLE IF EXISTS CaSe_TesT`) + if err != nil { + return err + } + + _, err = tx.Exec(`CREATE TABLE CaSe_TesT ( + Case_Test string + )`) + if err != nil { + return err + } + if err = tx.Commit(); err != nil { return err } @@ -330,6 +389,20 @@ type OddEven struct { OmitMe bool `json:"omit_me" db:"-" bson:"-"` } +// Struct that relies on explicit mapping. +type mapE struct { + Id uint `db:"ID,omitempty" bson:"-"` + MongoId bson.ObjectId `db:"-" bson:"_id,omitempty"` + CaseTest string `db:"Case_Test" bson:"Case_Test"` +} + +// Struct that will fallback to default mapping. +type mapN struct { + Id uint `db:",omitempty"` + MongoId bson.ObjectId `db:"-" bson:"_id,omitempty"` + Casetest string +} + func even(i int) bool { if i%2 == 0 { return true @@ -355,11 +428,11 @@ func TestOpen(t *testing.T) { var sess db.Database sess, err = db.Open(wrapper, *settings[wrapper]) if err != nil { - t.Fatalf(`Test for wrapper %s failed: %s`, wrapper, err.Error()) + t.Fatalf(`Test for wrapper %s failed: %q`, wrapper, err) } err = sess.Close() if err != nil { - t.Fatalf(`Test for wrapper %s failed: %s`, wrapper, err.Error()) + t.Fatalf(`Test for wrapper %s failed: %q`, wrapper, err) } } } @@ -375,21 +448,20 @@ func TestSetup(t *testing.T) { sess, err = db.Open(wrapper, *settings[wrapper]) if err != nil { - t.Fatalf(`Test for wrapper %s failed: %s`, wrapper, err.Error()) + t.Fatalf(`Test for wrapper %s failed: %q`, wrapper, err) } if setupFn[wrapper] == nil { t.Fatalf(`Missing setup function for wrapper %s.`, wrapper) } else { - err = setupFn[wrapper](sess.Driver()) - if err != nil { - t.Fatalf(`Failed to setup wrapper %s: %s`, wrapper, err.Error()) + if err = setupFn[wrapper](sess.Driver()); err != nil { + t.Fatalf(`Failed to setup wrapper %s: %q`, wrapper, err) } } err = sess.Close() if err != nil { - t.Fatalf(`Could not close %s: %s`, wrapper, err.Error()) + t.Fatalf(`Could not close %s: %q`, wrapper, err) } } @@ -409,7 +481,7 @@ func TestSimpleCRUD(t *testing.T) { sess, err = db.Open(wrapper, *settings[wrapper]) if err != nil { - t.Fatalf(`Test for wrapper %s failed: %s`, wrapper, err.Error()) + t.Fatalf(`Test for wrapper %s failed: %q`, wrapper, err) } defer sess.Close() @@ -425,14 +497,14 @@ func TestSimpleCRUD(t *testing.T) { if wrapper == `mongo` && err == db.ErrCollectionDoesNotExist { // Expected error with mongodb. } else { - t.Fatalf(`Could not use collection with wrapper %s: %s`, wrapper, err.Error()) + t.Fatalf(`Could not use collection with wrapper %s: %q`, wrapper, err) } } var id interface{} if id, err = col.Append(controlItem); err != nil { - t.Fatalf(`Could not append item with wrapper %s: %s`, wrapper, err.Error()) + t.Fatalf(`Could not append item with wrapper %s: %q`, wrapper, err) } var res db.Result @@ -486,7 +558,7 @@ func TestSimpleCRUD(t *testing.T) { err = res.Update(controlItem) if err != nil { - t.Fatalf(`Could not update with wrapper %s: %s`, wrapper, err.Error()) + t.Fatalf(`Could not update with wrapper %s: %q`, wrapper, err) } res.One(&testItem) @@ -498,23 +570,23 @@ func TestSimpleCRUD(t *testing.T) { err = res.Remove() if err != nil { - t.Fatalf(`Could not remove with wrapper %s: %s`, wrapper, err.Error()) + t.Fatalf(`Could not remove with wrapper %s: %q`, wrapper, err) } total, err = res.Count() if total != 0 { - t.Fatalf(`Expecting no items %s: %s`, wrapper, err.Error()) + t.Fatalf(`Expecting no items %s: %q`, wrapper, err) } err = res.Close() if err != nil { - t.Errorf("Failed to close result %s: %s.", wrapper, err.Error()) + t.Errorf("Failed to close result %s: %q.", wrapper, err) } err = sess.Close() if err != nil { - t.Errorf("Failed to close %s: %s.", wrapper, err.Error()) + t.Errorf("Failed to close %s: %q.", wrapper, err) } } @@ -534,7 +606,7 @@ func TestFibonacci(t *testing.T) { sess, err = db.Open(wrapper, *settings[wrapper]) if err != nil { - t.Fatalf(`Test for wrapper %s failed: %s`, wrapper, err.Error()) + t.Fatalf(`Test for wrapper %s failed: %q`, wrapper, err) } defer sess.Close() @@ -545,7 +617,7 @@ func TestFibonacci(t *testing.T) { if wrapper == `mongo` && err == db.ErrCollectionDoesNotExist { // Expected error with mongodb. } else { - t.Fatalf(`Could not use collection with wrapper %s: %s`, wrapper, err.Error()) + t.Fatalf(`Could not use collection with wrapper %s: %q`, wrapper, err) } } @@ -555,7 +627,7 @@ func TestFibonacci(t *testing.T) { item := Fibonacci{Input: i, Output: fib(i)} _, err = col.Append(item) if err != nil { - t.Fatalf(`Could not append item with wrapper %s: %s`, wrapper, err.Error()) + t.Fatalf(`Could not append item with wrapper %s: %q`, wrapper, err) } } @@ -584,7 +656,7 @@ func TestFibonacci(t *testing.T) { total, err = res.Count() if err != nil { - t.Fatalf(`%s: %s`, wrapper, err.Error()) + t.Fatalf(`%s: %q`, wrapper, err) } if total != 4 { @@ -606,7 +678,7 @@ func TestFibonacci(t *testing.T) { total, err = res.Count() if err != nil { - t.Fatalf(`%s: %s`, wrapper, err.Error()) + t.Fatalf(`%s: %q`, wrapper, err) } if total != 4 { @@ -631,7 +703,7 @@ func TestFibonacci(t *testing.T) { } else if err == db.ErrNoMoreRows { break } else { - t.Fatalf(`%s: %s`, wrapper, err.Error()) + t.Fatalf(`%s: %q`, wrapper, err) } } @@ -648,7 +720,7 @@ func TestFibonacci(t *testing.T) { ).Sort("-input") if total, err = res.Count(); err != nil { - t.Fatalf(`%s: %s`, wrapper, err.Error()) + t.Fatalf(`%s: %q`, wrapper, err) } if total != 4 { @@ -674,16 +746,16 @@ func TestFibonacci(t *testing.T) { } else if err == db.ErrNoMoreRows { break } else { - t.Fatalf(`%s: %s`, wrapper, err.Error()) + t.Fatalf(`%s: %q`, wrapper, err) } } if err = res.Remove(); err != nil { - t.Fatalf(`%s: %s`, wrapper, err.Error()) + t.Fatalf(`%s: %q`, wrapper, err) } if total, err = res.Count(); err != nil { - t.Fatalf(`%s: %s`, wrapper, err.Error()) + t.Fatalf(`%s: %q`, wrapper, err) } if total != 0 { @@ -702,7 +774,7 @@ func TestFibonacci(t *testing.T) { err = res.All(&items) if err != nil { - t.Fatalf(`%s: %s`, wrapper, err.Error()) + t.Fatalf(`%s: %q`, wrapper, err) } for _, item := range items { @@ -723,12 +795,12 @@ func TestFibonacci(t *testing.T) { err = res.Close() if err != nil { - t.Errorf("Failed to close result %s: %s.", wrapper, err.Error()) + t.Errorf("Failed to close result %s: %q.", wrapper, err) } err = sess.Close() if err != nil { - t.Errorf("Failed to close %s: %s.", wrapper, err.Error()) + t.Errorf("Failed to close %s: %q.", wrapper, err) } } @@ -746,7 +818,7 @@ func TestEven(t *testing.T) { sess, err = db.Open(wrapper, *settings[wrapper]) if err != nil { - t.Fatalf(`Test for wrapper %s failed: %s`, wrapper, err.Error()) + t.Fatalf(`Test for wrapper %s failed: %q`, wrapper, err) } defer sess.Close() @@ -757,7 +829,7 @@ func TestEven(t *testing.T) { if wrapper == `mongo` && err == db.ErrCollectionDoesNotExist { // Expected error with mongodb. } else { - t.Fatalf(`Could not use collection with wrapper %s: %s`, wrapper, err.Error()) + t.Fatalf(`Could not use collection with wrapper %s: %q`, wrapper, err) } } @@ -767,7 +839,7 @@ func TestEven(t *testing.T) { item := OddEven{Input: i, IsEven: even(i)} _, err = col.Append(item) if err != nil { - t.Fatalf(`Could not append item with wrapper %s: %s`, wrapper, err.Error()) + t.Fatalf(`Could not append item with wrapper %s: %q`, wrapper, err) } } @@ -790,7 +862,7 @@ func TestEven(t *testing.T) { } if err = res.Remove(); err != nil { - t.Fatalf(`Could not remove with wrapper %s: %s`, wrapper, err.Error()) + t.Fatalf(`Could not remove with wrapper %s: %q`, wrapper, err) } res = col.Find() @@ -872,3 +944,110 @@ func TestEven(t *testing.T) { } } + +func TestExplicitAndDefaultMapping(t *testing.T) { + var err error + var col db.Collection + var sess db.Database + var res db.Result + + var testE mapE + var testN mapN + + for _, wrapper := range wrappers { + + if settings[wrapper] == nil { + t.Fatalf(`No such settings entry for wrapper %s.`, wrapper) + } else { + + if sess, err = db.Open(wrapper, *settings[wrapper]); err != nil { + t.Fatalf(`Test for wrapper %s failed: %q`, wrapper, err) + } + + defer sess.Close() + + col, err = sess.Collection("Case_Test") + + if col, err = sess.Collection("CaSe_TesT"); err != nil { + if wrapper == `mongo` && err == db.ErrCollectionDoesNotExist { + // Nothing, it's expected. + } else { + t.Fatal(err) + } + } + + if err = col.Truncate(); err != nil { + if wrapper == `mongo` { + // Nothing, it's expected. + } else { + t.Fatal(err) + } + } + + // Testing explicit mapping. + testE = mapE{ + CaseTest: "Hello!", + } + + if _, err = col.Append(testE); err != nil { + t.Fatal(err) + } + + res = col.Find(db.Cond{"Case_Test": "Hello!"}) + + if wrapper == `ql` { + res = res.Select(`id() as ID`, `Case_Test`) + } + + if err = res.One(&testE); err != nil { + t.Fatal(err) + } + + if wrapper == `mongo` { + if testE.MongoId.Valid() == false { + t.Fatalf("Expecting an ID.") + } + } else { + if testE.Id == 0 { + t.Fatalf("Expecting an ID.") + } + } + + // Testing default mapping. + testN = mapN{ + Casetest: "World!", + } + + if _, err = col.Append(testN); err != nil { + t.Fatal(err) + } + + if wrapper == `mongo` { + // We don't have this kind of control with mongodb. + res = col.Find(db.Cond{"casetest": "World!"}) + } else { + res = col.Find(db.Cond{"Case_Test": "World!"}) + } + + if wrapper == `ql` { + res = res.Select(`id() as ID`, `Case_Test`) + } + + if err = res.One(&testN); err != nil { + t.Fatal(err) + } + + if wrapper == `mongo` { + if testN.MongoId.Valid() == false { + t.Fatalf("Expecting an ID.") + } + } else { + if testN.Id == 0 { + t.Fatalf("Expecting an ID.") + } + } + + } + } + +} diff --git a/mysql/_dumps/structs.sql b/mysql/_dumps/structs.sql index aab3b4339b6cba3007d591e6bb30fdbb7d58cadc..e5c8ccb7c61345300bb28d94d75c894fb0ef0959 100644 --- a/mysql/_dumps/structs.sql +++ b/mysql/_dumps/structs.sql @@ -51,13 +51,6 @@ CREATE TABLE data_types ( _time TIME NOT NULL ); -DROP TABLE IF EXISTS case_test; - -CREATE TABLE CaSe_TesT ( - id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY(id), - Case_Test VARCHAR(60) -); - DROP TABLE IF EXISTS stats_test; CREATE TABLE stats_test ( diff --git a/postgresql/collection.go b/postgresql/collection.go index fdbd24f9ea449434e718437749dc1da9a08b309d..7a166f5a2ce55e170325a2c0d2c3886054aa86bb 100644 --- a/postgresql/collection.go +++ b/postgresql/collection.go @@ -276,7 +276,7 @@ func (self *table) Append(item interface{}) (interface{}, error) { var row *sql.Row // A primary key was found. - stmt.Extra = sqlgen.Extra(fmt.Sprintf(`RETURNING %s`, pKey)) + stmt.Extra = sqlgen.Extra(fmt.Sprintf(`RETURNING "%s"`, pKey)) if row, err = self.source.doQueryRow(stmt, arguments...); err != nil { return nil, err } diff --git a/postgresql/database.go b/postgresql/database.go index 7e56921a68c033f958812066e4941d4b60025178..313913458a505b413dbbee86788300fffb8ea420 100644 --- a/postgresql/database.go +++ b/postgresql/database.go @@ -451,7 +451,7 @@ func (self *source) Collection(names ...string) (db.Collection, error) { col.Columns = make([]string, 0, len(columns_t)) for _, column := range columns_t { - col.Columns = append(col.Columns, strings.ToLower(column.Name)) + col.Columns = append(col.Columns, column.Name) } } } @@ -481,14 +481,14 @@ func (self *source) getPrimaryKey(tableName string) (string, error) { {`pg_attribute.attname`}, }, Where: sqlgen.Where{ - sqlgen.ColumnValue{sqlgen.Column{`pg_class.oid`}, `=`, sqlgen.Value{sqlgen.Raw{`?::regclass`}}}, + sqlgen.ColumnValue{sqlgen.Column{`pg_class.oid`}, `=`, sqlgen.Value{sqlgen.Raw{`'"` + tableName + `"'::regclass`}}}, sqlgen.ColumnValue{sqlgen.Column{`indrelid`}, `=`, sqlgen.Value{sqlgen.Raw{`pg_class.oid`}}}, sqlgen.ColumnValue{sqlgen.Column{`pg_attribute.attrelid`}, `=`, sqlgen.Value{sqlgen.Raw{`pg_class.oid`}}}, sqlgen.ColumnValue{sqlgen.Column{`pg_attribute.attnum`}, `=`, sqlgen.Value{sqlgen.Raw{`any(pg_index.indkey)`}}}, sqlgen.Raw{`indisprimary`}, }, Limit: 1, - }, tableName) + }) if err != nil { return "", err diff --git a/ql/database.go b/ql/database.go index bb7af1345aa3eba25bd138e156922dbe8f5a0e23..d0e4653f593be6f2ab179955bc9745dbc2c92262 100644 --- a/ql/database.go +++ b/ql/database.go @@ -60,8 +60,8 @@ type source struct { } type columnSchema_t struct { - ColumnName string `db:"name"` - DataType string `db:"type"` + ColumnName string `db:"Name"` + DataType string `db:"Type"` } func debugEnabled() bool { @@ -458,7 +458,6 @@ func (self *source) Collection(names ...string) (db.Collection, error) { for i, column := range columns_t { - column.ColumnName = strings.ToLower(column.ColumnName) column.DataType = strings.ToLower(column.DataType) col.Columns[i] = column.ColumnName diff --git a/ql/util.go b/ql/util.go index 6d54f46eef0b40260236ccf2813518999ef7e7e5..6785e66fc2ed5da4ffb8a03794404ad458cc840b 100644 --- a/ql/util.go +++ b/ql/util.go @@ -24,30 +24,12 @@ package ql import ( "database/sql" "reflect" - "strings" "menteslibres.net/gosexy/to" "upper.io/db" "upper.io/db/util" ) -// Returns (lowercased) columns names. -func getRowColumns(rows *sql.Rows) ([]string, error) { - // Column names. - columns, err := rows.Columns() - - if err != nil { - return nil, err - } - - // Column names to lower case. - for i := range columns { - columns[i] = strings.ToLower(columns[i]) - } - - return columns, nil -} - func (self *table) fetchRow(rows *sql.Rows, dst interface{}) error { var err error @@ -70,7 +52,7 @@ func (self *table) fetchRow(rows *sql.Rows, dst interface{}) error { var columns []string - if columns, err = getRowColumns(rows); err != nil { + if columns, err = rows.Columns(); err != nil { return err } @@ -169,7 +151,7 @@ func (self *table) fetchRows(rows *sql.Rows, dst interface{}) error { var columns []string - if columns, err = getRowColumns(rows); err != nil { + if columns, err = rows.Columns(); err != nil { return err } diff --git a/util/sqlutil/main.go b/util/sqlutil/main.go index 76054607ab9472832c0f85c3bd4b06e37bf7a8d2..9583d2593e684657fffe5ee1a8a55740ebbf375a 100644 --- a/util/sqlutil/main.go +++ b/util/sqlutil/main.go @@ -201,26 +201,11 @@ func fetchResult(item_t reflect.Type, rows *sql.Rows, columns []string) (reflect return item, nil } -// Returns (lowercased) columns names. -func getRowColumns(rows *sql.Rows) ([]string, error) { - // Column names. - columns, err := rows.Columns() - - if err != nil { - return nil, err - } - - // Column names to lower case. - for i, _ := range columns { - columns[i] = strings.ToLower(columns[i]) - } - - return columns, nil -} - // FetchRow() receives a *sql.Rows value and tries to map all the rows into a // single struct given by the pointer `dst`. func FetchRow(rows *sql.Rows, dst interface{}) error { + var columns []string + var err error dstv := reflect.ValueOf(dst) @@ -230,9 +215,7 @@ func FetchRow(rows *sql.Rows, dst interface{}) error { item_v := dstv.Elem() - columns, err := getRowColumns(rows) - - if err != nil { + if columns, err = rows.Columns(); err != nil { return err } @@ -261,6 +244,8 @@ func FetchRow(rows *sql.Rows, dst interface{}) error { // FetchRow() receives a *sql.Rows value and tries to map all the rows into a // slice of structs given by the pointer `dst`. func FetchRows(rows *sql.Rows, dst interface{}) error { + var columns []string + var err error // Destination. dstv := reflect.ValueOf(dst) @@ -277,9 +262,7 @@ func FetchRows(rows *sql.Rows, dst interface{}) error { return db.ErrExpectingSliceMapStruct } - columns, err := getRowColumns(rows) - - if err != nil { + if columns, err = rows.Columns(); err != nil { return err }