<commit_before><?php
namespace StudioNet\GraphQL;

use GraphQL\Executor\Executor;
use GraphQL\GraphQL as GraphQLBase;
use GraphQL\Schema;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type as Type;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Foundation\Application;
use StudioNet\GraphQL\Cache\CachePool;
use StudioNet\GraphQL\Support\Definition\Definition;
use GraphQL\Error\Error;
use StudioNet\GraphQL\Error\ValidationError;
use GraphQL\Error\Debug;
use GraphQL\Error\FormattedError;

/**
 * GraphQL implementation singleton
 *
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 */
class GraphQL {
	/** @var Application $app */
	private $app;

	/** @var CachePool $cache */
	private $cache;

	/** @var int Depth-level, how deep fields will be fetched for relations guessing */
	const FIELD_SELECTION_DEPTH = 3;

	/**
	 * __construct
	 *
	 * @param  Application $app
	 * @return void
	 */
	public function __construct(Application $app, CachePool $cache) {
		$this->app = $app;
		$this->cache = $cache;
	}

	/**
	 * Return built schema
	 *
	 * @param  string $name
	 * @return Schema
	 */
	public function getSchema($name) {
		if (!$this->hasSchema($name)) {
			throw new Exception\SchemaNotFoundException('Cannot find schema ' . $name);
		}

		// Represents an array like
		//
		// [
		//    'query'    => [],
		//    'mutation' => []
		// ]
		$schema = $this->get('schema', $name);
		$schema['query'] = $this->manageQuery($schema['query']);
		$schema['mutation'] = $this->manageMutation($schema['mutation']);

		return new Schema($schema);
	}

	/**
	 * Return existing type
	 *
	 * @param  string $name
	 * @return ObjectType
	 */
	public function type($name) {
		$name = strtolower($name);

		if ($this->has('definition', $name)) {
			return $this->get('definition', $name)->resolveType();
		}

		throw new Exception\TypeNotFoundException('Cannot find type ' . $name);
	}

	/**
	 * Return input
	 *
	 * @param  string $name
	 * @return \GraphQL\Type\Definition\InputObjectType
	 */
	public function input($name) {
		$name = strtolower($name);

		if ($this->has('definition', $name)) {
			return $this->get('definition', $name)->resolveInputType();
		}

		throw new Exception\TypeNotFoundException('Cannot find type ' . $name);
	}

	/**
	 * Return existing type as lifeOf
	 *
	 * @param  string $name
	 * @return \GraphQL\Type\Definition\ListOfType
	 */
	public function listOf($name) {
		return Type::listOf($this->type($name));
	}

	/**
	 * Execute query
	 *
	 * @param  string $query
	 * @param  array  $variables
	 * @param  array  $opts
	 *
	 * @return array
	 */
	public function execute($query, $variables = [], $opts = []) {
		$root = array_get($opts, 'root', null);
		$context = array_get($opts, 'context', null);
		$schemaName = array_get($opts, 'schema', null);
		$operation = array_get($opts, 'operationName', null);
		$schema = $this->getSchema($schemaName);
		$fieldResolver = function ($source, $args, $context, $info) {
			$result = Executor::defaultFieldResolver($source, $args, $context, $info);

			if (is_null($result)) {
				$result = data_get($source, snake_case($info->fieldName));
			}

			return $result;
		};

		// rethrow internal exception (will be catched in the controller)
		return GraphQLBase::executeQuery($schema, $query, $root, $context, $variables, $operation, $fieldResolver)
			// override default error formatter to handle dev mode
			->setErrorFormatter(function (Error $error) {
				return self::formatGraphQLException($error->getPrevious());
			})
			->toArray();
	}

