package explorer import ( "context" "encoding/json" "fmt" "strings" "time" "github.com/google/uuid" "github.com/jmoiron/sqlx" "go.signoz.io/signoz/pkg/query-service/auth" v3 "go.signoz.io/signoz/pkg/query-service/model/v3" ) var db *sqlx.DB type SavedView struct { UUID string `json:"uuid" db:"uuid"` Name string `json:"name" db:"name"` Category string `json:"category" db:"category"` CreatedAt time.Time `json:"created_at" db:"created_at"` CreatedBy string `json:"created_by" db:"created_by"` UpdatedAt time.Time `json:"updated_at" db:"updated_at"` UpdatedBy string `json:"updated_by" db:"updated_by"` SourcePage string `json:"source_page" db:"source_page"` Tags string `json:"tags" db:"tags"` Data string `json:"data" db:"data"` ExtraData string `json:"extra_data" db:"extra_data"` } // InitWithDSN sets up setting up the connection pool global variable. func InitWithDSN(dataSourceName string) (*sqlx.DB, error) { var err error db, err = sqlx.Open("sqlite3", dataSourceName) if err != nil { return nil, err } tableSchema := `CREATE TABLE IF NOT EXISTS saved_views ( uuid TEXT PRIMARY KEY, name TEXT NOT NULL, category TEXT NOT NULL, created_at datetime NOT NULL, created_by TEXT, updated_at datetime NOT NULL, updated_by TEXT, source_page TEXT NOT NULL, tags TEXT, data TEXT NOT NULL, extra_data TEXT );` _, err = db.Exec(tableSchema) if err != nil { return nil, fmt.Errorf("error in creating saved views table: %s", err.Error()) } return db, nil } func InitWithDB(sqlDB *sqlx.DB) { db = sqlDB } func GetViews() ([]*v3.SavedView, error) { var views []SavedView err := db.Select(&views, "SELECT * FROM saved_views") if err != nil { return nil, fmt.Errorf("error in getting saved views: %s", err.Error()) } var savedViews []*v3.SavedView for _, view := range views { var compositeQuery v3.CompositeQuery err = json.Unmarshal([]byte(view.Data), &compositeQuery) if err != nil { return nil, fmt.Errorf("error in unmarshalling explorer query data: %s", err.Error()) } savedViews = append(savedViews, &v3.SavedView{ UUID: view.UUID, Name: view.Name, Category: view.Category, CreatedAt: view.CreatedAt, CreatedBy: view.CreatedBy, UpdatedAt: view.UpdatedAt, UpdatedBy: view.UpdatedBy, Tags: strings.Split(view.Tags, ","), SourcePage: view.SourcePage, CompositeQuery: &compositeQuery, ExtraData: view.ExtraData, }) } return savedViews, nil } func GetViewsForFilters(sourcePage string, name string, category string) ([]*v3.SavedView, error) { var views []SavedView var err error if len(category) == 0 { err = db.Select(&views, "SELECT * FROM saved_views WHERE source_page = ? AND name LIKE ?", sourcePage, "%"+name+"%") } else { err = db.Select(&views, "SELECT * FROM saved_views WHERE source_page = ? AND category LIKE ? AND name LIKE ?", sourcePage, "%"+category+"%", "%"+name+"%") } if err != nil { return nil, fmt.Errorf("error in getting saved views: %s", err.Error()) } var savedViews []*v3.SavedView for _, view := range views { var compositeQuery v3.CompositeQuery err = json.Unmarshal([]byte(view.Data), &compositeQuery) if err != nil { return nil, fmt.Errorf("error in unmarshalling explorer query data: %s", err.Error()) } savedViews = append(savedViews, &v3.SavedView{ UUID: view.UUID, Name: view.Name, CreatedAt: view.CreatedAt, CreatedBy: view.CreatedBy, UpdatedAt: view.UpdatedAt, UpdatedBy: view.UpdatedBy, Tags: strings.Split(view.Tags, ","), SourcePage: view.SourcePage, CompositeQuery: &compositeQuery, ExtraData: view.ExtraData, }) } return savedViews, nil } func CreateView(ctx context.Context, view v3.SavedView) (string, error) { data, err := json.Marshal(view.CompositeQuery) if err != nil { return "", fmt.Errorf("error in marshalling explorer query data: %s", err.Error()) } uuid_ := view.UUID if uuid_ == "" { uuid_ = uuid.New().String() } createdAt := time.Now() updatedAt := time.Now() email, err := auth.GetEmailFromJwt(ctx) if err != nil { return "", err } createBy := email updatedBy := email _, err = db.Exec( "INSERT INTO saved_views (uuid, name, category, created_at, created_by, updated_at, updated_by, source_page, tags, data, extra_data) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", uuid_, view.Name, view.Category, createdAt, createBy, updatedAt, updatedBy, view.SourcePage, strings.Join(view.Tags, ","), data, view.ExtraData, ) if err != nil { return "", fmt.Errorf("error in creating saved view: %s", err.Error()) } return uuid_, nil } func GetView(uuid_ string) (*v3.SavedView, error) { var view SavedView err := db.Get(&view, "SELECT * FROM saved_views WHERE uuid = ?", uuid_) if err != nil { return nil, fmt.Errorf("error in getting saved view: %s", err.Error()) } var compositeQuery v3.CompositeQuery err = json.Unmarshal([]byte(view.Data), &compositeQuery) if err != nil { return nil, fmt.Errorf("error in unmarshalling explorer query data: %s", err.Error()) } return &v3.SavedView{ UUID: view.UUID, Name: view.Name, Category: view.Category, CreatedAt: view.CreatedAt, CreatedBy: view.CreatedBy, UpdatedAt: view.UpdatedAt, UpdatedBy: view.UpdatedBy, SourcePage: view.SourcePage, Tags: strings.Split(view.Tags, ","), CompositeQuery: &compositeQuery, ExtraData: view.ExtraData, }, nil } func UpdateView(ctx context.Context, uuid_ string, view v3.SavedView) error { data, err := json.Marshal(view.CompositeQuery) if err != nil { return fmt.Errorf("error in marshalling explorer query data: %s", err.Error()) } email, err := auth.GetEmailFromJwt(ctx) if err != nil { return err } updatedAt := time.Now() updatedBy := email _, err = db.Exec("UPDATE saved_views SET updated_at = ?, updated_by = ?, name = ?, category = ?, source_page = ?, tags = ?, data = ?, extra_data = ? WHERE uuid = ?", updatedAt, updatedBy, view.Name, view.Category, view.SourcePage, strings.Join(view.Tags, ","), data, view.ExtraData, uuid_) if err != nil { return fmt.Errorf("error in updating saved view: %s", err.Error()) } return nil } func DeleteView(uuid_ string) error { _, err := db.Exec("DELETE FROM saved_views WHERE uuid = ?", uuid_) if err != nil { return fmt.Errorf("error in deleting explorer query: %s", err.Error()) } return nil }