diff --git a/composer.json b/composer.json
index a792038..3650240 100644
--- a/composer.json
+++ b/composer.json
@@ -17,7 +17,8 @@
"autoload-dev": {
"psr-4": {
"Test\\Unit\\": "./tests/unit",
- "Test\\Integration\\": "./tests/integration"
+ "Test\\Integration\\": "./tests/integration",
+ "Test\\Integration\\SQLite\\": "./tests/integration/sqlite"
}
}
}
\ No newline at end of file
diff --git a/composer.lock b/composer.lock
index 50d47e2..3f0b880 100644
--- a/composer.lock
+++ b/composer.lock
@@ -619,16 +619,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "11.1.3",
+ "version": "11.2.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "d475be032238173ca3b0a516f5cc291d174708ae"
+ "reference": "705eba0190afe04bc057f565ad843267717cf109"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d475be032238173ca3b0a516f5cc291d174708ae",
- "reference": "d475be032238173ca3b0a516f5cc291d174708ae",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/705eba0190afe04bc057f565ad843267717cf109",
+ "reference": "705eba0190afe04bc057f565ad843267717cf109",
"shasum": ""
},
"require": {
@@ -667,7 +667,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "11.1-dev"
+ "dev-main": "11.2-dev"
}
},
"autoload": {
@@ -699,7 +699,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/11.1.3"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/11.2.0"
},
"funding": [
{
@@ -715,7 +715,7 @@
"type": "tidelift"
}
],
- "time": "2024-04-24T06:34:25+00:00"
+ "time": "2024-06-07T04:48:50+00:00"
},
{
"name": "sebastian/cli-parser",
diff --git a/src/Configuration.php b/src/Configuration.php
index b562e7b..c12a6ae 100644
--- a/src/Configuration.php
+++ b/src/Configuration.php
@@ -58,4 +58,10 @@ class Configuration
return self::$_pdo;
}
+
+
+ public static function resetPDO(): void
+ {
+ self::$_pdo = null;
+ }
}
diff --git a/src/Custom.php b/src/Custom.php
index 5ba6663..740868b 100644
--- a/src/Custom.php
+++ b/src/Custom.php
@@ -4,6 +4,7 @@ namespace BitBadger\PDODocument;
use BitBadger\PDODocument\Mapper\Mapper;
use PDO;
+use PDOException;
use PDOStatement;
/**
@@ -22,7 +23,13 @@ class Custom
public static function &runQuery(string $query, array $parameters): PDOStatement
{
$debug = defined('PDO_DOC_DEBUG_SQL');
- $stmt = Configuration::dbConn()->prepare($query);
+ try {
+ $stmt = Configuration::dbConn()->prepare($query);
+ } catch (PDOException $ex) {
+ $keyword = explode(' ', $query, 2)[0];
+ throw new DocumentException("Error executing $keyword statement: " . Configuration::dbConn()->errorCode(),
+ previous: $ex);
+ }
foreach ($parameters as $key => $value) {
if ($debug) echo "
Binding $value to $key\n
";
$dataType = match (true) {
@@ -115,7 +122,7 @@ class Custom
* @return mixed|false|T The scalar value if found, false if not
* @throws DocumentException If any is encountered
*/
- public static function scalar(string $query, array $parameters, Mapper $mapper, ?PDO $pdo = null): mixed
+ public static function scalar(string $query, array $parameters, Mapper $mapper): mixed
{
try {
$stmt = &self::runQuery($query, $parameters);
diff --git a/src/Mapper/StringMapper.php b/src/Mapper/StringMapper.php
index 3ed781f..c923fc5 100644
--- a/src/Mapper/StringMapper.php
+++ b/src/Mapper/StringMapper.php
@@ -3,7 +3,7 @@
namespace BitBadger\PDODocument\Mapper;
/**
- * Map a string result from the given
+ * Map a string result from the
*
* @implements Mapper
*/
diff --git a/tests/integration/.gitkeep b/tests/integration/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/integration/SubDocument.php b/tests/integration/SubDocument.php
new file mode 100644
index 0000000..3c5eb58
--- /dev/null
+++ b/tests/integration/SubDocument.php
@@ -0,0 +1,11 @@
+dbName = ThrowawayDb::create();
+ }
+
+ public function tearDown(): void
+ {
+ ThrowawayDb::destroy($this->dbName);
+ }
+
+ public function testRunQuerySucceedsWithAValidQuery()
+ {
+ $stmt = &Custom::runQuery('SELECT data FROM ' . ThrowawayDb::TABLE . ' LIMIT 1', []);
+ try {
+ $this->assertNotNull($stmt, 'The statement should not have been null');
+ } finally {
+ $stmt = null;
+ }
+ }
+
+ public function testRunQueryFailsWithAnInvalidQuery()
+ {
+ $this->expectException(DocumentException::class);
+ $stmt = &Custom::runQuery('GRAB stuff FROM over_there UNTIL done', []);
+ try {
+ $this->assertTrue(false, 'This code should not be reached');
+ } finally {
+ $stmt = null;
+ }
+ }
+
+ public function testListSucceedsWhenDataIsFound()
+ {
+ $list = Custom::list(Query::selectFromTable(ThrowawayDb::TABLE), [], new DocumentMapper(TestDocument::class));
+ $this->assertNotNull($list, 'The document list should not be null');
+ $count = 0;
+ foreach ($list->items() as $ignored) $count++;
+ $this->assertEquals(5, $count, 'There should have been 5 documents in the list');
+ }
+
+ public function testListSucceedsWhenNoDataIsFound()
+ {
+ $list = Custom::list(Query::selectFromTable(ThrowawayDb::TABLE) . " WHERE data->>'num_value' > :value",
+ [':value' => 100], new DocumentMapper(TestDocument::class));
+ $this->assertNotNull($list, 'The document list should not be null');
+ $count = 0;
+ foreach ($list->items() as $ignored) $count++;
+ $this->assertEquals(0, $count, 'There should have been no documents in the list');
+ }
+
+ public function testArraySucceedsWhenDataIsFound()
+ {
+ $array = Custom::array(Query::selectFromTable(ThrowawayDb::TABLE) . " WHERE data->>'sub' IS NOT NULL", [],
+ new DocumentMapper(TestDocument::class));
+ $this->assertNotNull($array, 'The document array should not be null');
+ $this->assertCount(2, $array, 'There should have been 2 documents in the array');
+ }
+
+ public function testArraySucceedsWhenNoDataIsFound()
+ {
+ $array = Custom::array(Query::selectFromTable(ThrowawayDb::TABLE) . " WHERE data->>'value' = :value",
+ [':value' => 'not there'], new DocumentMapper(TestDocument::class));
+ $this->assertNotNull($array, 'The document array should not be null');
+ $this->assertCount(0, $array, 'There should have been no documents in the array');
+ }
+
+ public function testSingleSucceedsWhenARowIsFound(): void
+ {
+ $doc = Custom::single('SELECT data FROM ' . ThrowawayDb::TABLE . " WHERE data->>'id' = :id", [':id' => 'one'],
+ new DocumentMapper(TestDocument::class));
+ $this->assertNotNull($doc, 'There should have been a document returned');
+ $this->assertEquals('one', $doc->id, 'The incorrect document was returned');
+ }
+
+ public function testSingleSucceedsWhenARowIsNotFound(): void
+ {
+ $doc = Custom::single('SELECT data FROM ' . ThrowawayDb::TABLE . " WHERE data->>'id' = :id",
+ [':id' => 'eighty'], new DocumentMapper(TestDocument::class));
+ $this->assertFalse($doc, 'There should not have been a document returned');
+ }
+
+ public function testNonQuerySucceedsWhenOperatingOnData()
+ {
+ Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []);
+ try {
+ $remaining = Count::all(ThrowawayDb::TABLE);
+ $this->assertEquals(0, $remaining, 'There should be no documents remaining in the table');
+ } finally {
+ $this->dbName = ThrowawayDb::exchange($this->dbName);
+ }
+ }
+
+ public function testNonQuerySucceedsWhenNoDataMatchesWhereClause()
+ {
+ Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE . " WHERE data->>'num_value' > :value", [':value' => 100]);
+ $remaining = Count::all(ThrowawayDb::TABLE);
+ $this->assertEquals(5, $remaining, 'There should be 5 documents remaining in the table');
+ }
+
+ public function testScalarSucceeds()
+ {
+ $value = Custom::scalar("SELECT 5 AS it", [], new CountMapper());
+ $this->assertEquals(5, $value, 'The scalar value was not returned correctly');
+ }
+}
diff --git a/tests/integration/sqlite/ThrowawayDb.php b/tests/integration/sqlite/ThrowawayDb.php
new file mode 100644
index 0000000..5a3ab64
--- /dev/null
+++ b/tests/integration/sqlite/ThrowawayDb.php
@@ -0,0 +1,71 @@
+