2026-03-07 19:27:44 +08:00
|
|
|
package stardb
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"strings"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// QueryBuilder helps build SQL queries
|
|
|
|
|
type QueryBuilder struct {
|
2026-03-20 13:36:59 +08:00
|
|
|
table string
|
|
|
|
|
columns []string
|
|
|
|
|
joins []string
|
|
|
|
|
where []string
|
|
|
|
|
whereArgs []interface{}
|
|
|
|
|
groupBy []string
|
|
|
|
|
having []string
|
|
|
|
|
havingArgs []interface{}
|
|
|
|
|
orderBy string
|
|
|
|
|
limit int
|
|
|
|
|
offset int
|
2026-03-07 19:27:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-20 13:36:59 +08:00
|
|
|
// 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
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-07 19:27:44 +08:00
|
|
|
// 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))
|
|
|
|
|
|
2026-03-20 13:36:59 +08:00
|
|
|
// JOIN
|
|
|
|
|
if len(qb.joins) > 0 {
|
|
|
|
|
parts = append(parts, strings.Join(qb.joins, " "))
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-07 19:27:44 +08:00
|
|
|
// WHERE
|
|
|
|
|
if len(qb.where) > 0 {
|
|
|
|
|
parts = append(parts, "WHERE "+strings.Join(qb.where, " AND "))
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-20 13:36:59 +08:00
|
|
|
// 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 "))
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-07 19:27:44 +08:00
|
|
|
// 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))
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-20 13:36:59 +08:00
|
|
|
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
|
2026-03-07 19:27:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Query executes the query
|
|
|
|
|
func (qb *QueryBuilder) Query(db *StarDB) (*StarRows, error) {
|
|
|
|
|
query, args := qb.Build()
|
|
|
|
|
return db.Query(query, args...)
|
|
|
|
|
}
|