示例#1
0
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	sql "github.com/aodin/sol"
	"github.com/aodin/sol/dialect"
	"github.com/aodin/sol/types"
)

// The sql dialect must implement the dialect interface
var _ dialect.Dialect = &Sqlite3{}

var things = sql.Table("things",
	sql.Column("name", types.Varchar()),
	sql.Column("created_at", types.Timestamp()), // TODO auto-timestamp?
)

type thing struct {
	Name      string
	CreatedAt *time.Time `db:",omitempty"`
}

// Connect to an in-memory sqlite3 instance and execute some statements.
func TestSqlite3(t *testing.T) {
	conn, err := sql.Open("sqlite3", ":memory:")
	require.Nil(t, err, `Failed to connect to in-memory sqlite3 instance`)
	defer conn.Close()

	require.Nil(t,
		conn.Query(things.Create()),
示例#2
0
文件: sol_test.go 项目: pgrunde/sol
package sol

import (
	"time"

	"github.com/aodin/sol/types"
)

// Valid schemas should not panic
var users = Table("users",
	Column("id", types.Integer()),
	Column("email", types.Varchar().Limit(256).NotNull()), // TODO unique
	Column("name", types.Varchar().Limit(32).NotNull()),
	Column("password", types.Varchar()),
	Column("created_at", types.Timestamp()),
	PrimaryKey("id"),
	Unique("email"),
)

var contacts = Table("contacts",
	Column("id", types.Integer()),
	Column("user_id", types.Integer()), // TODO FK
	Column("key", types.Varchar()),
	Column("value", types.Varchar()),
	PrimaryKey("id"),
	Unique("user_id", "key"),
)

type user struct {
	ID        uint64 `db:",omitempty"`
	Email     string
示例#3
0
文件: tester.go 项目: aodin/sol
// IntegrationTest runs a large, neutral dialect test
func IntegrationTest(t *testing.T, conn *DB, ddlCommit bool) {
	// Perform all tests in a transaction
	// TODO What features should be tested outside of a transaction?

	// CREATE TABLE is performed outside of the transaction because any
	// change to the DDL in MySQL is a implicit commit
	// Other databases: http://stackoverflow.com/a/4736346
	testusers := Table("testusers",
		Column("id", types.Integer()),
		Column("email", types.Varchar().Limit(255).NotNull()),
		Column("is_admin", types.Boolean().NotNull()),
		Column("created_at", types.Timestamp()),
		PrimaryKey("id"),
		Unique("email"),
	)

	type testuser struct {
		ID        int64
		Email     string
		IsAdmin   bool
		CreatedAt time.Time
	}

	tx, err := conn.Begin()
	if err != nil {
		t.Fatalf("Creating a new transaction should not error: %s", err)
	}
	defer tx.Rollback()

	if ddlCommit {
		if err = conn.Query(testusers.Create().IfNotExists()); err != nil {
			t.Fatalf("CREATE TABLE should not error: %s", err)
		}
	} else {
		if err = tx.Query(testusers.Create().IfNotExists()); err != nil {
			t.Fatalf("CREATE TABLE should not error: %s", err)
		}
	}

	// INSERT by struct
	// Truncate the time.Time field to avoid significant digit errors
	admin := testuser{
		ID:        1,
		Email:     "*****@*****.**",
		IsAdmin:   true,
		CreatedAt: time.Now().UTC().Truncate(time.Second),
	}

	if err = tx.Query(testusers.Insert().Values(admin)); err != nil {
		t.Fatalf("INSERT by struct should not fail %s", err)
	}

	// SELECT
	var selected testuser
	if err = tx.Query(
		testusers.Select().Where(testusers.C("id").Equals(admin.ID)),
		&selected,
	); err != nil {
		t.Fatalf("SELECT should not fail: %s", err)
	}

	// TODO test with direct comparison: selected == admin
	// For now, test each field since DATETIME handling is terribly
	// inconsistent across databases
	if selected.ID != admin.ID {
		t.Errorf(
			"Unequal testusers id: have %d, want %d",
			selected.ID, admin.ID,
		)
	}
	if selected.Email != admin.Email {
		t.Errorf(
			"Unequal testusers email: have %s, want %s",
			selected.Email, admin.Email,
		)
	}
	if selected.IsAdmin != admin.IsAdmin {
		t.Errorf(
			"Unequal testusers is_admin: have %t, want %t",
			selected.IsAdmin, admin.IsAdmin,
		)
	}
	if !selected.CreatedAt.Equal(admin.CreatedAt) {
		t.Errorf(
			"Unequal testusers created_at: have %v, want %v",
			selected.CreatedAt, admin.CreatedAt,
		)
	}

	// UPDATE
	if err = tx.Query(
		testusers.Update().Values(
			Values{"is_admin": false},
		).Where(testusers.C("id").Equals(admin.ID)),
	); err != nil {
		t.Fatalf("UPDATE should not fail: %s", err)
	}

	var updated testuser
	if err = tx.Query(testusers.Select().Limit(1), &updated); err != nil {
		t.Fatalf("SELECT should not fail: %s", err)
	}

	selected.IsAdmin = false
	if updated != selected {
		t.Errorf(
			"Unequal testusers: have %+v, want %+v",
			updated, selected,
		)
	}

	// INSERT by values
	client := Values{
		"id":         2,
		"email":      "*****@*****.**",
		"is_admin":   false,
		"created_at": time.Now().UTC().Truncate(time.Second),
	}

	if err = tx.Query(testusers.Insert().Values(client)); err != nil {
		t.Fatalf("INSERT by values should not fail %s", err)
	}
	var list []testuser
	if err = tx.Query(
		testusers.Select().OrderBy(testusers.C("id").Desc()),
		&list,
	); err != nil {
		t.Fatalf("SELECT with ORDER BY should not fail: %s", err)
	}

	if len(list) != 2 {
		t.Fatalf("Unexpected length of list: want 2, have %d", len(list))
	}

	// The client should be first
	if list[0].Email != "*****@*****.**" {
		t.Errorf(
			"Unexpected email: want [email protected], have %s",
			list[0].Email,
		)
	}

	var count int64
	if err = tx.Query(Select(Count(testusers.C("id"))), &count); err != nil {
		t.Fatalf("SELECT with COUNT should not fail: %s", err)
	}
	if count != 2 {
		t.Errorf("Unexpected COUNT: want 2, have %d", count)
	}

	// DELETE
	if err = tx.Query(
		testusers.Delete().Where(testusers.C("email").Equals(admin.Email)),
	); err != nil {
		t.Fatalf("DELETE should not fail: %s", err)
	}

	// DROP TABLE
	// TODO Since this is a DDL, this will likely commit in MySQL
	if err = tx.Query(testusers.Drop()); err != nil {
		t.Fatalf("DROP TABLE should not fail %s", err)
	}

	// Test a recover
	func() {
		defer func() {
			if panicked := recover(); panicked == nil {
				t.Errorf("Connection failed to panic on error")
			}
		}()
		conn.Must().Query(testusers.Select(), list)
	}()
}