Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions router/cmd/plan_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func PlanGenerator(args []string) {
f.BoolVar(&cfg.FailOnPlanError, "fail-on-error", false, "if at least one plan fails, the command exit code will be 1")
f.BoolVar(&cfg.FailFast, "fail-fast", false, "stop as soon as possible if a plan fails")
f.StringVar(&cfg.LogLevel, "log-level", "warn", "log level to use (debug, info, warn, error, panic, fatal)")
f.BoolVar(&cfg.Raw, "raw", false, "get the raw json output of the plan generator")
Comment thread
SkArchon marked this conversation as resolved.
Outdated
Comment thread
SkArchon marked this conversation as resolved.
Outdated
f.UintVar(&cfg.MaxDataSourceCollectorsConcurrency, "max-collectors", 0, "max number of concurrent data source collectors, if unset or 0, no limit will be enforced")

if err := f.Parse(args[1:]); err != nil {
Expand Down
10 changes: 9 additions & 1 deletion router/core/plan_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package core

import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
Expand Down Expand Up @@ -65,7 +66,7 @@ func NewPlanner(planConfiguration *plan.Configuration, definition *ast.Document,
}, nil
}

func (pl *Planner) PlanOperation(operationFilePath string) (string, error) {
func (pl *Planner) PlanOperation(operationFilePath string, rawQueryPlan bool) (string, error) {
operation, err := pl.parseOperation(operationFilePath)
if err != nil {
return "", &PlannerOperationValidationError{err: err}
Expand All @@ -91,6 +92,13 @@ func (pl *Planner) PlanOperation(operationFilePath string) (string, error) {
return "", fmt.Errorf("failed to plan operation: %w", err)
}

if rawQueryPlan {
marshal, err := json.Marshal(rawPlan)
if err != nil {
return "", fmt.Errorf("failed to marshal raw plan: %w", err)
}
return string(marshal), nil
}
return rawPlan.PrettyPrint(), nil
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

Expand Down
11 changes: 8 additions & 3 deletions router/pkg/plan_generator/plan_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type QueryPlanConfig struct {
OutputReport bool
FailOnPlanError bool
FailFast bool
Raw bool
LogLevel string
Logger *zap.Logger
MaxDataSourceCollectorsConcurrency uint
Expand Down Expand Up @@ -140,9 +141,13 @@ func PlanGenerator(ctx context.Context, cfg QueryPlanConfig) error {

queryFilePath := filepath.Join(queriesPath, queryFile.Name())

outContent, err := planner.PlanOperation(queryFilePath)
outContent, err := planner.PlanOperation(queryFilePath, cfg.Raw)
fileName := queryFile.Name()
if cfg.Raw {
fileName += ".json"
}
res := QueryPlanResult{
FileName: queryFile.Name(),
FileName: fileName,
Plan: outContent,
}
if err != nil {
Expand All @@ -160,7 +165,7 @@ func PlanGenerator(ctx context.Context, cfg QueryPlanConfig) error {
}

if cfg.OutputFiles {
outFileName := filepath.Join(outPath, queryFile.Name())
outFileName := filepath.Join(outPath, fileName)
err = os.WriteFile(outFileName, []byte(outContent), 0644)
if err != nil {
cancelError(fmt.Errorf("failed to write file: %v", err))
Expand Down
103 changes: 103 additions & 0 deletions router/pkg/plan_generator/plan_generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,4 +331,107 @@ func TestPlanGenerator(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, errMsg, writtenResults.Error)
})

t.Run("generates raw json plans when Raw is enabled", func(t *testing.T) {
tempDir, err := os.MkdirTemp("", "plans-")
Comment thread
SkArchon marked this conversation as resolved.
Outdated
require.NoError(t, err)
defer func() {
_ = os.RemoveAll(tempDir)
}()

cfg := QueryPlanConfig{
SourceDir: path.Join(getTestDataDir(), "queries", "base"),
OutDir: tempDir,
ExecutionConfig: path.Join(getTestDataDir(), "execution_config", "base.json"),
Timeout: "30s",
OutputFiles: true,
Raw: true,
}

err = PlanGenerator(context.Background(), cfg)
assert.NoError(t, err)

entriesInOutDir, err := os.ReadDir(tempDir)
assert.NoError(t, err)
assert.Len(t, entriesInOutDir, len(allFiles))

for _, de := range entriesInOutDir {
name := de.Name()
content, err := os.ReadFile(path.Join(tempDir, name))
assert.NoError(t, err)
var m map[string]interface{}

// One of the queries produces a failed result
if err := json.Unmarshal(content, &m); err != nil {
assert.True(t, strings.HasPrefix(string(content), "Warning:"))
} else {
assert.NotEmpty(t, m)
}
Comment thread
SkArchon marked this conversation as resolved.
}
})

t.Run("report file uses .json filenames when Raw is enabled", func(t *testing.T) {
tempDir, err := os.MkdirTemp("", "plans-")
require.NoError(t, err)
defer func() {
_ = os.RemoveAll(tempDir)
}()

cfg := QueryPlanConfig{
SourceDir: path.Join(getTestDataDir(), "queries", "base"),
OutDir: tempDir,
ExecutionConfig: path.Join(getTestDataDir(), "execution_config", "base.json"),
Timeout: "30s",
OutputReport: true,
Raw: true,
}

err = PlanGenerator(context.Background(), cfg)
assert.NoError(t, err)

results, err := os.ReadFile(path.Join(tempDir, ReportFileName))
assert.NoError(t, err)
var writtenResults QueryPlanResults
assert.NoError(t, json.Unmarshal(results, &writtenResults))
assert.Len(t, writtenResults.Plans, len(allFiles))
for _, pr := range writtenResults.Plans {
assert.True(t, strings.HasSuffix(pr.FileName, ".json"))
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
})

t.Run("generates non-raw textual plans when Raw is disabled", func(t *testing.T) {
tempDir, err := os.MkdirTemp("", "plans-")
require.NoError(t, err)
defer func() {
_ = os.RemoveAll(tempDir)
}()

cfg := QueryPlanConfig{
SourceDir: path.Join(getTestDataDir(), "queries", "base"),
OutDir: tempDir,
ExecutionConfig: path.Join(getTestDataDir(), "execution_config", "base.json"),
Timeout: "30s",
OutputFiles: true,
}

err = PlanGenerator(context.Background(), cfg)
assert.NoError(t, err)

entriesInOutDir, err := os.ReadDir(tempDir)
assert.NoError(t, err)
assert.Len(t, entriesInOutDir, len(allFiles))

for _, de := range entriesInOutDir {
name := de.Name()
assert.True(t, strings.HasSuffix(name, ".graphql"))
content, err := os.ReadFile(path.Join(tempDir, name))
assert.NoError(t, err)
var m map[string]interface{}
assert.Error(t, json.Unmarshal(content, &m))
// Should be textual query plan or warning
s := string(content)
assert.True(t, strings.HasPrefix(s, "QueryPlan {") || strings.HasPrefix(s, "Warning:"))
Comment thread
SkArchon marked this conversation as resolved.
}
})

}
Loading