Skip to content

Commit

Permalink
Implementation of type-safe fetch methods (#175)
Browse files Browse the repository at this point in the history
* Write tests for #115

* Implement type-safe fetch functionality, closes #115

* Use existing fetch functions

* Introduce `Fetchable` trait to share code over Database, QueryCollection
  • Loading branch information
g105b authored Oct 31, 2019
1 parent 716a6b2 commit c371fc7
Show file tree
Hide file tree
Showing 9 changed files with 387 additions and 34 deletions.
16 changes: 16 additions & 0 deletions src/Connection/Driver.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@
namespace Gt\Database\Connection;

class Driver {
const AVAILABLE_DRIVERS = [
"cubrid",
"dblib", // Sybase databases
"sybase",
"firebird",
"ibm",
"informix",
"mysql",
"sqlsrv", // MS SQL Server and SQL Azure databases
"oci", // Oracle
"odbc",
"pgsql", // PostgreSQL
"sqlite",
"4D",
];

/** @var SettingsInterface */
protected $settings;
/** @var Connection */
Expand Down
13 changes: 3 additions & 10 deletions src/Database.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php
namespace Gt\Database;

use DateTime;
use Gt\Database\Connection\Connection;
use Gt\Database\Result\Row;
use Gt\Database\Connection\DefaultSettings;
Expand All @@ -18,6 +19,8 @@
* required as the default name will be used.
*/
class Database {
use Fetchable;

const COLLECTION_SEPARATOR_CHARACTERS = [".", "/", "\\"];
/** @var QueryCollectionFactory[] */
protected $queryCollectionFactoryArray;
Expand All @@ -36,16 +39,6 @@ public function __construct(SettingsInterface...$connectionSettings) {
$this->storeQueryCollectionFactoryFromSettings($connectionSettings);
}

public function fetch(string $queryName, ...$bindings):?Row {
$result = $this->query($queryName, $bindings);

return $result->fetch();
}

public function fetchAll(string $queryName, ...$bindings):ResultSet {
return $this->query($queryName, $bindings);
}

public function insert(string $queryName, ...$bindings):int {
$result = $this->query($queryName, $bindings);

Expand Down
158 changes: 158 additions & 0 deletions src/Fetchable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
<?php
namespace Gt\Database;

use DateTime;
use Gt\Database\Result\ResultSet;
use Gt\Database\Result\Row;

trait Fetchable {
public function fetch(string $queryName, ...$bindings):?Row {
/** @var ResultSet $result */
$result = $this->query($queryName, ...$bindings);
return $result->current();
}

public function fetchAll(string $queryName, ...$bindings):ResultSet {
return $this->query($queryName, ...$bindings);
}

public function fetchBool(string $queryName, ...$bindings):?bool {
return $this->fetchTyped(
Type::BOOL,
$queryName,
$bindings
);
}

public function fetchString(string $queryName, ...$bindings):?string {
return $this->fetchTyped(
Type::STRING,
$queryName,
$bindings
);
}

public function fetchInt(string $queryName, ...$bindings):?int {
return $this->fetchTyped(
Type::INT,
$queryName,
$bindings
);
}

public function fetchFloat(string $queryName, ...$bindings):?float {
return $this->fetchTyped(
Type::FLOAT,
$queryName,
$bindings
);
}

public function fetchDateTime(string $queryName, ...$bindings):?DateTime {
return $this->fetchTyped(
Type::DATETIME,
$queryName,
$bindings
);
}

/** @return bool[] */
public function fetchAllBool(string $queryName, ...$bindings):array {
return $this->fetchAllTyped(
Type::BOOL,
$queryName,
$bindings
);
}

/** @return string[] */
public function fetchAllString(string $queryName, ...$bindings):array {
return $this->fetchAllTyped(
Type::STRING,
$queryName,
$bindings
);
}

/** @return int[] */
public function fetchAllInt(string $queryName, ...$bindings):array {
return $this->fetchAllTyped(
Type::INT,
$queryName,
$bindings
);
}

/** @return float[] */
public function fetchAllFloat(string $queryName, ...$bindings):array {
return $this->fetchAllTyped(
Type::FLOAT,
$queryName,
$bindings
);
}

/** @return DateTime[] */
public function fetchAllDateTime(string $queryName, ...$bindings):array {
return $this->fetchAllTyped(
Type::DATETIME,
$queryName,
$bindings
);
}

protected function fetchTyped(
string $type,
string $queryName,
...$bindings
) {
$row = $this->fetch($queryName, ...$bindings);
if(is_null($row)) {
return null;
}

return $this->castRow($type, $row);
}

protected function fetchAllTyped(
string $type,
string $queryName,
...$bindings
):array {
$array = [];

$resultSet = $this->fetchAll($queryName, ...$bindings);
foreach($resultSet as $row) {
$array []= $this->castRow($type, $row);
}

return $array;
}

protected function castRow(string $type, Row $row) {
$assocArray = $row->toArray();
reset($assocArray);
$key = key($assocArray);
$value = $assocArray[$key];

switch($type) {
case Type::BOOL:
case "boolean":
return (bool)$value;

case Type::STRING:
return (string)$value;

case Type::INT:
case "integer":
return (int)$value;

case Type::FLOAT:
return (float)$value;

case Type::DATETIME:
case "datetime":
return new DateTime($value);
}
}
}
41 changes: 22 additions & 19 deletions src/Query/QueryCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
namespace Gt\Database\Query;

use Gt\Database\Connection\Driver;
use Gt\Database\Fetchable;
use Gt\Database\Result\ResultSet;
use Gt\Database\Result\Row;

class QueryCollection {
use Fetchable;

/** @var string */
protected $directoryPath;
/** @var QueryFactory */
Expand Down Expand Up @@ -56,25 +59,25 @@ public function insert(
)->lastInsertId();
}

public function fetch(
string $name,
...$placeholderMap
):?Row {
return $this->query(
$name,
...$placeholderMap
)->current();
}

public function fetchAll(
string $name,
...$placeholderMap
):ResultSet {
return $this->query(
$name,
...$placeholderMap
);
}
// public function fetch(
// string $name,
// ...$placeholderMap
// ):?Row {
// return $this->query(
// $name,
// ...$placeholderMap
// )->current();
// }
//
// public function fetchAll(
// string $name,
// ...$placeholderMap
// ):ResultSet {
// return $this->query(
// $name,
// ...$placeholderMap
// );
// }

public function update(
string $name,
Expand Down
1 change: 0 additions & 1 deletion src/Result/ResultSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ public function rewind():void {

public function current():?Row {
$this->fetchUpToIteratorIndex();

return $this->current_row;
}

Expand Down
10 changes: 10 additions & 0 deletions src/Type.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php
namespace Gt\Database;

class Type {
const BOOL = "bool";
const STRING = "string";
const INT = "int";
const FLOAT = "float";
const DATETIME = "datetime";
}
1 change: 0 additions & 1 deletion test/unit/DatabaseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use Gt\Database\Query\QueryCollection;
use Gt\Database\Query\QueryCollectionNotFoundException;
use PHPUnit\Framework\TestCase;
use Gt\Database\Test\Helper\Helper;

class DatabaseTest extends TestCase {
public function testInterface() {
Expand Down
Loading

0 comments on commit c371fc7

Please sign in to comment.