Skip to content
Merged
2 changes: 1 addition & 1 deletion .github/workflows/php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ jobs:
with:
php-version: ${{ matrix.php }}
tools: phpunit:${{ matrix.phpunit-version || env.phpunit-version }}
extensions: pdo
extensions: pdo, pdo-sqlite

- name: Setup dependencies
run: composer install -n --no-progress
Expand Down
92 changes: 92 additions & 0 deletions src/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,98 @@ public function fetchScalar($stmt, array $values = null)
->fetchColumn(0);
}

/**
* Yield each result row
*
* `Connection::yieldAll(Select|string $stmt [[, array $values], int $fetchMode [, mixed ...$fetchModeOptions]])`
*
* @param Select|string $stmt The SQL statement to prepare and execute.
* @param mixed ...$args Values to bind to the statement, fetch mode for the statement, fetch mode options
*
* @return \Generator
*/
public function yieldAll($stmt, ...$args)
{
$values = null;

if (! empty($args)) {
if (is_array($args[0])) {
$values = array_shift($args);
}
}

$fetchMode = null;

if (! empty($args)) {
$fetchMode = array_shift($args);

switch ($fetchMode) {
case PDO::FETCH_KEY_PAIR:
foreach ($this->yieldPairs($stmt, $values) as $key => $value) {
yield $key => $value;
}

return;
case PDO::FETCH_COLUMN:
if (empty($args)) {
$args[] = 0;
}

break;
}
}

$sth = $this->prepexec($stmt, $values);

if ($fetchMode !== null) {
$sth->setFetchMode($fetchMode, ...$args);
}

foreach ($sth as $key => $row) {
yield $key => $row;
}
}

/**
* Yield the first column of each result row
*
* @param Select|string $stmt The SQL statement to prepare and execute
* @param array $values Values to bind to the statement
*
* @return \Generator
*/
public function yieldCol($stmt, array $values = null)
{
$sth = $this->prepexec($stmt, $values);

$sth->setFetchMode(PDO::FETCH_COLUMN, 0);

foreach ($sth as $key => $row) {
yield $key => $row;
}
}

/**
* Yield key-value pairs with the first column as key and the second column as value for each result row
*
* @param Select|string $stmt The SQL statement to prepare and execute
* @param array $values Values to bind to the statement
*
* @return \Generator
*/
public function yieldPairs($stmt, array $values = null)
{
$sth = $this->prepexec($stmt, $values);

$sth->setFetchMode(PDO::FETCH_NUM);

foreach ($sth as $row) {
list($key, $value) = $row;

yield $key => $value;
}
}

/**
* Prepare and execute the given statement
*
Expand Down
110 changes: 110 additions & 0 deletions src/Cursor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?php

namespace ipl\Sql;

use ipl\Stdlib\Contract\Paginatable;
use IteratorAggregate;

/**
* Cursor for ipl SQL queries
*/
class Cursor implements IteratorAggregate, Paginatable
{
/** @var Connection */
protected $db;

/** @var Select */
protected $select;

/** @var array */
protected $fetchModeAndArgs = [];

/**
* Create a new cursor for the given connection and query
*
* @param Connection $db
* @param Select $select
*/
public function __construct(Connection $db, Select $select)
{
$this->db = $db;
$this->select = $select;
}

/**
* Get the fetch mode
*
* @return array
*/
public function getFetchMode()
{
return $this->fetchModeAndArgs;
}

/**
* Set the fetch mode
*
* @param int $fetchMode Fetch mode as one of the PDO fetch mode constants.
* Please see {@link https://www.php.net/manual/en/pdostatement.setfetchmode} for details
* @param mixed ...$args Fetch mode arguments
*
* @return $this
*/
public function setFetchMode($fetchMode, ...$args)
{
array_unshift($args, $fetchMode);

$this->fetchModeAndArgs = $args;

return $this;
}

/**
* @inheritDoc
*
* @return \Generator
*/
public function getIterator()
{
return $this->db->yieldAll($this->select, ...$this->getFetchMode());
}

public function hasLimit()
{
return $this->select->hasLimit();
}

public function getLimit()
{
return $this->select->getLimit();
}

public function limit($limit)
{
$this->select->limit($limit);

return $this;
}

public function hasOffset()
{
return $this->select->hasOffset();
}

public function getOffset()
{
return $this->select->getOffset();
}

public function offset($offset)
{
$this->select->offset($offset);

return $this;
}

public function count()
{
return $this->db->select($this->select->getCountQuery())->fetchColumn(0);
}
}
68 changes: 0 additions & 68 deletions src/PaginationAdapter.php

This file was deleted.

32 changes: 32 additions & 0 deletions tests/ConnectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,36 @@ public function testConstructException()
{
new Connection(['db' => 'exception']);
}

public function testYieldCol()
{
$generator = $this->getFixturesDb()->yieldCol('SELECT username, id, password FROM user');

$this->assertInstanceOf(\Generator::class, $generator);

$this->assertSame(['admin', 'guest'], iterator_to_array($generator));
}

public function testYieldPairs()
{
$generator = $this->getFixturesDb()->yieldPairs('SELECT username, id, password FROM user');

$this->assertInstanceOf(\Generator::class, $generator);

$this->assertSame(['admin' => '1', 'guest' => '2'], iterator_to_array($generator));
}

protected function getFixturesDb()
{
$db = new Connection([
'db' => 'sqlite',
'dbname' => ':memory:'
]);

$fixtures = file_get_contents(__DIR__ . '/fixtures.sql');

$db->exec($fixtures);

return $db;
}
}
Loading