Fine-grained type checks for Executor

This commit is contained in:
vladar 2015-10-17 17:34:51 +06:00
parent 1c58fb5e71
commit 2d54f654c2
2 changed files with 41 additions and 4 deletions

View File

@ -415,11 +415,16 @@ class Executor
if ($mapFn) { if ($mapFn) {
try { try {
$mapped = call_user_func($mapFn, $sourceValueList, $args, $info); $mapped = call_user_func($mapFn, $sourceValueList, $args, $info);
$validType = is_array($mapped) || ($mapped instanceof \Traversable && $mapped instanceof \Countable);
$mappedCount = count($mapped);
$sourceCount = count($sourceValueList);
Utils::invariant( Utils::invariant(
is_array($mapped) && count($mapped) === count($sourceValueList), $validType && count($mapped) === count($sourceValueList),
"Function `map` of $parentType.$fieldName is expected to return array " . "Function `map` of $parentType.$fieldName is expected to return array or " .
"with exact same number of items as list being mapped (first argument of `map`)" "countable traversable with exact same number of items as list being mapped. ".
"Got '%s' with count '$mappedCount' against '$sourceCount' expected.",
Utils::getVariableType($mapped)
); );
} catch (\Exception $error) { } catch (\Exception $error) {
@ -682,7 +687,8 @@ class Executor
// Collect sub-fields to execute to complete this value. // Collect sub-fields to execute to complete this value.
$subFieldASTs = self::collectSubFields($exeContext, $objectType, $fieldASTs); $subFieldASTs = self::collectSubFields($exeContext, $objectType, $fieldASTs);
return self::executeFields($exeContext, $objectType, [$result], $subFieldASTs)[0]; $executed = self::executeFields($exeContext, $objectType, [$result], $subFieldASTs);
return isset($executed[0]) ? $executed[0] : null;
} }
/** /**

View File

@ -86,6 +86,24 @@ class Utils
return $map; return $map;
} }
/**
* @param $traversable
* @param callable $fn
* @return array
* @throws \Exception
*/
public static function mapKeyValue($traversable, callable $fn)
{
self::invariant(is_array($traversable) || $traversable instanceof \Traversable, __METHOD__ . ' expects array or Traversable');
$map = [];
foreach ($traversable as $key => $value) {
list($newKey, $newValue) = $fn($value, $key);
$map[$newKey] = $newValue;
}
return $map;
}
/** /**
* @param $traversable * @param $traversable
* @param callable $keyFn function($value, $key) => $newKey * @param callable $keyFn function($value, $key) => $newKey
@ -106,6 +124,19 @@ class Utils
return $map; return $map;
} }
/**
* @param $traversable
* @param callable $fn
*/
public static function each($traversable, callable $fn)
{
self::invariant(is_array($traversable) || $traversable instanceof \Traversable, __METHOD__ . ' expects array or Traversable');
foreach ($traversable as $key => $item) {
$fn($item, $key);
}
}
/** /**
* Splits original traversable to several arrays with keys equal to $keyFn return * Splits original traversable to several arrays with keys equal to $keyFn return
* *