From 5c112c73f6b5155c36e867fc88c0261b7b0e96cb Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Sat, 26 Jun 2021 00:04:41 +0700 Subject: [PATCH] feat: added has query --- append.go | 15 ++++++++++++++- bob.go | 16 ++++++++++++++++ create_test.go | 11 +++++++++++ has.go | 51 +++++++++++++++++++++++++++++++++++++++++++++++--- has_test.go | 43 ++++++++++++++++++++++++++++++++++++++++++ placeholder.go | 17 ++++++++++++++++- 6 files changed, 148 insertions(+), 5 deletions(-) create mode 100644 has_test.go diff --git a/append.go b/append.go index dbecf34..0710745 100644 --- a/append.go +++ b/append.go @@ -2,7 +2,7 @@ package bob import "io" -func AppendToSql(parts []BobBuilder, w io.Writer, sep string, args []interface{}) ([]interface{}, error) { +func appendToSql(parts []BobBuilder, w io.Writer, sep string, args []interface{}) ([]interface{}, error) { for i, p := range parts { partSql, partArgs, err := p.ToSql() if err != nil { @@ -26,3 +26,16 @@ func AppendToSql(parts []BobBuilder, w io.Writer, sep string, args []interface{} } return args, nil } + +// createArgs should create an argument []interface{} for SQL query +// I'm using the idiot approach for creating args +func createArgs(keys ...string) []interface{} { + var args []interface{} + for _, v := range keys { + if v == "" { + continue + } + args = append(args, v) + } + return args +} diff --git a/bob.go b/bob.go index 8d4165c..804e273 100644 --- a/bob.go +++ b/bob.go @@ -12,8 +12,24 @@ func (b BobBuilderType) CreateTable(table string) CreateBuilder { return CreateBuilder(b).Name(table) } +func (b BobBuilderType) HasTable(table string) HasBuilder { + return HasBuilder(b).HasTable(table) +} + +func (b BobBuilderType) HasColumn(column string) HasBuilder { + return HasBuilder(b).HasColumn(column) +} + var BobStmtBuilder = BobBuilderType(builder.EmptyBuilder) func CreateTable(table string) CreateBuilder { return BobStmtBuilder.CreateTable(table) } + +func HasTable(table string) HasBuilder { + return BobStmtBuilder.HasTable(table) +} + +func HasColumn(col string) HasBuilder { + return BobStmtBuilder.HasColumn(col) +} diff --git a/create_test.go b/create_test.go index 2d727c8..8f48a68 100644 --- a/create_test.go +++ b/create_test.go @@ -34,6 +34,17 @@ func TestCreate(t *testing.T) { } }) + t.Run("should be able to have a schema name", func(t *testing.T) { + sql, _, err := bob.CreateTable("users").WithSchema("private").Columns("name", "password", "date").Types("varchar(255)", "text", "date").ToSql() + if err != nil { + t.Fatal(err.Error()) + } + result := "CREATE TABLE `private`.`users` (`name` varchar(255), `password` text, `date` date);" + if sql != result { + t.Fatal("sql is not equal to result:", sql) + } + }) + t.Run("should emit error on unmatched column and types length", func(t *testing.T) { _, _, err := bob.CreateTable("users"). Columns("id", "name", "email", "password", "date"). diff --git a/has.go b/has.go index 11f0b52..1e0051b 100644 --- a/has.go +++ b/has.go @@ -1,6 +1,11 @@ package bob -import "github.com/lann/builder" +import ( + "bytes" + "errors" + + "github.com/lann/builder" +) // TODO - The whole file is a todo // Meant to find two things: HasTable and HasColumn(s) @@ -9,7 +14,9 @@ type HasBuilder builder.Builder type hasData struct { Name string - Placeholder PlaceholderFormat + Column string + Schema string + Placeholder string } func init() { @@ -20,6 +27,44 @@ func (h HasBuilder) HasTable(table string) HasBuilder { return builder.Set(h, "Name", table).(HasBuilder) } -func (h HasBuilder) PlaceholderFormat(f PlaceholderFormat) HasBuilder { +func (h HasBuilder) HasColumn(column string) HasBuilder { + return builder.Set(h, "Column", column).(HasBuilder) +} + +func (h HasBuilder) WithSchema(schema string) HasBuilder { + return builder.Set(h, "Schema", schema).(HasBuilder) +} + +func (h HasBuilder) PlaceholderFormat(f string) HasBuilder { return builder.Set(h, "Placeholder", f).(HasBuilder) } + +func (h HasBuilder) ToSql() (string, []interface{}, error) { + data := builder.GetStruct(h).(hasData) + return data.ToSql() +} + +func (d *hasData) ToSql() (sqlStr string, args []interface{}, err error) { + sql := &bytes.Buffer{} + if d.Name == "" { + err = errors.New("has statement should have a table name") + return + } + + if d.Column != "" && d.Name != "" { + // search for column + sql.WriteString("SELECT * FROM information_schema.columns WHERE table_name = ? AND column_name = ?") + } else if d.Name != "" && d.Column == "" { + sql.WriteString("SELECT * FROM information_schema.tables WHERE table_name = ?") + } + + if d.Schema != "" { + sql.WriteString(" AND table_schema = ?;") + } else { + sql.WriteString(" AND table_schema = current_schema();") + } + + sqlStr = ReplacePlaceholder(sql.String(), d.Placeholder) + args = createArgs(d.Name, d.Column, d.Schema) + return +} diff --git a/has_test.go b/has_test.go new file mode 100644 index 0000000..4c4ad46 --- /dev/null +++ b/has_test.go @@ -0,0 +1,43 @@ +package bob_test + +import ( + "testing" + + "github.com/aldy505/bob" +) + +// TODO - do more test + +func TestHas(t *testing.T) { + t.Run("should be able to create a hasTable query", func(t *testing.T) { + sql, args, err := bob.HasTable("users").ToSql() + if err != nil { + t.Fatal(err.Error()) + } + + result := "SELECT * FROM information_schema.tables WHERE table_name = ? AND table_schema = current_schema();" + if sql != result { + t.Fatal("sql is not equal with result:", sql) + } + + if len(args) != 1 { + t.Fatal("args is not equal with argsResult:", args) + } + }) + + t.Run("should be able to create a hasColumn query", func(t *testing.T) { + sql, args, err := bob.HasTable("users").HasColumn("name").ToSql() + if err != nil { + t.Fatal(err.Error()) + } + + result := "SELECT * FROM information_schema.columns WHERE table_name = ? AND column_name = ? AND table_schema = current_schema();" + if sql != result { + t.Fatal("sql is not equal with result:", sql) + } + + if len(args) != 2 { + t.Fatal("args is not equal with argsResult:", args) + } + }) +} diff --git a/placeholder.go b/placeholder.go index 6e49a7f..dd45abc 100644 --- a/placeholder.go +++ b/placeholder.go @@ -1,7 +1,22 @@ package bob -// TODO +import "strings" + +const ( + Question = "?" + Dollar = "$" + Colon = ":" + AtP = "@p" +) type PlaceholderFormat interface { ReplacePlaceholders(sql string) (string, error) } + +// TODO - test this one +func ReplacePlaceholder(sql string, format string) string { + if format == "" { + format = Question + } + return strings.ReplaceAll(sql, "?", format) +}