func (s *Server) execQuery(ctx context.Context, compiler *ast.Compiler, txn storage.Transaction, query ast.Body, explainMode explainModeV1) (interface{}, error) { t := topdown.New(ctx, query, s.Compiler(), s.store, txn) var buf *topdown.BufferTracer if explainMode != explainOffV1 { buf = topdown.NewBufferTracer() t.Tracer = buf } resultSet := adhocQueryResultSetV1{} err := topdown.Eval(t, func(t *topdown.Topdown) error { result := map[string]interface{}{} var err error t.Locals.Iter(func(k, v ast.Value) bool { kv, ok := k.(ast.Var) if !ok { return false } if kv.IsWildcard() { return false } vv, e := topdown.ValueToInterface(v, t) if e != nil { err = e return true } result[string(kv)] = vv return false }) if err != nil { return err } if len(result) > 0 { resultSet = append(resultSet, result) } return nil }) if err != nil { return nil, err } switch explainMode { case explainFullV1: return newTraceV1(*buf), nil case explainTruthV1: answer, err := explain.Truth(compiler, *buf) if err != nil { return nil, err } return newTraceV1(answer), nil default: return resultSet, nil } }
func (r *REPL) printTrace(ctx context.Context, compiler *ast.Compiler, trace []*topdown.Event) { if r.explain == explainTruth { answer, err := explain.Truth(compiler, trace) if err != nil { fmt.Fprintf(r.output, "error: %v\n", err) } trace = answer } mangleTrace(ctx, r.store, r.txn, trace) topdown.PrettyTrace(r.output, trace) }
func (s *Server) v1DataGet(w http.ResponseWriter, r *http.Request) { // Gather request parameters. ctx := r.Context() vars := mux.Vars(r) path := stringPathToDataRef(vars["path"]) pretty := getPretty(r.URL.Query()["pretty"]) explainMode := getExplain(r.URL.Query()["explain"]) request, nonGround, err := parseRequest(r.URL.Query()[ParamRequestV1]) if err != nil { handleError(w, 400, err) return } if nonGround && explainMode != explainOffV1 { handleError(w, 400, fmt.Errorf("explanations with non-ground request values not supported")) return } // Prepare for query. txn, err := s.store.NewTransaction(ctx) if err != nil { handleErrorAuto(w, err) return } defer s.store.Close(ctx, txn) compiler := s.Compiler() params := topdown.NewQueryParams(ctx, compiler, s.store, txn, request, path) var buf *topdown.BufferTracer if explainMode != explainOffV1 { buf = topdown.NewBufferTracer() params.Tracer = buf } // Execute query. qrs, err := topdown.Query(params) // Handle results. if err != nil { handleErrorAuto(w, err) return } if qrs.Undefined() { if explainMode == explainFullV1 { handleResponseJSON(w, 404, newTraceV1(*buf), pretty) } else { handleResponse(w, 404, nil) } return } if nonGround { handleResponseJSON(w, 200, newQueryResultSetV1(qrs), pretty) return } result := qrs[0].Result switch explainMode { case explainOffV1: handleResponseJSON(w, 200, result, pretty) case explainFullV1: handleResponseJSON(w, 200, newTraceV1(*buf), pretty) case explainTruthV1: answer, err := explain.Truth(compiler, *buf) if err != nil { handleErrorAuto(w, err) return } handleResponseJSON(w, 200, newTraceV1(answer), pretty) } }