2017-08-22 4 views
0

私の目標は、graphql Javaドキュメントオブジェクトをトラバースし、最大深さを返すことです。どのように私は再帰的にJavaのgraphqlドキュメントをトラバースし、到達する最も深いレベルを見つける

例:深さ0

{ 
    name 
} 

例:深さ1

{ 
    viewer{ 
    viewerId 
    } 
} 

例:深さ2

{ 
    viewer{ 
    albums{ 
     albumId 
    } 
    } 
} 

例:あなたは、両方のアルバム/曲を見ることができるように深さ2同じ親のビューアの下にある

{ 
    viewer{ 
    albums{ 
     albumId 
    } 
    songs{ 
     songId 
    } 
    } 
} 

例:深さ3

{ 
    viewer{ 
    albums{ 
     tracks{ 
      trackId 
     } 
    } 
    } 
} 

が、私はそれを横断するベースコードを書かれているが、私のコードは、それは深さ= 3の代わりに、2返し深さ= 2の第二版では動作しません。なぜなら、それは同じ親の下で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()); 

} 

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; 

} 

String query = "{ 
     viewer{ 
      viewerId 
     }" 
QueryComplexity c = new QueryComplexity(); 
int depth = c.checkDepthLimit(query); 

私はこだわっていますし、再帰の深い知識を持つ誰かが私を助けることができるかどう非常に感謝します。

答えて

3

エラーは、子を反復する場所です。既に認識しているように(「2回カウント」)、すべての子の深さを現在の深度に追加しますが、最も深いものを追加するだけです。

このトリックん:、ビルトインQueryTraversalクラスは深さを制限するためのクエリASTおよび関連機器を点検してあなたを助けるためにgraphql-のJava V4.0のよう

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

完璧な回答!魅力のように動作します。Robert、再帰関数を呼び出すときに、どのようにコードを変更して現在の深度を渡すことができますか?他のチケットのスコアの複雑さをどのように計算するかを知るために、フィールドの時に現在の深さを知りたい。 – user1172490

1

があります:MaxQueryDepthInstrumentation

ただ、他の計測器のようにそれを登録します。

GraphQL runtime = GraphQL.newGraphQL(schema) 
    .instrumentation(new MaxQueryDepthInstrumentation(MAX_DEPTH)) 
    .build(); 

もあります10。

GraphQL runtime = GraphQL.newGraphQL(schema) 
    .instrumentation(new ComplexityAnalysisInstrumentation(new JavaScriptEvaluator(), MAX_DEPTH)) 
    .build(); 

それともSPQRのGraphQLRuntimeラッパーを使用して:あなたは上記のように、手動で同じことをComplexityAnalysisInstrumentationを登録

public static class PetService { 

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

:(私が書いた)

graphql-spqr

も宣言的な方法は、フィールドの複雑さを指定します:

GraphQL runtime = GraphQLRuntime.newGraphQL(schema) 
      .maximumQueryComplexity(maxComplexity) 
      .build(); 
関連する問題