Skip to content

Commit 2d54f65

Browse files
committed
Fine-grained type checks for Executor
1 parent 1c58fb5 commit 2d54f65

File tree

2 files changed

+41
-4
lines changed

2 files changed

+41
-4
lines changed

src/Executor/Executor.php

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -415,11 +415,16 @@ private static function resolveField(ExecutionContext $exeContext, ObjectType $p
415415
if ($mapFn) {
416416
try {
417417
$mapped = call_user_func($mapFn, $sourceValueList, $args, $info);
418+
$validType = is_array($mapped) || ($mapped instanceof \Traversable && $mapped instanceof \Countable);
419+
$mappedCount = count($mapped);
420+
$sourceCount = count($sourceValueList);
418421

419422
Utils::invariant(
420-
is_array($mapped) && count($mapped) === count($sourceValueList),
421-
"Function `map` of $parentType.$fieldName is expected to return array " .
422-
"with exact same number of items as list being mapped (first argument of `map`)"
423+
$validType && count($mapped) === count($sourceValueList),
424+
"Function `map` of $parentType.$fieldName is expected to return array or " .
425+
"countable traversable with exact same number of items as list being mapped. ".
426+
"Got '%s' with count '$mappedCount' against '$sourceCount' expected.",
427+
Utils::getVariableType($mapped)
423428
);
424429

425430
} catch (\Exception $error) {
@@ -682,7 +687,8 @@ private static function completeValue(ExecutionContext $exeContext, Type $return
682687

683688
// Collect sub-fields to execute to complete this value.
684689
$subFieldASTs = self::collectSubFields($exeContext, $objectType, $fieldASTs);
685-
return self::executeFields($exeContext, $objectType, [$result], $subFieldASTs)[0];
690+
$executed = self::executeFields($exeContext, $objectType, [$result], $subFieldASTs);
691+
return isset($executed[0]) ? $executed[0] : null;
686692
}
687693

688694
/**

src/Utils.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,24 @@ public static function map($traversable, callable $fn)
8686
return $map;
8787
}
8888

89+
/**
90+
* @param $traversable
91+
* @param callable $fn
92+
* @return array
93+
* @throws \Exception
94+
*/
95+
public static function mapKeyValue($traversable, callable $fn)
96+
{
97+
self::invariant(is_array($traversable) || $traversable instanceof \Traversable, __METHOD__ . ' expects array or Traversable');
98+
99+
$map = [];
100+
foreach ($traversable as $key => $value) {
101+
list($newKey, $newValue) = $fn($value, $key);
102+
$map[$newKey] = $newValue;
103+
}
104+
return $map;
105+
}
106+
89107
/**
90108
* @param $traversable
91109
* @param callable $keyFn function($value, $key) => $newKey
@@ -106,6 +124,19 @@ public static function keyMap($traversable, callable $keyFn)
106124
return $map;
107125
}
108126

127+
/**
128+
* @param $traversable
129+
* @param callable $fn
130+
*/
131+
public static function each($traversable, callable $fn)
132+
{
133+
self::invariant(is_array($traversable) || $traversable instanceof \Traversable, __METHOD__ . ' expects array or Traversable');
134+
135+
foreach ($traversable as $key => $item) {
136+
$fn($item, $key);
137+
}
138+
}
139+
109140
/**
110141
* Splits original traversable to several arrays with keys equal to $keyFn return
111142
*

0 commit comments

Comments
 (0)