// Attempts to count all rows in our newly defined set. func TestResultCount(t *testing.T) { var err error var res db.Result var sess db.Database var artist db.Collection var total uint64 if sess, err = db.Open(Adapter, settings); err != nil { t.Fatal(err) } defer sess.Close() // We should close the database when it's no longer in use. if artist, err = sess.Collection("artist"); err != nil { t.Fatal(err) } // Defining a set with no conditions. res = artist.Find() // Counting all the matching rows. if total, err = res.Count(); err != nil { t.Fatal(err) } if total == 0 { t.Fatalf("Counter should not be zero, we've just added some rows!") } }
// Benchmarking Append(). // // Contributed by wei2912 // See: https://github.com/gosexy/db/issues/20#issuecomment-20097801 func BenchmarkAppendUpper(b *testing.B) { var sess db.Database var artist db.Collection var err error if sess, err = db.Open(Adapter, settings); err != nil { b.Fatal(err) } defer sess.Close() if artist, err = sess.Collection("artist"); err != nil { b.Fatal(err) } artist.Truncate() item := struct { Name string `db:"name"` }{"Hayao Miyazaki"} b.ResetTimer() for i := 0; i < b.N; i++ { if _, err = artist.Append(item); err != nil { b.Fatal(err) } } }
func SetupCollection() (col db.Collection) { var ( err error sess db.Database settings db.Settings ) settings = db.Settings{ Database: `:memory:`, } if sess, err = db.Open("sqlite", settings); err != nil { panic(err) } if _, err = sess.Driver().(*sql.DB).Exec(`CREATE TABLE users ( id INTEGER, first_name VARCHAR(80), last_name VARCHAR(80), age INTEGER ); `); err != nil { panic(err) } if col, err = sess.Collection("users"); err != nil { panic(err) } return col }
// MongoDB: Does not support schemas so it can't has composite keys. We're // testing db.Constrainer and db.IDSetter interface. func TestSetterAndConstrainer(t *testing.T) { var err error var id interface{} var sess db.Database var compositeKeys db.Collection if sess, err = db.Open(Adapter, settings); err != nil { t.Fatal(err) } defer sess.Close() if compositeKeys, err = sess.Collection("composite_keys"); err != nil { if err != db.ErrCollectionDoesNotExist { t.Fatal(err) } } //n := rand.Intn(100000) item := itemWithKey{ // "ABCDEF", // strconv.Itoa(n), SomeVal: "Some value", } if id, err = compositeKeys.Append(&item); err != nil { t.Fatal(err) } // ids := id.([]interface{}) // if ids[0].(string) != item.Code { // t.Fatal(`Keys must match.`) // } // // if ids[1].(string) != item.UserID { // t.Fatal(`Keys must match.`) // } // Using constraint interface. res := compositeKeys.Find(itemWithKey{ID: id.(bson.ObjectId)}) var item2 itemWithKey if item2.SomeVal == item.SomeVal { t.Fatal(`Values must be different before query.`) } if err := res.One(&item2); err != nil { t.Fatal(err) } if item2.SomeVal != item.SomeVal { t.Fatal(`Values must be equal after query.`) } }
func TestGroup(t *testing.T) { var err error var sess db.Database var stats db.Collection if sess, err = db.Open(Adapter, settings); err != nil { t.Fatal(err) } type statsType struct { Numeric int `db:"numeric"` Value int `db:"value"` } defer sess.Close() if stats, err = sess.Collection("stats_test"); err != nil { t.Fatal(err) } // Truncating table. if err = stats.Truncate(); err != nil { t.Fatal(err) } // Adding row append. for i := 0; i < 1000; i++ { numeric, value := rand.Intn(10), rand.Intn(100) if _, err = stats.Append(statsType{numeric, value}); err != nil { t.Fatal(err) } } // db.Func{"COUNT", 1}, // db.Func{"SUM", `value`}, // Testing GROUP BY res := stats.Find().Select( `numeric`, db.Raw{`COUNT(1) AS counter`}, db.Raw{`SUM(value) AS total`}, ).Group(`numeric`) var results []map[string]interface{} if err = res.All(&results); err != nil { t.Fatal(err) } if len(results) != 10 { t.Fatalf(`Expecting exactly 10 results, this could fail, but it's very unlikely to happen.`) } }
// Attempts to use functions within database queries. func TestFunction(t *testing.T) { var err error var res db.Result var sess db.Database var artist db.Collection var total uint64 if sess, err = db.Open(Adapter, settings); err != nil { t.Fatal(err) } defer sess.Close() if artist, err = sess.Collection("artist"); err != nil { t.Fatal(err) } row_s := struct { Id uint64 Name string }{} res = artist.Find(db.Cond{"id NOT IN": []int{0, -1}}) if err = res.One(&row_s); err != nil { t.Fatal(err) } if total, err = res.Count(); err != nil { t.Fatal(err) } if total != 3 { t.Fatalf("Expecting 3 items.") } res = artist.Find(db.Cond{"id": db.Func{"NOT IN", []int{0, -1}}}) if err = res.One(&row_s); err != nil { t.Fatal(err) } if total, err = res.Count(); err != nil { t.Fatal(err) } if total != 3 { t.Fatalf("Expecting 3 items.") } res.Close() }
// Attempts to add many different datatypes to a single row in a collection, // then it tries to get the stored datatypes and check if the stored and the // original values match. func TestDataTypes(t *testing.T) { var res db.Result var sess db.Database var dataTypes db.Collection var err error var id interface{} var exists uint64 if sess, err = db.Open(Adapter, settings); err != nil { t.Fatal(err) } defer sess.Close() // Getting a pointer to the "data_types" collection. if dataTypes, err = sess.Collection("data_types"); err != nil { t.Fatal(err) } // Removing all data. if err = dataTypes.Truncate(); err != nil { t.Fatal(err) } // Appending our test subject. if id, err = dataTypes.Append(testValues); err != nil { t.Fatal(err) } // Defining our set. res = dataTypes.Find(db.Cond{"id": id}) if exists, err = res.Count(); err != nil { t.Fatal(err) } if exists == 0 { t.Fatalf("Expecting an item.") } // Trying to dump the subject into an empty structure of the same type. var item testValuesStruct res.One(&item) // The original value and the test subject must match. if reflect.DeepEqual(item, testValues) == false { t.Fatalf("Struct is different.") } }
// Attempts to test composite keys. func TestCompositeKeys(t *testing.T) { var err error var sess db.Database var compositeKeys db.Collection if sess, err = db.Open(Adapter, settings); err != nil { t.Fatal(err) } defer sess.Close() if compositeKeys, err = sess.Collection("composite_keys"); err != nil { t.Fatal(err) } n := rand.Intn(100000) item := itemWithKey{ "ABCDEF", strconv.Itoa(n), "Some value", } if _, err = compositeKeys.Append(&item); err != nil { t.Fatal(err) } // Using constraint interface. var item2 itemWithKey if item2.SomeVal == item.SomeVal { t.Fatal(`Values must be different before query.`) } res := compositeKeys.Find(item) if err := res.One(&item2); err != nil { t.Fatal(err) } if item2.SomeVal != item.SomeVal { t.Fatal(`Values must be equal after query.`) } }
// Attempts to get all collections and truncate each one of them. func TestTruncate(t *testing.T) { var err error var sess db.Database var collections []string var col db.Collection // Opening database. if sess, err = db.Open(Adapter, settings); err != nil { t.Fatal(err) } // We should close the database when it's no longer in use. defer sess.Close() // Getting a list of all collections in this database. if collections, err = sess.Collections(); err != nil { t.Fatal(err) } if len(collections) == 0 { t.Fatalf("Expecting some collections.") } // Walking over collections. for _, name := range collections { // Getting a collection. if col, err = sess.Collection(name); err != nil { t.Fatal(err) } // Table must exists before we can use it. if col.Exists() == true { // Truncating the table. if err = col.Truncate(); err != nil { t.Fatal(err) } } } }
// Attempts to delete previously added rows. func TestRemove(t *testing.T) { var err error var res db.Result var sess db.Database var artist db.Collection if sess, err = db.Open(Adapter, settings); err != nil { t.Fatal(err) } defer sess.Close() if artist, err = sess.Collection("artist"); err != nil { t.Fatal(err) } // Getting the artist with id = 1 res = artist.Find(db.Cond{"id": 1}) // Trying to remove the row. if err = res.Remove(); err != nil { t.Fatal(err) } }
// Attempts to test nullable fields. func TestNullableFields(t *testing.T) { var err error var sess db.Database var col db.Collection var id interface{} if sess, err = db.Open(Adapter, settings); err != nil { t.Fatal(err) } defer sess.Close() type testType struct { ID int64 `db:"id,omitempty"` NullStringTest sql.NullString `db:"_string"` NullInt64Test sql.NullInt64 `db:"_int64"` NullFloat64Test sql.NullFloat64 `db:"_float64"` NullBoolTest sql.NullBool `db:"_bool"` } var test testType if col, err = sess.Collection(`data_types`); err != nil { t.Fatal(err) } if err = col.Truncate(); err != nil { t.Fatal(err) } // Testing insertion of invalid nulls. test = testType{ NullStringTest: sql.NullString{"", false}, NullInt64Test: sql.NullInt64{0, false}, NullFloat64Test: sql.NullFloat64{0.0, false}, NullBoolTest: sql.NullBool{false, false}, } if id, err = col.Append(testType{}); err != nil { t.Fatal(err) } // Testing fetching of invalid nulls. if err = col.Find(db.Cond{"id": id}).One(&test); err != nil { t.Fatal(err) } if test.NullInt64Test.Valid { t.Fatalf(`Expecting invalid null.`) } if test.NullFloat64Test.Valid { t.Fatalf(`Expecting invalid null.`) } if test.NullBoolTest.Valid { t.Fatalf(`Expecting invalid null.`) } if test.NullStringTest.Valid { t.Fatalf(`Expecting invalid null.`) } // Testing insertion of valid nulls. test = testType{ NullStringTest: sql.NullString{"", true}, NullInt64Test: sql.NullInt64{0, true}, NullFloat64Test: sql.NullFloat64{0.0, true}, NullBoolTest: sql.NullBool{false, true}, } if id, err = col.Append(test); err != nil { t.Fatal(err) } // Testing fetching of valid nulls. if err = col.Find(db.Cond{"id": id}).One(&test); err != nil { t.Fatal(err) } if test.NullInt64Test.Valid == false { t.Fatalf(`Expecting valid value.`) } if test.NullFloat64Test.Valid == false { t.Fatalf(`Expecting valid value.`) } if test.NullBoolTest.Valid == false { t.Fatalf(`Expecting valid value.`) } if test.NullStringTest.Valid == false { t.Fatalf(`Expecting valid value.`) } }
// Attempts to append some data into the "artist" table. func TestAppend(t *testing.T) { var err error var id interface{} var sess db.Database var artist db.Collection var total uint64 if sess, err = db.Open(Adapter, settings); err != nil { t.Fatal(err) } defer sess.Close() if artist, err = sess.Collection("artist"); err != nil { t.Fatal(err) } // Attempt to append a map. itemMap := map[string]string{ "name": "Ozzie", } if id, err = artist.Append(itemMap); err != nil { t.Fatal(err) } if to.Int64(id) == 0 { t.Fatalf("Expecting an ID.") } // Attempt to append a struct. itemStruct := struct { Name string `db:"name"` }{ "Flea", } if id, err = artist.Append(itemStruct); err != nil { t.Fatal(err) } if to.Int64(id) == 0 { t.Fatalf("Expecting an ID.") } // Attempt to append a tagged struct. itemStruct2 := struct { ArtistName string `db:"name"` }{ "Slash", } if id, err = artist.Append(itemStruct2); err != nil { t.Fatal(err) } if to.Int64(id) == 0 { t.Fatalf("Expecting an ID.") } // Attempt to append and update a private key itemStruct3 := artistWithInt64Key{ Name: "Janus", } if _, err = artist.Append(&itemStruct3); err != nil { t.Fatal(err) } if itemStruct3.id == 0 { t.Fatalf("Expecting an ID.") } // Counting elements, must be exactly 4 elements. if total, err = artist.Find().Count(); err != nil { t.Fatal(err) } if total != 4 { t.Fatalf("Expecting exactly 4 rows.") } }
// Attempts to modify previously added rows. func TestUpdate(t *testing.T) { var err error var sess db.Database var artist db.Collection if sess, err = db.Open(Adapter, settings); err != nil { t.Fatal(err) } defer sess.Close() if artist, err = sess.Collection("artist"); err != nil { t.Fatal(err) } // Defining destination struct value := struct { ID uint64 Name string }{} // Getting the first artist. res := artist.Find(db.Cond{"id !=": 0}).Limit(1) if err = res.One(&value); err != nil { t.Fatal(err) } // Updating set with a map rowMap := map[string]interface{}{ "name": strings.ToUpper(value.Name), } if err = res.Update(rowMap); err != nil { t.Fatal(err) } // Pulling it again. if err = res.One(&value); err != nil { t.Fatal(err) } // Verifying. if value.Name != rowMap["name"] { t.Fatalf("Expecting a modification.") } // Updating set with a struct rowStruct := struct { Name string }{strings.ToLower(value.Name)} if err = res.Update(rowStruct); err != nil { t.Fatal(err) } // Pulling it again. if err = res.One(&value); err != nil { t.Fatal(err) } // Verifying if value.Name != rowStruct.Name { t.Fatalf("Expecting a modification.") } // Updating set with a tagged struct rowStruct2 := struct { Value1 string `db:"name"` }{strings.Replace(value.Name, "z", "Z", -1)} if err = res.Update(rowStruct2); err != nil { t.Fatal(err) } // Pulling it again. if err = res.One(&value); err != nil { t.Fatal(err) } // Verifying if value.Name != rowStruct2.Value1 { t.Fatalf("Expecting a modification.") } }
func TestGroup(t *testing.T) { var err error var sess db.Database var stats db.Collection if sess, err = db.Open(Adapter, settings); err != nil { t.Fatal(err) } type stats_t struct { Numeric int `db:"numeric" bson:"numeric"` Value int `db:"value" bson:"value"` } defer sess.Close() if stats, err = sess.Collection("stats_test"); err != nil { if err != db.ErrCollectionDoesNotExist { t.Fatal(err) } } // Truncating table. if err == nil { if err = stats.Truncate(); err != nil { t.Fatal(err) } } // Adding row append. for i := 0; i < 1000; i++ { numeric, value := rand.Intn(10), rand.Intn(100) if _, err = stats.Append(stats_t{numeric, value}); err != nil { t.Fatal(err) } } // db.stats_test.group({key: {numeric: true}, initial: {sum: 0}, reduce: function(doc, prev) { prev.sum += 1}}); // Testing GROUP BY res := stats.Find().Group(bson.M{ "key": bson.M{"numeric": true}, "initial": bson.M{"sum": 0}, "reduce": `function(doc, prev) { prev.sum += 1}`, }) var results []map[string]interface{} err = res.All(&results) // Currently not supported. if err != db.ErrUnsupported { t.Fatal(err) } //if len(results) != 10 { // t.Fatalf(`Expecting exactly 10 results, this could fail, but it's very unlikely to happen.`) //} }
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.") } } } } }
func TestEven(t *testing.T) { var err error for _, wrapper := range wrappers { if settings[wrapper] == nil { t.Fatalf(`No such settings entry for wrapper %s.`, wrapper) } else { var sess db.Database sess, err = db.Open(wrapper, *settings[wrapper]) if err != nil { t.Fatalf(`Test for wrapper %s failed: %q`, wrapper, err) } defer sess.Close() var col db.Collection col, err = sess.Collection("is_even") if err != nil { if wrapper == `mongo` && err == db.ErrCollectionDoesNotExist { // Expected error with mongodb. } else { t.Fatalf(`Could not use collection with wrapper %s: %q`, wrapper, err) } } // Adding some items. var i int for i = 1; i < 100; i++ { item := oddEven{Input: i, IsEven: even(i)} _, err = col.Append(item) if err != nil { t.Fatalf(`Could not append item with wrapper %s: %q`, wrapper, err) } } // Retrieving items res := col.Find(db.Cond{"is_even": true}) for { var item oddEven err = res.Next(&item) if err != nil { if err == db.ErrNoMoreRows { break } else { t.Fatalf(`%s: %v`, wrapper, err) } } if item.Input%2 != 0 { t.Fatalf("Expecting even numbers with wrapper %s. Got: %v\n", wrapper, item) } } if err = res.Remove(); err != nil { t.Fatalf(`Could not remove with wrapper %s: %q`, wrapper, err) } res = col.Find() for { // Testing named inputs (using tags). var item struct { Value uint `db:"input" bson:"input"` // The "bson" tag is required by mgo. } err = res.Next(&item) if err != nil { if err == db.ErrNoMoreRows { break } else { t.Fatalf(`%s: %v`, wrapper, err) } } if item.Value%2 == 0 { t.Fatalf("Expecting odd numbers only with wrapper %s. Got: %v\n", wrapper, item) } } for { // Testing inline tag. var item struct { oddEven `db:",inline" bson:",inline"` } err = res.Next(&item) if err != nil { if err == db.ErrNoMoreRows { break } else { t.Fatalf(`%s: %v`, wrapper, err) } } if item.Input%2 == 0 { t.Fatalf("Expecting odd numbers only with wrapper %s. Got: %v\n", wrapper, item) } } // Testing omision tag. for { var item struct { Value uint `db:"-"` } err = res.Next(&item) if err != nil { if err == db.ErrNoMoreRows { break } else { t.Fatalf(`%s: %v`, wrapper, err) } } if item.Value != 0 { t.Fatalf("Expecting no data with wrapper %s. Got: %v\n", wrapper, item) } } // Testing (deprecated) "field" tag. for { // Testing named inputs (using tags). var item struct { Value uint `field:"input"` } err = res.Next(&item) if err != nil { if err == db.ErrNoMoreRows { break } else { t.Fatalf(`%s: %v`, wrapper, err) } } if item.Value%2 == 0 { t.Fatalf("Expecting no data with wrapper %s. Got: %v\n", wrapper, item) } } } } }
func TestFibonacci(t *testing.T) { var err error var res db.Result var total uint64 for _, wrapper := range wrappers { if settings[wrapper] == nil { t.Fatalf(`No such settings entry for wrapper %s.`, wrapper) } else { var sess db.Database sess, err = db.Open(wrapper, *settings[wrapper]) if err != nil { t.Fatalf(`Test for wrapper %s failed: %q`, wrapper, err) } defer sess.Close() var col db.Collection col, err = sess.Collection("fibonacci") if err != nil { if wrapper == `mongo` && err == db.ErrCollectionDoesNotExist { // Expected error with mongodb. } else { t.Fatalf(`Could not use collection with wrapper %s: %q`, wrapper, err) } } // Adding some items. var i uint64 for i = 0; i < 10; i++ { item := fibonacci{Input: i, Output: fib(i)} _, err = col.Append(item) if err != nil { t.Fatalf(`Could not append item with wrapper %s: %q`, wrapper, err) } } // Testing sorting by function. res = col.Find( // 5, 6, 7, 3 db.Or{ db.And{ db.Cond{"input >=": 5}, db.Cond{"input <=": 7}, }, db.Cond{"input": 3}, }, ) // Testing sort by function. switch wrapper { case `postgresql`: res = res.Sort(db.Raw{`RANDOM()`}) case `sqlite`: res = res.Sort(db.Raw{`RANDOM()`}) case `mysql`: res = res.Sort(db.Raw{`RAND()`}) } total, err = res.Count() if err != nil { t.Fatalf(`%s: %q`, wrapper, err) } if total != 4 { t.Fatalf("%s: Expecting a count of 4, got %d.", wrapper, total) } // Find() with IN/$in var whereIn db.Cond switch wrapper { case `mongo`: whereIn = db.Cond{"input": db.Func{"$in", []int{3, 5, 6, 7}}} default: whereIn = db.Cond{"input": db.Func{"IN", []int{3, 5, 6, 7}}} } res = col.Find(whereIn).Sort("input") total, err = res.Count() if err != nil { t.Fatalf(`%s: %q`, wrapper, err) } if total != 4 { t.Fatalf(`Expecting a count of 4.`) } res = res.Skip(1).Limit(2) for { var item fibonacci err = res.Next(&item) if err == nil { switch item.Input { case 5: case 6: if fib(item.Input) != item.Output { t.Fatalf(`Unexpected value in item with wrapper %s.`, wrapper) } default: t.Fatalf(`Unexpected item: %v with wrapper %s.`, item, wrapper) } } else if err == db.ErrNoMoreRows { break } else { t.Fatalf(`%s: %q`, wrapper, err) } } // Find() with range res = col.Find( // 5, 6, 7, 3 db.Or{ db.And{ db.Cond{"input >=": 5}, db.Cond{"input <=": 7}, }, db.Cond{"input": 3}, }, ).Sort("-input") if total, err = res.Count(); err != nil { t.Fatalf(`%s: %q`, wrapper, err) } if total != 4 { t.Fatalf(`Expecting a count of 4.`) } // Skipping. res = res.Skip(1).Limit(2) for { var item fibonacci err = res.Next(&item) if err == nil { switch item.Input { case 5: case 6: if fib(item.Input) != item.Output { t.Fatalf(`Unexpected value in item with wrapper %s.`, wrapper) } default: t.Fatalf(`Unexpected item: %v with wrapper %s.`, item, wrapper) } } else if err == db.ErrNoMoreRows { break } else { t.Fatalf(`%s: %q`, wrapper, err) } } if err = res.Remove(); err != nil { t.Fatalf(`%s: %q`, wrapper, err) } if total, err = res.Count(); err != nil { t.Fatalf(`%s: %q`, wrapper, err) } if total != 0 { t.Fatalf(`%s: Unexpected count %d.`, wrapper, total) } res = col.Find() total, err = res.Count() if total != 6 { t.Fatalf(`%s: Unexpected count %d.`, wrapper, total) } var items []fibonacci err = res.All(&items) if err != nil { t.Fatalf(`%s: %q`, wrapper, err) } for _, item := range items { switch item.Input { case 0: case 1: case 2: case 4: case 8: case 9: if fib(item.Input) != item.Output { t.Fatalf(`Unexpected value in item with wrapper %s.`, wrapper) } default: t.Fatalf(`Unexpected item: %v with wrapper %s.`, item, wrapper) } } err = res.Close() if err != nil { t.Errorf("Failed to close result %s: %q.", wrapper, err) } err = sess.Close() if err != nil { t.Errorf("Failed to close %s: %q.", wrapper, err) } } } }
func TestSimpleCRUD(t *testing.T) { var err error var controlItem birthday for _, wrapper := range wrappers { if settings[wrapper] == nil { t.Fatalf(`No such settings entry for wrapper %s.`, wrapper) } else { var sess db.Database sess, err = db.Open(wrapper, *settings[wrapper]) if err != nil { t.Fatalf(`Test for wrapper %s failed: %q`, wrapper, err) } defer sess.Close() born := time.Date(1941, time.January, 5, 0, 0, 0, 0, time.Local) controlItem = birthday{ Name: "Hayao Miyazaki", Born: born, BornUT: &timeType{born}, } col, err := sess.Collection(`birthdays`) if err != nil { if wrapper == `mongo` && err == db.ErrCollectionDoesNotExist { // Expected error with mongodb. } else { 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: %q`, wrapper, err) } var res db.Result switch wrapper { case `mongo`: res = col.Find(db.Cond{"_id": id.(bson.ObjectId)}) case `ql`: res = col.Find(db.Cond{"id()": id}) default: res = col.Find(db.Cond{"id": id}) } var total uint64 total, err = res.Count() if total != 1 { t.Fatalf("%s: Expecting one row.", wrapper) } // No support for Marshaler and Unmarshaler is implemeted for QL and // MongoDB. if wrapper == `ql` || wrapper == `mongo` { continue } var testItem birthday err = res.One(&testItem) if err != nil { t.Fatalf("%s One(): %s", wrapper, err) } if reflect.DeepEqual(testItem, controlItem) == false { t.Errorf("%s: testItem: %v (ts: %v)\n", wrapper, testItem, testItem.BornUT.value.Unix()) t.Errorf("%s: controlItem: %v (ts: %v)\n", wrapper, controlItem, controlItem.BornUT.value.Unix()) t.Fatalf("%s: Structs are different", wrapper) } var testItems []birthday err = res.All(&testItems) if err != nil { t.Fatalf("%s All(): %s", wrapper, err) } if len(testItems) == 0 { t.Fatalf("%s All(): Expecting at least one row.", wrapper) } for _, testItem = range testItems { if reflect.DeepEqual(testItem, controlItem) == false { t.Errorf("%s: testItem: %v\n", wrapper, testItem) t.Errorf("%s: controlItem: %v\n", wrapper, controlItem) t.Fatalf("%s: Structs are different", wrapper) } } controlItem.Name = `宮崎駿` err = res.Update(controlItem) if err != nil { t.Fatalf(`Could not update with wrapper %s: %q`, wrapper, err) } res.One(&testItem) if reflect.DeepEqual(testItem, controlItem) == false { t.Fatalf("Struct is different with wrapper %s.", wrapper) } err = res.Remove() if err != nil { t.Fatalf(`Could not remove with wrapper %s: %q`, wrapper, err) } total, err = res.Count() if total != 0 { t.Fatalf(`Expecting no items %s: %q`, wrapper, err) } err = res.Close() if err != nil { t.Errorf("Failed to close result %s: %q.", wrapper, err) } err = sess.Close() if err != nil { t.Errorf("Failed to close %s: %q.", wrapper, err) } } } }
func TestFinds(t *testing.T) { var err error for _, wrapper := range wrappers { if settings[wrapper] == nil { t.Fatalf(`No such settings entry for wrapper %s.`, wrapper) } else { 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()) } var col db.Collection col, err = sess.Collection("fibonacci") if err != nil { if wrapper == `mongo` && err == db.ErrCollectionDoesNotExists { // Expected error with mongodb. } else { t.Fatalf(`Could not use collection with wrapper %s: %s`, wrapper, err.Error()) } } // Adding some items. var i uint64 for i = 0; i < 10; i++ { item := Fibonacci{i, fib(i)} _, err = col.Append(item) if err != nil { t.Fatalf(`Could not append item with wrapper %s: %s`, wrapper, err.Error()) } } // Querying range. res := col.Find( // 5, 6, 7, 3 db.Or{ db.And{ db.Cond{"input >=": 5}, db.Cond{"input <=": 7}, }, db.Cond{"input": 3}, }, ).Skip(1).Limit(2).Sort("-input") var total uint64 total, err = res.Count() if err != nil { t.Fatalf(`%s: %s`, wrapper, err.Error()) } if total != 4 { t.Fatalf(`Expecting a count of 4.`) } for { var item Fibonacci err = res.Next(&item) if err == nil { switch item.Input { case 5: case 6: if fib(item.Input) != item.Output { t.Fatalf(`Unexpected value in item with wrapper %s.`, wrapper) } default: t.Fatalf(`Unexpected item: %v with wrapper %s.`, item, wrapper) } } else if err == db.ErrNoMoreRows { break } else { t.Fatalf(`%s: %s`, wrapper, err.Error()) } } err = res.Remove() if err != nil { t.Fatalf(`%s: %s`, wrapper, err.Error()) } total, err = res.Count() if total != 0 { t.Fatalf(`Unexpected count %s.`, wrapper) } res = col.Find() total, err = res.Count() if total != 6 { t.Fatalf(`Unexpected count %s.`, wrapper) } var items []Fibonacci err = res.All(&items) if err != nil { t.Fatalf(`%s: %s`, wrapper, err.Error()) } for _, item := range items { switch item.Input { case 0: case 1: case 2: case 4: case 8: case 9: if fib(item.Input) != item.Output { t.Fatalf(`Unexpected value in item with wrapper %s.`, wrapper) } default: t.Fatalf(`Unexpected item: %v with wrapper %s.`, item, wrapper) } } err = res.Close() if err != nil { t.Errorf("Failed to close result %s: %s.", wrapper, err.Error()) } err = sess.Close() if err != nil { t.Errorf("Failed to close %s: %s.", wrapper, err.Error()) } } } }
// Attempts to fetch results one by one. func TestResultFetch(t *testing.T) { var err error var res db.Result var sess db.Database var artist db.Collection if sess, err = db.Open(Adapter, settings); err != nil { t.Fatal(err) } defer sess.Close() if artist, err = sess.Collection("artist"); err != nil { t.Fatal(err) } // Dumping into a map. rowMap := map[string]interface{}{} res = artist.Find() for { err = res.Next(&rowMap) if err == db.ErrNoMoreRows { break } if err == nil { if to.Int64(rowMap["id"]) == 0 { t.Fatalf("Expecting a not null ID.") } if to.String(rowMap["name"]) == "" { t.Fatalf("Expecting a name.") } } else { t.Fatal(err) } } res.Close() // Dumping into an struct with no tags. rowStruct := struct { ID uint64 Name string }{} res = artist.Find() for { err = res.Next(&rowStruct) if err == db.ErrNoMoreRows { break } if err == nil { if rowStruct.ID == 0 { t.Fatalf("Expecting a not null ID.") } if rowStruct.Name == "" { t.Fatalf("Expecting a name.") } } else { t.Fatal(err) } } res.Close() // Dumping into a tagged struct. rowStruct2 := struct { Value1 uint64 `field:"id"` Value2 string `field:"name"` }{} res = artist.Find() for { err = res.Next(&rowStruct2) if err == db.ErrNoMoreRows { break } if err == nil { if rowStruct2.Value1 == 0 { t.Fatalf("Expecting a not null ID.") } if rowStruct2.Value2 == "" { t.Fatalf("Expecting a name.") } } else { t.Fatal(err) } } res.Close() // Dumping into an slice of maps. allRowsMap := []map[string]interface{}{} res = artist.Find() if err = res.All(&allRowsMap); err != nil { t.Fatal(err) } if len(allRowsMap) != 4 { t.Fatalf("Expecting 4 items.") } for _, singleRowMap := range allRowsMap { if to.Int64(singleRowMap["id"]) == 0 { t.Fatalf("Expecting a not null ID.") } } // Dumping into an slice of structs. allRowsStruct := []struct { ID uint64 Name string }{} res = artist.Find() if err = res.All(&allRowsStruct); err != nil { t.Fatal(err) } if len(allRowsStruct) != 4 { t.Fatalf("Expecting 4 items.") } for _, singleRowStruct := range allRowsStruct { if singleRowStruct.ID == 0 { t.Fatalf("Expecting a not null ID.") } } // Dumping into an slice of tagged structs. allRowsStruct2 := []struct { Value1 uint64 `field:"id"` Value2 string `field:"name"` }{} res = artist.Find() if err = res.All(&allRowsStruct2); err != nil { t.Fatal(err) } if len(allRowsStruct2) != 4 { t.Fatalf("Expecting 4 items.") } for _, singleRowStruct2 := range allRowsStruct2 { if singleRowStruct2.Value1 == 0 { t.Fatalf("Expecting a not null ID.") } } }
// Attempts to test database transactions. func TestTransactionsAndRollback(t *testing.T) { var sess db.Database var err error type artistType struct { ID int64 `db:"id,omitempty"` Name string `db:"name"` } if sess, err = db.Open(Adapter, settings); err != nil { t.Fatal(err) } defer sess.Close() // Simple transaction that should not fail. var tx db.Tx if tx, err = sess.Transaction(); err != nil { t.Fatal(err) } var artist db.Collection if artist, err = tx.Collection("artist"); err != nil { t.Fatal(err) } if err = artist.Truncate(); err != nil { t.Fatal(err) } // Simple transaction if _, err = artist.Append(artistType{1, "First"}); err != nil { t.Fatal(err) } if err = tx.Commit(); err != nil { t.Fatal(err) } // Attempt to use the same transaction should fail. if _, err = tx.Collection("artist"); err == nil { t.Fatalf("Illegal, transaction has already been commited.") } // Use another transaction. if tx, err = sess.Transaction(); err != nil { t.Fatal(err) } if artist, err = tx.Collection("artist"); err != nil { t.Fatal(err) } // Won't fail. if _, err = artist.Append(artistType{2, "Second"}); err != nil { t.Fatal(err) } // Won't fail. if _, err = artist.Append(artistType{3, "Third"}); err != nil { t.Fatal(err) } // Will fail. if _, err = artist.Append(artistType{1, "Duplicated"}); err == nil { t.Fatal("Should have failed, as we have already inserted ID 1.") } if err = tx.Rollback(); err != nil { t.Fatal(err) } if err = tx.Commit(); err == nil { t.Fatalf("Should have failed, as we've already rolled back.") } // Let's verify we still have one element. if artist, err = sess.Collection("artist"); err != nil { t.Fatal(err) } var count uint64 if count, err = artist.Find().Count(); err != nil { t.Fatal(err) } if count != 1 { t.Fatalf("Expecting only one element.") } // Attempt to add some rows. if tx, err = sess.Transaction(); err != nil { t.Fatal(err) } if artist, err = tx.Collection("artist"); err != nil { t.Fatal(err) } // Won't fail. if _, err = artist.Append(artistType{2, "Second"}); err != nil { t.Fatal(err) } // Won't fail. if _, err = artist.Append(artistType{3, "Third"}); err != nil { t.Fatal(err) } // Then rollback for no reason. if err = tx.Rollback(); err != nil { t.Fatal(err) } if err = tx.Commit(); err == nil { t.Fatalf("Should have failed, as we've already rolled back.") } // Let's verify we still have one element. if artist, err = sess.Collection("artist"); err != nil { t.Fatal(err) } if count, err = artist.Find().Count(); err != nil { t.Fatal(err) } if count != 1 { t.Fatalf("Expecting only one element.") } // Attempt to add some rows. if tx, err = sess.Transaction(); err != nil { t.Fatal(err) } if artist, err = tx.Collection("artist"); err != nil { t.Fatal(err) } // Won't fail. if _, err = artist.Append(artistType{2, "Second"}); err != nil { t.Fatal(err) } // Won't fail. if _, err = artist.Append(artistType{3, "Third"}); err != nil { t.Fatal(err) } if err = tx.Commit(); err != nil { t.Fatal(err) } if err = tx.Rollback(); err == nil { t.Fatalf("Should have failed, as we've already commited.") } // Let's verify we have 3 rows. if artist, err = sess.Collection("artist"); err != nil { t.Fatal(err) } if count, err = artist.Find().Count(); err != nil { t.Fatal(err) } if count != 3 { t.Fatalf("Expecting 3 elements.") } }
// Attempts to use functions within database queries. func TestFunction(t *testing.T) { var err error var res db.Result var sess db.Database var artist db.Collection var total uint64 var rowMap map[string]interface{} if sess, err = db.Open(Adapter, settings); err != nil { t.Fatal(err) } defer sess.Close() if artist, err = sess.Collection("artist"); err != nil { t.Fatal(err) } rowStruct := struct { ID uint64 Name string }{} res = artist.Find(db.Cond{"id NOT IN": []int{0, -1}}) if err = res.One(&rowStruct); err != nil { t.Fatal(err) } if total, err = res.Count(); err != nil { t.Fatal(err) } if total != 4 { t.Fatalf("Expecting 4 items.") } // Testing conditions res = artist.Find(db.Cond{"id": db.Func{"NOT IN", []int{0, -1}}}) if err = res.One(&rowStruct); err != nil { t.Fatal(err) } if total, err = res.Count(); err != nil { t.Fatal(err) } if total != 4 { t.Fatalf("Expecting 4 items.") } // Testing DISTINCT (function) res = artist.Find().Select( db.Func{`DISTINCT`, `name`}, ) if err = res.One(&rowMap); err != nil { t.Fatal(err) } if total, err = res.Count(); err != nil { t.Fatal(err) } if total != 4 { t.Fatalf("Expecting 4 items.") } // Testing DISTINCT (raw) res = artist.Find().Select( db.Raw{`DISTINCT(name)`}, ) if err = res.One(&rowMap); err != nil { t.Fatal(err) } if total, err = res.Count(); err != nil { t.Fatal(err) } if total != 4 { t.Fatalf("Expecting 4 items.") } res.Close() }
// Attempts to append some data into the "artist" table. func TestAppend(t *testing.T) { var err error var id interface{} var sess db.Database var artist db.Collection var total uint64 if sess, err = db.Open(Adapter, settings); err != nil { t.Fatal(err) } defer sess.Close() if artist, err = sess.Collection("artist"); err != nil { t.Fatal(err) } // Attempt to append a map. item_m := map[string]string{ "name": "Ozzie", } if id, err = artist.Append(item_m); err != nil { t.Fatal(err) } if to.Int64(id) == 0 { t.Fatalf("Expecting an ID.") } // Attempt to append a struct. item_s := struct { Name string `db:"name"` }{ "Flea", } if id, err = artist.Append(item_s); err != nil { t.Fatal(err) } if to.Int64(id) == 0 { t.Fatalf("Expecting an ID.") } // Append to append a tagged struct. item_t := struct { ArtistName string `db:"name"` }{ "Slash", } if id, err = artist.Append(item_t); err != nil { t.Fatal(err) } if to.Int64(id) == 0 { t.Fatalf("Expecting an ID.") } // Counting elements, must be exactly 3 elements. if total, err = artist.Find().Count(); err != nil { t.Fatal(err) } if total != 3 { t.Fatalf("Expecting exactly 3 rows.") } }
// Attempts to use SQL raw statements. func TestRawRelations(t *testing.T) { var sess db.Database var err error var artist db.Collection var publication db.Collection var review db.Collection type artistType struct { ID int64 `db:"id,omitempty"` Name string `db:"name"` } type publicationType struct { ID int64 `db:"id,omitempty"` Title string `db:"title"` AuthorID int64 `db:"author_id"` } type reviewType struct { ID int64 `db:"id,omitempty"` PublicationID int64 `db:"publication_id"` Name string `db:"name"` Comments string `db:"comments"` Created time.Time `db:"created"` } if sess, err = db.Open(Adapter, settings); err != nil { t.Fatal(err) } defer sess.Close() // Artist collection. if artist, err = sess.Collection("artist"); err != nil { t.Fatal(err) } if err = artist.Truncate(); err != nil { t.Fatal(err) } // Publication collection. if publication, err = sess.Collection("publication"); err != nil { t.Fatal(err) } if err = publication.Truncate(); err != nil { t.Fatal(err) } // Review collection. if review, err = sess.Collection("review"); err != nil { t.Fatal(err) } if err = review.Truncate(); err != nil { t.Fatal(err) } // Adding some artists. var miyazakiID interface{} miyazaki := artistType{Name: `Hayao Miyazaki`} if miyazakiID, err = artist.Append(miyazaki); err != nil { t.Fatal(err) } miyazaki.ID = miyazakiID.(int64) var asimovID interface{} asimov := artistType{Name: `Isaac Asimov`} if asimovID, err = artist.Append(asimov); err != nil { t.Fatal(err) } var marquezID interface{} marquez := artistType{Name: `Gabriel García Márquez`} if marquezID, err = artist.Append(marquez); err != nil { t.Fatal(err) } // Adding some publications. publication.Append(publicationType{ Title: `Tonari no Totoro`, AuthorID: miyazakiID.(int64), }) publication.Append(publicationType{ Title: `Howl's Moving Castle`, AuthorID: miyazakiID.(int64), }) publication.Append(publicationType{ Title: `Ponyo`, AuthorID: miyazakiID.(int64), }) publication.Append(publicationType{ Title: `Memoria de mis Putas Tristes`, AuthorID: marquezID.(int64), }) publication.Append(publicationType{ Title: `El Coronel no tiene quien le escriba`, AuthorID: marquezID.(int64), }) publication.Append(publicationType{ Title: `El Amor en los tiempos del Cólera`, AuthorID: marquezID.(int64), }) publication.Append(publicationType{ Title: `I, Robot`, AuthorID: asimovID.(int64), }) var foundationID interface{} foundationID, err = publication.Append(publicationType{ Title: `Foundation`, AuthorID: asimovID.(int64), }) if err != nil { t.Fatal(err) } publication.Append(publicationType{ Title: `The Robots of Dawn`, AuthorID: asimovID.(int64), }) // Adding reviews for foundation. review.Append(reviewType{ PublicationID: foundationID.(int64), Name: "John Doe", Comments: "I love The Foundation series.", Created: time.Now(), }) review.Append(reviewType{ PublicationID: foundationID.(int64), Name: "Edr Pls", Comments: "The Foundation series made me fall in love with Isaac Asimov.", Created: time.Now(), }) // Exec'ing a raw query. var artistPublication db.Collection if artistPublication, err = sess.Collection(`artist AS a`, `publication AS p`); err != nil { t.Fatal(err) } res := artistPublication.Find( db.Raw{`a.id = p.author_id`}, ).Select( "p.id", "p.title as publication_title", "a.name AS artist_name", ) type artistPublicationType struct { ID int64 `db:"id"` PublicationTitle string `db:"publication_title"` ArtistName string `db:"artist_name"` } all := []artistPublicationType{} if err = res.All(&all); err != nil { t.Fatal(err) } if len(all) != 9 { t.Fatalf("Expecting some rows.") } }
func TestSimpleCRUD(t *testing.T) { var err error var controlItem Birthday for _, wrapper := range wrappers { if settings[wrapper] == nil { t.Fatalf(`No such settings entry for wrapper %s.`, wrapper) } else { 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()) } controlItem = Birthday{ Name: "Hayao Miyazaki", Born: time.Date(1941, time.January, 5, 0, 0, 0, 0, time.Local), } col, err := sess.Collection(`birthdays`) if err != nil { if wrapper == `mongo` && err == db.ErrCollectionDoesNotExists { // Expected error with mongodb. } else { t.Fatalf(`Could not use collection with wrapper %s: %s`, wrapper, err.Error()) } } var id interface{} id, err = col.Append(controlItem) if err != nil { t.Fatalf(`Could not append item with wrapper %s: %s`, wrapper, err.Error()) } var res db.Result if wrapper == `mongo` { res = col.Find(db.Cond{"_id": id}) } else { res = col.Find(db.Cond{"id": id}) } var testItem Birthday res.One(&testItem) if reflect.DeepEqual(testItem, controlItem) == false { t.Errorf("Struct is different with wrapper %s.", wrapper) } controlItem.Name = `宮崎駿` err = res.Update(controlItem) if err != nil { t.Fatalf(`Could not update with wrapper %s: %s`, wrapper, err.Error()) } res.One(&testItem) if reflect.DeepEqual(testItem, controlItem) == false { t.Errorf("Struct is different with wrapper %s.", wrapper) } err = res.Remove() if err != nil { t.Fatalf(`Could not update with wrapper %s: %s`, wrapper, err.Error()) } var total uint64 total, err = res.Count() if total != 0 { t.Fatalf(`Expecting no items %s: %s`, wrapper, err.Error()) } err = res.Close() if err != nil { t.Errorf("Failed to close result %s: %s.", wrapper, err.Error()) } err = sess.Close() if err != nil { t.Errorf("Failed to close %s: %s.", wrapper, err.Error()) } } } }