194 lines
5.5 KiB
Go
194 lines
5.5 KiB
Go
package cards
|
|
|
|
import (
|
|
"github.com/go-playground/validator/v10"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// CardBase Common fields for the Card entity
|
|
type CardBase struct {
|
|
Name string `json:"name" validate:"required"`
|
|
IsPublic bool `json:"isPublic" validate:"omitempty"`
|
|
DefaultConfig map[string]any `json:"defaultConfig"`
|
|
Config map[string]any `json:"config"`
|
|
Thumbnail *string `json:"thumbnail" validate:"omitempty,url"`
|
|
MetricType string `json:"metricType" validate:"required,oneof=timeseries table funnel"`
|
|
MetricOf string `json:"metricOf" validate:"required,oneof=session_count user_count"`
|
|
MetricFormat string `json:"metricFormat" validate:"required,oneof=default percentage"`
|
|
ViewType string `json:"viewType" validate:"required,oneof=line_chart table_view"`
|
|
MetricValue []string `json:"metricValue" validate:"omitempty"`
|
|
SessionID *int64 `json:"sessionId" validate:"omitempty"`
|
|
Series []CardSeriesBase `json:"series" validate:"required,dive"`
|
|
}
|
|
|
|
// Card Fields specific to database operations
|
|
type Card struct {
|
|
CardBase
|
|
ProjectID int64 `json:"projectId" validate:"required"`
|
|
UserID int64 `json:"userId" validate:"required"`
|
|
CardID int64 `json:"cardId"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
DeletedAt *time.Time `json:"deleted_at,omitempty"`
|
|
EditedAt *time.Time `json:"edited_at,omitempty"`
|
|
}
|
|
|
|
type CardSeriesBase struct {
|
|
Name string `json:"name" validate:"required"`
|
|
CreatedAt time.Time `json:"createdAt" validate:"omitempty"`
|
|
DeletedAt *time.Time `json:"deletedAt" validate:"omitempty"`
|
|
Index int64 `json:"index" validate:"required"`
|
|
Filter SeriesFilter `json:"filter"`
|
|
}
|
|
|
|
type CardSeries struct {
|
|
SeriesID int64 `json:"seriesId" validate:"omitempty"`
|
|
MetricID int64 `json:"metricId" validate:"omitempty"`
|
|
CardSeriesBase
|
|
}
|
|
|
|
type SeriesFilter struct {
|
|
EventOrder string `json:"eventOrder" validate:"required,oneof=then or and"`
|
|
Filters []FilterItem `json:"filters"`
|
|
}
|
|
|
|
type FilterItem struct {
|
|
Type string `json:"type" validate:"required"`
|
|
Operator string `json:"operator" validate:"required"`
|
|
Source string `json:"source" validate:"required"`
|
|
SourceOperator string `json:"sourceOperator" validate:"required"`
|
|
Value []string `json:"value" validate:"required,dive,required"`
|
|
IsEvent bool `json:"isEvent"`
|
|
}
|
|
|
|
// CardCreateRequest Fields required for creating a card (from the frontend)
|
|
type CardCreateRequest struct {
|
|
CardBase
|
|
}
|
|
|
|
type CardGetResponse struct {
|
|
Card
|
|
Series []CardSeries `json:"series"`
|
|
}
|
|
|
|
type CardUpdateRequest struct {
|
|
CardBase
|
|
}
|
|
|
|
type GetCardsResponse struct {
|
|
Cards []Card `json:"cards"`
|
|
}
|
|
|
|
type GetCardsResponsePaginated struct {
|
|
Cards []Card `json:"cards"`
|
|
Total int `json:"total"`
|
|
}
|
|
|
|
/************************************************************
|
|
* CardListFilter and Sorter
|
|
*/
|
|
|
|
// Supported filters, fields, and orders
|
|
var (
|
|
SupportedFilterKeys = map[string]bool{
|
|
"name": true,
|
|
"metric_type": true,
|
|
"dashboard_ids": true,
|
|
}
|
|
SupportedSortFields = map[string]string{
|
|
"name": "m.name",
|
|
"created_at": "m.created_at",
|
|
"metric_type": "m.metric_type",
|
|
}
|
|
SupportedSortOrders = map[string]bool{
|
|
"asc": true,
|
|
"desc": true,
|
|
}
|
|
)
|
|
|
|
// CardListFilter holds filtering criteria for listing cards.
|
|
type CardListFilter struct {
|
|
// Keys: "name" (string), "metric_type" (string), "dashboard_ids" ([]int)
|
|
Filters map[string]interface{} `validate:"supportedFilters"`
|
|
}
|
|
|
|
// CardListSort holds sorting criteria.
|
|
type CardListSort struct {
|
|
Field string `validate:"required,supportedSortField"`
|
|
Order string `validate:"required,supportedSortOrder"`
|
|
}
|
|
|
|
// Validator singleton
|
|
var validate *validator.Validate
|
|
|
|
func GetValidator() *validator.Validate {
|
|
if validate == nil {
|
|
validate = validator.New()
|
|
// Register custom validations
|
|
_ = validate.RegisterValidation("supportedFilters", supportedFiltersValidator)
|
|
_ = validate.RegisterValidation("supportedSortField", supportedSortFieldValidator)
|
|
_ = validate.RegisterValidation("supportedSortOrder", supportedSortOrderValidator)
|
|
}
|
|
return validate
|
|
}
|
|
|
|
func ValidateStruct(obj interface{}) error {
|
|
return GetValidator().Struct(obj)
|
|
}
|
|
|
|
// Custom validations
|
|
func supportedFiltersValidator(fl validator.FieldLevel) bool {
|
|
filters, ok := fl.Field().Interface().(map[string]interface{})
|
|
if !ok {
|
|
return false
|
|
}
|
|
for k := range filters {
|
|
if !SupportedFilterKeys[k] {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func supportedSortFieldValidator(fl validator.FieldLevel) bool {
|
|
field := strings.ToLower(fl.Field().String())
|
|
_, ok := SupportedSortFields[field]
|
|
return ok
|
|
}
|
|
|
|
func supportedSortOrderValidator(fl validator.FieldLevel) bool {
|
|
order := strings.ToLower(fl.Field().String())
|
|
return SupportedSortOrders[order]
|
|
}
|
|
|
|
// Filter helpers
|
|
func (f *CardListFilter) GetNameFilter() *string {
|
|
if val, ok := f.Filters["name"].(string); ok && val != "" {
|
|
return &val
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (f *CardListFilter) GetMetricTypeFilter() *string {
|
|
if val, ok := f.Filters["metric_type"].(string); ok && val != "" {
|
|
return &val
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (f *CardListFilter) GetDashboardIDs() []int {
|
|
if val, ok := f.Filters["dashboard_ids"].([]int); ok && len(val) > 0 {
|
|
return val
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Sort helpers
|
|
func (s *CardListSort) GetSQLField() string {
|
|
return SupportedSortFields[strings.ToLower(s.Field)]
|
|
}
|
|
|
|
func (s *CardListSort) GetSQLOrder() string {
|
|
return strings.ToUpper(s.Order)
|
|
}
|