diff --git a/src/php/coll/Cursor.php b/src/php/coll/Cursor.php index f1ec9d9..b10d011 100644 --- a/src/php/coll/Cursor.php +++ b/src/php/coll/Cursor.php @@ -2,6 +2,7 @@ namespace nur\sery\wip\php\coll; use Iterator; +use IteratorAggregate; use nulib\cl; use nulib\php\func; use nur\sery\wip\php\iter; @@ -33,7 +34,7 @@ class Cursor implements Iterator { * alors retourner le tableau * ["a" => $row["a"], "b" => $row["x"], "c" => "y", "d" => null] */ - private static function map_row(array $row, ?array $map): array { + protected static function map_row(array $row, ?array $map): array { if ($map === null) return $row; $index = 0; $mapped = []; @@ -48,7 +49,7 @@ class Cursor implements Iterator { $mapped[$key] = $func->invoke([$value, $key, $row]); } else { if ($value === null) $mapped[$key] = null; - else $mapped[$key] = cl::get($row, $key); + else $mapped[$key] = cl::get($row, $value); } } return $mapped; @@ -67,7 +68,7 @@ class Cursor implements Iterator { * - une valeur associative $key => $value indique que la clé correspondante * doit exiter avec la valeur spécifiée */ - private static function filter_row(array $row, $filter): bool { + protected static function filter_row(array $row, $filter): bool { if ($filter === null) return false; if (!is_array($filter)) $filter = [$filter]; if (!$filter) return false; @@ -79,12 +80,12 @@ class Cursor implements Iterator { if (!array_key_exists($value, $row)) return false; } elseif (is_bool($value)) { if ($value) { - if (!array_key_exists($value, $row)) return false; + if (!array_key_exists($key, $row)) return false; } else { - if (array_key_exists($value, $row)) return false; + if (array_key_exists($key, $row)) return false; } } else { - if (!array_key_exists($value, $row)) return false; + if (!array_key_exists($key, $row)) return false; if ($row[$key] !== $value) return false; } } @@ -114,6 +115,11 @@ class Cursor implements Iterator { $this->rowsGenerator = $rowsGenerator; $this->rowsFunc = $rowsFunc; + $this->cols = $params["cols"] ?? null; + $colsFunc = $params["cols_func"] ?? null; + if ($colsFunc !== null) $colsFunc = func::with($colsFunc); + $this->colsFunc = $colsFunc; + $map = $params["map"] ?? null; $mapFunc = $params["map_func"] ?? null; if ($mapFunc !== null) { @@ -140,16 +146,16 @@ class Cursor implements Iterator { /** un générateur de lignes */ private ?Traversable $rowsGenerator; - /** une fonction de signature function(Cursor):?iterable */ + /** une fonction de signature function(Cursor): ?iterable */ private ?func $rowsFunc; - /** une fonction de signature function(Cursor):?array */ + /** une fonction de signature function(Cursor): ?array */ private ?func $colsFunc; - /** une fonction de signature function(Cursor):?array */ + /** une fonction de signature function(Cursor): ?array */ private ?func $mapFunc; - /** une fonction de signature function(Cursor):bool */ + /** une fonction de signature function(Cursor): bool */ private ?func $filterFunc; protected ?iterable $rows; @@ -173,6 +179,10 @@ class Cursor implements Iterator { return null; } + protected function cols(): ?array { + return $this->row !== null? array_keys($this->row): null; + } + protected function filter(): bool { return false; } @@ -185,20 +195,24 @@ class Cursor implements Iterator { # Iterator function rewind() { + $this->cols = null; $this->index = 0; $this->origIndex = 0; $this->key = null; $this->raw = null; $this->row = null; if ($this->rowsGenerator !== null) { - $this->rows = $this->rowsGenerator; - $this->rows->rewind(); + $rows = $this->rowsGenerator; + if ($rows instanceof IteratorAggregate) $rows = $rows->getIterator(); + $rows->rewind(); + $this->rows = $rows; } else { $this->rows = $this->rowsFunc->invoke(); } } - function valid() { + function valid(): bool { + $cols = $this->colsFunc; $filter = $this->filterFunc; $map = $this->mapFunc; while ($valid = iter::valid($this->rows)) { @@ -210,6 +224,10 @@ class Cursor implements Iterator { if (!$filtered) { if ($map === null) $this->row = $this->map(); else $this->row = $map->invoke([$this]); + if ($this->cols === null) { + if ($cols === null) $this->cols = $this->cols(); + else $this->cols = $cols->invoke([$this]); + } break; } else { iter::next($this->rows); @@ -219,6 +237,7 @@ class Cursor implements Iterator { if (!$valid) { iter::close($this->rows); $this->rows = null; + $this->cols = null; $this->index = -1; $this->origIndex = -1; $this->key = null; @@ -228,7 +247,7 @@ class Cursor implements Iterator { return $valid; } - function current() { + function current(): ?array { return $this->row; } diff --git a/tests/wip/php/coll/CursorTest.php b/tests/wip/php/coll/CursorTest.php index ec820d8..f28bc95 100644 --- a/tests/wip/php/coll/CursorTest.php +++ b/tests/wip/php/coll/CursorTest.php @@ -13,6 +13,43 @@ class CursorTest extends TestCase { msg::set_messenger(new StdMessenger()); } + function test_map_row() { + $cursor = new class extends Cursor { + function mapRow(array $row, ?array $map): array { + return self::map_row($row, $map); + } + }; + $row = ["a" => 1, "b" => 2, "c" => 3, "x" => 99]; + $map = ["a", "b" => "x", "c" => function() { return "y"; }, "d" => null]; + self::assertSame([ + "a" => $row["a"], + "b" => $row["x"], + "c" => "y", + "d" => null + ], $cursor->mapRow($row, $map)); + } + + function test_filter_row() { + $cursor = new class extends Cursor { + function filterRow(array $row, $filter): bool { + return self::filter_row($row, $filter); + } + }; + $row = ["a" => 1, "b" => 2, "c" => 3, "x" => 99]; + self::assertTrue($cursor->filterRow($row, "a")); + self::assertTrue($cursor->filterRow($row, ["a"])); + self::assertTrue($cursor->filterRow($row, ["a" => true])); + self::assertFalse($cursor->filterRow($row, ["a" => false])); + self::assertTrue($cursor->filterRow($row, ["a" => 1])); + self::assertFalse($cursor->filterRow($row, ["a" => 2])); + + self::assertFalse($cursor->filterRow($row, "z")); + self::assertFalse($cursor->filterRow($row, ["z"])); + self::assertFalse($cursor->filterRow($row, ["z" => true])); + self::assertTrue($cursor->filterRow($row, ["z" => false])); + self::assertFalse($cursor->filterRow($row, ["z" => 1])); + } + const SCALARS = [0, 1, 2, 3, 4]; function generator() { @@ -41,6 +78,15 @@ class CursorTest extends TestCase { return cl::all($c); }); + $c = new Cursor(null, [ + "rows" => $this->generator(), + ]); + self::assertSame([[0], [1], [2], [3], [4]], cl::all($c)); + self::assertException(Exception::class, function() use ($c) { + // pas possible de rewind un générateur + return cl::all($c); + }); + $c = new Cursor(null, [ "rows_func" => function() { return self::SCALARS;