-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
Copy pathanalysis.rb
96 lines (84 loc) · 3.01 KB
/
analysis.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# frozen_string_literal: true
require "graphql/analysis/visitor"
require "graphql/analysis/analyzer"
require "graphql/analysis/field_usage"
require "graphql/analysis/query_complexity"
require "graphql/analysis/max_query_complexity"
require "graphql/analysis/query_depth"
require "graphql/analysis/max_query_depth"
module GraphQL
module Analysis
AST = self
class TimeoutError < AnalysisError
def initialize(...)
super("Timeout on validation of query")
end
end
module_function
# Analyze a multiplex, and all queries within.
# Multiplex analyzers are ran for all queries, keeping state.
# Query analyzers are ran per query, without carrying state between queries.
#
# @param multiplex [GraphQL::Execution::Multiplex]
# @param analyzers [Array<GraphQL::Analysis::Analyzer>]
# @return [Array<Any>] Results from multiplex analyzers
def analyze_multiplex(multiplex, analyzers)
multiplex_analyzers = analyzers.map { |analyzer| analyzer.new(multiplex) }
multiplex.current_trace.analyze_multiplex(multiplex: multiplex) do
query_results = multiplex.queries.map do |query|
if query.valid?
analyze_query(
query,
query.analyzers,
multiplex_analyzers: multiplex_analyzers
)
else
[]
end
end
multiplex_results = multiplex_analyzers.map(&:result)
multiplex_errors = analysis_errors(multiplex_results)
multiplex.queries.each_with_index do |query, idx|
query.analysis_errors = multiplex_errors + analysis_errors(query_results[idx])
end
multiplex_results
end
end
# @param query [GraphQL::Query]
# @param analyzers [Array<GraphQL::Analysis::Analyzer>]
# @return [Array<Any>] Results from those analyzers
def analyze_query(query, analyzers, multiplex_analyzers: [])
query.current_trace.analyze_query(query: query) do
query_analyzers = analyzers
.map { |analyzer| analyzer.new(query) }
.tap { _1.select!(&:analyze?) }
analyzers_to_run = query_analyzers + multiplex_analyzers
if !analyzers_to_run.empty?
analyzers_to_run.select!(&:visit?)
if !analyzers_to_run.empty?
visitor = GraphQL::Analysis::Visitor.new(
query: query,
analyzers: analyzers_to_run,
timeout: query.validate_timeout_remaining,
)
visitor.visit
if !visitor.rescued_errors.empty?
return visitor.rescued_errors
end
end
query_analyzers.map(&:result)
else
[]
end
end
rescue TimeoutError => err
[err]
rescue GraphQL::UnauthorizedError, GraphQL::ExecutionError
# This error was raised during analysis and will be returned the client before execution
[]
end
def analysis_errors(results)
results.flatten.tap { _1.select! { |r| r.is_a?(GraphQL::AnalysisError) } }
end
end
end