mirror of https://github.com/aldy505/bob.git
Merge pull request #13 from aldy505/feat/create_index
feat: create index method
This commit is contained in:
commit
2f066ace06
20
bob.go
20
bob.go
|
@ -40,6 +40,16 @@ func (b BobBuilderType) CreateTableIfNotExists(table string) CreateBuilder {
|
||||||
return CreateBuilder(b).name(table).ifNotExists()
|
return CreateBuilder(b).name(table).ifNotExists()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateIndex creates an index with CreateIndexBuilder interface.
|
||||||
|
func (b BobBuilderType) CreateIndex(name string) IndexBuilder {
|
||||||
|
return IndexBuilder(b).name(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateIndexIfNotExists creates an index with CreateIndexBuilder interface, if the index doesn't exists.
|
||||||
|
func (b BobBuilderType) CreateIndexIfNotExists(name string) IndexBuilder {
|
||||||
|
return IndexBuilder(b).name(name).ifNotExists()
|
||||||
|
}
|
||||||
|
|
||||||
// HasTable checks if a table exists with HasBuilder interface
|
// HasTable checks if a table exists with HasBuilder interface
|
||||||
func (b BobBuilderType) HasTable(table string) HasBuilder {
|
func (b BobBuilderType) HasTable(table string) HasBuilder {
|
||||||
return HasBuilder(b).HasTable(table)
|
return HasBuilder(b).HasTable(table)
|
||||||
|
@ -172,3 +182,13 @@ func Truncate(table string) TruncateBuilder {
|
||||||
func Upsert(table string, dialect int) UpsertBuilder {
|
func Upsert(table string, dialect int) UpsertBuilder {
|
||||||
return BobStmtBuilder.Upsert(table, dialect)
|
return BobStmtBuilder.Upsert(table, dialect)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateIndex creates an index with CreateIndexBuilder interface.
|
||||||
|
func CreateIndex(name string) IndexBuilder {
|
||||||
|
return BobStmtBuilder.CreateIndex(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateIndexIfNotExists creates an index with CreateIndexBuilder interface, if the index doesn't exists.
|
||||||
|
func CreateIndexIfNotExists(name string) IndexBuilder {
|
||||||
|
return BobStmtBuilder.CreateIndexIfNotExists(name)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
package bob
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/lann/builder"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IndexBuilder builder.Builder
|
||||||
|
|
||||||
|
type indexData struct {
|
||||||
|
Unique bool
|
||||||
|
Spatial bool
|
||||||
|
Fulltext bool
|
||||||
|
Name string
|
||||||
|
TableName string
|
||||||
|
Columns []IndexColumn
|
||||||
|
IfNotExists bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type IndexColumn struct {
|
||||||
|
Name string
|
||||||
|
Extras []string
|
||||||
|
Collate string
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
builder.Register(IndexBuilder{}, indexData{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IndexBuilder) Unique() IndexBuilder {
|
||||||
|
return builder.Set(i, "Unique", true).(IndexBuilder)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IndexBuilder) Spatial() IndexBuilder {
|
||||||
|
return builder.Set(i, "Spatial", true).(IndexBuilder)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IndexBuilder) Fulltext() IndexBuilder {
|
||||||
|
return builder.Set(i, "Fulltext", true).(IndexBuilder)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IndexBuilder) name(name string) IndexBuilder {
|
||||||
|
return builder.Set(i, "Name", name).(IndexBuilder)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IndexBuilder) ifNotExists() IndexBuilder {
|
||||||
|
return builder.Set(i, "IfNotExists", true).(IndexBuilder)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IndexBuilder) On(table string) IndexBuilder {
|
||||||
|
return builder.Set(i, "TableName", table).(IndexBuilder)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IndexBuilder) Columns(column IndexColumn) IndexBuilder {
|
||||||
|
return builder.Append(i, "Columns", column).(IndexBuilder)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IndexBuilder) ToSql() (string, []interface{}, error) {
|
||||||
|
data := builder.GetStruct(i).(indexData)
|
||||||
|
return data.ToSql()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *indexData) ToSql() (sqlStr string, args []interface{}, err error) {
|
||||||
|
if i.Name == "" {
|
||||||
|
err = errors.New("index name is required on create index statement")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if i.TableName == "" {
|
||||||
|
err = errors.New("a table name must be specified on create index statement")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(i.Columns) == 0 {
|
||||||
|
err = errors.New("should at least specify one column for create index statement")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var sql strings.Builder
|
||||||
|
|
||||||
|
sql.WriteString("CREATE ")
|
||||||
|
|
||||||
|
if i.Unique {
|
||||||
|
sql.WriteString("UNIQUE ")
|
||||||
|
}
|
||||||
|
|
||||||
|
if i.Fulltext {
|
||||||
|
sql.WriteString("FULLTEXT ")
|
||||||
|
}
|
||||||
|
|
||||||
|
if i.Spatial {
|
||||||
|
sql.WriteString("SPATIAL ")
|
||||||
|
}
|
||||||
|
|
||||||
|
sql.WriteString("INDEX ")
|
||||||
|
|
||||||
|
if i.IfNotExists {
|
||||||
|
sql.WriteString("IF NOT EXISTS ")
|
||||||
|
}
|
||||||
|
|
||||||
|
sql.WriteString(i.Name + " ")
|
||||||
|
|
||||||
|
sql.WriteString("ON ")
|
||||||
|
|
||||||
|
sql.WriteString(i.TableName + " ")
|
||||||
|
|
||||||
|
var columns []string
|
||||||
|
for _, column := range i.Columns {
|
||||||
|
var colBuilder strings.Builder
|
||||||
|
colBuilder.WriteString(column.Name)
|
||||||
|
if column.Collate != "" {
|
||||||
|
colBuilder.WriteString(" COLLATE " + column.Collate)
|
||||||
|
}
|
||||||
|
if len(column.Extras) > 0 {
|
||||||
|
colBuilder.WriteString(" " + strings.Join(column.Extras, " "))
|
||||||
|
}
|
||||||
|
columns = append(columns, colBuilder.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
sql.WriteString("(")
|
||||||
|
sql.WriteString(strings.Join(columns, ", "))
|
||||||
|
sql.WriteString(");")
|
||||||
|
|
||||||
|
sqlStr = sql.String()
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
package bob_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/aldy505/bob"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCreateIndex(t *testing.T) {
|
||||||
|
sql, _, err := bob.
|
||||||
|
CreateIndexIfNotExists("email_idx").
|
||||||
|
On("users").
|
||||||
|
Unique().
|
||||||
|
Spatial().
|
||||||
|
Fulltext().
|
||||||
|
Columns(bob.IndexColumn{Name: "email"}).
|
||||||
|
ToSql()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
result := "CREATE UNIQUE FULLTEXT SPATIAL INDEX IF NOT EXISTS email_idx ON users (email);"
|
||||||
|
if sql != result {
|
||||||
|
t.Fatal("sql is not equal to result:", sql)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateIndex_Simple(t *testing.T) {
|
||||||
|
sql, _, err := bob.
|
||||||
|
CreateIndex("idx_email").
|
||||||
|
On("users").
|
||||||
|
Columns(bob.IndexColumn{Name: "email", Collate: "DEFAULT", Extras: []string{"ASC"}}).
|
||||||
|
Columns(bob.IndexColumn{Name: "name", Extras: []string{"DESC"}}).
|
||||||
|
ToSql()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
result := "CREATE INDEX idx_email ON users (email COLLATE DEFAULT ASC, name DESC);"
|
||||||
|
if sql != result {
|
||||||
|
t.Fatal("sql is not equal to result:", sql)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateIndex_Error(t *testing.T) {
|
||||||
|
t.Run("without index", func(t *testing.T) {
|
||||||
|
_, _, err := bob.
|
||||||
|
CreateIndex("").
|
||||||
|
On("users").
|
||||||
|
Columns(bob.IndexColumn{Name: "email", Collate: "DEFAULT", Extras: []string{"ASC"}}).
|
||||||
|
Columns(bob.IndexColumn{Name: "name", Extras: []string{"DESC"}}).
|
||||||
|
ToSql()
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("error is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err.Error() != "index name is required on create index statement" {
|
||||||
|
t.Fatal("error is not equal to result:", err.Error())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("without table name", func(t *testing.T) {
|
||||||
|
_, _, err := bob.
|
||||||
|
CreateIndex("name").
|
||||||
|
On("").
|
||||||
|
Columns(bob.IndexColumn{Name: "email", Collate: "DEFAULT", Extras: []string{"ASC"}}).
|
||||||
|
Columns(bob.IndexColumn{Name: "name", Extras: []string{"DESC"}}).
|
||||||
|
ToSql()
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("error is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err.Error() != "a table name must be specified on create index statement" {
|
||||||
|
t.Fatal("error is not equal to result:", err.Error())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("without columns", func(t *testing.T) {
|
||||||
|
_, _, err := bob.
|
||||||
|
CreateIndex("name").
|
||||||
|
On("users").
|
||||||
|
ToSql()
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("error is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err.Error() != "should at least specify one column for create index statement" {
|
||||||
|
t.Fatal("error is not equal to result:", err.Error())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
package bob_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/aldy505/bob"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCreateTable(t *testing.T) {
|
||||||
|
sql, _, err := bob.
|
||||||
|
CreateTable("users").
|
||||||
|
UUIDColumn("uuid").
|
||||||
|
StringColumn("string").
|
||||||
|
TextColumn("text").
|
||||||
|
DateColumn("date").
|
||||||
|
BooleanColumn("boolean").
|
||||||
|
IntegerColumn("integer").
|
||||||
|
IntColumn("int").
|
||||||
|
TimeStampColumn("timestamp").
|
||||||
|
TimeColumn("time").
|
||||||
|
DateColumn("date").
|
||||||
|
DateTimeColumn("datetime").
|
||||||
|
JSONColumn("json").
|
||||||
|
JSONBColumn("jsonb").
|
||||||
|
BlobColumn("blob").
|
||||||
|
RealColumn("real").
|
||||||
|
FloatColumn("float").
|
||||||
|
AddColumn(bob.ColumnDef{Name: "custom", Type: "custom"}).
|
||||||
|
ToSql()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
result := "CREATE TABLE \"users\" (\"uuid\" UUID, \"string\" VARCHAR(255), \"text\" TEXT, \"date\" DATE, \"boolean\" BOOLEAN, \"integer\" INTEGER, \"int\" INT, \"timestamp\" TIMESTAMP, \"time\" TIME, \"date\" DATE, \"datetime\" DATETIME, \"json\" JSON, \"jsonb\" JSONB, \"blob\" BLOB, \"real\" REAL, \"float\" FLOAT, \"custom\" custom);"
|
||||||
|
if sql != result {
|
||||||
|
t.Fatal("sql is not equal to result:", sql)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateTable_Extras(t *testing.T) {
|
||||||
|
sql, _, err := bob.CreateTable("users").
|
||||||
|
UUIDColumn("id", "PRIMARY KEY").
|
||||||
|
StringColumn("email", "NOT NULL", "UNIQUE").
|
||||||
|
ToSql()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
result := "CREATE TABLE \"users\" (\"id\" UUID PRIMARY KEY, \"email\" VARCHAR(255) NOT NULL UNIQUE);"
|
||||||
|
if sql != result {
|
||||||
|
t.Fatal("sql is not equal to result:", sql)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateTable_Schema(t *testing.T) {
|
||||||
|
sql, _, err := bob.
|
||||||
|
CreateTable("users").
|
||||||
|
WithSchema("private").
|
||||||
|
StringColumn("name").
|
||||||
|
ToSql()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
result := "CREATE TABLE \"private\".\"users\" (\"name\" VARCHAR(255));"
|
||||||
|
if sql != result {
|
||||||
|
t.Fatal("sql is not equal to result:", sql)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateTable_Error(t *testing.T) {
|
||||||
|
t.Run("should emit error on empty table name", func(t *testing.T) {
|
||||||
|
_, _, err := bob.
|
||||||
|
CreateTable("").
|
||||||
|
StringColumn("name").
|
||||||
|
ToSql()
|
||||||
|
if err.Error() != "create statements must specify a table" {
|
||||||
|
t.Fatal("should throw an error, it didn't:", err.Error())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should emit error if no column were specified", func(t *testing.T) {
|
||||||
|
_, _, err := bob.
|
||||||
|
CreateTable("users").
|
||||||
|
ToSql()
|
||||||
|
if err.Error() != "a table should at least have one column" {
|
||||||
|
t.Fatal("should throw an error, it didn't:", err.Error())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateTable_IfNotExists(t *testing.T) {
|
||||||
|
sql, _, err := bob.
|
||||||
|
CreateTableIfNotExists("users").
|
||||||
|
TextColumn("name").
|
||||||
|
ToSql()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
result := "CREATE TABLE IF NOT EXISTS \"users\" (\"name\" TEXT);"
|
||||||
|
if sql != result {
|
||||||
|
t.Fatal("sql is not equal to result: ", sql)
|
||||||
|
}
|
||||||
|
}
|
102
create_test.go
102
create_test.go
|
@ -1,102 +0,0 @@
|
||||||
package bob_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/aldy505/bob"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCreate(t *testing.T) {
|
|
||||||
t.Run("should return correct sql string with all columns and types", func(t *testing.T) {
|
|
||||||
sql, _, err := bob.
|
|
||||||
CreateTable("users").
|
|
||||||
UUIDColumn("uuid").
|
|
||||||
StringColumn("string").
|
|
||||||
TextColumn("text").
|
|
||||||
DateColumn("date").
|
|
||||||
BooleanColumn("boolean").
|
|
||||||
IntegerColumn("integer").
|
|
||||||
IntColumn("int").
|
|
||||||
TimeStampColumn("timestamp").
|
|
||||||
TimeColumn("time").
|
|
||||||
DateColumn("date").
|
|
||||||
DateTimeColumn("datetime").
|
|
||||||
JSONColumn("json").
|
|
||||||
JSONBColumn("jsonb").
|
|
||||||
BlobColumn("blob").
|
|
||||||
RealColumn("real").
|
|
||||||
FloatColumn("float").
|
|
||||||
AddColumn(bob.ColumnDef{Name: "custom", Type: "custom"}).
|
|
||||||
ToSql()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err.Error())
|
|
||||||
}
|
|
||||||
result := "CREATE TABLE \"users\" (\"uuid\" UUID, \"string\" VARCHAR(255), \"text\" TEXT, \"date\" DATE, \"boolean\" BOOLEAN, \"integer\" INTEGER, \"int\" INT, \"timestamp\" TIMESTAMP, \"time\" TIME, \"date\" DATE, \"datetime\" DATETIME, \"json\" JSON, \"jsonb\" JSONB, \"blob\" BLOB, \"real\" REAL, \"float\" FLOAT, \"custom\" custom);"
|
|
||||||
if sql != result {
|
|
||||||
t.Fatal("sql is not equal to result:", sql)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("should return correct sql with extras", func(t *testing.T) {
|
|
||||||
sql, _, err := bob.CreateTable("users").
|
|
||||||
UUIDColumn("id", "PRIMARY KEY").
|
|
||||||
StringColumn("email", "NOT NULL", "UNIQUE").
|
|
||||||
ToSql()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err.Error())
|
|
||||||
}
|
|
||||||
result := "CREATE TABLE \"users\" (\"id\" UUID PRIMARY KEY, \"email\" VARCHAR(255) NOT NULL UNIQUE);"
|
|
||||||
if sql != result {
|
|
||||||
t.Fatal("sql is not equal to result:", sql)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("should be able to have a schema name", func(t *testing.T) {
|
|
||||||
sql, _, err := bob.
|
|
||||||
CreateTable("users").
|
|
||||||
WithSchema("private").
|
|
||||||
StringColumn("name").
|
|
||||||
ToSql()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err.Error())
|
|
||||||
}
|
|
||||||
result := "CREATE TABLE \"private\".\"users\" (\"name\" VARCHAR(255));"
|
|
||||||
if sql != result {
|
|
||||||
t.Fatal("sql is not equal to result:", sql)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("should emit error on empty table name", func(t *testing.T) {
|
|
||||||
_, _, err := bob.
|
|
||||||
CreateTable("").
|
|
||||||
StringColumn("name").
|
|
||||||
ToSql()
|
|
||||||
if err.Error() != "create statements must specify a table" {
|
|
||||||
t.Fatal("should throw an error, it didn't:", err.Error())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("should emit error if no column were specified", func(t *testing.T) {
|
|
||||||
_, _, err := bob.
|
|
||||||
CreateTable("users").
|
|
||||||
ToSql()
|
|
||||||
if err.Error() != "a table should at least have one column" {
|
|
||||||
t.Fatal("should throw an error, it didn't:", err.Error())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("should emit create if not exists", func(t *testing.T) {
|
|
||||||
sql, _, err := bob.
|
|
||||||
CreateTableIfNotExists("users").
|
|
||||||
TextColumn("name").
|
|
||||||
ToSql()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err.Error())
|
|
||||||
}
|
|
||||||
result := "CREATE TABLE IF NOT EXISTS \"users\" (\"name\" TEXT);"
|
|
||||||
if sql != result {
|
|
||||||
t.Fatal("sql is not equal to result: ", sql)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
Loading…
Reference in New Issue