예제 #1
0
// 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)
		}
	}
}
예제 #2
0
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
}
예제 #3
0
// Benchmarking raw database/sql.
func BenchmarkAppendTxRawSQL(b *testing.B) {
	var err error
	var sess db.Database
	var tx *sql.Tx

	if sess, err = db.Open(Adapter, settings); err != nil {
		b.Fatal(err)
	}

	defer sess.Close()

	driver := sess.Driver().(*sql.DB)

	if tx, err = driver.Begin(); err != nil {
		b.Fatal(err)
	}

	if _, err = tx.Exec("TRUNCATE TABLE `artist`"); err != nil {
		b.Fatal(err)
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if _, err = tx.Exec("INSERT INTO `artist` (`name`) VALUES('Hayao Miyazaki')"); err != nil {
			b.Fatal(err)
		}
	}

	if err = tx.Commit(); err != nil {
		b.Fatal(err)
	}
}
예제 #4
0
// 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!")
	}
}
예제 #5
0
func TestSetup(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)
			}

			if setupFn[wrapper] == nil {
				t.Fatalf(`Missing setup function for wrapper %s.`, wrapper)
			} else {
				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: %q`, wrapper, err)
			}

		}
	}
}
예제 #6
0
// Benchmarking raw database/sql.
func BenchmarkAppendRawSQL(b *testing.B) {
	var err error
	var sess db.Database

	if sess, err = db.Open(Adapter, settings); err != nil {
		b.Fatal(err)
	}

	defer sess.Close()

	driver := sess.Driver().(*sql.DB)

	if _, err = driver.Exec(`DELETE FROM "artist"`); err != nil {
		b.Fatal(err)
	}

	b.ResetTimer()
	stmt, err := driver.Prepare(
		`INSERT INTO "artist" ("name") VALUES('Hayao Miyazaki')`)
	if err != nil {
		b.Fatal(err)
	}
	for i := 0; i < b.N; i++ {
		if _, err = stmt.Exec(); err != nil {
			b.Fatal(err)
		}
	}
}
예제 #7
0
// 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.`)
	}

}
예제 #8
0
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.`)
	}
}
예제 #9
0
// 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()
}
예제 #10
0
// 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.")
	}
}
예제 #11
0
// Old settings must be compatible.
func TestOldSettings(t *testing.T) {
	var err error
	var sess db.Database

	oldSettings := db.Settings{
		Database: database,
	}

	// Opening database.
	if sess, err = db.Open(Adapter, oldSettings); err != nil {
		t.Fatal(err)
	}

	// Closing database.
	sess.Close()
}
예제 #12
0
// 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.`)
	}

}
예제 #13
0
func TestRawQuery(t *testing.T) {
	var sess db.Database
	var rows *sql.Rows
	var err error
	var drv *sql.DB

	type publicationType struct {
		ID       int64  `db:"id,omitempty"`
		Title    string `db:"title"`
		AuthorID int64  `db:"author_id"`
	}

	if sess, err = db.Open(Adapter, settings); err != nil {
		t.Fatal(err)
	}

	defer sess.Close()

	drv = sess.Driver().(*sql.DB)

	rows, err = drv.Query(`
		SELECT
			p.id,
			p.title AS publication_title,
			a.name AS artist_name
		FROM
			artist AS a,
			publication AS p
		WHERE
			a.id = p.author_id
	`)

	if err != nil {
		t.Fatal(err)
	}

	var all []publicationType

	if err = sqlutil.FetchRows(rows, &all); err != nil {
		t.Fatal(err)
	}

	if len(all) != 9 {
		t.Fatalf("Expecting some rows.")
	}
}
예제 #14
0
// Test USE
func TestUse(t *testing.T) {
	var err error
	var sess db.Database

	// Opening database, no error expected.
	if sess, err = db.Open(Adapter, settings); err != nil {
		t.Fatal(err)
	}

	// Connecting to another database, error expected.
	if err = sess.Use("Another database"); err == nil {
		t.Fatal("This database does not exists!")
	}

	// Closing connection.
	sess.Close()
}
예제 #15
0
func TestOpen(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)
			}
			err = sess.Close()
			if err != nil {
				t.Fatalf(`Test for wrapper %s failed: %q`, wrapper, err)
			}
		}
	}
}
예제 #16
0
// Old settings must be compatible.
func TestOldSettings(t *testing.T) {
	var err error
	var sess db.Database

	oldSettings := db.Settings{
		Database: database,
		User:     username,
		Password: password,
		Host:     *host,
	}

	// Opening database.
	if sess, err = db.Open(Adapter, oldSettings); err != nil {
		t.Fatal(err)
	}

	// Closing database.
	sess.Close()
}
예제 #17
0
// Benchmarking Append() with map.
func BenchmarkAppendTxUpperMap(b *testing.B) {
	var sess db.Database
	var err error

	if sess, err = db.Open(Adapter, settings); err != nil {
		b.Fatal(err)
	}

	defer sess.Close()

	var tx db.Tx
	if tx, err = sess.Transaction(); err != nil {
		b.Fatal(err)
	}

	var artist db.Collection
	if artist, err = tx.Collection("artist"); err != nil {
		b.Fatal(err)
	}

	if err = artist.Truncate(); err != nil {
		b.Fatal(err)
	}

	item := map[string]string{"name": "Hayao Miyazaki"}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if _, err = artist.Append(item); err != nil {
			b.Fatal(err)
		}
	}

	if err = tx.Commit(); err != nil {
		b.Fatal(err)
	}
}
예제 #18
0
// 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)
	}
}
예제 #19
0
// 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)
			}
		}
	}

}
예제 #20
0
// 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()
}
예제 #21
0
// 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.")
	}
}
예제 #22
0
// 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.")
		}
	}
}
예제 #23
0
// 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.`)
	}
}
예제 #24
0
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)
			}

		}
	}
}
예제 #25
0
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)
				}
			}

		}
	}

}
예제 #26
0
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.")
				}
			}

		}
	}

}
예제 #27
0
// 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.")
	}

}
예제 #28
0
// 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.")
	}

}
예제 #29
0
// 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.")
	}

}
예제 #30
0
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.`)
	//}

}