diff --git a/src/Cursor.php b/src/Cursor.php index 131f99e7358f79ad20b47a2be7db1acbc7d7b956..d2ef5baa66e62adcbcc20af448c03e4b8227207b 100644 --- a/src/Cursor.php +++ b/src/Cursor.php @@ -57,7 +57,7 @@ final class Cursor implements ICursor if ($index < 0) { throw new \InvalidArgumentException("Negative index not supported. Use moveFromEndTo() instead."); } - $this->headOnRecord = $this->driver->moveTo($this->name, $index); + $this->headOnRecord = $this->driver->moveFromBeginningTo($this->name, $index); } public function moveFromEndTo(int $index) diff --git a/src/Driver/ICursorDriver.php b/src/Driver/ICursorDriver.php index 1fd54938e350e2cdaa67960b234884200efe41bf..5ce13f23ab19bb869717fd0c57a2be4faaed986c 100644 --- a/src/Driver/ICursorDriver.php +++ b/src/Driver/ICursorDriver.php @@ -33,7 +33,7 @@ interface ICursorDriver * @param int $index * @return bool Head on record? */ - public function moveTo(string $name, int $index) : bool; + public function moveFromBeginningTo(string $name, int $index) : bool; /** * Move cursor from the END to given position diff --git a/src/Driver/PostgresCursorDriver.php b/src/Driver/PostgresCursorDriver.php index 984424ebf9d59a2670e5cf456997b1c616588b13..656337dd452da04e38e009abba6ad8a9949de3f2 100644 --- a/src/Driver/PostgresCursorDriver.php +++ b/src/Driver/PostgresCursorDriver.php @@ -31,7 +31,7 @@ class PostgresCursorDriver implements ICursorDriver return $this->connection; } - public function moveTo(string $name, int $index) : bool + public function moveFromBeginningTo(string $name, int $index) : bool { if ($index < 0) { throw new \InvalidArgumentException("Negative index not supported. Use moveFromEndTo() instead."); diff --git a/tests/Cursor/CursorTest.phpt b/tests/Cursor/CursorTest.phpt index e6f165e5af5f405f425ace36b469f96474a02d39..efa87419bec1c1088576f745155b23eb7829c03f 100644 --- a/tests/Cursor/CursorTest.phpt +++ b/tests/Cursor/CursorTest.phpt @@ -6,7 +6,7 @@ namespace Grifart\Mappi\Tests\Cursor; use Grifart\Mappi\Cursor\Cursor; -use Grifart\Mappi\Cursor\Driver\ArrayCursorDriver; +use Grifart\Mappi\Tests\Cursor\Driver\ArrayCursorDriver; use Grifart\Mappi\Cursor\ICursor; require_once __DIR__ . "/../bootstrap.php"; diff --git a/src/Driver/ArrayCursorDriver.php b/tests/Cursor/Driver/ArrayCursorDriver.php similarity index 51% rename from src/Driver/ArrayCursorDriver.php rename to tests/Cursor/Driver/ArrayCursorDriver.php index 029dd0deff187cc6de2f9e87705064cac51f7e86..663988e0380dc900c96d62e26bf7e1a7ea42b4c5 100644 --- a/src/Driver/ArrayCursorDriver.php +++ b/tests/Cursor/Driver/ArrayCursorDriver.php @@ -3,8 +3,9 @@ * This file is part of mappi/cursor. */ -namespace Grifart\Mappi\Cursor\Driver; +namespace Grifart\Mappi\Tests\Cursor\Driver; use Grifart\Mappi\Cursor\CursorException; +use Grifart\Mappi\Cursor\Driver\ICursorDriver; /** * Array Cursor simulates scrolling cursor as implemented in PostgreSQL 9.5. @@ -18,29 +19,64 @@ class ArrayCursorDriver implements ICursorDriver private $cursors = []; private $indexes = []; + /** + * Creates test cursor with given name + * @param string $name + * @param int $length + */ public function createTestCursor(string $name, int $length) { if(isset($this->cursors[$name])) { throw new CursorException("Cursor with name $name already exists"); } - $this->cursors[$name] = range(0, $length+1); - $this->cursors[$name][0] = null; - $this->cursors[$name][$length+1] = null; + $this->cursors[$name] = $this->generateCursorData($length); $this->indexes[$name] = 0; } + /** + * Closes test cursor + * @param string $name + * @return bool + */ public function close(string $name) : bool { unset($this->cursors[$name]); + unset($this->indexes[$name]); return TRUE; } + /** + * Cursor data is table with one column with name "n" which contains current row index as value + * @param int $length length of values + * @return array + */ + private function generateCursorData(int $length): array + { + $data = []; + $data[0] = null; + $data[$length+1] = null; + for($i = 1; $i <= $length; $i++) { + $data[$i] = ["n" => $i]; + } + return $data; + } + + /** + * Returns END position index from LEFT + * @param string $name The cursor name + * @return int + */ private function getMaxIndex(string $name) { return count($this->cursors[$name])-1; } + /** + * Normalizes index to be between BEGINNING and END of cursor + * @param string $name The cursor name + * @param int $index The index to normalize + */ private function normalizeIndex(string $name, int &$index) { if($index < 0) { @@ -52,38 +88,46 @@ class ArrayCursorDriver implements ICursorDriver } } - private function pointerMoveTo(string $name, int $index) + /** + * Moves internal cursor pointer to position from BEGINNING + * @param string $name The cursor name + * @param int $index The index from the BEGINNING; index is normalized before move + */ + private function pointerMoveToFromBeginning(string $name, int $index) { $this->normalizeIndex($name, $index); $this->indexes[$name] = $index; } - private function getCurrentIndex(string $name) : int + /** + * Moves internal cursor pointer to position from the END + * @param string $name The cursor name + * @param int $index The index from the ENG; + */ + private function pointerMoveToFromEnd(string $name, int $index) + { + $indexFromLeft = $this->getMaxIndex($name) - $index; + $this->normalizeIndex($name, $indexFromLeft); + + $this->moveFromBeginningTo($name, $indexFromLeft); + } + + private function getCurrentIndexFromBeginning(string $name) : int { return $this->indexes[$name]; } - private function getCurrentValue(string $name) { - return $this->cursors[$name][$this->getCurrentIndex($name)]; + private function retrieveCurrentRow(string $name) { + return $this->cursors[$name][$this->getCurrentIndexFromBeginning($name)]; } - public function moveTo(string $name, int $index) : bool + public function moveFromBeginningTo(string $name, int $index) : bool { if ($index < 0) { throw new \InvalidArgumentException("Negative index not supported. Use moveFromEndTo() instead."); } - $this->pointerMoveTo($name, $index); - return !!$this->getCurrentValue($name); - } - - private function cursorArrayMoveFromEndTo(string $name, int $index) - { - $max = $this->getMaxIndex($name); - - $indexFromLeft = $max - $index; - $this->normalizeIndex($name, $indexFromLeft); - - $this->moveTo($name, $indexFromLeft); + $this->pointerMoveToFromBeginning($name, $index); + return !!$this->retrieveCurrentRow($name); } public function moveFromEndTo(string $name, int $index) : bool @@ -91,24 +135,24 @@ class ArrayCursorDriver implements ICursorDriver if ($index < 0) { throw new \InvalidArgumentException("Negative index not supported. Use moveTo() instead."); } - $this->cursorArrayMoveFromEndTo($name, $index); - return !!$this->getCurrentValue($name); + $this->pointerMoveToFromEnd($name, $index); + return !!$this->retrieveCurrentRow($name); } public function moveBy(string $name, int $offset) : bool { - $i = $this->getCurrentIndex($name); + $i = $this->getCurrentIndexFromBeginning($name); $indexFromLeft = $i + $offset; $this->normalizeIndex($name, $indexFromLeft); - $this->moveTo($name, $indexFromLeft); - return !!$this->getCurrentValue($name); + $this->moveFromBeginningTo($name, $indexFromLeft); + return !!$this->retrieveCurrentRow($name); } // ----------------- FETCH --------------------- public function fetchRange(string $name, int $offset) : array { - $currentKey = $this->getCurrentIndex($name); + $currentKey = $this->getCurrentIndexFromBeginning($name); if($offset === self::FETCH_FOREGOING) { $finalKey = PHP_INT_MIN; } elseif ($offset === self::FETCH_REMAINING) { @@ -120,26 +164,26 @@ class ArrayCursorDriver implements ICursorDriver $data = []; if($offset === 0) { - $v = $this->getCurrentValue($name); + $v = $this->retrieveCurrentRow($name); if($v !== NULL) { - $data[] = ["n" => $this->getCurrentValue($name)]; + $data[] = $v; } return $data; } if($finalKey < $currentKey) { // backwards for($i = $currentKey-1; $i >= $finalKey; $i--) { - $this->moveTo($name, $i); - $v = $this->getCurrentValue($name); + $this->moveFromBeginningTo($name, $i); + $v = $this->retrieveCurrentRow($name); if($v === NULL) {break;} - $data[] = ["n" => $this->getCurrentValue($name)]; + $data[] = $v; } } else { for($i = $currentKey+1; $i <= $finalKey; $i++) { - $this->moveTo($name, $i); - $v = $this->getCurrentValue($name); + $this->moveFromBeginningTo($name, $i); + $v = $this->retrieveCurrentRow($name); if($v === NULL) {break;} - $data[] = ["n" => $this->getCurrentValue($name)]; + $data[] = $v; } } return $data; @@ -150,7 +194,7 @@ class ArrayCursorDriver implements ICursorDriver if($index < 0) { $this->moveFromEndTo($name, abs($index)); } else { - $this->moveTo($name, $index); + $this->moveFromBeginningTo($name, abs($index)); } $data = $this->fetchRange($name, 0); if(count($data) === 0) { diff --git a/tests/Cursor/SemanticCursorIntegration.phpt b/tests/Cursor/SemanticCursorIntegration.phpt index b343ec84dd8985b5c2bedae8354cf14af4b84a10..5cf8cb2715fbc11f5c7d9c1ed0ceecaf3d7fbdc5 100644 --- a/tests/Cursor/SemanticCursorIntegration.phpt +++ b/tests/Cursor/SemanticCursorIntegration.phpt @@ -6,7 +6,7 @@ namespace Grifart\Mappi\Tests\Cursor; use Grifart\Mappi\Cursor\Cursor; -use Grifart\Mappi\Cursor\Driver\ArrayCursorDriver; +use Grifart\Mappi\Tests\Cursor\Driver\ArrayCursorDriver; use Grifart\Mappi\Cursor\SemanticCursor; use Mockery; @@ -27,7 +27,7 @@ class SemanticCursorIntegrationTest extends ICursorTest protected function setUp() { - $driver = new ArrayCursorDriver(); + $driver = new Driver\ArrayCursorDriver(); $driver->createTestCursor("test", 1000); $cursor = new Cursor( $driver, diff --git a/tests/Cursor/TrackedCursorTest.phpt b/tests/Cursor/TrackedCursorTest.phpt index 570473598bf9b89b81a4eb27ccad34f9f1c2a53e..ade58f53bb5534aeab914d2415ab9dca8dab912e 100644 --- a/tests/Cursor/TrackedCursorTest.phpt +++ b/tests/Cursor/TrackedCursorTest.phpt @@ -10,7 +10,7 @@ namespace Grifart\Mappi\Tests\Cursor; use Grifart\Mappi\Cursor\Cursor; use Grifart\Mappi\Cursor\CursorPosition; -use Grifart\Mappi\Cursor\Driver\ArrayCursorDriver; +use Grifart\Mappi\Tests\Cursor\Driver\ArrayCursorDriver; use Grifart\Mappi\Cursor\TrackedCursor; use Tester\Assert; @@ -27,7 +27,7 @@ class TrackedCursorTest extends ICursorTest protected function setUp() { - $driver = new ArrayCursorDriver(); + $driver = new Driver\ArrayCursorDriver(); $driver->createTestCursor("test", 1000); $cursor = new Cursor( $driver,