From 6f79141593041a82284d8ad3f488aff1e487aae5 Mon Sep 17 00:00:00 2001 From: Mesut GENEZ Date: Fri, 18 Oct 2024 12:01:39 +0300 Subject: [PATCH] git commit -m "feat: Add query reset support, reflection-based string reset, and sanitize SQL values - Implemented query reset using reflection. - Refactored ToSql to auto-reset state. - Fixed addWhereClause formatting. - Removed placeholders in between and IN clauses for cross-db compatibility. - Secured Insert method with value sanitization. - Added tests for Insert and between clauses." --- README.md | 46 +++---- builder.go | 313 +++++++++++++++++++++++++++++------------------- builder_test.go | 106 ++++++---------- example/main.go | 52 ++++---- go.mod | 2 - go.sum | 2 - 6 files changed, 279 insertions(+), 242 deletions(-) diff --git a/README.md b/README.md index e6f00aa..2072b37 100644 --- a/README.md +++ b/README.md @@ -12,20 +12,20 @@ var gb GoBuilder ```go // all columns -gb.Select("users").Where("id","=","1").ToSql() +gb.Table("users").Select().Where("id","=","1").ToSql() // filter columns -gb.Select("users", "firstname", "lastname", "create_date"). - Where("id", "=", "1"). +gb.Table("users").Select("firstname", "lastname", "created_at"). + Where("id", "=", 1). ToSql() ``` ```sql Result: SELECT * FROM users WHERE id = '1' -Result: SELECT firstname,lastname,create_date FROM users WHERE id = '1' +Result: SELECT firstname,lastname,created_at FROM users WHERE id = 1 ``` ### where orWhere ```go -gb.Select("users"). +gb.Table("users").Select(). Where("id", "=", "1"). OrWhere("email", "=", "loremipsum@lrmpsm.com"). ToSql() @@ -35,7 +35,7 @@ Result: SELECT * FROM users WHERE id='1' OR email='loremipsum@lrmpsm.com' ``` ### join ```go -gb.Select("users as u", "u.firstname", "u.lastname", "a.address"). +gb.Table("users as u").Select("u.firstname", "u.lastname", "a.address"). Join("INNER", "address as a", "a.user_id=u.id"). Where("u.email", "=", "loremipsum@lrmpsm.com"). ToSql() @@ -45,52 +45,52 @@ Result: SELECT u.firstname,u.lastname,a.address FROM users as u INNER JOIN addre ``` ### between ```go -gb.Select("users"). +gb.Table("users").Select(). Where("id", "=", "1"). - Between("create_date", "2021-01-01", "2021-03-16"). + Between("created_at", "2021-01-01", "2021-03-16"). ToSql() ``` ```sql -Result: SELECT * FROM users WHERE id='1' AND create_date BETWEEN '2021-01-01' AND '2021-03-16' +Result: SELECT * FROM users WHERE id='1' AND created_at BETWEEN '2021-01-01' AND '2021-03-16' ``` ### limit ```go -gb.Select("users"). +gb.Table("users").Select(). Where("id", "=", "1"). - Between("create_date", "2021-01-01", "2021-03-16"). + Between("created_at", "2021-01-01", "2021-03-16"). Limit(1, 5). ToSql() ``` ```sql -Result: SELECT * FROM users WHERE id='1' AND create_date BETWEEN '2021-01-01' AND '2021-03-16' LIMIT 1,5 +Result: SELECT * FROM users WHERE id='1' AND created_at BETWEEN '2021-01-01' AND '2021-03-16' LIMIT 1,5 ``` ### group by ```go -gb.Select("users"). +gb.Table("users").Select(). Where("id", "=", "1"). - Between("create_date", "2021-01-01", "2021-03-16"). + Between("created_at", "2021-01-01", "2021-03-16"). GroupBy("lastname"). ToSql() ``` ```sql -Result: SELECT * FROM users WHERE id='1' AND create_date BETWEEN '2021-01-01' AND '2021-03-16' GROUP BY lastname +Result: SELECT * FROM users WHERE id='1' AND created_at BETWEEN '2021-01-01' AND '2021-03-16' GROUP BY lastname ``` ### order by ```go -gb.Select("users"). +gb.Table("users").Select(). Where("id", "=", "1"). - Between("create_date", "2021-01-01", "2021-03-16"). + Between("created_at", "2021-01-01", "2021-03-16"). GroupBy("lastname"). OrderBy("id", "DESC"). ToSql() ``` ```sql -Result: SELECT * FROM users WHERE id='1' AND create_date BETWEEN '2021-01-01' AND '2021-03-16' GROUP BY lastname ORDER BY id DESC +Result: SELECT * FROM users WHERE id='1' AND created_at BETWEEN '2021-01-01' AND '2021-03-16' GROUP BY lastname ORDER BY id DESC ``` ### union ```go -s1 := gb.Select("users").Where("lastname", "=", "lorem").ToSql() -s2 := gb.Select("users").Where("lastname", "=", "ipsum").Union(s1).ToSql() +s1 := gb.Table("users").Select().Where("lastname", "=", "lorem").ToSql() +s2 := gb.Table("users").Select().Where("lastname", "=", "ipsum").Union(s1).ToSql() ``` ```sql Result: SELECT * FROM users WHERE lastname='ipsum' UNION SELECT * FROM users WHERE lastname='lorem' @@ -102,7 +102,7 @@ args := map[string]string{ "firstname": "Lorem", "lastname": "IPSUM", } -gb.Insert("users", args).ToSql() +gb.Table("users").Insert(args).ToSql() ``` ```sql Result : INSERT INTO users (lastname,firstname) VALUES ('Lorem','IPSUM') @@ -114,7 +114,7 @@ args := map[string]string{ "firstname": "Lorem", "lastname": "IPSUM", } -gb.Update("users", args).Where("email", "=", "loremipsum@lrmpsm.com").ToSql() +gb.Table("users").Update(args).Where("email", "=", "loremipsum@lrmpsm.com").ToSql() ``` ```sql Result: UPDATE users SET firstname='Lorem', lastname='IPSUM' WHERE email='loremipsum@lrmpsm.com' @@ -122,7 +122,7 @@ Result: UPDATE users SET firstname='Lorem', lastname='IPSUM' WHERE email='loremi ## Delete ```go -gb.Delete("users").Where("email", "=", "loremipsum@lrmpsm.com").ToSql() +gb.Table("users").Delete().Where("email", "=", "loremipsum@lrmpsm.com").ToSql() ``` ```sql Result: DELETE FROM users WHERE email='loremipsum@lrmpsm.com' diff --git a/builder.go b/builder.go index e2c3eb6..77cbed7 100644 --- a/builder.go +++ b/builder.go @@ -2,230 +2,301 @@ package gobuilder import ( "fmt" + "reflect" + "regexp" "strings" +) - "golang.org/x/exp/maps" +const ( + InnerJoin = "INNER" + LeftJoin = "LEFT" + RightJoin = "RIGHT" + FullJoin = "FULL" ) type GoBuilder struct { - sql string + TableClause string + SelectClause string + WhereClause string + JoinClause string + GroupByClause string + HavingClause string + OrderByClause string + LimitClause string + UnionClause string +} + +// NewGoBuilder initializes a new instance of GoBuilder +func NewGoBuilder() *GoBuilder { + return &GoBuilder{} } -func (gb *GoBuilder) Select(table string, columns ...string) *GoBuilder { +// Table specifies the table name for the query +func (gb *GoBuilder) Table(table string) *GoBuilder { + gb.TableClause = table + return gb +} + +// Select defines the columns to be selected in the query +func (gb *GoBuilder) Select(columns ...string) *GoBuilder { if len(columns) == 0 { columns = append(columns, "*") } - gb.sql = fmt.Sprintf("SELECT %v FROM %v", strings.Join(columns, ", "), table) + gb.SelectClause = fmt.Sprintf("SELECT %s FROM %s", strings.Join(columns, ", "), gb.TableClause) return gb } -func (gb *GoBuilder) SelectDistinct(table string, columns ...string) *GoBuilder { +// SelectDistinct defines the distinct columns to be selected +func (gb *GoBuilder) SelectDistinct(columns ...string) *GoBuilder { if len(columns) == 0 { columns = append(columns, "*") } - gb.sql = fmt.Sprintf("SELECT DISTINCT %v FROM %v", strings.Join(columns, ", "), table) + gb.SelectClause = fmt.Sprintf("SELECT DISTINCT %s FROM %s", strings.Join(columns, ", "), gb.TableClause) return gb } -func (gb *GoBuilder) Insert(table string, args map[string]any) *GoBuilder { +// Insert adds an INSERT INTO statement to the query with bind parameters +func (gb *GoBuilder) Insert(args map[string]any) *GoBuilder { if len(args) != 0 { - keys := maps.Keys(args) - var values []string - for _, v := range maps.Values(args) { - values = append(values, fmt.Sprintf("'%v'", v)) + keys := make([]string, 0, len(args)) + values := make([]string, 0, len(args)) + + for key, value := range args { + cleanedValue := cleanValue(value) + keys = append(keys, key) + values = append(values, cleanedValue) } - gb.sql = fmt.Sprintf("INSERT INTO %v (%v) VALUES (%v)", table, strings.Join(keys, ", "), strings.Join(values, ", ")) + + gb.SelectClause = fmt.Sprintf("INSERT INTO %s (%v) VALUES (%v)", gb.TableClause, strings.Join(keys, ", "), strings.Join(values, ", ")) } return gb } -func (gb *GoBuilder) Update(table string, args map[string]any) *GoBuilder { +// Update builds an UPDATE statement with bind parameters +func (gb *GoBuilder) Update(args map[string]any) *GoBuilder { if len(args) != 0 { - var setClauses []string + setClauses := make([]string, 0, len(args)) + for key, value := range args { - setClauses = append(setClauses, fmt.Sprintf("%v = '%v'", key, value)) + setClauses = append(setClauses, fmt.Sprintf("%s = %v", key, cleanValue(value))) } - gb.sql = fmt.Sprintf("UPDATE %v SET %v", table, strings.Join(setClauses, ", ")) + + gb.SelectClause = fmt.Sprintf("UPDATE %s SET %v", gb.TableClause, strings.Join(setClauses, ", ")) } return gb } -func (gb *GoBuilder) Delete(table string) *GoBuilder { - gb.sql = fmt.Sprintf("DELETE FROM %v", table) +// Delete builds a DELETE statement +func (gb *GoBuilder) Delete() *GoBuilder { + gb.SelectClause = fmt.Sprintf("DELETE FROM %v", gb.TableClause) return gb } +// Where adds a WHERE clause with bind parameters func (gb *GoBuilder) Where(key, opt string, val any) *GoBuilder { - return gb.where("AND", key, opt, val) + return gb.addWhereClause("AND", key, opt, val) } +// OrWhere adds an OR WHERE clause with bind parameters func (gb *GoBuilder) OrWhere(key, opt string, val any) *GoBuilder { - return gb.where("OR", key, opt, val) -} - -func (gb *GoBuilder) where(OP, key, opt string, val any) *GoBuilder { - var clause string - - switch v := val.(type) { - case int, int64, float32, float64: - clause = fmt.Sprintf("%v %v %v", key, opt, v) - case *GoBuilder: - clause = fmt.Sprintf("%v %v (%v)", key, opt, v.ToSql()) - default: - clause = fmt.Sprintf("%v %v '%v'", key, opt, v) - } - - if strings.Contains(gb.sql, "WHERE") { - gb.sql = fmt.Sprintf("%v %v %v", gb.sql, OP, clause) - } else { - gb.sql = fmt.Sprintf("%v WHERE %v", gb.sql, clause) - } - return gb + return gb.addWhereClause("OR", key, opt, val) } +// In adds an IN clause with bind parameters func (gb *GoBuilder) In(column string, args ...any) *GoBuilder { - return gb.in("AND", column, args...) + return gb.addInClause("AND", column, args...) } +// OrIn adds an OR IN clause with bind parameters func (gb *GoBuilder) OrIn(column string, args ...any) *GoBuilder { - return gb.in("OR", column, args...) -} - -func (gb *GoBuilder) in(OP, column string, args ...any) *GoBuilder { - if len(args) > 0 { - var values []string - for _, arg := range args { - switch v := arg.(type) { - case int, int64, float32, float64: - values = append(values, fmt.Sprintf("%v", v)) - default: - values = append(values, fmt.Sprintf("'%v'", v)) - } - } - clause := fmt.Sprintf("%v IN (%v)", column, strings.Join(values, ", ")) - if strings.Contains(gb.sql, "WHERE") { - gb.sql = fmt.Sprintf("%v %v %v", gb.sql, OP, clause) - } else { - gb.sql = fmt.Sprintf("%v WHERE %v", gb.sql, clause) - } - } - return gb + return gb.addInClause("OR", column, args...) } +// Between adds a BETWEEN clause with bind parameters func (gb *GoBuilder) Between(column string, args ...any) *GoBuilder { return gb.between("AND", column, args...) } +// OrBetween adds an OR BETWEEN clause with bind parameters func (gb *GoBuilder) OrBetween(column string, args ...any) *GoBuilder { return gb.between("OR", column, args...) } -func (gb *GoBuilder) between(OP, column string, args ...any) *GoBuilder { - if len(args) == 2 { - var clause string - switch args[0].(type) { - case int, int64, float32, float64: - clause = fmt.Sprintf("%v BETWEEN %v AND %v", column, args[0], args[1]) - default: - clause = fmt.Sprintf("%v BETWEEN '%v' AND '%v'", column, args[0], args[1]) - } - if strings.Contains(gb.sql, "WHERE") { - gb.sql = fmt.Sprintf("%v %v %v", gb.sql, OP, clause) - } else { - gb.sql = fmt.Sprintf("%v WHERE %v", gb.sql, clause) - } - } - return gb -} - +// IsNull adds an IS NULL clause func (gb *GoBuilder) IsNull(column string) *GoBuilder { - clause := fmt.Sprintf("%v IS NULL", column) - if strings.Contains(gb.sql, "WHERE") { - gb.sql = fmt.Sprintf("%v AND %v", gb.sql, clause) - } else { - gb.sql = fmt.Sprintf("%v WHERE %v", gb.sql, clause) - } + clause := fmt.Sprintf("%s IS NULL", column) + gb.addClause("AND", clause) return gb } +// OrIsNull adds an OR IS NULL clause func (gb *GoBuilder) OrIsNull(column string) *GoBuilder { - clause := fmt.Sprintf("%v IS NULL", column) - if strings.Contains(gb.sql, "WHERE") { - gb.sql = fmt.Sprintf("%v OR %v", gb.sql, clause) - } else { - gb.sql = fmt.Sprintf("%v WHERE %v", gb.sql, clause) - } + clause := fmt.Sprintf("%s IS NULL", column) + gb.addClause("OR", clause) return gb } +// IsNotNull adds an IS NOT NULL clause func (gb *GoBuilder) IsNotNull(column string) *GoBuilder { - clause := fmt.Sprintf("%v IS NOT NULL", column) - if strings.Contains(gb.sql, "WHERE") { - gb.sql = fmt.Sprintf("%v AND %v", gb.sql, clause) - } else { - gb.sql = fmt.Sprintf("%v WHERE %v", gb.sql, clause) - } + clause := fmt.Sprintf("%s IS NOT NULL", column) + gb.addClause("AND", clause) return gb } +// OrIsNotNull adds an OR IS NOT NULL clause func (gb *GoBuilder) OrIsNotNull(column string) *GoBuilder { - clause := fmt.Sprintf("%v IS NOT NULL", column) - if strings.Contains(gb.sql, "WHERE") { - gb.sql = fmt.Sprintf("%v OR %v", gb.sql, clause) - } else { - gb.sql = fmt.Sprintf("%v WHERE %v", gb.sql, clause) - } + clause := fmt.Sprintf("%s IS NOT NULL", column) + gb.addClause("OR", clause) return gb } +// Having adds a HAVING clause func (gb *GoBuilder) Having(condition string) *GoBuilder { - if strings.Contains(gb.sql, "HAVING") { - gb.sql = fmt.Sprintf("%v AND %v", gb.sql, condition) - } else { - gb.sql = fmt.Sprintf("%v HAVING %v", gb.sql, condition) - } + gb.HavingClause = fmt.Sprintf("HAVING %s", condition) return gb } +// OrHaving adds an OR HAVING clause func (gb *GoBuilder) OrHaving(condition string) *GoBuilder { - if strings.Contains(gb.sql, "HAVING") { - gb.sql = fmt.Sprintf("%v OR %v", gb.sql, condition) + if gb.HavingClause != "" { + gb.HavingClause = fmt.Sprintf("%s OR %s", gb.HavingClause, condition) } else { - gb.sql = fmt.Sprintf("%v HAVING %v", gb.sql, condition) + gb.HavingClause = fmt.Sprintf("HAVING %s", condition) } return gb } -func (gb *GoBuilder) Join(joinType, table, onCondition string) *GoBuilder { - gb.sql = fmt.Sprintf("%v %v JOIN %v ON %v", gb.sql, joinType, table, onCondition) +// Join adds a JOIN clause +func (gb *GoBuilder) Join(joinType, table, condition string) *GoBuilder { + gb.JoinClause = fmt.Sprintf("%s JOIN %s ON %s", joinType, table, condition) return gb } +// Limit adds a LIMIT clause func (gb *GoBuilder) Limit(start, limit int) *GoBuilder { - gb.sql = fmt.Sprintf("%v LIMIT %v, %v", gb.sql, start, limit) + gb.LimitClause = fmt.Sprintf("LIMIT %d, %d", start, limit) return gb } +// GroupBy adds a GROUP BY clause func (gb *GoBuilder) GroupBy(columns ...string) *GoBuilder { - gb.sql = fmt.Sprintf("%v GROUP BY %v", gb.sql, strings.Join(columns, ", ")) + gb.GroupByClause = fmt.Sprintf("GROUP BY %v", strings.Join(columns, ", ")) return gb } +// OrderBy adds an ORDER BY ASC clause func (gb *GoBuilder) OrderBy(columns ...string) *GoBuilder { - gb.sql = fmt.Sprintf("%v ORDER BY %v ASC", gb.sql, strings.Join(columns, ", ")) + gb.OrderByClause = fmt.Sprintf("ORDER BY %v ASC", strings.Join(columns, ", ")) return gb } +// OrderByDesc adds an ORDER BY DESC clause func (gb *GoBuilder) OrderByDesc(columns ...string) *GoBuilder { - gb.sql = fmt.Sprintf("%v ORDER BY %v DESC", gb.sql, strings.Join(columns, ", ")) + gb.OrderByClause = fmt.Sprintf("ORDER BY %v DESC", strings.Join(columns, ", ")) return gb } +// Union adds a UNION clause func (gb *GoBuilder) Union(sql string) *GoBuilder { - gb.sql = fmt.Sprintf("%v UNION %v", gb.sql, sql) + if gb.UnionClause == "" { + gb.UnionClause = fmt.Sprintf("UNION %v", sql) + } else { + gb.UnionClause = fmt.Sprintf("%v UNION %v", gb.UnionClause, sql) + } return gb } +// ToSql returns the final SQL query and the associated bind parameters func (gb *GoBuilder) ToSql() string { - return gb.sql + clauses := []string{ + gb.SelectClause, + gb.JoinClause, + gb.WhereClause, + gb.GroupByClause, + gb.HavingClause, + gb.OrderByClause, + gb.LimitClause, + gb.UnionClause, + } + query := strings.Join(clauses, " ") + re := regexp.MustCompile(`\s+`) + gb.reset() + return strings.TrimSpace(re.ReplaceAllString(query, " ")) +} + +// Private method to RESET builder +func (gb *GoBuilder) reset() { + v := reflect.ValueOf(gb).Elem() + for i := 0; i < v.NumField(); i++ { + field := v.Field(i) + if field.Kind() == reflect.String { + field.SetString("") + } + } +} + +// Private method to add WHERE or OR WHERE clauses with bind parameters +func (gb *GoBuilder) addWhereClause(OP, key, opt string, val any) *GoBuilder { + clause := "" + switch v := val.(type) { + case *GoBuilder: + clause = fmt.Sprintf("%v %v (%v)", key, opt, v.ToSql()) + default: + clause = fmt.Sprintf("%v %v %v", key, opt, cleanValue(val)) + } + gb.addClause(OP, clause) + return gb +} + +// Private method to add clauses with logical operators +func (gb *GoBuilder) addClause(OP, clause string) { + if gb.WhereClause != "" { + gb.WhereClause = fmt.Sprintf("%v %v %v", gb.WhereClause, OP, clause) + } else { + gb.WhereClause = fmt.Sprintf("WHERE %v", clause) + } +} + +// Private method to add IN clauses with values directly +func (gb *GoBuilder) addInClause(OP, column string, args ...any) *GoBuilder { + if len(args) > 0 { + values := make([]string, len(args)) + for i, arg := range args { + switch v := arg.(type) { + case string: + values[i] = fmt.Sprintf("%v", cleanValue(v)) + default: + values[i] = fmt.Sprintf("%d", v) + } + } + clause := fmt.Sprintf("%v IN (%v)", column, strings.Join(values, ", ")) + gb.addClause(OP, clause) + } + return gb +} + +// Private method to add BETWEEN clauses with values directly +func (gb *GoBuilder) between(OP, column string, args ...any) *GoBuilder { + if len(args) == 2 { + var clause string + switch args[0].(type) { + case string: + clause = fmt.Sprintf("%v BETWEEN %s AND %s", column, cleanValue(fmt.Sprintf("%v", args[0])), cleanValue(fmt.Sprintf("%v", args[1]))) + default: + clause = fmt.Sprintf("%v BETWEEN %v AND %v", column, args[0], args[1]) + } + gb.addClause(OP, clause) + } + return gb +} + +// cleanValue trims and escapes potentially harmful characters from the value +func cleanValue(value any) string { + switch v := value.(type) { + case string: + cleaned := strings.ReplaceAll(v, "'", "''") + return "'" + cleaned + "'" + default: + return fmt.Sprintf("%v", v) + } } diff --git a/builder_test.go b/builder_test.go index a5ea1d1..609bc43 100644 --- a/builder_test.go +++ b/builder_test.go @@ -12,18 +12,16 @@ var ( ) func TestSql_Select(t *testing.T) { - s.sql = "" expected = "SELECT * FROM users" - got = s.Select("users").ToSql() + got = s.Table("users").Select().ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) } } func TestSql_Select_With_Columns(t *testing.T) { - s.sql = "" expected = "SELECT firstname, lastname FROM users" - got = s.Select("users", "firstname", "lastname").ToSql() + got = s.Table("users").Select("firstname", "lastname").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) } @@ -31,44 +29,40 @@ func TestSql_Select_With_Columns(t *testing.T) { func TestSql_Distinct(t *testing.T) { expected = "SELECT DISTINCT name, age FROM users" - got = s.SelectDistinct("users", "name", "age").ToSql() + got = s.Table("users").SelectDistinct("name", "age").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) } } func TestSql_Insert(t *testing.T) { - s.sql = "" insert := map[string]any{"firstname": "Mesut", "lastname": "GENEZ"} expected = "INSERT INTO users (firstname, lastname) VALUES ('Mesut', 'GENEZ')" - got = s.Insert("users", insert).ToSql() + got = s.Table("users").Insert(insert).ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) } } func TestSql_Update(t *testing.T) { - s.sql = "" // sometimes it may not pass the test because the map is unordered expected = "UPDATE users SET firstname = 'Mesut', lastname = 'GENEZ'" - got = s.Update("users", map[string]any{"firstname": "Mesut", "lastname": "GENEZ"}).ToSql() + got = s.Table("users").Update(map[string]any{"firstname": "Mesut", "lastname": "GENEZ"}).ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) } } func TestSql_Delete(t *testing.T) { - s.sql = "" expected = "DELETE FROM users" - got = s.Delete("users").ToSql() + got = s.Table("users").Delete().ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) } } func TestSql_Where(t *testing.T) { - s.sql = "" - expected = " WHERE firstname = 'Mesut'" + expected = "WHERE firstname = 'Mesut'" got = s.Where("firstname", "=", "Mesut").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -76,8 +70,7 @@ func TestSql_Where(t *testing.T) { } func TestSql_WhereWithInt(t *testing.T) { - s.sql = "" - expected = " WHERE id = 55" + expected = "WHERE id = 55" got = s.Where("id", "=", 55).ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -85,8 +78,7 @@ func TestSql_WhereWithInt(t *testing.T) { } func TestSql_WhereWithFloat(t *testing.T) { - s.sql = "" - expected = " WHERE amount = 55.5" + expected = "WHERE amount = 55.5" got = s.Where("amount", "=", 55.5).ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -94,8 +86,7 @@ func TestSql_WhereWithFloat(t *testing.T) { } func TestSql_Where_With_And(t *testing.T) { - s.sql = "" - expected = " WHERE firstname = 'Mesut' AND lastname = 'GENEZ'" + expected = "WHERE firstname = 'Mesut' AND lastname = 'GENEZ'" got = s.Where("firstname", "=", "Mesut").Where("lastname", "=", "GENEZ").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -103,8 +94,7 @@ func TestSql_Where_With_And(t *testing.T) { } func TestSql_OrWhere(t *testing.T) { - s.sql = "" - expected = " WHERE firstname = 'Mesut'" + expected = "WHERE firstname = 'Mesut'" got = s.OrWhere("firstname", "=", "Mesut").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -112,8 +102,7 @@ func TestSql_OrWhere(t *testing.T) { } func TestSql_OrWhere_With_And(t *testing.T) { - s.sql = "" - expected = " WHERE firstname = 'Mesut' OR lastname = 'GENEZ'" + expected = "WHERE firstname = 'Mesut' OR lastname = 'GENEZ'" got = s.OrWhere("firstname", "=", "Mesut").OrWhere("lastname", "=", "GENEZ").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -121,17 +110,15 @@ func TestSql_OrWhere_With_And(t *testing.T) { } func TestSql_In(t *testing.T) { - s.sql = "" - expected = " WHERE firstname IN ('Mesut')" - got = s.In("firstname", "Mesut").ToSql() + expected = "WHERE firstname IN ('Mesut', 33)" + got = s.In("firstname", "Mesut", 33).ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) } } func TestSql_InWithInt(t *testing.T) { - s.sql = "" - expected = " WHERE id IN (12, 34, 55)" + expected = "WHERE id IN (12, 34, 55)" got = s.In("id", 12, 34, 55).ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -139,8 +126,7 @@ func TestSql_InWithInt(t *testing.T) { } func TestSql_InAnd(t *testing.T) { - s.sql = "" - expected = " WHERE firstname IN ('Mesut') AND lastname IN ('GENEZ')" + expected = "WHERE firstname IN ('Mesut') AND lastname IN ('GENEZ')" got = s.In("firstname", "Mesut").In("lastname", "GENEZ").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -148,8 +134,7 @@ func TestSql_InAnd(t *testing.T) { } func TestSql_OrIn(t *testing.T) { - s.sql = "" - expected = " WHERE firstname IN ('Mesut')" + expected = "WHERE firstname IN ('Mesut')" got = s.OrIn("firstname", "Mesut").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -157,8 +142,7 @@ func TestSql_OrIn(t *testing.T) { } func TestSql_OrInAnd(t *testing.T) { - s.sql = "" - expected = " WHERE firstname IN ('Mesut', 'GENEZ') OR lastname IN ('GENEZ')" + expected = "WHERE firstname IN ('Mesut', 'GENEZ') OR lastname IN ('GENEZ')" got = s.OrIn("firstname", "Mesut", "GENEZ").OrIn("lastname", "GENEZ").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -166,8 +150,7 @@ func TestSql_OrInAnd(t *testing.T) { } func TestSql_Between(t *testing.T) { - s.sql = "" - expected = " WHERE firstname BETWEEN 'Mesut' AND 'GENEZ'" + expected = "WHERE firstname BETWEEN 'Mesut' AND 'GENEZ'" got = s.Between("firstname", "Mesut", "GENEZ").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -175,8 +158,7 @@ func TestSql_Between(t *testing.T) { } func TestSql_BetweenWithInt(t *testing.T) { - s.sql = "" - expected = " WHERE id BETWEEN 12 AND 55" + expected = "WHERE id BETWEEN 12 AND 55" got = s.Between("id", 12, 55).ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -184,8 +166,7 @@ func TestSql_BetweenWithInt(t *testing.T) { } func TestSql_BetweenWithWhere(t *testing.T) { - s.sql = "" - expected = " WHERE firstname BETWEEN 'Mesut' AND 'GENEZ' AND lastname BETWEEN 'Mesut' AND 'GENEZ'" + expected = "WHERE firstname BETWEEN 'Mesut' AND 'GENEZ' AND lastname BETWEEN 'Mesut' AND 'GENEZ'" got = s.Between("firstname", "Mesut", "GENEZ").Between("lastname", "Mesut", "GENEZ").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -193,8 +174,7 @@ func TestSql_BetweenWithWhere(t *testing.T) { } func TestSql_OrBetween(t *testing.T) { - s.sql = "" - expected = " WHERE firstname BETWEEN 'Mesut' AND 'GENEZ'" + expected = "WHERE firstname BETWEEN 'Mesut' AND 'GENEZ'" got = s.OrBetween("firstname", "Mesut", "GENEZ").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -202,8 +182,7 @@ func TestSql_OrBetween(t *testing.T) { } func TestSql_OrBetweenWithWhere(t *testing.T) { - s.sql = "" - expected = " WHERE firstname BETWEEN 'Mesut' AND 'GENEZ' OR lastname BETWEEN 'Mesut' AND 'GENEZ'" + expected = "WHERE firstname BETWEEN 'Mesut' AND 'GENEZ' OR lastname BETWEEN 'Mesut' AND 'GENEZ'" got = s.OrBetween("firstname", "Mesut", "GENEZ").OrBetween("lastname", "Mesut", "GENEZ").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -212,7 +191,7 @@ func TestSql_OrBetweenWithWhere(t *testing.T) { func TestSql_IsNull(t *testing.T) { expected = "SELECT * FROM users WHERE age = 30 AND name IS NULL" - got = s.Select("users").Where("age", "=", 30).IsNull("name").ToSql() + got = s.Table("users").Select().Where("age", "=", 30).IsNull("name").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) } @@ -220,7 +199,7 @@ func TestSql_IsNull(t *testing.T) { func TestSql_IsNotNull(t *testing.T) { expected = "SELECT * FROM users WHERE age = 30 AND name IS NOT NULL" - got = s.Select("users").Where("age", "=", 30).IsNotNull("name").ToSql() + got = s.Table("users").Select().Where("age", "=", 30).IsNotNull("name").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) } @@ -228,7 +207,7 @@ func TestSql_IsNotNull(t *testing.T) { func TestSql_Having(t *testing.T) { expected = "SELECT * FROM orders GROUP BY user_id HAVING COUNT(*) > 1" - got = s.Select("orders").GroupBy("user_id").Having("COUNT(*) > 1").ToSql() + got = s.Table("orders").Select().GroupBy("user_id").Having("COUNT(*) > 1").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) } @@ -236,15 +215,14 @@ func TestSql_Having(t *testing.T) { func TestSql_OrHaving(t *testing.T) { expected = "SELECT * FROM orders GROUP BY user_id HAVING COUNT(*) > 1 OR COUNT(*) < 5" - got = s.Select("orders").GroupBy("user_id").OrHaving("COUNT(*) > 1").OrHaving("COUNT(*) < 5").ToSql() + got = s.Table("orders").Select().GroupBy("user_id").OrHaving("COUNT(*) > 1").OrHaving("COUNT(*) < 5").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) } } func TestSql_Join(t *testing.T) { - s.sql = "" - expected = " INNER JOIN users ON roles" + expected = "INNER JOIN users ON roles" got = s.Join("INNER", "users", "roles").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -252,8 +230,7 @@ func TestSql_Join(t *testing.T) { } func TestSql_Limit(t *testing.T) { - s.sql = "" - expected = " LIMIT 1, 5" + expected = "LIMIT 1, 5" got = s.Limit(1, 5).ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -261,8 +238,7 @@ func TestSql_Limit(t *testing.T) { } func TestSql_Group(t *testing.T) { - s.sql = "" - expected = " GROUP BY firstname" + expected = "GROUP BY firstname" got = s.GroupBy("firstname").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -270,8 +246,7 @@ func TestSql_Group(t *testing.T) { } func TestSql_GroupMultiple(t *testing.T) { - s.sql = "" - expected = " GROUP BY firstname, lastname, email" + expected = "GROUP BY firstname, lastname, email" got = s.GroupBy("firstname", "lastname", "email").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -279,8 +254,7 @@ func TestSql_GroupMultiple(t *testing.T) { } func TestSql_OrderBy(t *testing.T) { - s.sql = "" - expected = " ORDER BY firstname ASC" + expected = "ORDER BY firstname ASC" got = s.OrderBy("firstname").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -288,8 +262,7 @@ func TestSql_OrderBy(t *testing.T) { } func TestSql_OrderByMultiple(t *testing.T) { - s.sql = "" - expected = " ORDER BY firstname, lastname ASC" + expected = "ORDER BY firstname, lastname ASC" got = s.OrderBy("firstname", "lastname").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -297,8 +270,7 @@ func TestSql_OrderByMultiple(t *testing.T) { } func TestSql_OrderByDesc(t *testing.T) { - s.sql = "" - expected = " ORDER BY firstname DESC" + expected = "ORDER BY firstname DESC" got = s.OrderByDesc("firstname").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -306,8 +278,7 @@ func TestSql_OrderByDesc(t *testing.T) { } func TestSql_OrderByDescMultiple(t *testing.T) { - s.sql = "" - expected = " ORDER BY firstname, lastname DESC" + expected = "ORDER BY firstname, lastname DESC" got = s.OrderByDesc("firstname", "lastname").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -315,8 +286,7 @@ func TestSql_OrderByDescMultiple(t *testing.T) { } func TestSql_Union(t *testing.T) { - s.sql = "" - expected = " UNION select * from companies" + expected = "UNION select * from companies" got = s.Union("select * from companies").ToSql() if !reflect.DeepEqual(expected, got) { t.Errorf("expected = %v, got %v", expected, got) @@ -327,8 +297,8 @@ func TestSql_SubQuery(t *testing.T) { mainBuilder := &GoBuilder{} subBuilder := &GoBuilder{} - subBuilder.Select("users", "id").Where("age", ">", 30) - mainBuilder.Select("orders", "order_id", "user_id").Where("user_id", "IN", subBuilder) + subBuilder.Table("users").Select("id").Where("age", ">", 30) + mainBuilder.Table("orders").Select("order_id", "user_id").Where("user_id", "IN", subBuilder) expected = "SELECT order_id, user_id FROM orders WHERE user_id IN (SELECT id FROM users WHERE age > 30)" got = mainBuilder.ToSql() diff --git a/example/main.go b/example/main.go index 57cb5c3..67e5769 100644 --- a/example/main.go +++ b/example/main.go @@ -13,64 +13,64 @@ var ( func main() { - sql = gb.Select("users").Where("id", "=", "1").ToSql() - fmt.Printf("All Columns: \n%s\n", sql) + sql = gb.Table("users").Select().Where("id", "=", "1").ToSql() + fmt.Printf("All Columns: \n%s\n\n", sql) - sql = gb.Select("users", "firstname", "lastname", "create_date"). - Where("id", "=", "1"). + sql = gb.Table("users").Select("firstname", "lastname", "created_at"). + Where("id", "=", 1). ToSql() - fmt.Printf("Filter Columns: \n%s\n", sql) + fmt.Printf("Filter Columns: \n%s\n\n", sql) - sql = gb.Select("users"). + sql = gb.Table("users").Select(). Where("id", "=", "1"). OrWhere("email", "=", "loremipsum@lrmpsm.com"). ToSql() - fmt.Printf("Where Or Where: \n%s\n", sql) + fmt.Printf("Where Or Where: \n%s\n\n", sql) - sql = gb.Select("users as u", "u.firstname", "u.lastname", "a.address"). + sql = gb.Table("users as u").Select("u.firstname", "u.lastname", "a.address"). Join("INNER", "address as a", "a.user_id=u.id"). Where("u.email", "=", "loremipsum@lrmpsm.com"). ToSql() - fmt.Printf("Join: \n%s\n", sql) + fmt.Printf("Join: \n%s\n\n", sql) - sql = gb.Select("users"). + sql = gb.Table("users").Select(). Where("id", "=", "1"). - Between("create_date", "2021-01-01", "2021-03-16"). + Between("created_at", "2021-01-01", "2021-03-16"). ToSql() - fmt.Printf("Between: \n%s\n", sql) + fmt.Printf("Between: \n%s\n\n", sql) - sql = gb.Select("users"). + sql = gb.Table("users").Select(). Where("id", "=", "1"). - Between("create_date", "2021-01-01", "2021-03-16"). + Between("created_at", "2021-01-01", "2021-03-16"). Limit(1, 5). ToSql() - fmt.Printf("Limit: \n%s\n", sql) + fmt.Printf("Limit: \n%s\n\n", sql) - sql = gb.Select("users"). + sql = gb.Table("users").Select(). Where("id", "=", "1"). - Between("create_date", "2021-01-01", "2021-03-16"). + Between("created_at", "2021-01-01", "2021-03-16"). GroupBy("lastname"). ToSql() - fmt.Printf("Group By: \n%s\n", sql) + fmt.Printf("Group By: \n%s\n\n", sql) - sql = gb.Select("users"). + sql = gb.Table("users").Select(). Where("id", "=", "1"). - Between("create_date", "2021-01-01", "2021-03-16"). + Between("created_at", "2021-01-01", "2021-03-16"). GroupBy("lastname"). OrderBy("id"). ToSql() - fmt.Printf("Order By: \n%s\n", sql) + fmt.Printf("Order By: \n%s\n\n", sql) - sql = gb.Select("users").Where("lastname", "=", "lorem").ToSql() - sql = gb.Select("users").Where("lastname", "=", "ipsum").Union(sql).ToSql() - fmt.Printf("Union: \n%s\n", sql) + sql = gb.Table("users").Select().Where("lastname", "=", "lorem").ToSql() + sql = gb.Table("users").Select().Where("lastname", "=", "ipsum").Union(sql).ToSql() + fmt.Printf("Union: \n%s\n\n", sql) // example subquery mainBuilder := &query.GoBuilder{} subBuilder := &query.GoBuilder{} - subBuilder.Select("users", "id").Where("age", ">", 30) - mainBuilder.Select("orders", "order_id", "user_id").Where("user_id", "IN", subBuilder) + subBuilder.Table("users").Select("id").Where("age", ">", 30) + mainBuilder.Table("orders").Select("order_id", "user_id").Where("user_id", "IN", subBuilder) fmt.Println(mainBuilder.ToSql()) // SELECT order_id, user_id FROM orders WHERE user_id IN (SELECT id FROM users WHERE age > '30') diff --git a/go.mod b/go.mod index ca7a7db..93e295e 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,3 @@ module github.com/mstgnz/gobuilder go 1.22 - -require golang.org/x/exp v0.0.0-20220609121020-a51bd0440498 diff --git a/go.sum b/go.sum index 43a2583..e69de29 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +0,0 @@ -golang.org/x/exp v0.0.0-20220609121020-a51bd0440498 h1:TF0FvLUGEq/8wOt/9AV1nj6D4ViZGUIGCMQfCv7VRXY= -golang.org/x/exp v0.0.0-20220609121020-a51bd0440498/go.mod h1:yh0Ynu2b5ZUe3MQfp2nM0ecK7wsgouWTDN0FNeJuIys=