/** * Coroutine to walk the query and schema in DFS manner (see AbstractQueryVisitor docs for more info) and yield a * tuple of (queryNode, schemaNode, childScore) * * childScore costs are accumulated via values sent into the coroutine. * * Most of the branching in this function is just to handle the different types in a query: Queries, Unions, * Fragments (anonymous and named), and Fields. The core of the function is simple: recurse until we hit the base * case of a Field and yield that back up to the visitor up in `doVisit`. * * @param Query|Field|\Youshido\GraphQL\Parser\Ast\Interfaces\FragmentInterface $queryNode * @param FieldInterface $currentLevelAST * * @return \Generator */ protected function walkQuery($queryNode, FieldInterface $currentLevelAST) { $childrenScore = 0; if (!$queryNode instanceof FieldAst) { foreach ($queryNode->getFields() as $queryField) { if ($queryField instanceof FragmentInterface) { if ($queryField instanceof FragmentReference) { $queryField = $this->executionContext->getRequest()->getFragment($queryField->getName()); } // the next 7 lines are essentially equivalent to `yield from $this->walkQuery(...)` in PHP7. // for backwards compatibility this is equivalent. // This pattern is repeated multiple times in this function, and unfortunately cannot be extracted or // made less verbose. $gen = $this->walkQuery($queryField, $currentLevelAST); $next = $gen->current(); while ($next) { $received = (yield $next); $childrenScore += (int) $received; $next = $gen->send($received); } } else { $fieldType = $currentLevelAST->getType()->getNamedType(); if ($fieldType instanceof AbstractUnionType) { foreach ($fieldType->getTypes() as $unionFieldType) { if ($fieldAst = $unionFieldType->getField($queryField->getName())) { $gen = $this->walkQuery($queryField, $fieldAst); $next = $gen->current(); while ($next) { $received = (yield $next); $childrenScore += (int) $received; $next = $gen->send($received); } } } } elseif ($fieldType instanceof AbstractObjectType && ($fieldAst = $fieldType->getField($queryField->getName()))) { $gen = $this->walkQuery($queryField, $fieldAst); $next = $gen->current(); while ($next) { $received = (yield $next); $childrenScore += (int) $received; $next = $gen->send($received); } } } } } // sanity check. don't yield fragments; they don't contribute to cost if ($queryNode instanceof Query || $queryNode instanceof FieldAst) { // BASE CASE. If we're here we're done recursing - // this node is either a field, or a query that we've finished recursing into. (yield [$queryNode, $currentLevelAST, $childrenScore]); } }
protected function resolveQuery(AstQuery $query) { $schema = $this->executionContext->getSchema(); $type = $query instanceof AstMutation ? $schema->getMutationType() : $schema->getQueryType(); $field = new Field(['name' => $query instanceof AstMutation ? 'mutation' : 'query', 'type' => $type]); if (self::TYPE_NAME_QUERY == $query->getName()) { return [$this->getAlias($query) => $type->getName()]; } $this->resolveValidator->assetTypeHasField($type, $query); $value = $this->resolveField($field, $query); return [$this->getAlias($query) => $value]; }
public function testQuery() { $arguments = [new Argument('limit', new Literal('10', new Location(1, 1)), new Location(1, 1))]; $fields = [new Field('id', null, [], new Location(1, 1))]; $query = new Query('ships', 'lastShips', $arguments, $fields, new Location(1, 1)); $this->assertEquals('ships', $query->getName()); $this->assertEquals('lastShips', $query->getAlias()); $this->assertEquals($arguments, $query->getArguments()); $this->assertEquals(['limit' => '10'], $query->getKeyValueArguments()); $this->assertEquals($fields, $query->getFields()); $this->assertTrue($query->hasArguments()); $this->assertTrue($query->hasFields()); $query->setFields([]); $query->setArguments([]); $this->assertEmpty($query->getArguments()); $this->assertEmpty($query->getFields()); $this->assertEmpty($query->getKeyValueArguments()); $this->assertFalse($query->hasArguments()); $this->assertFalse($query->hasFields()); $query->addArgument(new Argument('offset', new Literal(10, new Location(1, 1)), new Location(1, 1))); $this->assertTrue($query->hasArguments()); }