Initial SQLite development #1
43
src/Count.php
Normal file
43
src/Count.php
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace BitBadger\PDODocument;
|
||||||
|
|
||||||
|
use BitBadger\PDODocument\Mapper\CountMapper;
|
||||||
|
use PDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Functions to count documents
|
||||||
|
*/
|
||||||
|
class Count
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Count all documents in a table
|
||||||
|
*
|
||||||
|
* @param string $tableName The name of the table in which documents should be counted
|
||||||
|
* @param PDO|null $pdo The database connection to use (optional; will obtain one if not provided)
|
||||||
|
* @return int The count of documents in the table
|
||||||
|
* @throws DocumentException If one is encountered
|
||||||
|
*/
|
||||||
|
public static function all(string $tableName, ?PDO $pdo = null): int
|
||||||
|
{
|
||||||
|
return Custom::scalar(Query\Count::all($tableName), [], new CountMapper(), $pdo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count matching documents using a comparison on JSON fields
|
||||||
|
*
|
||||||
|
* @param string $tableName The name of the table in which documents should be counted
|
||||||
|
* @param array|Field[] $fields The field comparison to match
|
||||||
|
* @param PDO|null $pdo The database connection to use (optional; will obtain one if not provided)
|
||||||
|
* @param string $conjunction How to handle multiple conditions (optional; defaults to `AND`)
|
||||||
|
* @return int The count of documents matching the field comparison
|
||||||
|
* @throws DocumentException If one is encountered
|
||||||
|
*/
|
||||||
|
public static function byFields(string $tableName, array $fields, ?PDO $pdo = null,
|
||||||
|
string $conjunction = 'AND'): int
|
||||||
|
{
|
||||||
|
$namedFields = Parameters::nameFields($fields);
|
||||||
|
return Custom::scalar(Query\Count::byFields($tableName, $namedFields, $conjunction),
|
||||||
|
Parameters::addFields($namedFields, []), new CountMapper(), $pdo);
|
||||||
|
}
|
||||||
|
}
|
117
src/Custom.php
Normal file
117
src/Custom.php
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace BitBadger\PDODocument;
|
||||||
|
|
||||||
|
use BitBadger\PDODocument\Mapper\Mapper;
|
||||||
|
use PDO;
|
||||||
|
use PDOStatement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Functions to execute custom queries
|
||||||
|
*/
|
||||||
|
class Custom
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Prepare a query for execution and run it
|
||||||
|
*
|
||||||
|
* @param string $query The query to be run
|
||||||
|
* @param array $parameters The parameters for the query
|
||||||
|
* @param PDO $pdo The database connection on which the query should be run
|
||||||
|
* @return PDOStatement The result of executing the query
|
||||||
|
*/
|
||||||
|
public static function runQuery(string $query, array $parameters, PDO $pdo): PDOStatement
|
||||||
|
{
|
||||||
|
$debug = defined('PDO_DOC_DEBUG_SQL');
|
||||||
|
$stmt = $pdo->prepare($query);
|
||||||
|
foreach ($parameters as $key => $value) {
|
||||||
|
if ($debug) echo "<pre>Binding $value to $key\n</pre>";
|
||||||
|
$stmt->bindValue($key, $value);
|
||||||
|
}
|
||||||
|
if ($debug) echo '<pre>SQL: ' . $stmt->queryString . '</pre>';
|
||||||
|
$stmt->execute();
|
||||||
|
return $stmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a query that returns a list of results (lazy)
|
||||||
|
*
|
||||||
|
* @template TDoc The domain type of the document to retrieve
|
||||||
|
* @param string $query The query to be executed
|
||||||
|
* @param array $parameters Parameters to use in executing the query
|
||||||
|
* @param Mapper<TDoc> $mapper Mapper to deserialize the result
|
||||||
|
* @return DocumentList<TDoc> The items matching the query
|
||||||
|
* @throws DocumentException If any is encountered
|
||||||
|
*/
|
||||||
|
public static function list(string $query, array $parameters, Mapper $mapper): DocumentList
|
||||||
|
{
|
||||||
|
return DocumentList::create($query, $parameters, $mapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a query that returns an array of results (eager)
|
||||||
|
*
|
||||||
|
* @template TDoc The domain type of the document to retrieve
|
||||||
|
* @param string $query The query to be executed
|
||||||
|
* @param array $parameters Parameters to use in executing the query
|
||||||
|
* @param Mapper<TDoc> $mapper Mapper to deserialize the result
|
||||||
|
* @return TDoc[] The items matching the query
|
||||||
|
* @throws DocumentException If any is encountered
|
||||||
|
*/
|
||||||
|
public static function array(string $query, array $parameters, Mapper $mapper): array
|
||||||
|
{
|
||||||
|
return iterator_to_array(self::list($query, $parameters, $mapper)->items());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a query that returns one or no results (returns false if not found)
|
||||||
|
*
|
||||||
|
* @template TDoc The domain type of the document to retrieve
|
||||||
|
* @param string $query The query to be executed (will have "LIMIT 1" appended)
|
||||||
|
* @param array $parameters Parameters to use in executing the query
|
||||||
|
* @param Mapper<TDoc> $mapper Mapper to deserialize the result
|
||||||
|
* @return false|TDoc The item if it is found, false if not
|
||||||
|
* @throws DocumentException If any is encountered
|
||||||
|
*/
|
||||||
|
public static function single(string $query, array $parameters, Mapper $mapper): mixed
|
||||||
|
{
|
||||||
|
return empty($results = self::array("$query LIMIT 1", $parameters, $mapper)) ? false : $results[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a query that does not return a value
|
||||||
|
*
|
||||||
|
* @param string $query The query to execute
|
||||||
|
* @param array $parameters Parameters to use in executing the query
|
||||||
|
* @param PDO|null $pdo The database connection to use (optional; will obtain one if not provided)
|
||||||
|
* @throws DocumentException If any is encountered
|
||||||
|
*/
|
||||||
|
public static function nonQuery(string $query, array $parameters, ?PDO $pdo = null): void
|
||||||
|
{
|
||||||
|
$stmt = self::runQuery($query, $parameters, $pdo ?? Configuration::dbConn());
|
||||||
|
if ($stmt->errorCode()) throw new DocumentException('Error executing command: ' . $stmt->errorCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a query that returns a scalar value
|
||||||
|
*
|
||||||
|
* @template T The scalar type to return
|
||||||
|
* @param string $query The query to retrieve the value
|
||||||
|
* @param array $parameters Parameters to use in executing the query
|
||||||
|
* @param Mapper<T> $mapper The mapper to obtain the result
|
||||||
|
* @param PDO|null $pdo The database connection to use (optional; will obtain one if not provided)
|
||||||
|
* @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
|
||||||
|
{
|
||||||
|
$stmt = self::runQuery($query, $parameters, $pdo ?? Configuration::dbConn());
|
||||||
|
if ($stmt->errorCode()) {
|
||||||
|
throw new DocumentException('Error retrieving scalar value: ' . $stmt->errorCode());
|
||||||
|
}
|
||||||
|
if ($stmt->rowCount() > 0) {
|
||||||
|
$first = $stmt->fetch(PDO::FETCH_NUM);
|
||||||
|
return $first ? $mapper->map($first) : false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
38
src/Definition.php
Normal file
38
src/Definition.php
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace BitBadger\PDODocument;
|
||||||
|
|
||||||
|
use PDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Functions to create tables and indexes
|
||||||
|
*/
|
||||||
|
class Definition
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Ensure a document table exists
|
||||||
|
*
|
||||||
|
* @param string $name The name of the table to be created if it does not exist
|
||||||
|
* @param PDO|null $pdo The database connection to use (optional; will obtain one if not provided)
|
||||||
|
* @throws DocumentException If any is encountered
|
||||||
|
*/
|
||||||
|
public static function ensureTable(string $name, ?PDO $pdo = null): void
|
||||||
|
{
|
||||||
|
Custom::nonQuery(Query\Definition::ensureTable($name), [], $pdo);
|
||||||
|
Custom::nonQuery(Query\Definition::ensureKey($name), [], $pdo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure a field index exists on a document table
|
||||||
|
*
|
||||||
|
* @param string $tableName The name of the table which should be indexed
|
||||||
|
* @param string $indexName The name of the index
|
||||||
|
* @param array $fields Fields which should be a part of this index
|
||||||
|
* @param PDO|null $pdo The database connection to use (optional; will obtain one if not provided)
|
||||||
|
* @throws DocumentException If any is encountered
|
||||||
|
*/
|
||||||
|
public static function ensureFieldIndex(string $tableName, string $indexName, array $fields, ?PDO $pdo = null): void
|
||||||
|
{
|
||||||
|
Custom::nonQuery(Query\Definition::ensureIndexOn($tableName, $indexName, $fields), [], $pdo);
|
||||||
|
}
|
||||||
|
}
|
41
src/Delete.php
Normal file
41
src/Delete.php
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace BitBadger\PDODocument;
|
||||||
|
|
||||||
|
use PDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Functions to delete documents
|
||||||
|
*/
|
||||||
|
class Delete
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Delete a document by its ID
|
||||||
|
*
|
||||||
|
* @param string $tableName The table from which the document should be deleted
|
||||||
|
* @param mixed $docId The ID of the document to be deleted
|
||||||
|
* @param PDO|null $pdo The database connection to use (optional; will obtain one if not provided)
|
||||||
|
* @throws DocumentException If any is encountered
|
||||||
|
*/
|
||||||
|
public static function byId(string $tableName, mixed $docId, ?PDO $pdo = null): void
|
||||||
|
{
|
||||||
|
Custom::nonQuery(Query\Delete::byId($tableName), Parameters::id($docId), $pdo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete documents by matching a comparison on JSON fields
|
||||||
|
*
|
||||||
|
* @param string $tableName The table from which documents should be deleted
|
||||||
|
* @param array|Field[] $fields The field comparison to match
|
||||||
|
* @param PDO|null $pdo The database connection to use (optional; will obtain one if not provided)
|
||||||
|
* @param string $conjunction How to handle multiple conditions (optional; defaults to `AND`)
|
||||||
|
* @throws DocumentException If any is encountered
|
||||||
|
*/
|
||||||
|
public static function byFields(string $tableName, array $fields, ?PDO $pdo = null,
|
||||||
|
string $conjunction = 'AND'): void
|
||||||
|
{
|
||||||
|
$namedFields = Parameters::nameFields($fields);
|
||||||
|
Custom::nonQuery(Query\Delete::byFields($tableName, $namedFields, $conjunction),
|
||||||
|
Parameters::addFields($namedFields, []), $pdo);
|
||||||
|
}
|
||||||
|
}
|
37
src/Document.php
Normal file
37
src/Document.php
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace BitBadger\PDODocument;
|
||||||
|
|
||||||
|
use PDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Functions that apply at a whole document level
|
||||||
|
*/
|
||||||
|
class Document
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Insert a new document
|
||||||
|
*
|
||||||
|
* @param string $tableName The name of the table into which the document should be inserted
|
||||||
|
* @param array|object $document The document to be inserted
|
||||||
|
* @param PDO|null $pdo The database connection to use (optional; will obtain one if not provided)
|
||||||
|
* @throws DocumentException If any is encountered
|
||||||
|
*/
|
||||||
|
public static function insert(string $tableName, array|object $document, ?PDO $pdo = null): void
|
||||||
|
{
|
||||||
|
Custom::nonQuery(Query::insert($tableName), Parameters::json('@data', $document), $pdo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save a document, inserting it if it does not exist and updating it if it does (AKA "upsert")
|
||||||
|
*
|
||||||
|
* @param string $tableName The name of the table to which the document should be saved
|
||||||
|
* @param array|object $document The document to be saved
|
||||||
|
* @param PDO|null $pdo The database connection to use (optional; will obtain one if not provided)
|
||||||
|
* @throws DocumentException If any is encountered
|
||||||
|
*/
|
||||||
|
public static function save(string $tableName, array|object $document, ?PDO $pdo = null): void
|
||||||
|
{
|
||||||
|
Custom::nonQuery(Query::save($tableName), Parameters::json('@data', $document), $pdo);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,10 @@
|
||||||
|
|
||||||
namespace BitBadger\PDODocument;
|
namespace BitBadger\PDODocument;
|
||||||
|
|
||||||
|
use BitBadger\PDODocument\Mapper\Mapper;
|
||||||
use Generator;
|
use Generator;
|
||||||
|
use PDO;
|
||||||
|
use PDOStatement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A lazy iterator of results in a list; implementations will create new connections to the database and close/dispose
|
* A lazy iterator of results in a list; implementations will create new connections to the database and close/dispose
|
||||||
|
@ -10,14 +13,16 @@ use Generator;
|
||||||
*
|
*
|
||||||
* @template TDoc The domain class for items returned by this list
|
* @template TDoc The domain class for items returned by this list
|
||||||
*/
|
*/
|
||||||
interface DocumentList
|
readonly class DocumentList
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The items from the query result
|
* Constructor
|
||||||
*
|
*
|
||||||
* @return Generator<TDoc> The query results as a lazily-iterated generator
|
* @param PDO $pdo The database connection against which the query was opened
|
||||||
|
* @param PDOStatement $result The result of the query
|
||||||
|
* @param Mapper<TDoc> $mapper The mapper to deserialize JSON
|
||||||
*/
|
*/
|
||||||
public function items(): Generator;
|
private function __construct(private PDO $pdo, private PDOStatement $result, private Mapper $mapper) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new document list
|
* Construct a new document list
|
||||||
|
@ -25,12 +30,28 @@ interface DocumentList
|
||||||
* @param string $query The query to run to retrieve results
|
* @param string $query The query to run to retrieve results
|
||||||
* @param array $parameters An associative array of parameters for the query
|
* @param array $parameters An associative array of parameters for the query
|
||||||
* @param Mapper<TDoc> $mapper A mapper to deserialize JSON documents
|
* @param Mapper<TDoc> $mapper A mapper to deserialize JSON documents
|
||||||
* @return static The `DocumentList`-implementing instance
|
* @return static The document list instance
|
||||||
|
* @throws DocumentException If any is encountered
|
||||||
*/
|
*/
|
||||||
public static function create(string $query, array $parameters, Mapper $mapper): static;
|
public static function create(string $query, array $parameters, Mapper $mapper): static
|
||||||
|
{
|
||||||
|
$pdo = Configuration::dbConn();
|
||||||
|
$stmt = Custom::runQuery($query, $parameters, $pdo);
|
||||||
|
if ($stmt->errorCode()) {
|
||||||
|
throw new DocumentException('Error retrieving data: ' . $stmt->errorCode());
|
||||||
|
}
|
||||||
|
return new static($pdo, $stmt, $mapper);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clean up database connection resources
|
* The items from the query result
|
||||||
|
*
|
||||||
|
* @return Generator<TDoc> The items from the document list
|
||||||
*/
|
*/
|
||||||
public function __destruct();
|
public function items(): Generator
|
||||||
|
{
|
||||||
|
if ($this->result) {
|
||||||
|
while ($row = $this->result->fetch(PDO::FETCH_ASSOC)) yield $this->mapper->map($row);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
17
src/Mapper/CountMapper.php
Normal file
17
src/Mapper/CountMapper.php
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace BitBadger\PDODocument\Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mapper that returns the integer value of the first item in the results
|
||||||
|
*/
|
||||||
|
class CountMapper implements Mapper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function map(array $result): int
|
||||||
|
{
|
||||||
|
return (int) $result[0];
|
||||||
|
}
|
||||||
|
}
|
26
src/Mapper/ExistsMapper.php
Normal file
26
src/Mapper/ExistsMapper.php
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace BitBadger\PDODocument\Mapper;
|
||||||
|
|
||||||
|
use BitBadger\PDODocument\Configuration;
|
||||||
|
use BitBadger\PDODocument\DocumentException;
|
||||||
|
use BitBadger\PDODocument\Mode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map an EXISTS result to a boolean value
|
||||||
|
*/
|
||||||
|
class ExistsMapper implements Mapper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
* @throws DocumentException If the database mode has not been set
|
||||||
|
*/
|
||||||
|
public function map(array $result): bool
|
||||||
|
{
|
||||||
|
return match (Configuration::$mode) {
|
||||||
|
Mode::PgSQL => (bool)$result[0],
|
||||||
|
Mode::SQLite => (int)$result[0] > 0,
|
||||||
|
default => throw new DocumentException('Database mode not set; cannot map existence result'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
81
src/Parameters.php
Normal file
81
src/Parameters.php
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace BitBadger\PDODocument;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Functions to create parameters for queries
|
||||||
|
*/
|
||||||
|
class Parameters
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create an ID parameter (name "@id", key will be treated as a string)
|
||||||
|
*
|
||||||
|
* @param mixed $key The key representing the ID of the document
|
||||||
|
* @return array|string[] An associative array with an "@id" parameter/value pair
|
||||||
|
*/
|
||||||
|
public static function id(mixed $key): array
|
||||||
|
{
|
||||||
|
return ['@id' => is_string($key) ? $key : "$key"];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a parameter with a JSON value
|
||||||
|
*
|
||||||
|
* @param string $name The name of the JSON parameter
|
||||||
|
* @param object|array $document The value that should be passed as a JSON string
|
||||||
|
* @return array An associative array with the named parameter/value pair
|
||||||
|
*/
|
||||||
|
public static function json(string $name, object|array $document): array
|
||||||
|
{
|
||||||
|
return [$name => json_encode($document, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill in parameter names for any fields missing one
|
||||||
|
*
|
||||||
|
* @param array|Field[] $fields The fields for the query
|
||||||
|
* @return array|Field[] The fields, all with non-blank parameter names
|
||||||
|
*/
|
||||||
|
public static function nameFields(array $fields): array
|
||||||
|
{
|
||||||
|
for ($idx = 0; $idx < sizeof($fields); $idx++) {
|
||||||
|
if ($fields[$idx]->paramName == '') $fields[$idx]->paramName = "@field$idx";
|
||||||
|
}
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add field parameters to the given set of parameters
|
||||||
|
*
|
||||||
|
* @param array|Field[] $fields The fields being compared in the query
|
||||||
|
* @param array $parameters An associative array of parameters to which the fields should be added
|
||||||
|
* @return array An associative array of parameter names and values with the fields added
|
||||||
|
*/
|
||||||
|
public static function addFields(array $fields, array $parameters): array
|
||||||
|
{
|
||||||
|
return array_reduce($fields, fn($carry, $item) => $item->appendParameter($carry), $parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create JSON field name parameters for the given field names to the given parameter
|
||||||
|
*
|
||||||
|
* @param string $paramName The name of the parameter for the field names
|
||||||
|
* @param array|string[] $fieldNames The names of the fields for the parameter
|
||||||
|
* @return array An associative array of parameter/value pairs for the field names
|
||||||
|
* @throws DocumentException If the database mode has not been set
|
||||||
|
*/
|
||||||
|
public static function fieldNames(string $paramName, array $fieldNames): array
|
||||||
|
{
|
||||||
|
switch (Configuration::$mode) {
|
||||||
|
case Mode::PgSQL:
|
||||||
|
return [$paramName => "ARRAY['" . implode("','", $fieldNames) . "']"];
|
||||||
|
case Mode::SQLite:
|
||||||
|
$it = [];
|
||||||
|
$idx = 0;
|
||||||
|
foreach ($fieldNames as $field) $it[$paramName . $idx++] = $field;
|
||||||
|
return $it;
|
||||||
|
default:
|
||||||
|
throw new DocumentException('Database mode not set; cannot generate field name parameters');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,11 +12,13 @@ use PHPUnit\Framework\TestCase;
|
||||||
*/
|
*/
|
||||||
class ConfigurationTest extends TestCase
|
class ConfigurationTest extends TestCase
|
||||||
{
|
{
|
||||||
|
#[TestDox('ID field default succeeds')]
|
||||||
public function testIdFieldDefaultSucceeds(): void
|
public function testIdFieldDefaultSucceeds(): void
|
||||||
{
|
{
|
||||||
$this->assertEquals('id', Configuration::$idField, 'Default ID field should be "id"');
|
$this->assertEquals('id', Configuration::$idField, 'Default ID field should be "id"');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[TestDox('ID field change succeeds')]
|
||||||
public function testIdFieldChangeSucceeds()
|
public function testIdFieldChangeSucceeds()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|
17
tests/unit/Mapper/CountMapperTest.php
Normal file
17
tests/unit/Mapper/CountMapperTest.php
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Test\Unit\Mapper;
|
||||||
|
|
||||||
|
use BitBadger\PDODocument\Mapper\CountMapper;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for the CountMapper class
|
||||||
|
*/
|
||||||
|
class CountMapperTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testMapSucceeds(): void
|
||||||
|
{
|
||||||
|
$this->assertEquals(5, (new CountMapper())->map([5, 8, 10]), 'Count not correct');
|
||||||
|
}
|
||||||
|
}
|
45
tests/unit/Mapper/ExistsMapperTest.php
Normal file
45
tests/unit/Mapper/ExistsMapperTest.php
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Test\Unit\Mapper;
|
||||||
|
|
||||||
|
use BitBadger\PDODocument\Configuration;
|
||||||
|
use BitBadger\PDODocument\DocumentException;
|
||||||
|
use BitBadger\PDODocument\Mapper\ExistsMapper;
|
||||||
|
use BitBadger\PDODocument\Mode;
|
||||||
|
use PHPUnit\Framework\Attributes\TestDox;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for the ExistsMapper class
|
||||||
|
*/
|
||||||
|
class ExistsMapperTest extends TestCase
|
||||||
|
{
|
||||||
|
#[TestDox('Map succeeds for PostgreSQL')]
|
||||||
|
public function testMapSucceedsForPostgreSQL(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Configuration::$mode = Mode::PgSQL;
|
||||||
|
$this->assertFalse((new ExistsMapper())->map([false, 'nope']), 'Result should have been false');
|
||||||
|
} finally {
|
||||||
|
Configuration::$mode = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('Map succeeds for SQLite')]
|
||||||
|
public function testMapSucceedsForSQLite(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Configuration::$mode = Mode::SQLite;
|
||||||
|
$this->assertTrue((new ExistsMapper())->map([1, 'yep']), 'Result should have been true');
|
||||||
|
} finally {
|
||||||
|
Configuration::$mode = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMapFailsWhenModeNotSet(): void
|
||||||
|
{
|
||||||
|
$this->expectException(DocumentException::class);
|
||||||
|
Configuration::$mode = null;
|
||||||
|
(new ExistsMapper())->map(['0']);
|
||||||
|
}
|
||||||
|
}
|
83
tests/unit/ParametersTest.php
Normal file
83
tests/unit/ParametersTest.php
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Unit;
|
||||||
|
|
||||||
|
use BitBadger\PDODocument\Configuration;
|
||||||
|
use BitBadger\PDODocument\DocumentException;
|
||||||
|
use BitBadger\PDODocument\Field;
|
||||||
|
use BitBadger\PDODocument\Mode;
|
||||||
|
use BitBadger\PDODocument\Parameters;
|
||||||
|
use PHPUnit\Framework\Attributes\TestDox;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for the Parameters class
|
||||||
|
*/
|
||||||
|
class ParametersTest extends TestCase
|
||||||
|
{
|
||||||
|
#[TestDox('ID succeeds with string')]
|
||||||
|
public function testIdSucceedsWithString(): void
|
||||||
|
{
|
||||||
|
$this->assertEquals(['@id' => 'key'], Parameters::id('key'), 'ID parameter not constructed correctly');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('ID succeeds with non string')]
|
||||||
|
public function testIdSucceedsWithNonString(): void
|
||||||
|
{
|
||||||
|
$this->assertEquals(['@id' => '7'], Parameters::id(7), 'ID parameter not constructed correctly');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testJsonSucceeds(): void
|
||||||
|
{
|
||||||
|
$this->assertEquals(['@it' => '{"id":18,"url":"https://www.unittest.com"}'],
|
||||||
|
Parameters::json('@it', ['id' => 18, 'url' => 'https://www.unittest.com']),
|
||||||
|
'JSON parameter not constructed correctly');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNameFieldsSucceeds(): void
|
||||||
|
{
|
||||||
|
$named = Parameters::nameFields([Field::EQ('it', 17), Field::EQ('also', 22, '@also'), Field::EQ('other', 24)]);
|
||||||
|
$this->assertCount(3, $named, 'There should be 3 parameters in the array');
|
||||||
|
$this->assertEquals('@field0', $named[0]->paramName, 'Parameter 1 not named correctly');
|
||||||
|
$this->assertEquals('@also', $named[1]->paramName, 'Parameter 2 not named correctly');
|
||||||
|
$this->assertEquals('@field2', $named[2]->paramName, 'Parameter 3 not named correctly');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAddFieldsSucceeds(): void
|
||||||
|
{
|
||||||
|
$this->assertEquals(['@a' => 1, '@b' => 'two', '@z' => 18],
|
||||||
|
Parameters::addFields([Field::EQ('b', 'two', '@b'), Field::EQ('z', 18, '@z')], ['@a' => 1]),
|
||||||
|
'Field parameters not added correctly');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('Field names succeeds for PostgreSQL')]
|
||||||
|
public function testFieldNamesSucceedsForPostgreSQL(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Configuration::$mode = Mode::PgSQL;
|
||||||
|
$this->assertEquals(['@names' => "ARRAY['one','two','seven']"],
|
||||||
|
Parameters::fieldNames('@names', ['one', 'two', 'seven']), 'Field name parameters not correct');
|
||||||
|
} finally {
|
||||||
|
Configuration::$mode = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[TestDox('Field names succeeds for SQLite')]
|
||||||
|
public function testFieldNamesSucceedsForSQLite(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Configuration::$mode = Mode::SQLite;
|
||||||
|
$this->assertEquals(['@it0' => 'test', '@it1' => 'unit', '@it2' => 'wow'],
|
||||||
|
Parameters::fieldNames('@it', ['test', 'unit', 'wow']), 'Field name parameters not correct');
|
||||||
|
} finally {
|
||||||
|
Configuration::$mode = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFieldNamesFailsWhenModeNotSet(): void
|
||||||
|
{
|
||||||
|
$this->expectException(DocumentException::class);
|
||||||
|
Configuration::$mode = null;
|
||||||
|
Parameters::fieldNames('', []);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user