déplacer les fonctions dans nulib
This commit is contained in:
parent
1c45bcb4af
commit
d17b826b5a
168
src/php/iter.php
168
src/php/iter.php
@ -1,168 +0,0 @@
|
|||||||
<?php # -*- coding: utf-8 mode: php -*- vim:sw=2:sts=2:et:ai:si:sta:fenc=utf-8
|
|
||||||
namespace nulib\php;
|
|
||||||
|
|
||||||
use Exception;
|
|
||||||
use Generator;
|
|
||||||
use Iterator;
|
|
||||||
use IteratorAggregate;
|
|
||||||
use nulib\StopException;
|
|
||||||
use nulib\ValueException;
|
|
||||||
use Traversable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class iter: gestion des itérateurs
|
|
||||||
*/
|
|
||||||
class iter {
|
|
||||||
private static function unexpected_type($object): ValueException {
|
|
||||||
return ValueException::invalid_type($object, "iterable");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fermer "proprement" un itérateur ou un générateur. retourner true en cas de
|
|
||||||
* succès, ou false si c'est un générateur et qu'il ne supporte pas l'arrêt
|
|
||||||
* avec StopException (la valeur de retour n'est alors pas disponible)
|
|
||||||
*/
|
|
||||||
static function close($it): bool {
|
|
||||||
if ($it instanceof ICloseable) {
|
|
||||||
$it->close();
|
|
||||||
return true;
|
|
||||||
} elseif ($it instanceof Generator) {
|
|
||||||
try {
|
|
||||||
$it->throw(new StopException());
|
|
||||||
return true;
|
|
||||||
} catch (StopException $e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* retourner la première valeur du tableau, de l'itérateur ou de l'instance
|
|
||||||
* de Traversable, ou $default si aucun élément n'est trouvé.
|
|
||||||
*/
|
|
||||||
static final function first($values, $default=null) {
|
|
||||||
if ($values instanceof IteratorAggregate) $values = $values->getIterator();
|
|
||||||
if ($values instanceof Iterator) {
|
|
||||||
try {
|
|
||||||
$values->rewind();
|
|
||||||
$value = $values->valid()? $values->current(): $default;
|
|
||||||
} finally {
|
|
||||||
self::close($values);
|
|
||||||
}
|
|
||||||
} elseif (is_array($values) || $values instanceof Traversable) {
|
|
||||||
$value = $default;
|
|
||||||
foreach ($values as $value) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw self::unexpected_type($values);
|
|
||||||
}
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* retourner la première clé du tableau, de l'itérateur ou de l'instance
|
|
||||||
* de Traversable, ou $default si aucun élément n'est trouvé.
|
|
||||||
*/
|
|
||||||
static final function first_key($values, $default=null) {
|
|
||||||
if ($values instanceof IteratorAggregate) $values = $values->getIterator();
|
|
||||||
if ($values instanceof Iterator) {
|
|
||||||
try {
|
|
||||||
$values->rewind();
|
|
||||||
$key = $values->valid()? $values->key(): $default;
|
|
||||||
} finally {
|
|
||||||
self::close($values);
|
|
||||||
}
|
|
||||||
} elseif (is_array($values) || $values instanceof Traversable) {
|
|
||||||
$key = $default;
|
|
||||||
foreach ($values as $key => $ignored) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw self::unexpected_type($values);
|
|
||||||
}
|
|
||||||
return $key;
|
|
||||||
}
|
|
||||||
|
|
||||||
#############################################################################
|
|
||||||
# outils pour gérer de façon générique des instances de {@link Iterator} ou
|
|
||||||
# des arrays
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $it ?iterable|array
|
|
||||||
* @return bool true si l'itérateur ou le tableau ont pu être réinitialisés
|
|
||||||
*/
|
|
||||||
static function rewind(&$it, ?Exception &$exception=null): bool {
|
|
||||||
if ($it instanceof Iterator) {
|
|
||||||
try {
|
|
||||||
$exception = null;
|
|
||||||
$it->rewind();
|
|
||||||
return true;
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$exception = $e;
|
|
||||||
}
|
|
||||||
} elseif ($it !== null) {
|
|
||||||
reset($it);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $it ?iterable|array
|
|
||||||
*/
|
|
||||||
static function valid($it): bool {
|
|
||||||
if ($it instanceof Iterator) {
|
|
||||||
return $it->valid();
|
|
||||||
} elseif ($it !== null) {
|
|
||||||
return key($it) !== null;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $it ?iterable|array
|
|
||||||
*/
|
|
||||||
static function current($it, &$key=null) {
|
|
||||||
if ($it instanceof Iterator) {
|
|
||||||
$key = $it->key();
|
|
||||||
return $it->current();
|
|
||||||
} elseif ($it !== null) {
|
|
||||||
$key = key($it);
|
|
||||||
return current($it);
|
|
||||||
} else {
|
|
||||||
$key = null;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $it ?iterable|array
|
|
||||||
*/
|
|
||||||
static function next(&$it, ?Exception &$exception=null): void {
|
|
||||||
if ($it instanceof Iterator) {
|
|
||||||
try {
|
|
||||||
$exception = null;
|
|
||||||
$it->next();
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$exception = $e;
|
|
||||||
}
|
|
||||||
} elseif ($it !== null) {
|
|
||||||
next($it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* obtenir la valeur de retour si $it est un générateur terminé, ou null sinon
|
|
||||||
*/
|
|
||||||
static function get_return($it) {
|
|
||||||
if ($it instanceof Generator) {
|
|
||||||
try {
|
|
||||||
return $it->getReturn();
|
|
||||||
} catch (Exception $e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,310 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace nulib\php\iter;
|
|
||||||
|
|
||||||
use ArrayAccess;
|
|
||||||
use Iterator;
|
|
||||||
use IteratorAggregate;
|
|
||||||
use nulib\cl;
|
|
||||||
use nulib\php\func;
|
|
||||||
use nulib\php\iter;
|
|
||||||
use Traversable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class Cursor: parcours des lignes itérable
|
|
||||||
*
|
|
||||||
* XXX si on spécifie $cols ou $colsFunc, il y a une possibilité que les clés de
|
|
||||||
* $row ne soient pas dans le bon ordre, ou que les clés de $cols ne soient pas
|
|
||||||
* présentes dans $row. ajouter les paramètres ensure_keys et order_keys
|
|
||||||
*
|
|
||||||
* @property-read array|null $value alias pour $row
|
|
||||||
* @property-read iterable|null $rows la source des lignes
|
|
||||||
*/
|
|
||||||
class Cursor implements Iterator, ArrayAccess {
|
|
||||||
const PARAMS_SCHEMA = [
|
|
||||||
"rows" => ["?iterable"],
|
|
||||||
"rows_func" => ["?callable"],
|
|
||||||
"filter" => ["?array"],
|
|
||||||
"filter_func" => ["?callable"],
|
|
||||||
"map" => ["?array"],
|
|
||||||
"map_func" => ["?callable"],
|
|
||||||
"cols" => ["?array"],
|
|
||||||
"cols_func" => ["?callable"],
|
|
||||||
];
|
|
||||||
|
|
||||||
function __construct(?iterable $rows=null, ?array $params=null) {
|
|
||||||
if ($rows !== null) $params["rows"] = $rows;
|
|
||||||
|
|
||||||
$rows = $params["rows"] ?? null;
|
|
||||||
$rowsGenerator = null;
|
|
||||||
$rowsFunc = $params["rows_func"] ?? null;
|
|
||||||
if ($rowsFunc !== null) {
|
|
||||||
if ($rowsFunc instanceof Traversable) {
|
|
||||||
$rowsGenerator = $rowsFunc;
|
|
||||||
$rowsFunc = null;
|
|
||||||
} else {
|
|
||||||
$rowsFunc = func::with($rowsFunc, [$rows, $this]);
|
|
||||||
}
|
|
||||||
} elseif ($rows instanceof Traversable) {
|
|
||||||
$rowsGenerator = $rows;
|
|
||||||
} else {
|
|
||||||
$rowsFunc = func::with(function() use ($rows) {
|
|
||||||
return $rows;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
$this->rowsGenerator = $rowsGenerator;
|
|
||||||
$this->rowsFunc = $rowsFunc;
|
|
||||||
|
|
||||||
$filter = $params["filter"] ?? null;
|
|
||||||
$filterFunc = $params["filter_func"] ?? null;
|
|
||||||
if ($filterFunc !== null) $this->setFilterFunc($filterFunc);
|
|
||||||
elseif ($filter !== null) $this->setFilter($filter);
|
|
||||||
|
|
||||||
$map = $params["map"] ?? null;
|
|
||||||
$mapFunc = $params["map_func"] ?? null;
|
|
||||||
if ($mapFunc !== null) $this->setMapFunc($mapFunc);
|
|
||||||
elseif ($map !== null) $this->setMap($map);
|
|
||||||
|
|
||||||
$this->cols = $params["cols"] ?? null;
|
|
||||||
$this->setColsFunc($params["cols_func"] ?? null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** un générateur de lignes */
|
|
||||||
private ?Traversable $rowsGenerator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* une fonction de signature <code>function(mixed $rows, Cursor): ?iterable</code>
|
|
||||||
*/
|
|
||||||
private ?func $rowsFunc;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* une fonction de signature <code>function(?array $row, Cursor): bool</code>
|
|
||||||
*/
|
|
||||||
private ?func $filterFunc = null;
|
|
||||||
|
|
||||||
function setFilter(array $filter): self {
|
|
||||||
$this->filterFunc = func::with(function(?array $row) use ($filter) {
|
|
||||||
return cl::filter($row, $filter);
|
|
||||||
});
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setFilterFunc(?callable $func): self {
|
|
||||||
if ($func === null) $this->filterFunc = null;
|
|
||||||
else $this->filterFunc = func::with($func)->bind($this);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* une fonction de signature <code>function(?array $row, Cursor): ?array</code>
|
|
||||||
*/
|
|
||||||
private ?func $mapFunc = null;
|
|
||||||
|
|
||||||
function setMap(array $map): self {
|
|
||||||
$this->mapFunc = func::with(function(?array $row) use ($map) {
|
|
||||||
return cl::map($row, $map);
|
|
||||||
});
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setMapFunc(?callable $func): self {
|
|
||||||
if ($func === null) $this->mapFunc = null;
|
|
||||||
else $this->mapFunc = func::with($func)->bind($this);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* une fonction de signature <code>function(?array $row, Cursor): ?array</code>
|
|
||||||
*/
|
|
||||||
private ?func $colsFunc = null;
|
|
||||||
|
|
||||||
function setColsFunc(?callable $func): self {
|
|
||||||
$this->cols = null;
|
|
||||||
if ($func === null) $this->colsFunc = null;
|
|
||||||
else $this->colsFunc = func::with($func)->bind($this);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var iterable|null source des éléments */
|
|
||||||
protected ?iterable $rows;
|
|
||||||
|
|
||||||
/** @var array|null listes des colonnes de chaque enregistrement */
|
|
||||||
public ?array $cols;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var int index de l'enregistrement (en ne comptant pas les éléments filtrés)
|
|
||||||
*/
|
|
||||||
public int $index;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var int index original de l'enregistrement (en tenant compte des éléments
|
|
||||||
* filtrés)
|
|
||||||
*/
|
|
||||||
public int $origIndex;
|
|
||||||
|
|
||||||
/** @var string|int clé de l'enregistrement */
|
|
||||||
public $key;
|
|
||||||
|
|
||||||
/** @var mixed élément original récupéré depuis la source */
|
|
||||||
public $raw;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array|null enregistrement après conversion en tableau et application
|
|
||||||
* du mapping
|
|
||||||
*/
|
|
||||||
public ?array $row;
|
|
||||||
|
|
||||||
function __get($name) {
|
|
||||||
if ($name === "value") return $this->row;
|
|
||||||
elseif ($name == "rows") return $this->rows;
|
|
||||||
trigger_error("Undefined property $name");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function offsetExists($offset): bool {
|
|
||||||
return cl::has($this->row, $offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
function offsetGet($offset) {
|
|
||||||
return cl::get($this->row, $offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
function offsetSet($offset, $value): void {
|
|
||||||
cl::set($this->row, $offset, $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
function offsetUnset($offset): void {
|
|
||||||
cl::del($this->row, $offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* données de session: cela permet de maintenir certaines informations pendant
|
|
||||||
* le parcours des données
|
|
||||||
*/
|
|
||||||
protected ?array $data;
|
|
||||||
|
|
||||||
/** @param string|int $key */
|
|
||||||
function has($key): bool {
|
|
||||||
return cl::has($this->data, $key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param string|int $key */
|
|
||||||
function get($key) {
|
|
||||||
return cl::get($this->data, $key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param string|int $key */
|
|
||||||
function set($key, $value): void {
|
|
||||||
$this->data[$key] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param string|int $key */
|
|
||||||
function del($key) {
|
|
||||||
$orig = cl::get($this->data, $key);
|
|
||||||
unset($this->data[$key]);
|
|
||||||
return $orig;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function convertToRow($raw): ?array {
|
|
||||||
return cl::withn($raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function filterFunc(?array $row): bool {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function mapFunc(?array $row): ?array {
|
|
||||||
return $this->row;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function colsFunc(?array $row): ?array {
|
|
||||||
return $this->row !== null? array_keys($this->row): null;
|
|
||||||
}
|
|
||||||
|
|
||||||
#############################################################################
|
|
||||||
# Iterator
|
|
||||||
|
|
||||||
function rewind() {
|
|
||||||
$this->cols = null;
|
|
||||||
$this->index = 0;
|
|
||||||
$this->origIndex = 0;
|
|
||||||
$this->key = null;
|
|
||||||
$this->raw = null;
|
|
||||||
$this->row = null;
|
|
||||||
$this->data = null;
|
|
||||||
if ($this->rowsGenerator !== null) {
|
|
||||||
$rows = $this->rowsGenerator;
|
|
||||||
if ($rows instanceof IteratorAggregate) $rows = $rows->getIterator();
|
|
||||||
$rows->rewind();
|
|
||||||
$this->rows = $rows;
|
|
||||||
} else {
|
|
||||||
$this->rows = $this->rowsFunc->invoke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function valid(): bool {
|
|
||||||
$colsFunc = $this->colsFunc;
|
|
||||||
$filterFunc = $this->filterFunc;
|
|
||||||
$mapFunc = $this->mapFunc;
|
|
||||||
while ($valid = iter::valid($this->rows)) {
|
|
||||||
$this->raw = iter::current($this->rows, $this->key);
|
|
||||||
# conversion en enregistrement
|
|
||||||
$this->key ??= $this->origIndex;
|
|
||||||
$this->row = $this->convertToRow($this->raw);
|
|
||||||
# filtrage
|
|
||||||
if ($filterFunc === null) $filtered = $this->filterFunc($this->row);
|
|
||||||
else $filtered = $filterFunc->invoke([$this->row, $this]);
|
|
||||||
if ($filtered) {
|
|
||||||
iter::next($this->rows);
|
|
||||||
$this->origIndex++;
|
|
||||||
} else {
|
|
||||||
# l'enregistrement n'as pas été filtré: faire le mapping
|
|
||||||
if ($mapFunc === null) $this->row = $this->mapFunc($this->row);
|
|
||||||
else $this->row = $mapFunc->invoke([$this->row, $this]);
|
|
||||||
# calculer la liste des colonnes le cas échéant
|
|
||||||
if ($this->cols === null) {
|
|
||||||
if ($colsFunc === null) $this->cols = $this->colsFunc($this->row);
|
|
||||||
else $this->cols = $colsFunc->invoke([$this->row, $this]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!$valid) {
|
|
||||||
iter::close($this->rows);
|
|
||||||
$this->rows = null;
|
|
||||||
$this->cols = null;
|
|
||||||
$this->index = -1;
|
|
||||||
$this->origIndex = -1;
|
|
||||||
$this->key = null;
|
|
||||||
$this->raw = null;
|
|
||||||
$this->row = null;
|
|
||||||
# ne pas toucher à data, l'utilisateur peut vouloir continuer à consulter
|
|
||||||
# les valeurs
|
|
||||||
}
|
|
||||||
return $valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
function current(): ?array {
|
|
||||||
return $this->row;
|
|
||||||
}
|
|
||||||
|
|
||||||
function key() {
|
|
||||||
return $this->key;
|
|
||||||
}
|
|
||||||
|
|
||||||
function next() {
|
|
||||||
iter::next($this->rows);
|
|
||||||
$this->index++;
|
|
||||||
$this->origIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
#############################################################################
|
|
||||||
|
|
||||||
function each(callable $func): void {
|
|
||||||
$func = func::with($func);
|
|
||||||
$this->rewind();
|
|
||||||
while ($this->valid()) {
|
|
||||||
$func->invoke([$this]);
|
|
||||||
$this->next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,152 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace nulib\php\coll;
|
|
||||||
|
|
||||||
use Exception;
|
|
||||||
use nulib\cl;
|
|
||||||
use nulib\tests\TestCase;
|
|
||||||
use TypeError;
|
|
||||||
|
|
||||||
class CursorTest extends TestCase {
|
|
||||||
function test_map_row() {
|
|
||||||
$cursor = new class extends Cursor {
|
|
||||||
function mapRow(array $row, ?array $map): array {
|
|
||||||
return cl::map($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 cl::filter($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() {
|
|
||||||
yield from self::SCALARS;
|
|
||||||
}
|
|
||||||
|
|
||||||
function testVanilla() {
|
|
||||||
$c = new Cursor(self::SCALARS);
|
|
||||||
self::assertSame([[0], [1], [2], [3], [4]], cl::all($c));
|
|
||||||
self::assertSame([[0], [1], [2], [3], [4]], cl::all($c));
|
|
||||||
|
|
||||||
$c = new Cursor($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" => function() {
|
|
||||||
return self::SCALARS;
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
self::assertError(TypeError::class, function() use ($c) {
|
|
||||||
// rows doit être un iterable, pas une fonction
|
|
||||||
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;
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
self::assertSame([[0], [1], [2], [3], [4]], cl::all($c));
|
|
||||||
self::assertSame([[0], [1], [2], [3], [4]], cl::all($c));
|
|
||||||
|
|
||||||
$c = new Cursor(null, [
|
|
||||||
"rows_func" => $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() {
|
|
||||||
yield from self::SCALARS;
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
self::assertSame([[0], [1], [2], [3], [4]], cl::all($c));
|
|
||||||
self::assertSame([[0], [1], [2], [3], [4]], cl::all($c));
|
|
||||||
}
|
|
||||||
|
|
||||||
function testMap() {
|
|
||||||
$c = new Cursor(self::SCALARS, [
|
|
||||||
"map_func" => function(Cursor $c) {
|
|
||||||
return [$c->raw + 1];
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
self::assertSame([[1], [2], [3], [4], [5]], cl::all($c));
|
|
||||||
}
|
|
||||||
|
|
||||||
function testFilter() {
|
|
||||||
$c = new Cursor(self::SCALARS, [
|
|
||||||
"filter_func" => function(Cursor $c) {
|
|
||||||
return $c->raw % 2 == 0;
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
self::assertSame([[1], [3]], cl::all($c));
|
|
||||||
}
|
|
||||||
|
|
||||||
function testEach() {
|
|
||||||
$c = new Cursor(self::SCALARS, [
|
|
||||||
"filter_func" => function(Cursor $c) {
|
|
||||||
return $c->raw % 2 == 0;
|
|
||||||
},
|
|
||||||
"map_func" => function(Cursor $c) {
|
|
||||||
return [$c->raw + 1];
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
$xs = [];
|
|
||||||
$xitems = [];
|
|
||||||
$oxs = [];
|
|
||||||
$kitems = [];
|
|
||||||
$c->each(function(Cursor $c) use (&$xs, &$xitems, &$oxs, &$kitems) {
|
|
||||||
$xs[] = $c->index;
|
|
||||||
$oxs[] = $c->origIndex;
|
|
||||||
$xitems[$c->index] = $c->row[0];
|
|
||||||
$kitems[$c->key] = $c->row[0];
|
|
||||||
});
|
|
||||||
self::assertSame([0, 1], $xs);
|
|
||||||
self::assertSame([2, 4], $xitems);
|
|
||||||
self::assertSame([1, 3], $oxs);
|
|
||||||
self::assertSame([1 => 2, 3 => 4], $kitems);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user