package stardb import ( "fmt" "strings" ) // QueryBuilder helps build SQL queries type QueryBuilder struct { table string columns []string joins []string where []string whereArgs []interface{} groupBy []string having []string havingArgs []interface{} orderBy string limit int offset int } // NewQueryBuilder creates a new query builder func NewQueryBuilder(table string) *QueryBuilder { return &QueryBuilder{ table: table, columns: []string{"*"}, } } // Select sets the columns to select func (qb *QueryBuilder) Select(columns ...string) *QueryBuilder { qb.columns = columns return qb } // Where adds a WHERE condition func (qb *QueryBuilder) Where(condition string, args ...interface{}) *QueryBuilder { qb.where = append(qb.where, condition) qb.whereArgs = append(qb.whereArgs, args...) return qb } // Join adds a JOIN clause. func (qb *QueryBuilder) Join(clause string) *QueryBuilder { qb.joins = append(qb.joins, clause) return qb } // GroupBy sets GROUP BY columns. func (qb *QueryBuilder) GroupBy(columns ...string) *QueryBuilder { qb.groupBy = append(qb.groupBy, columns...) return qb } // Having adds a HAVING condition. func (qb *QueryBuilder) Having(condition string, args ...interface{}) *QueryBuilder { qb.having = append(qb.having, condition) qb.havingArgs = append(qb.havingArgs, args...) return qb } // OrderBy sets the ORDER BY clause func (qb *QueryBuilder) OrderBy(orderBy string) *QueryBuilder { qb.orderBy = orderBy return qb } // Limit sets the LIMIT func (qb *QueryBuilder) Limit(limit int) *QueryBuilder { qb.limit = limit return qb } // Offset sets the OFFSET func (qb *QueryBuilder) Offset(offset int) *QueryBuilder { qb.offset = offset return qb } // Build builds the SQL query and returns query string and args func (qb *QueryBuilder) Build() (string, []interface{}) { var parts []string // SELECT parts = append(parts, fmt.Sprintf("SELECT %s FROM %s", strings.Join(qb.columns, ", "), qb.table)) // JOIN if len(qb.joins) > 0 { parts = append(parts, strings.Join(qb.joins, " ")) } // WHERE if len(qb.where) > 0 { parts = append(parts, "WHERE "+strings.Join(qb.where, " AND ")) } // GROUP BY if len(qb.groupBy) > 0 { parts = append(parts, "GROUP BY "+strings.Join(qb.groupBy, ", ")) } // HAVING if len(qb.having) > 0 { parts = append(parts, "HAVING "+strings.Join(qb.having, " AND ")) } // ORDER BY if qb.orderBy != "" { parts = append(parts, "ORDER BY "+qb.orderBy) } // LIMIT if qb.limit > 0 { parts = append(parts, fmt.Sprintf("LIMIT %d", qb.limit)) } // OFFSET if qb.offset > 0 { parts = append(parts, fmt.Sprintf("OFFSET %d", qb.offset)) } args := make([]interface{}, 0, len(qb.whereArgs)+len(qb.havingArgs)) args = append(args, qb.whereArgs...) args = append(args, qb.havingArgs...) return strings.Join(parts, " "), args } // Query executes the query func (qb *QueryBuilder) Query(db *StarDB) (*StarRows, error) { query, args := qb.Build() return db.Query(query, args...) }