github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/model/annotation.go (about)

     1  package model
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/hashicorp/go-multierror"
     8  	"github.com/pkg/errors"
     9  	"github.com/pyroscope-io/pyroscope/pkg/flameql"
    10  )
    11  
    12  var (
    13  	ErrAnnotationInvalidAppName   = ValidationError{errors.New("invalid app name")}
    14  	ErrAnnotationInvalidTimestamp = ValidationError{errors.New("invalid timestamp")}
    15  	ErrAnnotationInvalidContent   = ValidationError{errors.New("invalid content")}
    16  )
    17  
    18  type Annotation struct {
    19  	AppName   string    `gorm:"index:idx_appname_timestamp,unique;not null;default:null"`
    20  	Timestamp time.Time `gorm:"index:idx_appname_timestamp,unique;not null;default:null"`
    21  	Content   string    `gorm:"not null;default:null"`
    22  	CreatedAt time.Time
    23  	UpdatedAt time.Time
    24  }
    25  
    26  type CreateAnnotation struct {
    27  	AppName   string
    28  	Content   string
    29  	Timestamp time.Time
    30  }
    31  
    32  // Parse parses and validates
    33  // It adds a default timestamp (to time.Now) if not present
    34  // And check required fields are set
    35  func (a *CreateAnnotation) Parse() error {
    36  	var err error
    37  
    38  	if a.Timestamp.IsZero() {
    39  		a.Timestamp = time.Now()
    40  	}
    41  
    42  	if a.AppName == "" {
    43  		err = multierror.Append(err, ErrAnnotationInvalidAppName)
    44  	} else {
    45  		if parseErr := a.handleAppNameQuery(); parseErr != nil {
    46  			err = multierror.Append(err, parseErr)
    47  		}
    48  	}
    49  
    50  	if a.Content == "" {
    51  		err = multierror.Append(err, ErrAnnotationInvalidContent)
    52  	}
    53  
    54  	return err
    55  }
    56  
    57  func (a *CreateAnnotation) handleAppNameQuery() error {
    58  	if a.AppName == "" {
    59  		return ErrAnnotationInvalidAppName
    60  	}
    61  
    62  	// Strip labels
    63  	key, parseErr := flameql.ParseQuery(a.AppName)
    64  	if parseErr != nil {
    65  		return fmt.Errorf("%w: %v", ErrAnnotationInvalidAppName, parseErr)
    66  	}
    67  
    68  	// Handle when only tags are passed
    69  	if key == nil || key.AppName == "" {
    70  		return ErrAnnotationInvalidAppName
    71  	}
    72  
    73  	a.AppName = key.AppName
    74  
    75  	return nil
    76  }