如何在java中递归遍历graphql文档并找到它达到的最深层次

use*_*490 0 java recursion graphql graphql-java

我的目标是遍历一个 graphql Java 文档对象并返回最大深度。

示例:深度 0

{
   name 
}
Run Code Online (Sandbox Code Playgroud)

示例:深度 1

{
   viewer{
     viewerId
   }
}
Run Code Online (Sandbox Code Playgroud)

示例:深度 2

{
   viewer{
     albums{
       albumId
     }
   }
}
Run Code Online (Sandbox Code Playgroud)

示例:深度 2。如您所见,两张专辑/歌曲都在同一个父“观众”下

{
   viewer{
     albums{
       albumId
     }
     songs{
        songId
     }
   }
}
Run Code Online (Sandbox Code Playgroud)

示例:深度 3

{
   viewer{
     albums{
       tracks{
          trackId
       }
     }
   }
}
Run Code Online (Sandbox Code Playgroud)

我已经编写了基本代码来遍历它,但我的代码不适用于第二个版本的 depth = 2。它返回 depth = 3 而不是 2。原因是因为它在同一个父项下计数两次。本质上的逻辑是这样的:depth = depth + 1 每当一个字段有子项时。

import graphql.language.Document;
import graphql.language.Node;
import graphql.language.OperationDefinition;

public int checkDepthLimit(String query) {
    Document document;
    try {
        document = documentParser.parseDocument(query);
    } catch (Exception e) {}

    Optional<Node> queryNode = document.getChildren().stream()
            .filter(n -> (n.getClass() == OperationDefinition.class))
            .findFirst();

    return checkDepthLimit(queryNode.get());

}
Run Code Online (Sandbox Code Playgroud)
private int checkDepthLimit(Node queryNode) {

    int depth = 0;
    String nodeType = queryNode.getClass().getSimpleName().toUpperCase();

    if (nodeType.equals("FIELD")) {
        if (!queryNode.getChildren().isEmpty()) {
            depth += 1;
        }
    }

    List<Node> nodeChildren = queryNode.getChildren();
    for (int i = 0; i < nodeChildren.size(); i++) {
        depth += checkDepthLimit(nodeChildren.get(i));
    }
    return depth;

}
Run Code Online (Sandbox Code Playgroud)
String query = "{
       viewer{
           viewerId
       }"
QueryComplexity c = new QueryComplexity();
int depth = c.checkDepthLimit(query);
Run Code Online (Sandbox Code Playgroud)

我被困住了,如果有更深入的递归知识的人能够帮助我,我将不胜感激。

kaq*_*qao 5

从 graphql-java v4.0 开始,有一个内置QueryTraversal类可以帮助您检查查询 AST 和用于限制深度的相关检测:MaxQueryDepthInstrumentation

只需像任何其他仪器一样注册它:

GraphQL runtime = GraphQL.newGraphQL(schema)
    .instrumentation(new MaxQueryDepthInstrumentation(MAX_DEPTH))
    .build();
Run Code Online (Sandbox Code Playgroud)

还有MaxQueryComplexityInstrumentation

graphql-spqr(由我编写)还具有指定字段复杂性的声明性方式:

public static class PetService {

    @GraphQLQuery(name = "pet")
    @GraphQLComplexity("type == 'big' ? 10 : 2") //JavaScript expression calculating the complexity
    public Pet findPet(@GraphQLArgument(name = "type") String type) {
        return db.findPetByType(type);
    }
}
Run Code Online (Sandbox Code Playgroud)

ComplexityAnalysisInstrumentation手动注册,与上面相同:

GraphQL runtime = GraphQL.newGraphQL(schema)
    .instrumentation(new ComplexityAnalysisInstrumentation(new JavaScriptEvaluator(), MAX_DEPTH))
    .build();
Run Code Online (Sandbox Code Playgroud)

或者使用 SPQR 的GraphQLRuntime包装器:

GraphQL runtime = GraphQLRuntime.newGraphQL(schema)
            .maximumQueryComplexity(maxComplexity)
            .build();
Run Code Online (Sandbox Code Playgroud)