Initial SQLite development #1
|
@ -47,7 +47,9 @@ class Custom
|
|||
if ($stmt->execute()) return $stmt;
|
||||
} catch (PDOException $ex) {
|
||||
$keyword = explode(' ', $query, 2)[0];
|
||||
throw new DocumentException("Error executing $keyword statement: " . $stmt->errorCode(), previous: $ex);
|
||||
throw new DocumentException(
|
||||
sprintf("Error executing %s statement: [%s] %s", $keyword, $stmt->errorCode(), $stmt->errorInfo()[2]),
|
||||
previous: $ex);
|
||||
}
|
||||
$keyword = explode(' ', $query, 2)[0];
|
||||
throw new DocumentException("Error executing $keyword statement: " . $stmt->errorCode());
|
||||
|
|
|
@ -15,13 +15,23 @@ use PDOStatement;
|
|||
*/
|
||||
class DocumentList
|
||||
{
|
||||
/** @var TDoc|null $_first The first item from the results */
|
||||
private mixed $_first = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param PDOStatement|null $result The result of the query
|
||||
* @param Mapper<TDoc> $mapper The mapper to deserialize JSON
|
||||
*/
|
||||
private function __construct(private ?PDOStatement &$result, private readonly Mapper $mapper) { }
|
||||
private function __construct(private ?PDOStatement &$result, private readonly Mapper $mapper)
|
||||
{
|
||||
if ($row = $this->result->fetch(PDO::FETCH_ASSOC)) {
|
||||
$this->_first = $this->mapper->map($row);
|
||||
} else {
|
||||
$this->result = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new document list
|
||||
|
@ -45,9 +55,29 @@ class DocumentList
|
|||
*/
|
||||
public function items(): Generator
|
||||
{
|
||||
if ($this->result) {
|
||||
while ($row = $this->result->fetch(PDO::FETCH_ASSOC)) yield $this->mapper->map($row);
|
||||
if (!$this->result) return;
|
||||
yield $this->_first;
|
||||
while ($row = $this->result->fetch(PDO::FETCH_ASSOC)) {
|
||||
yield $this->mapper->map($row);
|
||||
}
|
||||
$this->result = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this list have items remaining?
|
||||
*
|
||||
* @return bool True if there are items still to be retrieved from the list, false if not
|
||||
*/
|
||||
public function hasItems(): bool
|
||||
{
|
||||
return !is_null($this->result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the statement is destroyed if the generator is not exhausted
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if (!is_null($this->result)) $this->result = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ class Field
|
|||
* Get the WHERE clause fragment for this parameter
|
||||
*
|
||||
* @return string The WHERE clause fragment for this parameter
|
||||
* @throws DocumentException If the database mode has not been set
|
||||
*/
|
||||
public function toWhere(): string
|
||||
{
|
||||
|
@ -57,7 +58,18 @@ class Field
|
|||
default => " $this->paramName"
|
||||
};
|
||||
$prefix = $this->qualifier == '' ? '' : "$this->qualifier.";
|
||||
return "{$prefix}data->>'$this->fieldName' " . $this->op->toString() . $criteria;
|
||||
$fieldPath = match (Configuration::$mode) {
|
||||
Mode::SQLite => "{$prefix}data->>'"
|
||||
. (str_contains($this->fieldName, '.')
|
||||
? implode("'->>'", explode('.', $this->fieldName))
|
||||
: $this->fieldName)
|
||||
. "'",
|
||||
Mode::PgSQL => $this->op == Op::BT && is_numeric($this->value[0])
|
||||
? "({$prefix}data->>'$this->fieldName')::numeric"
|
||||
: "{$prefix}data->>'$this->fieldName'",
|
||||
default => throw new DocumentException('Database mode not set; cannot make field WHERE clause')
|
||||
};
|
||||
return $fieldPath . ' ' . $this->op->toString() . $criteria;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -72,7 +72,7 @@ class Parameters
|
|||
case Mode::SQLite:
|
||||
$it = [];
|
||||
$idx = 0;
|
||||
foreach ($fieldNames as $field) $it[$paramName . $idx++] = $field;
|
||||
foreach ($fieldNames as $field) $it[$paramName . $idx++] = "$.$field";
|
||||
return $it;
|
||||
default:
|
||||
throw new DocumentException('Database mode not set; cannot generate field name parameters');
|
||||
|
|
|
@ -3,8 +3,13 @@
|
|||
namespace Test\Integration\SQLite;
|
||||
|
||||
use BitBadger\PDODocument\{Count, Field};
|
||||
use PHPUnit\Framework\Attributes\TestDox;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* SQLite integration tests for the Count class
|
||||
*/
|
||||
#[TestDox('Count (SQLite integration)')]
|
||||
class CountTest extends TestCase
|
||||
{
|
||||
/** @var string Database name for throwaway database */
|
||||
|
|
|
@ -4,12 +4,14 @@ namespace Test\Integration\SQLite;
|
|||
|
||||
use BitBadger\PDODocument\{Count, Custom, DocumentException, Query};
|
||||
use BitBadger\PDODocument\Mapper\{CountMapper, DocumentMapper};
|
||||
use PHPUnit\Framework\Attributes\TestDox;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Test\Integration\TestDocument;
|
||||
|
||||
/**
|
||||
* SQLite Integration tests for the Custom class
|
||||
*/
|
||||
#[TestDox('Custom (SQLite integration)')]
|
||||
class CustomTest extends TestCase
|
||||
{
|
||||
/** @var string Database name for throwaway database */
|
||||
|
@ -61,9 +63,7 @@ class CustomTest extends TestCase
|
|||
$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');
|
||||
$this->assertFalse($list->hasItems(), 'There should have been no documents in the list');
|
||||
}
|
||||
|
||||
public function testArraySucceedsWhenDataIsFound()
|
||||
|
|
|
@ -4,11 +4,13 @@ namespace Test\Integration\SQLite;
|
|||
|
||||
use BitBadger\PDODocument\{Custom, Definition, DocumentException};
|
||||
use BitBadger\PDODocument\Mapper\ExistsMapper;
|
||||
use PHPUnit\Framework\Attributes\TestDox;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* SQLite integration tests for the Definition class
|
||||
*/
|
||||
#[TestDox('Definition (SQLite integration)')]
|
||||
class DefinitionTest extends TestCase
|
||||
{
|
||||
/** @var string Database name for throwaway database */
|
||||
|
|
59
tests/integration/sqlite/DeleteTest.php
Normal file
59
tests/integration/sqlite/DeleteTest.php
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Test\Integration\SQLite;
|
||||
|
||||
use BitBadger\PDODocument\{Count, Delete, Field};
|
||||
use PHPUnit\Framework\Attributes\TestDox;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* SQLite integration tests for the Delete class
|
||||
*/
|
||||
#[TestDox('Delete (SQLite integration)')]
|
||||
class DeleteTest extends TestCase
|
||||
{
|
||||
/** @var string Database name for throwaway database */
|
||||
private string $dbName;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->dbName = ThrowawayDb::create();
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
ThrowawayDb::destroy($this->dbName);
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
#[TestDox('By ID succeeds when a document is deleted')]
|
||||
public function testByIdSucceedsWhenADocumentIsDeleted(): void
|
||||
{
|
||||
$this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents to start');
|
||||
Delete::byId(ThrowawayDb::TABLE, 'four');
|
||||
$this->assertEquals(4, Count::all(ThrowawayDb::TABLE), 'There should have been 4 documents remaining');
|
||||
}
|
||||
|
||||
#[TestDox('By ID succeeds when a document is not deleted')]
|
||||
public function testByIdSucceedsWhenADocumentIsNotDeleted(): void
|
||||
{
|
||||
$this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents to start');
|
||||
Delete::byId(ThrowawayDb::TABLE, 'negative four');
|
||||
$this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents remaining');
|
||||
}
|
||||
|
||||
public function testByFieldsSucceedsWhenDocumentsAreDeleted(): void
|
||||
{
|
||||
$this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents to start');
|
||||
Delete::byFields(ThrowawayDb::TABLE, [Field::NE('value', 'purple')]);
|
||||
$this->assertEquals(2, Count::all(ThrowawayDb::TABLE), 'There should have been 2 documents remaining');
|
||||
}
|
||||
|
||||
public function testByFieldsSucceedsWhenDocumentsAreNotDeleted(): void
|
||||
{
|
||||
$this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents to start');
|
||||
Delete::byFields(ThrowawayDb::TABLE, [Field::EQ('value', 'crimson')]);
|
||||
$this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents remaining');
|
||||
}
|
||||
}
|
73
tests/integration/sqlite/DocumentListTest.php
Normal file
73
tests/integration/sqlite/DocumentListTest.php
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Test\Integration\SQLite;
|
||||
|
||||
use BitBadger\PDODocument\{DocumentList, Query};
|
||||
use BitBadger\PDODocument\Mapper\DocumentMapper;
|
||||
use PHPUnit\Framework\Attributes\TestDox;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Test\Integration\TestDocument;
|
||||
|
||||
/**
|
||||
* SQLite integration tests for the DocumentList class
|
||||
*/
|
||||
#[TestDox('DocumentList (SQLite integration)')]
|
||||
class DocumentListTest extends TestCase
|
||||
{
|
||||
/** @var string Database name for throwaway database */
|
||||
private string $dbName;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->dbName = ThrowawayDb::create();
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
ThrowawayDb::destroy($this->dbName);
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public function testCreateSucceeds(): void
|
||||
{
|
||||
$list = DocumentList::create(Query::selectFromTable(ThrowawayDb::TABLE), [],
|
||||
new DocumentMapper(TestDocument::class));
|
||||
$this->assertNotNull($list, 'There should have been a document list created');
|
||||
$list = null;
|
||||
}
|
||||
|
||||
public function testItems(): void
|
||||
{
|
||||
$list = DocumentList::create(Query::selectFromTable(ThrowawayDb::TABLE), [],
|
||||
new DocumentMapper(TestDocument::class));
|
||||
$this->assertNotNull($list, 'There should have been a document list created');
|
||||
$count = 0;
|
||||
foreach ($list->items() as $item) {
|
||||
$this->assertContains($item->id, ['one', 'two', 'three', 'four', 'five'],
|
||||
'An unexpected document ID was returned');
|
||||
$count++;
|
||||
}
|
||||
$this->assertEquals(5, $count, 'There should have been 5 documents returned');
|
||||
}
|
||||
|
||||
public function testHasItemsSucceedsWithEmptyResults(): void
|
||||
{
|
||||
$list = DocumentList::create(Query::selectFromTable(ThrowawayDb::TABLE) . " WHERE data->>'num_value' < 0", [],
|
||||
new DocumentMapper(TestDocument::class));
|
||||
$this->assertNotNull($list, 'There should have been a document list created');
|
||||
$this->assertFalse($list->hasItems(), 'There should be no items in the list');
|
||||
}
|
||||
|
||||
public function testHasItemsSucceedsWithNonEmptyResults(): void
|
||||
{
|
||||
$list = DocumentList::create(Query::selectFromTable(ThrowawayDb::TABLE), [],
|
||||
new DocumentMapper(TestDocument::class));
|
||||
$this->assertNotNull($list, 'There should have been a document list created');
|
||||
$this->assertTrue($list->hasItems(), 'There should be items in the list');
|
||||
foreach ($list->items() as $ignored) {
|
||||
$this->assertTrue($list->hasItems(), 'There should be items remaining in the list');
|
||||
}
|
||||
$this->assertFalse($list->hasItems(), 'There should be no remaining items in the list');
|
||||
}
|
||||
}
|
|
@ -3,12 +3,14 @@
|
|||
namespace Test\Integration\SQLite;
|
||||
|
||||
use BitBadger\PDODocument\{Document, DocumentException, Find};
|
||||
use PHPUnit\Framework\Attributes\TestDox;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Test\Integration\{SubDocument, TestDocument};
|
||||
|
||||
/**
|
||||
* SQLite integration tests for the Document class
|
||||
*/
|
||||
#[TestDox('Document (SQLite integration)')]
|
||||
class DocumentTest extends TestCase
|
||||
{
|
||||
/** @var string Database name for throwaway database */
|
||||
|
|
54
tests/integration/sqlite/ExistsTest.php
Normal file
54
tests/integration/sqlite/ExistsTest.php
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Test\Integration\SQLite;
|
||||
|
||||
use BitBadger\PDODocument\{Exists, Field};
|
||||
use PHPUnit\Framework\Attributes\TestDox;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* SQLite integration tests for the Exists class
|
||||
*/
|
||||
#[TestDox('Exists (SQLite integration)')]
|
||||
class ExistsTest extends TestCase
|
||||
{
|
||||
/** @var string Database name for throwaway database */
|
||||
private string $dbName;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->dbName = ThrowawayDb::create();
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
ThrowawayDb::destroy($this->dbName);
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
#[TestDox('By ID succeeds when a document exists')]
|
||||
public function testByIdSucceedsWhenADocumentExists(): void
|
||||
{
|
||||
$this->assertTrue(Exists::byId(ThrowawayDb::TABLE, 'three'), 'There should have been an existing document');
|
||||
}
|
||||
|
||||
#[TestDox('By ID succeeds when a document does not exist')]
|
||||
public function testByIdSucceedsWhenADocumentDoesNotExist(): void
|
||||
{
|
||||
$this->assertFalse(Exists::byId(ThrowawayDb::TABLE, 'seven'),
|
||||
'There should not have been an existing document');
|
||||
}
|
||||
|
||||
public function testByFieldsSucceedsWhenDocumentsExist(): void
|
||||
{
|
||||
$this->assertTrue(Exists::byFields(ThrowawayDb::TABLE, [Field::EQ('num_value', 10)]),
|
||||
'There should have been existing documents');
|
||||
}
|
||||
|
||||
public function testByFieldsSucceedsWhenNoMatchingDocumentsExist(): void
|
||||
{
|
||||
$this->assertFalse(Exists::byFields(ThrowawayDb::TABLE, [Field::LT('nothing', 'none')]),
|
||||
'There should not have been any existing documents');
|
||||
}
|
||||
}
|
100
tests/integration/sqlite/FindTest.php
Normal file
100
tests/integration/sqlite/FindTest.php
Normal file
|
@ -0,0 +1,100 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Test\Integration\SQLite;
|
||||
|
||||
use BitBadger\PDODocument\{Custom, Field, Find};
|
||||
use PHPUnit\Framework\Attributes\TestDox;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Test\Integration\TestDocument;
|
||||
|
||||
/**
|
||||
* SQLite integration tests for the Find class
|
||||
*/
|
||||
#[TestDox('Find (SQLite integration)')]
|
||||
class FindTest extends TestCase
|
||||
{
|
||||
/** @var string Database name for throwaway database */
|
||||
private string $dbName;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->dbName = ThrowawayDb::create();
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
ThrowawayDb::destroy($this->dbName);
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public function testAllSucceedsWhenThereIsData(): void
|
||||
{
|
||||
$docs = Find::all(ThrowawayDb::TABLE, TestDocument::class);
|
||||
$this->assertNotNull($docs, 'There should have been a document list returned');
|
||||
$count = 0;
|
||||
foreach ($docs->items() as $ignored) $count++;
|
||||
$this->assertEquals(5, $count, 'There should have been 5 documents in the list');
|
||||
}
|
||||
|
||||
public function testAllSucceedsWhenThereIsNoData(): void
|
||||
{
|
||||
Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []);
|
||||
$docs = Find::all(ThrowawayDb::TABLE, TestDocument::class);
|
||||
$this->assertNotNull($docs, 'There should have been a document list returned');
|
||||
$this->assertFalse($docs->hasItems(), 'There should have been no documents in the list');
|
||||
}
|
||||
|
||||
#[TestDox('By ID succeeds when a document is found')]
|
||||
public function testByIdSucceedsWhenADocumentIsFound(): void
|
||||
{
|
||||
$doc = Find::byId(ThrowawayDb::TABLE, 'two', TestDocument::class);
|
||||
$this->assertNotFalse($doc, 'There should have been a document returned');
|
||||
$this->assertEquals('two', $doc->id, 'An incorrect document was returned');
|
||||
}
|
||||
|
||||
#[TestDox('By ID succeeds when a document is not found')]
|
||||
public function testByIdSucceedsWhenADocumentIsNotFound(): void
|
||||
{
|
||||
$doc = Find::byId(ThrowawayDb::TABLE, 'seventy-five', TestDocument::class);
|
||||
$this->assertFalse($doc, 'There should not have been a document returned');
|
||||
}
|
||||
|
||||
public function testByFieldsSucceedsWhenDocumentsAreFound(): void
|
||||
{
|
||||
$docs = Find::byFields(ThrowawayDb::TABLE, [Field::GT('num_value', 15)], TestDocument::class);
|
||||
$this->assertNotNull($docs, 'There should have been a document list returned');
|
||||
$count = 0;
|
||||
foreach ($docs->items() as $ignored) $count++;
|
||||
$this->assertEquals(2, $count, 'There should have been 2 documents in the list');
|
||||
}
|
||||
|
||||
public function testByFieldsSucceedsWhenNoDocumentsAreFound(): void
|
||||
{
|
||||
$docs = Find::byFields(ThrowawayDb::TABLE, [Field::GT('num_value', 100)], TestDocument::class);
|
||||
$this->assertNotNull($docs, 'There should have been a document list returned');
|
||||
$count = 0;
|
||||
foreach ($docs->items() as $ignored) $count++;
|
||||
$this->assertFalse($docs->hasItems(), 'There should have been no documents in the list');
|
||||
}
|
||||
|
||||
public function testFirstByFieldsSucceedsWhenADocumentIsFound(): void
|
||||
{
|
||||
$doc = Find::firstByFields(ThrowawayDb::TABLE, [Field::EQ('value', 'another')], TestDocument::class);
|
||||
$this->assertNotFalse($doc, 'There should have been a document returned');
|
||||
$this->assertEquals('two', $doc->id, 'The incorrect document was returned');
|
||||
}
|
||||
|
||||
public function testFirstByFieldsSucceedsWhenMultipleDocumentsAreFound(): void
|
||||
{
|
||||
$doc = Find::firstByFields(ThrowawayDb::TABLE, [Field::EQ('sub.foo', 'green')], TestDocument::class);
|
||||
$this->assertNotFalse($doc, 'There should have been a document returned');
|
||||
$this->assertContains($doc->id, ['two', 'four'], 'An incorrect document was returned');
|
||||
}
|
||||
|
||||
public function testFirstByFieldsSucceedsWhenADocumentIsNotFound(): void
|
||||
{
|
||||
$doc = Find::firstByFields(ThrowawayDb::TABLE, [Field::EQ('value', 'absent')], TestDocument::class);
|
||||
$this->assertFalse($doc, 'There should not have been a document returned');
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ use Test\Integration\TestDocument;
|
|||
/**
|
||||
* SQLite integration tests for the Patch class
|
||||
*/
|
||||
#[TestDox('Patch (SQLite integration)')]
|
||||
class PatchTest extends TestCase
|
||||
{
|
||||
/** @var string Database name for throwaway database */
|
||||
|
|
74
tests/integration/sqlite/RemoveFieldsTest.php
Normal file
74
tests/integration/sqlite/RemoveFieldsTest.php
Normal file
|
@ -0,0 +1,74 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Test\Integration\SQLite;
|
||||
|
||||
use BitBadger\PDODocument\{Field, Find, RemoveFields};
|
||||
use PHPUnit\Framework\Attributes\TestDox;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Test\Integration\TestDocument;
|
||||
|
||||
/**
|
||||
* SQLite integration tests for the RemoveFields class
|
||||
*/
|
||||
#[TestDox('Remove Fields (SQLite integration)')]
|
||||
class RemoveFieldsTest extends TestCase
|
||||
{
|
||||
/** @var string Database name for throwaway database */
|
||||
private string $dbName;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->dbName = ThrowawayDb::create();
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
ThrowawayDb::destroy($this->dbName);
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
#[TestDox('By ID succeeds when fields are removed')]
|
||||
public function testByIdSucceedsWhenFieldsAreRemoved(): void
|
||||
{
|
||||
RemoveFields::byId(ThrowawayDb::TABLE, 'two', ['sub', 'value']);
|
||||
$doc = Find::byId(ThrowawayDb::TABLE, 'two', TestDocument::class);
|
||||
$this->assertNotFalse($doc, 'There should have been a document returned');
|
||||
$this->assertEquals('', $doc->value, 'Value should have been blank (its default value)');
|
||||
$this->assertNull($doc->sub, 'Sub-document should have been null');
|
||||
}
|
||||
|
||||
#[TestDox('By ID succeeds when a field is not removed')]
|
||||
public function testByIdSucceedsWhenAFieldIsNotRemoved(): void
|
||||
{
|
||||
RemoveFields::byId(ThrowawayDb::TABLE, 'one', ['a_field_that_does_not_exist']);
|
||||
$this->assertTrue(true, 'The above not throwing an exception is the test');
|
||||
}
|
||||
|
||||
#[TestDox('By ID succeeds when no document is matched')]
|
||||
public function testByIdSucceedsWhenNoDocumentIsMatched(): void
|
||||
{
|
||||
RemoveFields::byId(ThrowawayDb::TABLE, 'fifty', ['sub']);
|
||||
$this->assertTrue(true, 'The above not throwing an exception is the test');
|
||||
}
|
||||
|
||||
public function testByFieldsSucceedsWhenAFieldIsRemoved(): void
|
||||
{
|
||||
RemoveFields::byFields(ThrowawayDb::TABLE, [Field::EQ('num_value', 17)], ['sub']);
|
||||
$doc = Find::firstByFields(ThrowawayDb::TABLE, [Field::EQ('num_value', 17)], TestDocument::class);
|
||||
$this->assertNotFalse($doc, 'There should have been a document returned');
|
||||
$this->assertNull($doc->sub, 'Sub-document should have been null');
|
||||
}
|
||||
|
||||
public function testByFieldsSucceedsWhenAFieldIsNotRemoved(): void
|
||||
{
|
||||
RemoveFields::byFields(ThrowawayDb::TABLE, [Field::EQ('num_value', 17)], ['nada']);
|
||||
$this->assertTrue(true, 'The above not throwing an exception is the test');
|
||||
}
|
||||
|
||||
public function testByFieldsSucceedsWhenNoDocumentIsMatched(): void
|
||||
{
|
||||
RemoveFields::byFields(ThrowawayDb::TABLE, [Field::NE('missing', 'nope')], ['value']);
|
||||
$this->assertTrue(true, 'The above not throwing an exception is the test');
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Test\Unit;
|
||||
|
||||
use BitBadger\PDODocument\{Field, Op};
|
||||
use BitBadger\PDODocument\{Configuration, Field, Mode, Op};
|
||||
use PHPUnit\Framework\Attributes\TestDox;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
|
@ -36,46 +36,236 @@ class FieldTest extends TestCase
|
|||
'Field parameter not returned correctly');
|
||||
}
|
||||
|
||||
#[TestDox('To where succeeds for EX without qualifier')]
|
||||
public function testToWhereSucceedsForEXWithoutQualifier(): void
|
||||
#[TestDox('To where succeeds for EX without qualifier for PostgreSQL')]
|
||||
public function testToWhereSucceedsForEXWithoutQualifierForPostgreSQL(): void
|
||||
{
|
||||
$this->assertEquals("data->>'that_field' IS NOT NULL", Field::EX('that_field')->toWhere(),
|
||||
'WHERE fragment not generated correctly');
|
||||
Configuration::$mode = Mode::PgSQL;
|
||||
try {
|
||||
$this->assertEquals("data->>'that_field' IS NOT NULL", Field::EX('that_field')->toWhere(),
|
||||
'WHERE fragment not generated correctly');
|
||||
} finally {
|
||||
Configuration::$mode = null;
|
||||
}
|
||||
}
|
||||
|
||||
#[TestDox('To where succeeds for NEX without qualifier')]
|
||||
public function testToWhereSucceedsForNEXWithoutQualifier(): void
|
||||
#[TestDox('To where succeeds for EX without qualifier for SQLite')]
|
||||
public function testToWhereSucceedsForEXWithoutQualifierForSQLite(): void
|
||||
{
|
||||
$this->assertEquals("data->>'a_field' IS NULL", Field::NEX('a_field')->toWhere(),
|
||||
'WHERE fragment not generated correctly');
|
||||
Configuration::$mode = Mode::SQLite;
|
||||
try {
|
||||
$this->assertEquals("data->>'that_field' IS NOT NULL", Field::EX('that_field')->toWhere(),
|
||||
'WHERE fragment not generated correctly');
|
||||
} finally {
|
||||
Configuration::$mode = null;
|
||||
}
|
||||
}
|
||||
|
||||
#[TestDox('To where succeeds for BT without qualifier')]
|
||||
public function testToWhereSucceedsForBTWithoutQualifier(): void
|
||||
#[TestDox('To where succeeds for NEX without qualifier for PostgreSQL')]
|
||||
public function testToWhereSucceedsForNEXWithoutQualifierForPostgreSQL(): void
|
||||
{
|
||||
$this->assertEquals("data->>'age' BETWEEN @agemin AND @agemax", Field::BT('age', 13, 17, '@age')->toWhere(),
|
||||
'WHERE fragment not generated correctly');
|
||||
Configuration::$mode = Mode::PgSQL;
|
||||
try {
|
||||
$this->assertEquals("data->>'a_field' IS NULL", Field::NEX('a_field')->toWhere(),
|
||||
'WHERE fragment not generated correctly');
|
||||
} finally {
|
||||
Configuration::$mode = null;
|
||||
}
|
||||
}
|
||||
|
||||
public function testToWhereSucceedsForOthersWithoutQualifier(): void
|
||||
#[TestDox('To where succeeds for NEX without qualifier for SQLite')]
|
||||
public function testToWhereSucceedsForNEXWithoutQualifierForSQLite(): void
|
||||
{
|
||||
$this->assertEquals("data->>'some_field' = @value", Field::EQ('some_field', '', '@value')->toWhere(),
|
||||
'WHERE fragment not generated correctly');
|
||||
Configuration::$mode = Mode::SQLite;
|
||||
try {
|
||||
$this->assertEquals("data->>'a_field' IS NULL", Field::NEX('a_field')->toWhere(),
|
||||
'WHERE fragment not generated correctly');
|
||||
} finally {
|
||||
Configuration::$mode = null;
|
||||
}
|
||||
}
|
||||
|
||||
public function testToWhereSucceedsWithQualifierNoParameter(): void
|
||||
#[TestDox('To where succeeds for BT without qualifier for SQLite')]
|
||||
public function testToWhereSucceedsForBTWithoutQualifierForSQLite(): void
|
||||
{
|
||||
$field = Field::EX('no_field');
|
||||
$field->qualifier = 'test';
|
||||
$this->assertEquals("test.data->>'no_field' IS NOT NULL", $field->toWhere(),
|
||||
'WHERE fragment not generated correctly');
|
||||
Configuration::$mode = Mode::SQLite;
|
||||
try {
|
||||
$this->assertEquals("data->>'age' BETWEEN @agemin AND @agemax", Field::BT('age', 13, 17, '@age')->toWhere(),
|
||||
'WHERE fragment not generated correctly');
|
||||
} finally {
|
||||
Configuration::$mode = null;
|
||||
}
|
||||
}
|
||||
|
||||
public function testToWhereSucceedsWithQualifierAndParameter(): void
|
||||
#[TestDox('To where succeeds for BT without qualifier for PostgreSQL with numeric range')]
|
||||
public function testToWhereSucceedsForBTWithoutQualifierForPostgreSQLWithNumericRange(): void
|
||||
{
|
||||
$field = Field::LE('le_field', 18, '@it');
|
||||
$field->qualifier = 'q';
|
||||
$this->assertEquals("q.data->>'le_field' <= @it", $field->toWhere(), 'WHERE fragment not generated correctly');
|
||||
Configuration::$mode = Mode::PgSQL;
|
||||
try {
|
||||
$this->assertEquals("(data->>'age')::numeric BETWEEN @agemin AND @agemax",
|
||||
Field::BT('age', 13, 17, '@age')->toWhere(), 'WHERE fragment not generated correctly');
|
||||
} finally {
|
||||
Configuration::$mode = null;
|
||||
}
|
||||
}
|
||||
|
||||
#[TestDox('To where succeeds for BT without qualifier for PostgreSQL with non-numeric range')]
|
||||
public function testToWhereSucceedsForBTWithoutQualifierForPostgreSQLWithNonNumericRange(): void
|
||||
{
|
||||
Configuration::$mode = Mode::PgSQL;
|
||||
try {
|
||||
$this->assertEquals("data->>'city' BETWEEN :citymin AND :citymax",
|
||||
Field::BT('city', 'Atlanta', 'Chicago', ':city')->toWhere(), 'WHERE fragment not generated correctly');
|
||||
} finally {
|
||||
Configuration::$mode = null;
|
||||
}
|
||||
}
|
||||
|
||||
#[TestDox('To where succeeds for BT with qualifier for SQLite')]
|
||||
public function testToWhereSucceedsForBTWithQualifierForSQLite(): void
|
||||
{
|
||||
Configuration::$mode = Mode::SQLite;
|
||||
try {
|
||||
$field = Field::BT('age', 13, 17, '@age');
|
||||
$field->qualifier = 'me';
|
||||
$this->assertEquals("me.data->>'age' BETWEEN @agemin AND @agemax", $field->toWhere(),
|
||||
'WHERE fragment not generated correctly');
|
||||
} finally {
|
||||
Configuration::$mode = null;
|
||||
}
|
||||
}
|
||||
|
||||
#[TestDox('To where succeeds for BT with qualifier for PostgreSQL with numeric range')]
|
||||
public function testToWhereSucceedsForBTWithQualifierForPostgreSQLWithNumericRange(): void
|
||||
{
|
||||
Configuration::$mode = Mode::PgSQL;
|
||||
try {
|
||||
$field = Field::BT('age', 13, 17, '@age');
|
||||
$field->qualifier = 'me';
|
||||
$this->assertEquals("(me.data->>'age')::numeric BETWEEN @agemin AND @agemax", $field->toWhere(),
|
||||
'WHERE fragment not generated correctly');
|
||||
} finally {
|
||||
Configuration::$mode = null;
|
||||
}
|
||||
}
|
||||
|
||||
#[TestDox('To where succeeds for BT with qualifier for PostgreSQL with non-numeric range')]
|
||||
public function testToWhereSucceedsForBTWithQualifierForPostgreSQLWithNonNumericRange(): void
|
||||
{
|
||||
Configuration::$mode = Mode::PgSQL;
|
||||
try {
|
||||
$field = Field::BT('city', 'Atlanta', 'Chicago', ':city');
|
||||
$field->qualifier = 'me';
|
||||
$this->assertEquals("me.data->>'city' BETWEEN :citymin AND :citymax", $field->toWhere(),
|
||||
'WHERE fragment not generated correctly');
|
||||
} finally {
|
||||
Configuration::$mode = null;
|
||||
}
|
||||
}
|
||||
|
||||
#[TestDox('To where succeeds for others without qualifier for PostgreSQL')]
|
||||
public function testToWhereSucceedsForOthersWithoutQualifierForPostgreSQL(): void
|
||||
{
|
||||
Configuration::$mode = Mode::PgSQL;
|
||||
try {
|
||||
$this->assertEquals("data->>'some_field' = @value", Field::EQ('some_field', '', '@value')->toWhere(),
|
||||
'WHERE fragment not generated correctly');
|
||||
} finally {
|
||||
Configuration::$mode = null;
|
||||
}
|
||||
}
|
||||
|
||||
#[TestDox('To where succeeds for others without qualifier for SQLite')]
|
||||
public function testToWhereSucceedsForOthersWithoutQualifierForSQLite(): void
|
||||
{
|
||||
Configuration::$mode = Mode::SQLite;
|
||||
try {
|
||||
$this->assertEquals("data->>'some_field' = @value", Field::EQ('some_field', '', '@value')->toWhere(),
|
||||
'WHERE fragment not generated correctly');
|
||||
} finally {
|
||||
Configuration::$mode = null;
|
||||
}
|
||||
}
|
||||
|
||||
#[TestDox('To where succeeds with qualifier no parameter for PostgreSQL')]
|
||||
public function testToWhereSucceedsWithQualifierNoParameterForPostgreSQL(): void
|
||||
{
|
||||
Configuration::$mode = Mode::PgSQL;
|
||||
try {
|
||||
$field = Field::EX('no_field');
|
||||
$field->qualifier = 'test';
|
||||
$this->assertEquals("test.data->>'no_field' IS NOT NULL", $field->toWhere(),
|
||||
'WHERE fragment not generated correctly');
|
||||
} finally {
|
||||
Configuration::$mode = null;
|
||||
}
|
||||
}
|
||||
|
||||
#[TestDox('To where succeeds with qualifier no parameter for SQLite')]
|
||||
public function testToWhereSucceedsWithQualifierNoParameterForSQLite(): void
|
||||
{
|
||||
Configuration::$mode = Mode::SQLite;
|
||||
try {
|
||||
$field = Field::EX('no_field');
|
||||
$field->qualifier = 'test';
|
||||
$this->assertEquals("test.data->>'no_field' IS NOT NULL", $field->toWhere(),
|
||||
'WHERE fragment not generated correctly');
|
||||
} finally {
|
||||
Configuration::$mode = null;
|
||||
}
|
||||
}
|
||||
|
||||
#[TestDox('To where succeeds with qualifier and parameter for PostgreSQL')]
|
||||
public function testToWhereSucceedsWithQualifierAndParameterForPostgreSQL(): void
|
||||
{
|
||||
Configuration::$mode = Mode::PgSQL;
|
||||
try {
|
||||
$field = Field::LE('le_field', 18, '@it');
|
||||
$field->qualifier = 'q';
|
||||
$this->assertEquals("q.data->>'le_field' <= @it", $field->toWhere(),
|
||||
'WHERE fragment not generated correctly');
|
||||
} finally {
|
||||
Configuration::$mode = null;
|
||||
}
|
||||
}
|
||||
|
||||
#[TestDox('To where succeeds with qualifier and parameter for SQLite')]
|
||||
public function testToWhereSucceedsWithQualifierAndParameterForSQLite(): void
|
||||
{
|
||||
Configuration::$mode = Mode::SQLite;
|
||||
try {
|
||||
$field = Field::LE('le_field', 18, '@it');
|
||||
$field->qualifier = 'q';
|
||||
$this->assertEquals("q.data->>'le_field' <= @it", $field->toWhere(),
|
||||
'WHERE fragment not generated correctly');
|
||||
} finally {
|
||||
Configuration::$mode = null;
|
||||
}
|
||||
}
|
||||
|
||||
#[TestDox('To where succeeds with sub-document for PostgreSQL')]
|
||||
public function testToWhereSucceedsWithSubDocumentForPostgreSQL(): void
|
||||
{
|
||||
Configuration::$mode = Mode::PgSQL;
|
||||
try {
|
||||
$field = Field::EQ('sub.foo.bar', 22, '@it');
|
||||
$this->assertEquals("data->>'sub.foo.bar' = @it", $field->toWhere(),
|
||||
'WHERE fragment not generated correctly');
|
||||
} finally {
|
||||
Configuration::$mode = null;
|
||||
}
|
||||
}
|
||||
|
||||
#[TestDox('To where succeeds with sub-document for SQLite')]
|
||||
public function testToWhereSucceedsWithSubDocumentForSQLite(): void
|
||||
{
|
||||
Configuration::$mode = Mode::SQLite;
|
||||
try {
|
||||
$field = Field::EQ('sub.foo.bar', 22, '@it');
|
||||
$this->assertEquals("data->>'sub'->>'foo'->>'bar' = @it", $field->toWhere(),
|
||||
'WHERE fragment not generated correctly');
|
||||
} finally {
|
||||
Configuration::$mode = null;
|
||||
}
|
||||
}
|
||||
|
||||
#[TestDox('EQ succeeds without parameter')]
|
||||
|
|
|
@ -63,7 +63,7 @@ class ParametersTest extends TestCase
|
|||
{
|
||||
try {
|
||||
Configuration::$mode = Mode::SQLite;
|
||||
$this->assertEquals([':it0' => 'test', ':it1' => 'unit', ':it2' => 'wow'],
|
||||
$this->assertEquals([':it0' => '$.test', ':it1' => '$.unit', ':it2' => '$.wow'],
|
||||
Parameters::fieldNames(':it', ['test', 'unit', 'wow']), 'Field name parameters not correct');
|
||||
} finally {
|
||||
Configuration::$mode = null;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Test\Unit\Query;
|
||||
|
||||
use BitBadger\PDODocument\Field;
|
||||
use BitBadger\PDODocument\{Configuration, Field, Mode};
|
||||
use BitBadger\PDODocument\Query\Count;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
|
@ -20,7 +20,12 @@ class CountTest extends TestCase
|
|||
|
||||
public function testByFieldsSucceeds()
|
||||
{
|
||||
$this->assertEquals("SELECT COUNT(*) FROM somewhere WHERE data->>'errors' > :errors",
|
||||
Count::byFields('somewhere', [Field::GT('errors', 10, ':errors')]));
|
||||
Configuration::$mode = Mode::SQLite;
|
||||
try {
|
||||
$this->assertEquals("SELECT COUNT(*) FROM somewhere WHERE data->>'errors' > :errors",
|
||||
Count::byFields('somewhere', [Field::GT('errors', 10, ':errors')]));
|
||||
} finally {
|
||||
Configuration::$mode = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Test\Unit\Query;
|
||||
|
||||
use BitBadger\PDODocument\Field;
|
||||
use BitBadger\PDODocument\{Configuration, Field, Mode};
|
||||
use BitBadger\PDODocument\Query\Delete;
|
||||
use PHPUnit\Framework\Attributes\TestDox;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
@ -12,6 +12,16 @@ use PHPUnit\Framework\TestCase;
|
|||
*/
|
||||
class DeleteTest extends TestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
Configuration::$mode = Mode::SQLite;
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
Configuration::$mode = null;
|
||||
}
|
||||
|
||||
#[TestDox('By ID succeeds')]
|
||||
public function testByIdSucceeds(): void
|
||||
{
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Test\Unit\Query;
|
||||
|
||||
use BitBadger\PDODocument\Field;
|
||||
use BitBadger\PDODocument\{Configuration, Field, Mode};
|
||||
use BitBadger\PDODocument\Query\Exists;
|
||||
use PHPUnit\Framework\Attributes\TestDox;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
@ -12,6 +12,16 @@ use PHPUnit\Framework\TestCase;
|
|||
*/
|
||||
class ExistsTest extends TestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
Configuration::$mode = Mode::SQLite;
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
Configuration::$mode = null;
|
||||
}
|
||||
|
||||
public function testQuerySucceeds(): void
|
||||
{
|
||||
$this->assertEquals('SELECT EXISTS (SELECT 1 FROM abc WHERE def)', Exists::query('abc', 'def'),
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Test\Unit\Query;
|
||||
|
||||
use BitBadger\PDODocument\Field;
|
||||
use BitBadger\PDODocument\{Configuration, Field, Mode};
|
||||
use BitBadger\PDODocument\Query\Find;
|
||||
use PHPUnit\Framework\Attributes\TestDox;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
@ -12,6 +12,16 @@ use PHPUnit\Framework\TestCase;
|
|||
*/
|
||||
class FindTest extends TestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
Configuration::$mode = Mode::SQLite;
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
Configuration::$mode = null;
|
||||
}
|
||||
|
||||
#[TestDox('By ID succeeds')]
|
||||
public function testByIdSucceeds(): void
|
||||
{
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Test\Unit;
|
||||
|
||||
use BitBadger\PDODocument\{Field, Query};
|
||||
use BitBadger\PDODocument\{Configuration, Field, Mode, Query};
|
||||
use PHPUnit\Framework\Attributes\TestDox;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
|
@ -11,6 +11,16 @@ use PHPUnit\Framework\TestCase;
|
|||
*/
|
||||
class QueryTest extends TestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
Configuration::$mode = Mode::SQLite;
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
Configuration::$mode = null;
|
||||
}
|
||||
|
||||
public function testSelectFromTableSucceeds(): void
|
||||
{
|
||||
$this->assertEquals('SELECT data FROM testing', Query::selectFromTable('testing'),
|
||||
|
|
Loading…
Reference in New Issue
Block a user