github.com/influxdata/influxdb/v2@v2.7.6/influxql/query/result.go (about)

     1  package query
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  
     8  	"github.com/influxdata/influxdb/v2/models"
     9  	"github.com/influxdata/influxql"
    10  )
    11  
    12  const (
    13  	// WarningLevel is the message level for a warning.
    14  	WarningLevel = "warning"
    15  )
    16  
    17  // TagSet is a fundamental concept within the query system. It represents a composite series,
    18  // composed of multiple individual series that share a set of tag attributes.
    19  type TagSet struct {
    20  	Filters    []influxql.Expr
    21  	SeriesKeys []string
    22  	Key        []byte
    23  }
    24  
    25  // AddFilter adds a series-level filter to the Tagset.
    26  func (t *TagSet) AddFilter(key string, filter influxql.Expr) {
    27  	t.SeriesKeys = append(t.SeriesKeys, key)
    28  	t.Filters = append(t.Filters, filter)
    29  }
    30  
    31  func (t *TagSet) Len() int           { return len(t.SeriesKeys) }
    32  func (t *TagSet) Less(i, j int) bool { return t.SeriesKeys[i] < t.SeriesKeys[j] }
    33  func (t *TagSet) Swap(i, j int) {
    34  	t.SeriesKeys[i], t.SeriesKeys[j] = t.SeriesKeys[j], t.SeriesKeys[i]
    35  	t.Filters[i], t.Filters[j] = t.Filters[j], t.Filters[i]
    36  }
    37  
    38  // Reverse reverses the order of series keys and filters in the TagSet.
    39  func (t *TagSet) Reverse() {
    40  	for i, j := 0, len(t.Filters)-1; i < j; i, j = i+1, j-1 {
    41  		t.Filters[i], t.Filters[j] = t.Filters[j], t.Filters[i]
    42  		t.SeriesKeys[i], t.SeriesKeys[j] = t.SeriesKeys[j], t.SeriesKeys[i]
    43  	}
    44  }
    45  
    46  // LimitTagSets returns a tag set list with SLIMIT and SOFFSET applied.
    47  func LimitTagSets(a []*TagSet, slimit, soffset int) []*TagSet {
    48  	// Ignore if no limit or offset is specified.
    49  	if slimit == 0 && soffset == 0 {
    50  		return a
    51  	}
    52  
    53  	// If offset is beyond the number of tag sets then return nil.
    54  	if soffset > len(a) {
    55  		return nil
    56  	}
    57  
    58  	// Clamp limit to the max number of tag sets.
    59  	if soffset+slimit > len(a) {
    60  		slimit = len(a) - soffset
    61  	}
    62  	return a[soffset : soffset+slimit]
    63  }
    64  
    65  // Message represents a user-facing message to be included with the result.
    66  type Message struct {
    67  	Level string `json:"level"`
    68  	Text  string `json:"text"`
    69  }
    70  
    71  // ReadOnlyWarning generates a warning message that tells the user the command
    72  // they are using is being used for writing in a read only context.
    73  //
    74  // This is a temporary method while to be used while transitioning to read only
    75  // operations for issue #6290.
    76  func ReadOnlyWarning(stmt string) *Message {
    77  	return &Message{
    78  		Level: WarningLevel,
    79  		Text:  fmt.Sprintf("deprecated use of '%s' in a read only context, please use a POST request instead", stmt),
    80  	}
    81  }
    82  
    83  // Result represents a resultset returned from a single statement.
    84  // Rows represents a list of rows that can be sorted consistently by name/tag.
    85  type Result struct {
    86  	// StatementID is just the statement's position in the query. It's used
    87  	// to combine statement results if they're being buffered in memory.
    88  	StatementID int
    89  	Series      models.Rows
    90  	Messages    []*Message
    91  	Partial     bool
    92  	Err         error
    93  }
    94  
    95  // MarshalJSON encodes the result into JSON.
    96  func (r *Result) MarshalJSON() ([]byte, error) {
    97  	// Define a struct that outputs "error" as a string.
    98  	var o struct {
    99  		StatementID int           `json:"statement_id"`
   100  		Series      []*models.Row `json:"series,omitempty"`
   101  		Messages    []*Message    `json:"messages,omitempty"`
   102  		Partial     bool          `json:"partial,omitempty"`
   103  		Err         string        `json:"error,omitempty"`
   104  	}
   105  
   106  	// Copy fields to output struct.
   107  	o.StatementID = r.StatementID
   108  	o.Series = r.Series
   109  	o.Messages = r.Messages
   110  	o.Partial = r.Partial
   111  	if r.Err != nil {
   112  		o.Err = r.Err.Error()
   113  	}
   114  
   115  	return json.Marshal(&o)
   116  }
   117  
   118  // UnmarshalJSON decodes the data into the Result struct
   119  func (r *Result) UnmarshalJSON(b []byte) error {
   120  	var o struct {
   121  		StatementID int           `json:"statement_id"`
   122  		Series      []*models.Row `json:"series,omitempty"`
   123  		Messages    []*Message    `json:"messages,omitempty"`
   124  		Partial     bool          `json:"partial,omitempty"`
   125  		Err         string        `json:"error,omitempty"`
   126  	}
   127  
   128  	err := json.Unmarshal(b, &o)
   129  	if err != nil {
   130  		return err
   131  	}
   132  	r.StatementID = o.StatementID
   133  	r.Series = o.Series
   134  	r.Messages = o.Messages
   135  	r.Partial = o.Partial
   136  	if o.Err != "" {
   137  		r.Err = errors.New(o.Err)
   138  	}
   139  	return nil
   140  }