The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/services/sqlstore/searchstore/builder.go

154 lines
3.6 KiB

package searchstore
import (
"bytes"
"fmt"
"strings"
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
)
// Builder defaults to returning a SQL query to get a list of all dashboards
// in default order, but can be modified by applying filters.
type Builder struct {
// List of FilterWhere/FilterGroupBy/FilterOrderBy/FilterLeftJoin
// to modify the query.
Filters []interface{}
Dialect migrator.Dialect
params []interface{}
sql bytes.Buffer
}
// ToSQL builds the SQL query and returns it as a string, together with the SQL parameters.
func (b *Builder) ToSQL(limit, page int64) (string, []interface{}) {
b.params = make([]interface{}, 0)
b.sql = bytes.Buffer{}
b.buildSelect()
b.sql.WriteString("( ")
orderQuery := b.applyFilters()
b.sql.WriteString(b.Dialect.LimitOffset(limit, (page-1)*limit) + `) AS ids
INNER JOIN dashboard ON ids.id = dashboard.id`)
b.sql.WriteString("\n")
b.sql.WriteString(
`LEFT OUTER JOIN dashboard AS folder ON folder.id = dashboard.folder_id
LEFT OUTER JOIN dashboard_tag ON dashboard.id = dashboard_tag.dashboard_id`)
b.sql.WriteString("\n")
b.sql.WriteString(orderQuery)
return b.sql.String(), b.params
}
func (b *Builder) buildSelect() {
b.sql.WriteString(
`SELECT
dashboard.id,
dashboard.uid,
dashboard.title,
dashboard.slug,
dashboard_tag.term,
dashboard.is_folder,
dashboard.folder_id,
folder.uid AS folder_uid,
folder.slug AS folder_slug,
folder.title AS folder_title `)
for _, f := range b.Filters {
if f, ok := f.(FilterSelect); ok {
b.sql.WriteString(fmt.Sprintf(", %s", f.Select()))
}
}
b.sql.WriteString(` FROM `)
}
func (b *Builder) applyFilters() (ordering string) {
joins := []string{}
orderJoins := []string{}
wheres := []string{}
whereParams := []interface{}{}
groups := []string{}
groupParams := []interface{}{}
orders := []string{}
for _, f := range b.Filters {
if f, ok := f.(FilterLeftJoin); ok {
joins = append(joins, fmt.Sprintf(" LEFT OUTER JOIN %s ", f.LeftJoin()))
}
if f, ok := f.(FilterWhere); ok {
sql, params := f.Where()
if sql != "" {
wheres = append(wheres, sql)
whereParams = append(whereParams, params...)
}
}
if f, ok := f.(FilterGroupBy); ok {
sql, params := f.GroupBy()
if sql != "" {
groups = append(groups, sql)
groupParams = append(groupParams, params...)
}
}
if f, ok := f.(FilterOrderBy); ok {
if f, ok := f.(FilterLeftJoin); ok {
orderJoins = append(orderJoins, fmt.Sprintf(" LEFT OUTER JOIN %s ", f.LeftJoin()))
}
orders = append(orders, f.OrderBy())
}
}
b.sql.WriteString("SELECT dashboard.id FROM dashboard")
b.sql.WriteString(strings.Join(joins, ""))
if len(wheres) > 0 {
b.sql.WriteString(fmt.Sprintf(" WHERE %s", strings.Join(wheres, " AND ")))
b.params = append(b.params, whereParams...)
}
if len(orders) < 1 {
orders = append(orders, TitleSorter{}.OrderBy())
}
if len(groups) > 0 {
cols := make([]string, 0, len(orders)+len(groups))
for _, o := range orders {
o := strings.TrimSuffix(o, " DESC")
o = strings.TrimSuffix(o, " ASC")
exists := false
for _, g := range groups {
if g == o {
exists = true
break
}
}
if !exists {
cols = append(cols, o)
}
}
cols = append(cols, groups...)
b.sql.WriteString(fmt.Sprintf(" GROUP BY %s", strings.Join(cols, ", ")))
b.params = append(b.params, groupParams...)
}
orderByCols := []string{}
for _, o := range orders {
orderByCols = append(orderByCols, b.Dialect.OrderBy(o))
}
orderBy := fmt.Sprintf(" ORDER BY %s", strings.Join(orderByCols, ", "))
b.sql.WriteString(orderBy)
order := strings.Join(orderJoins, "")
order += orderBy
return order
}