From 4fb505dfe998980dec81f2111a8100725c9b31a7 Mon Sep 17 00:00:00 2001
From: Aliaksandr Valialkin <valyala@victoriametrics.com>
Date: Tue, 18 Jul 2023 19:18:17 -0700
Subject: [PATCH] vendor: update github.com/VictoriaMetrics/metricsql from
 v0.59.1 to v0.60.0

This update adds support for metricsql.Prettify() function, which is going to be used
for prettifying long MetricsQL queries in VMUI
---
 go.mod                                        |   2 +-
 go.sum                                        |   4 +-
 .../VictoriaMetrics/metricsql/parser.go       |  75 ++++---
 .../VictoriaMetrics/metricsql/prettifier.go   | 201 ++++++++++++++++++
 vendor/modules.txt                            |   2 +-
 5 files changed, 251 insertions(+), 33 deletions(-)
 create mode 100644 vendor/github.com/VictoriaMetrics/metricsql/prettifier.go

diff --git a/go.mod b/go.mod
index bc6317eb81..d9f96a639b 100644
--- a/go.mod
+++ b/go.mod
@@ -12,7 +12,7 @@ require (
 	// like https://github.com/valyala/fasthttp/commit/996610f021ff45fdc98c2ce7884d5fa4e7f9199b
 	github.com/VictoriaMetrics/fasthttp v1.2.0
 	github.com/VictoriaMetrics/metrics v1.24.0
-	github.com/VictoriaMetrics/metricsql v0.59.1
+	github.com/VictoriaMetrics/metricsql v0.60.0
 	github.com/aws/aws-sdk-go-v2 v1.19.0
 	github.com/aws/aws-sdk-go-v2/config v1.18.28
 	github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.72
diff --git a/go.sum b/go.sum
index 78b7b8daea..a2b4f20803 100644
--- a/go.sum
+++ b/go.sum
@@ -70,8 +70,8 @@ github.com/VictoriaMetrics/fasthttp v1.2.0 h1:nd9Wng4DlNtaI27WlYh5mGXCJOmee/2c2b
 github.com/VictoriaMetrics/fasthttp v1.2.0/go.mod h1:zv5YSmasAoSyv8sBVexfArzFDIGGTN4TfCKAtAw7IfE=
 github.com/VictoriaMetrics/metrics v1.24.0 h1:ILavebReOjYctAGY5QU2F9X0MYvkcrG3aEn2RKa1Zkw=
 github.com/VictoriaMetrics/metrics v1.24.0/go.mod h1:eFT25kvsTidQFHb6U0oa0rTrDRdz4xTYjpL8+UPohys=
-github.com/VictoriaMetrics/metricsql v0.59.1 h1:G7FJLyYQlM9kSIK9EWDW8Dc7J0Bke3Onfle3Syr3CBs=
-github.com/VictoriaMetrics/metricsql v0.59.1/go.mod h1:k4UaP/+CjuZslIjd+kCigNG9TQmUqh5v0TP/nMEy90I=
+github.com/VictoriaMetrics/metricsql v0.60.0 h1:KlVWTabXGu/50U3Dp72TyJYo01WTaxSsHwMLiE9yHuA=
+github.com/VictoriaMetrics/metricsql v0.60.0/go.mod h1:k4UaP/+CjuZslIjd+kCigNG9TQmUqh5v0TP/nMEy90I=
 github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
 github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
diff --git a/vendor/github.com/VictoriaMetrics/metricsql/parser.go b/vendor/github.com/VictoriaMetrics/metricsql/parser.go
index 209ed08fd7..55339f06c1 100644
--- a/vendor/github.com/VictoriaMetrics/metricsql/parser.go
+++ b/vendor/github.com/VictoriaMetrics/metricsql/parser.go
@@ -1696,22 +1696,7 @@ func (be *BinaryOpExpr) appendStringNoKeepMetricNames(dst []byte) []byte {
 		dst = be.Left.AppendString(dst)
 	}
 	dst = append(dst, ' ')
-	dst = append(dst, be.Op...)
-	if be.Bool {
-		dst = append(dst, "bool"...)
-	}
-	if be.GroupModifier.Op != "" {
-		dst = append(dst, ' ')
-		dst = be.GroupModifier.AppendString(dst)
-	}
-	if be.JoinModifier.Op != "" {
-		dst = append(dst, ' ')
-		dst = be.JoinModifier.AppendString(dst)
-		if prefix := be.JoinModifierPrefix; prefix != nil {
-			dst = append(dst, " prefix "...)
-			dst = prefix.AppendString(dst)
-		}
-	}
+	dst = be.appendModifiers(dst)
 	dst = append(dst, ' ')
 	if be.needRightParens() {
 		dst = appendArgInParens(dst, be.Right)
@@ -1737,12 +1722,32 @@ func (be *BinaryOpExpr) needRightParens() bool {
 		if isReservedBinaryOpIdent(t.Name) {
 			return true
 		}
-		return be.KeepMetricNames
+		return t.KeepMetricNames || be.KeepMetricNames
 	default:
 		return false
 	}
 }
 
+func (be *BinaryOpExpr) appendModifiers(dst []byte) []byte {
+	dst = append(dst, be.Op...)
+	if be.Bool {
+		dst = append(dst, "bool"...)
+	}
+	if be.GroupModifier.Op != "" {
+		dst = append(dst, ' ')
+		dst = be.GroupModifier.AppendString(dst)
+	}
+	if be.JoinModifier.Op != "" {
+		dst = append(dst, ' ')
+		dst = be.JoinModifier.AppendString(dst)
+		if prefix := be.JoinModifierPrefix; prefix != nil {
+			dst = append(dst, " prefix "...)
+			dst = prefix.AppendString(dst)
+		}
+	}
+	return dst
+}
+
 func needBinaryOpArgParens(arg Expr) bool {
 	switch t := arg.(type) {
 	case *BinaryOpExpr:
@@ -1827,6 +1832,10 @@ type FuncExpr struct {
 func (fe *FuncExpr) AppendString(dst []byte) []byte {
 	dst = appendEscapedIdent(dst, fe.Name)
 	dst = appendStringArgListExpr(dst, fe.Args)
+	return fe.appendModifiers(dst)
+}
+
+func (fe *FuncExpr) appendModifiers(dst []byte) []byte {
 	if fe.KeepMetricNames {
 		dst = append(dst, " keep_metric_names"...)
 	}
@@ -1855,6 +1864,10 @@ type AggrFuncExpr struct {
 func (ae *AggrFuncExpr) AppendString(dst []byte) []byte {
 	dst = appendEscapedIdent(dst, ae.Name)
 	dst = appendStringArgListExpr(dst, ae.Args)
+	return ae.appendModifiers(dst)
+}
+
+func (ae *AggrFuncExpr) appendModifiers(dst []byte) []byte {
 	if ae.Modifier.Op != "" {
 		dst = append(dst, ' ')
 		dst = ae.Modifier.AppendString(dst)
@@ -1954,18 +1967,7 @@ func (re *RollupExpr) ForSubquery() bool {
 
 // AppendString appends string representation of re to dst and returns the result.
 func (re *RollupExpr) AppendString(dst []byte) []byte {
-	needParens := func() bool {
-		if _, ok := re.Expr.(*RollupExpr); ok {
-			return true
-		}
-		if _, ok := re.Expr.(*BinaryOpExpr); ok {
-			return true
-		}
-		if ae, ok := re.Expr.(*AggrFuncExpr); ok && ae.Modifier.Op != "" {
-			return true
-		}
-		return false
-	}()
+	needParens := re.needParens()
 	if needParens {
 		dst = append(dst, '(')
 	}
@@ -1973,6 +1975,10 @@ func (re *RollupExpr) AppendString(dst []byte) []byte {
 	if needParens {
 		dst = append(dst, ')')
 	}
+	return re.appendModifiers(dst)
+}
+
+func (re *RollupExpr) appendModifiers(dst []byte) []byte {
 	if re.Window != nil || re.InheritStep || re.Step != nil {
 		dst = append(dst, '[')
 		dst = re.Window.AppendString(dst)
@@ -2002,6 +2008,17 @@ func (re *RollupExpr) AppendString(dst []byte) []byte {
 	return dst
 }
 
+func (re *RollupExpr) needParens() bool {
+	switch t := re.Expr.(type) {
+	case *RollupExpr, *BinaryOpExpr:
+		return true
+	case *AggrFuncExpr:
+		return t.Modifier.Op != ""
+	default:
+		return false
+	}
+}
+
 // LabelFilter represents MetricsQL label filter like `foo="bar"`.
 type LabelFilter struct {
 	// Label contains label name for the filter.
diff --git a/vendor/github.com/VictoriaMetrics/metricsql/prettifier.go b/vendor/github.com/VictoriaMetrics/metricsql/prettifier.go
new file mode 100644
index 0000000000..486a22492e
--- /dev/null
+++ b/vendor/github.com/VictoriaMetrics/metricsql/prettifier.go
@@ -0,0 +1,201 @@
+package metricsql
+
+// Prettify returns prettified representation of MetricsQL query q.
+func Prettify(q string) (string, error) {
+	e, err := Parse(q)
+	if err != nil {
+		return "", err
+	}
+	b := appendPrettifiedExpr(nil, e, 0, false)
+	return string(b), nil
+}
+
+// maxPrettifiedLineLen is the maximum length of a single line returned by Prettify().
+//
+// Actual lines may exceed the maximum length in some cases.
+const maxPrettifiedLineLen = 80
+
+func appendPrettifiedExpr(dst []byte, e Expr, indent int, needParens bool) []byte {
+	dstLen := len(dst)
+
+	// Try appending e to dst and check whether its length exceeds the maximum allowed line length.
+	dst = appendIndent(dst, indent)
+	if needParens {
+		dst = append(dst, '(')
+	}
+	dst = e.AppendString(dst)
+	if needParens {
+		dst = append(dst, ')')
+	}
+	if len(dst)-dstLen <= maxPrettifiedLineLen {
+		// There is no need in splitting the e string representation, since its' length doesn't exceed.
+		return dst
+	}
+
+	// The e string representation exceeds maxPrettifiedLineLen. Split it into multiple lines
+	dst = dst[:dstLen]
+	if needParens {
+		dst = appendIndent(dst, indent)
+		dst = append(dst, "(\n"...)
+		indent++
+	}
+	switch t := e.(type) {
+	case *BinaryOpExpr:
+		// Split:
+		//
+		//   a op b
+		//
+		// into:
+		//
+		//   foo
+		//     op
+		//   bar
+		if t.KeepMetricNames {
+			dst = appendIndent(dst, indent)
+			dst = append(dst, "(\n"...)
+			indent++
+		}
+		dst = appendPrettifiedExpr(dst, t.Left, indent, t.needLeftParens())
+		dst = append(dst, '\n')
+		dst = appendIndent(dst, indent+1)
+		dst = t.appendModifiers(dst)
+		dst = append(dst, '\n')
+		dst = appendPrettifiedExpr(dst, t.Right, indent, t.needRightParens())
+		if t.KeepMetricNames {
+			indent--
+			dst = append(dst, '\n')
+			dst = appendIndent(dst, indent)
+			dst = append(dst, ") keep_metric_names"...)
+		}
+	case *RollupExpr:
+		// Split:
+		//
+		//   q[d:s] offset off @ x
+		//
+		// into:
+		//
+		//   (
+		//     q
+		//   )[d:s] offset off @ x
+		dst = appendPrettifiedExpr(dst, t.Expr, indent, t.needParens())
+		dst = t.appendModifiers(dst)
+	case *AggrFuncExpr:
+		// Split:
+		//
+		//   aggr_func(arg1, ..., argN) modifiers
+		//
+		// into:
+		//
+		//   aggr_func(
+		//     arg1,
+		//     ...
+		//     argN
+		//   ) modifiers
+		dst = appendIndent(dst, indent)
+		dst = appendEscapedIdent(dst, t.Name)
+		dst = appendPrettifiedFuncArgs(dst, indent, t.Args)
+		dst = t.appendModifiers(dst)
+	case *FuncExpr:
+		// Split:
+		//
+		//   func(arg1, ..., argN) modifiers
+		//
+		// into:
+		//
+		//   func(
+		//     arg1,
+		//     ...
+		//     argN
+		//   ) modifiers
+		dst = appendIndent(dst, indent)
+		dst = appendEscapedIdent(dst, t.Name)
+		dst = appendPrettifiedFuncArgs(dst, indent, t.Args)
+		dst = t.appendModifiers(dst)
+	case *MetricExpr:
+		// Split:
+		//
+		//   metric{filters1 or ... or filtersN}
+		//
+		// into:
+		//
+		//   metric{
+		//     filters1
+		//       or
+		//     ...
+		//       or
+		//     filtersN
+		//   }
+		offset := 0
+		metricName := t.getMetricName()
+		if metricName != "" {
+			offset = 1
+		}
+		dst = appendIndent(dst, indent)
+		dst = appendEscapedIdent(dst, metricName)
+		dst = append(dst, "{\n"...)
+		lfss := t.LabelFilterss
+		for i, lfs := range lfss {
+			dst = appendPrettifiedLabelFilters(dst, indent+1, lfs[offset:])
+			dst = append(dst, '\n')
+			if i+1 < len(lfss) {
+				dst = appendIndent(dst, indent+2)
+				dst = append(dst, "or\n"...)
+			}
+		}
+		dst = appendIndent(dst, indent)
+		dst = append(dst, '}')
+	default:
+		// marshal other expressions as is
+		dst = t.AppendString(dst)
+	}
+	if needParens {
+		indent--
+		dst = append(dst, '\n')
+		dst = appendIndent(dst, indent)
+		dst = append(dst, ')')
+	}
+	return dst
+}
+
+func appendPrettifiedFuncArgs(dst []byte, indent int, args []Expr) []byte {
+	dst = append(dst, "(\n"...)
+	for i, arg := range args {
+		dst = appendPrettifiedExpr(dst, arg, indent+1, false)
+		if i+1 < len(args) {
+			dst = append(dst, ',')
+		}
+		dst = append(dst, '\n')
+	}
+	dst = appendIndent(dst, indent)
+	dst = append(dst, ')')
+	return dst
+}
+
+func appendPrettifiedLabelFilters(dst []byte, indent int, lfs []LabelFilter) []byte {
+	dstLen := len(dst)
+
+	// Try marshaling lfs into a single line
+	dst = appendIndent(dst, indent)
+	dst = appendLabelFilters(dst, lfs)
+	if len(dst)-dstLen <= maxPrettifiedLineLen {
+		return dst
+	}
+
+	// Too long line - split it into multiple lines
+	dst = dst[:dstLen]
+	for i := range lfs {
+		dst = appendIndent(dst, indent)
+		dst = lfs[i].AppendString(dst)
+		if i+1 < len(lfs) {
+			dst = append(dst, ",\n"...)
+		}
+	}
+	return dst
+}
+
+func appendIndent(dst []byte, indent int) []byte {
+	for i := 0; i < indent; i++ {
+		dst = append(dst, "  "...)
+	}
+	return dst
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index a79da88833..82c8a37ba4 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -99,7 +99,7 @@ github.com/VictoriaMetrics/fasthttp/stackless
 # github.com/VictoriaMetrics/metrics v1.24.0
 ## explicit; go 1.20
 github.com/VictoriaMetrics/metrics
-# github.com/VictoriaMetrics/metricsql v0.59.1
+# github.com/VictoriaMetrics/metricsql v0.60.0
 ## explicit; go 1.13
 github.com/VictoriaMetrics/metricsql
 github.com/VictoriaMetrics/metricsql/binaryop