// measurementsByExpr takes and expression containing only tags and returns // a list of matching *Measurement. func (d *DatabaseIndex) measurementsByExpr(expr influxql.Expr) (Measurements, error) { switch e := expr.(type) { case *influxql.BinaryExpr: switch e.Op { case influxql.EQ, influxql.NEQ, influxql.EQREGEX, influxql.NEQREGEX: tag, ok := e.LHS.(*influxql.VarRef) if !ok { return nil, fmt.Errorf("left side of '%s' must be a tag key", e.Op.String()) } tf := &TagFilter{ Op: e.Op, Key: tag.Val, } if influxql.IsRegexOp(e.Op) { re, ok := e.RHS.(*influxql.RegexLiteral) if !ok { return nil, fmt.Errorf("right side of '%s' must be a regular expression", e.Op.String()) } tf.Regex = re.Val } else { s, ok := e.RHS.(*influxql.StringLiteral) if !ok { return nil, fmt.Errorf("right side of '%s' must be a tag value string", e.Op.String()) } tf.Value = s.Val } // Match on name, if specified. if tag.Val == "name" { return d.measurementsByNameFilter(tf.Op, tf.Value, tf.Regex), nil } return d.measurementsByTagFilters([]*TagFilter{tf}), nil case influxql.OR, influxql.AND: lhsIDs, err := d.measurementsByExpr(e.LHS) if err != nil { return nil, err } rhsIDs, err := d.measurementsByExpr(e.RHS) if err != nil { return nil, err } if e.Op == influxql.OR { return lhsIDs.union(rhsIDs), nil } return lhsIDs.intersect(rhsIDs), nil default: return nil, fmt.Errorf("invalid operator") } case *influxql.ParenExpr: return d.measurementsByExpr(e.Expr) } return nil, fmt.Errorf("%#v", expr) }
// tagKeysByExpr extracts the tag keys wanted by the expression. func (m *Measurement) tagKeysByExpr(expr influxql.Expr) (stringSet, bool, error) { switch e := expr.(type) { case *influxql.BinaryExpr: switch e.Op { case influxql.EQ, influxql.NEQ, influxql.EQREGEX, influxql.NEQREGEX: tag, ok := e.LHS.(*influxql.VarRef) if !ok { return nil, false, fmt.Errorf("left side of '%s' must be a tag key", e.Op.String()) } if tag.Val != "_tagKey" { return nil, false, nil } tf := TagFilter{ Op: e.Op, } if influxql.IsRegexOp(e.Op) { re, ok := e.RHS.(*influxql.RegexLiteral) if !ok { return nil, false, fmt.Errorf("right side of '%s' must be a regular expression", e.Op.String()) } tf.Regex = re.Val } else { s, ok := e.RHS.(*influxql.StringLiteral) if !ok { return nil, false, fmt.Errorf("right side of '%s' must be a tag value string", e.Op.String()) } tf.Value = s.Val } return m.tagKeysByFilter(tf.Op, tf.Value, tf.Regex), true, nil case influxql.AND, influxql.OR: lhsKeys, lhsOk, err := m.tagKeysByExpr(e.LHS) if err != nil { return nil, false, err } rhsKeys, rhsOk, err := m.tagKeysByExpr(e.RHS) if err != nil { return nil, false, err } if lhsOk && rhsOk { if e.Op == influxql.OR { return lhsKeys.union(rhsKeys), true, nil } return lhsKeys.intersect(rhsKeys), true, nil } else if lhsOk { return lhsKeys, true, nil } else if rhsOk { return rhsKeys, true, nil } return nil, false, nil default: return nil, false, fmt.Errorf("invalid operator") } case *influxql.ParenExpr: return m.tagKeysByExpr(e.Expr) } return nil, false, fmt.Errorf("%#v", expr) }