	/**
	 * handle GraphQL exception
	 *
	 * @param  \Throwable $e
	 * @return array
	 * @static
	 */
	static public function formatGraphQLException(\Throwable $e): array {
		$debug = false;

		// if debug mode is activated, we have to include debug message and
		// trace to easily found exception
		if (config('app.debug')) {
			$debug = DEBUG::INCLUDE_DEBUG_MESSAGE | Debug::INCLUDE_TRACE;
		}

		// create the array exception based on default GraphQL implementation<commit_msg>fix(chore): an exception could not always inherit from \Trowable<commit_after><?php
namespace StudioNet\GraphQL;

use GraphQL\Executor\Executor;
use GraphQL\GraphQL as GraphQLBase;
use GraphQL\Schema;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type as Type;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Foundation\Application;
use StudioNet\GraphQL\Cache\CachePool;
use StudioNet\GraphQL\Support\Definition\Definition;
use GraphQL\Error\Error;
use StudioNet\GraphQL\Error\ValidationError;
use GraphQL\Error\Debug;
use GraphQL\Error\FormattedError;

/**
 * GraphQL implementation singleton
 *
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 */
class GraphQL {
	/** @var Application $app */
	private $app;

	/** @var CachePool $cache */
	private $cache;

	/** @var int Depth-level, how deep fields will be fetched for relations guessing */
	const FIELD_SELECTION_DEPTH = 3;

	/**
	 * __construct
	 *
	 * @param  Application $app
	 * @return void
	 */
	public function __construct(Application $app, CachePool $cache) {
		$this->app = $app;
		$this->cache = $cache;
	}

	/**
	 * Return built schema
	 *
	 * @param  string $name
	 * @return Schema
	 */
	public function getSchema($name) {
		if (!$this->hasSchema($name)) {
			throw new Exception\SchemaNotFoundException('Cannot find schema ' . $name);
		}

		// Represents an array like
		//
		// [
		//    'query'    => [],
		//    'mutation' => []
		// ]
		$schema = $this->get('schema', $name);
		$schema['query'] = $this->manageQuery($schema['query']);
		$schema['mutation'] = $this->manageMutation($schema['mutation']);

		return new Schema($schema);
	}

	/**
	 * Return existing type
	 *
	 * @param  string $name
	 * @return ObjectType
	 */
	public function type($name) {
		$name = strtolower($name);

		if ($this->has('definition', $name)) {
			return $this->get('definition', $name)->resolveType();
		}

		throw new Exception\TypeNotFoundException('Cannot find type ' . $name);
	}

	/**
	 * Return input
	 *
	 * @param  string $name
	 * @return \GraphQL\Type\Definition\InputObjectType
	 */
	public function input($name) {
		$name = strtolower($name);

		if ($this->has('definition', $name)) {
			return $this->get('definition', $name)->resolveInputType();
		}

		throw new Exception\TypeNotFoundException('Cannot find type ' . $name);
	}

	/**
	 * Return existing type as lifeOf
	 *
	 * @param  string $name
	 * @return \GraphQL\Type\Definition\ListOfType
	 */
	public function listOf($name) {
		return Type::listOf($this->type($name));
	}

	/**
	 * Execute query
	 *
	 * @param  string $query
	 * @param  array  $variables
	 * @param  array  $opts
	 *
	 * @return array
	 */
	public function execute($query, $variables = [], $opts = []) {
		$root = array_get($opts, 'root', null);
		$context = array_get($opts, 'context', null);
		$schemaName = array_get($opts, 'schema', null);
		$operation = array_get($opts, 'operationName', null);
		$schema = $this->getSchema($schemaName);
		$fieldResolver = function ($source, $args, $context, $info) {
			$result = Executor::defaultFieldResolver($source, $args, $context, $info);

			if (is_null($result)) {
				$result = data_get($source, snake_case($info->fieldName));
			}

			return $result;
		};

		// rethrow internal exception (will be catched in the controller)
		return GraphQLBase::executeQuery($schema, $query, $root, $context, $variables, $operation, $fieldResolver)
			// override default error formatter to handle dev mode
			->setErrorFormatter(function (Error $error) {
				return self::formatGraphQLException($error->getPrevious() ?? $error);
			})
			->toArray();
	}

	/**
	 * handle GraphQL exception
	 *
	 * @param  \Throwable|\GraphQL\Error\Error $e
	 * @return array
	 * @static
	 */
	static public function formatGraphQLException($e): array {
		$debug = false;

		// if debug mode is activated, we have to include debug message and
		// trace to easily found exception
		if (config('app.debug')) {
			$debug = DEBUG::INCLUDE_DEBUG_MESSAGE | Debug::INCLUDE_TRACE;
		}

		// create the array exception based on default GraphQL implementation
{'fraction_non_alphanumeric': 0.15193873830071716, 'fraction_numerical': 0.00024310198128114745, 'mean_word_length': 3.912238805970149, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '58683', 'n_tokens_mistral': 2788, 'n_tokens_neox': 2527, 'n_words': 635}