(
query: &str,
operation_name: Option<&str>,
)
| 194 | } |
| 195 | |
| 196 | fn classify_document( |
| 197 | query: &str, |
| 198 | operation_name: Option<&str>, |
| 199 | ) -> std::result::Result<GraphqlOperationInfo, String> { |
| 200 | let parser = Parser::new(query).recursion_limit(128).token_limit(20_000); |
| 201 | let cst = parser.parse(); |
| 202 | let mut parse_errors = cst.errors(); |
| 203 | if let Some(err) = parse_errors.next() { |
| 204 | return Err(format!("GraphQL document parse error: {err}")); |
| 205 | } |
| 206 | |
| 207 | let document = cst.document(); |
| 208 | let mut operations = Vec::new(); |
| 209 | let mut fragments = HashMap::new(); |
| 210 | |
| 211 | for definition in document.definitions() { |
| 212 | match definition { |
| 213 | cst::Definition::OperationDefinition(operation) => operations.push(operation), |
| 214 | cst::Definition::FragmentDefinition(fragment) => { |
| 215 | if let Some(name) = fragment.fragment_name().and_then(|n| n.name()) { |
| 216 | fragments.insert(name.text().to_string(), fragment); |
| 217 | } |
| 218 | } |
| 219 | _ => {} |
| 220 | } |
| 221 | } |
| 222 | |
| 223 | if operations.is_empty() { |
| 224 | return Err("GraphQL document contains no executable operation".to_string()); |
| 225 | } |
| 226 | |
| 227 | let selected = if let Some(expected_name) = operation_name.filter(|name| !name.is_empty()) { |
| 228 | operations |
| 229 | .into_iter() |
| 230 | .find(|op| { |
| 231 | op.name() |
| 232 | .is_some_and(|name| name.text().as_ref() == expected_name) |
| 233 | }) |
| 234 | .ok_or_else(|| format!("GraphQL operationName {expected_name:?} was not found"))? |
| 235 | } else if operations.len() == 1 { |
| 236 | operations.remove(0) |
| 237 | } else { |
| 238 | return Err("GraphQL document has multiple operations but no operationName".to_string()); |
| 239 | }; |
| 240 | |
| 241 | let operation_type = operation_type(&selected); |
| 242 | let operation_name = selected.name().map(|name| name.text().to_string()); |
| 243 | let selection_set = selected |
| 244 | .selection_set() |
| 245 | .ok_or_else(|| "GraphQL operation has no selection set".to_string())?; |
| 246 | let mut fields = HashSet::new(); |
| 247 | let mut visited_fragments = HashSet::new(); |
| 248 | collect_root_fields( |
| 249 | selection_set, |
| 250 | &fragments, |
| 251 | &mut visited_fragments, |
| 252 | &mut fields, |
| 253 | ); |
no test coverage detected