WIP on migrating Postgres integration tests
This commit is contained in:
parent
7cdbf5fcdb
commit
3ec1a05d82
60
tests/Integration/PgIntegrationTest.php
Normal file
60
tests/Integration/PgIntegrationTest.php
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
* @see https://github.com/Zaid-Ajaj/ThrowawayDb The origin concept
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Test\Integration;
|
||||||
|
|
||||||
|
use BitBadger\PDODocument\{Configuration, Custom, Delete, DocumentException, Field};
|
||||||
|
use BitBadger\PDODocument\Mapper\ExistsMapper;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Test\Integration\PostgreSQL\ThrowawayDb;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration Test Class wrapper for PostgreSQL integration tests
|
||||||
|
*/
|
||||||
|
class PgIntegrationTest extends TestCase
|
||||||
|
{
|
||||||
|
/** @var string Database name for throwaway database */
|
||||||
|
static private string $dbName = '';
|
||||||
|
|
||||||
|
public static function setUpBeforeClass(): void
|
||||||
|
{
|
||||||
|
self::$dbName = ThrowawayDb::create(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
ThrowawayDb::loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown(): void
|
||||||
|
{
|
||||||
|
Delete::byFields(ThrowawayDb::TABLE, [ Field::exists(Configuration::$idField)]);
|
||||||
|
parent::tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function tearDownAfterClass(): void
|
||||||
|
{
|
||||||
|
ThrowawayDb::destroy(self::$dbName);
|
||||||
|
self::$dbName = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the given named object exist in the database?
|
||||||
|
*
|
||||||
|
* @param string $name The name of the object whose existence should be verified
|
||||||
|
* @return bool True if the object exists, false if not
|
||||||
|
* @throws DocumentException If any is encountered
|
||||||
|
*/
|
||||||
|
protected function dbObjectExists(string $name): bool
|
||||||
|
{
|
||||||
|
return Custom::scalar('SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = :name)',
|
||||||
|
[':name' => $name], new ExistsMapper());
|
||||||
|
}
|
||||||
|
}
|
45
tests/Integration/PostgreSQL/CountTest.php
Normal file
45
tests/Integration/PostgreSQL/CountTest.php
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use BitBadger\PDODocument\{Count, Field};
|
||||||
|
use Test\Integration\PostgreSQL\ThrowawayDb;
|
||||||
|
|
||||||
|
pest()->group('integration', 'postgresql');
|
||||||
|
|
||||||
|
describe('::all()', function () {
|
||||||
|
test('counts all documents', function () {
|
||||||
|
expect(Count::all(ThrowawayDb::TABLE))->toBe(5);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('::byFields()', function () {
|
||||||
|
test('counts for numeric range correctly', function () {
|
||||||
|
expect(Count::byFields(ThrowawayDb::TABLE, [Field::between('num_value', 10, 20)]))->toBe(3);
|
||||||
|
});
|
||||||
|
test('counts for non-numeric range correctly', function () {
|
||||||
|
expect(Count::byFields(ThrowawayDb::TABLE, [Field::between('value', 'aardvark', 'apple')]))->toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('::byContains()', function () {
|
||||||
|
test('counts matching documents', function () {
|
||||||
|
expect(Count::byContains(ThrowawayDb::TABLE, ['value' => 'purple']))->toBe(2);
|
||||||
|
});
|
||||||
|
test('returns 0 for no matching documents', function () {
|
||||||
|
expect(Count::byContains(ThrowawayDb::TABLE, ['value' => 'magenta']))->toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('::byJsonPath()', function () {
|
||||||
|
test('counts matching documents', function () {
|
||||||
|
expect(Count::byJsonPath(ThrowawayDb::TABLE, '$.num_value ? (@ < 5)'))->toBe(2);
|
||||||
|
});
|
||||||
|
test('returns 0 for no matching documents', function () {
|
||||||
|
expect(Count::byJsonPath(ThrowawayDb::TABLE, '$.num_value ? (@ > 100)'))->toBe(0);
|
||||||
|
});
|
||||||
|
});
|
98
tests/Integration/PostgreSQL/CustomTest.php
Normal file
98
tests/Integration/PostgreSQL/CustomTest.php
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use BitBadger\PDODocument\{Count, Custom, DocumentException, Query};
|
||||||
|
use BitBadger\PDODocument\Mapper\{CountMapper, DocumentMapper};
|
||||||
|
use Test\Integration\PostgreSQL\ThrowawayDb;
|
||||||
|
use Test\Integration\TestDocument;
|
||||||
|
|
||||||
|
pest()->group('integration', 'postgresql');
|
||||||
|
|
||||||
|
describe('::runQuery()', function () {
|
||||||
|
test('runs a valid query successfully', function () {
|
||||||
|
$stmt = &Custom::runQuery('SELECT data FROM ' . ThrowawayDb::TABLE . ' LIMIT 1', []);
|
||||||
|
try {
|
||||||
|
expect($stmt)->not->toBeNull();
|
||||||
|
} finally {
|
||||||
|
$stmt = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
test('fails with an invalid query', function () {
|
||||||
|
$stmt = null;
|
||||||
|
try {
|
||||||
|
expect(function () use (&$stmt) { $stmt = &Custom::runQuery('GRAB stuff FROM over_there UNTIL done', []); })
|
||||||
|
->toThrow(DocumentException::class);
|
||||||
|
} finally {
|
||||||
|
$stmt = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('::list()', function () {
|
||||||
|
test('returns non-empty list when data found', function () {
|
||||||
|
$list = Custom::list(Query::selectFromTable(ThrowawayDb::TABLE), [], new DocumentMapper(TestDocument::class));
|
||||||
|
expect($list)->not->toBeNull();
|
||||||
|
$count = 0;
|
||||||
|
foreach ($list->items() as $ignored) $count++;
|
||||||
|
expect($count)->toBe(5);
|
||||||
|
});
|
||||||
|
test('returns empty list when no data found', function () {
|
||||||
|
expect(Custom::list(
|
||||||
|
Query::selectFromTable(ThrowawayDb::TABLE) . " WHERE (data->>'num_value')::numeric > :value",
|
||||||
|
[':value' => 100], new DocumentMapper(TestDocument::class)))
|
||||||
|
->not->toBeNull()
|
||||||
|
->hasItems()->toBeFalse();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('::array()', function () {
|
||||||
|
test('returns non-empty array when data found', function () {
|
||||||
|
expect(Custom::array(Query::selectFromTable(ThrowawayDb::TABLE) . " WHERE data->>'sub' IS NOT NULL", [],
|
||||||
|
new DocumentMapper(TestDocument::class)))
|
||||||
|
->not->toBeNull()
|
||||||
|
->toHaveCount(2);
|
||||||
|
});
|
||||||
|
test('returns empty array when no data found', function () {
|
||||||
|
expect(Custom::array(Query::selectFromTable(ThrowawayDb::TABLE) . " WHERE data->>'value' = :value",
|
||||||
|
[':value' => 'not there'], new DocumentMapper(TestDocument::class)))
|
||||||
|
->not->toBeNull()
|
||||||
|
->toBeEmpty();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('::single()', function () {
|
||||||
|
test('returns a document when one is found', function () {
|
||||||
|
expect(Custom::single('SELECT data FROM ' . ThrowawayDb::TABLE . " WHERE data->>'id' = :id", [':id' => 'one'],
|
||||||
|
new DocumentMapper(TestDocument::class)))
|
||||||
|
->isSome()->toBeTrue()
|
||||||
|
->get()->id->toBe('one');
|
||||||
|
});
|
||||||
|
test('returns no document when one is not found', function () {
|
||||||
|
expect(Custom::single('SELECT data FROM ' . ThrowawayDb::TABLE . " WHERE data->>'id' = :id",
|
||||||
|
[':id' => 'eighty'], new DocumentMapper(TestDocument::class)))
|
||||||
|
->isNone()->toBeTrue();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('::nonQuery()', function () {
|
||||||
|
test('works when documents match the WHERE clause', function () {
|
||||||
|
Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []);
|
||||||
|
expect(Count::all(ThrowawayDb::TABLE))->toBe(0);
|
||||||
|
});
|
||||||
|
test('works when no documents match the WHERE clause', function () {
|
||||||
|
Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE . " WHERE (data->>'num_value')::numeric > :value",
|
||||||
|
[':value' => 100]);
|
||||||
|
expect(Count::all(ThrowawayDb::TABLE))->toBe(5);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('::scalar()', function () {
|
||||||
|
test('returns a scalar value', function () {
|
||||||
|
expect(Custom::scalar("SELECT 5 AS it", [], new CountMapper()))->toBe(5);
|
||||||
|
});
|
||||||
|
});
|
47
tests/Integration/PostgreSQL/DefinitionTest.php
Normal file
47
tests/Integration/PostgreSQL/DefinitionTest.php
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use BitBadger\PDODocument\{Definition, DocumentIndex};
|
||||||
|
|
||||||
|
pest()->group('integration', 'postgresql');
|
||||||
|
|
||||||
|
describe('::ensureTable()', function () {
|
||||||
|
test('creates a table', function () {
|
||||||
|
expect($this->dbObjectExists('ensured'))->toBeFalse()
|
||||||
|
->and($this->dbObjectExists('idx_ensured_key'))->toBeFalse();
|
||||||
|
Definition::ensureTable('ensured');
|
||||||
|
expect($this->dbObjectExists('ensured'))->toBeTrue()
|
||||||
|
->and($this->dbObjectExists('idx_ensured_key'))->toBeTrue();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('::ensureFieldIndex()', function () {
|
||||||
|
test('creates an index', function () {
|
||||||
|
expect($this->dbObjectExists('idx_ensured_test'))->toBeFalse();
|
||||||
|
Definition::ensureTable('ensured');
|
||||||
|
Definition::ensureFieldIndex('ensured', 'test', ['name', 'age']);
|
||||||
|
expect($this->dbObjectExists('idx_ensured_test'))->toBeTrue();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('::ensureDocumentIndex()', function () {
|
||||||
|
test('creates a full index', function () {
|
||||||
|
$docIdx = 'idx_doc_table_document';
|
||||||
|
Definition::ensureTable('doc_table');
|
||||||
|
expect($this->dbObjectExists($docIdx))->toBeFalse();
|
||||||
|
Definition::ensureDocumentIndex('doc_table', DocumentIndex::Full);
|
||||||
|
expect($this->dbObjectExists($docIdx))->toBeTrue();
|
||||||
|
});
|
||||||
|
test('creates an optimized index', function () {
|
||||||
|
$docIdx = 'idx_doc_tbl_document';
|
||||||
|
Definition::ensureTable('doc_tbl');
|
||||||
|
expect($this->dbObjectExists($docIdx))->toBeFalse();
|
||||||
|
Definition::ensureDocumentIndex('doc_tbl', DocumentIndex::Optimized);
|
||||||
|
expect($this->dbObjectExists($docIdx))->toBeTrue();
|
||||||
|
});
|
||||||
|
});
|
64
tests/Integration/PostgreSQL/DeleteTest.php
Normal file
64
tests/Integration/PostgreSQL/DeleteTest.php
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use BitBadger\PDODocument\{Count, Delete, Field};
|
||||||
|
use Test\Integration\PostgreSQL\ThrowawayDb;
|
||||||
|
|
||||||
|
pest()->group('integration', 'postgresql');
|
||||||
|
|
||||||
|
describe('::byId()', function () {
|
||||||
|
test('deletes a document when ID is matched', function () {
|
||||||
|
expect(Count::all(ThrowawayDb::TABLE))->toBe(5);
|
||||||
|
Delete::byId(ThrowawayDb::TABLE, 'four');
|
||||||
|
expect(Count::all(ThrowawayDb::TABLE))->toBe(4);
|
||||||
|
});
|
||||||
|
test('does not delete a document when ID is not matched', function () {
|
||||||
|
expect(Count::all(ThrowawayDb::TABLE))->toBe(5);
|
||||||
|
Delete::byId(ThrowawayDb::TABLE, 'negative four');
|
||||||
|
expect(Count::all(ThrowawayDb::TABLE))->toBe(5);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('::byFields()', function () {
|
||||||
|
test('deletes documents when fields match', function () {
|
||||||
|
expect(Count::all(ThrowawayDb::TABLE))->toBe(5);
|
||||||
|
Delete::byFields(ThrowawayDb::TABLE, [Field::notEqual('value', 'purple')]);
|
||||||
|
expect(Count::all(ThrowawayDb::TABLE))->toBe(2);
|
||||||
|
});
|
||||||
|
test('does not delete documents when fields are not matched', function () {
|
||||||
|
expect(Count::all(ThrowawayDb::TABLE))->toBe(5);
|
||||||
|
Delete::byFields(ThrowawayDb::TABLE, [Field::equal('value', 'crimson')]);
|
||||||
|
expect(Count::all(ThrowawayDb::TABLE))->toBe(5);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('::byContains()', function () {
|
||||||
|
test('deletes documents when containment matches', function () {
|
||||||
|
expect(Count::all(ThrowawayDb::TABLE))->toBe(5);
|
||||||
|
Delete::byContains(ThrowawayDb::TABLE, ['value' => 'purple']);
|
||||||
|
expect(Count::all(ThrowawayDb::TABLE))->toBe(3);
|
||||||
|
});
|
||||||
|
test('does not delete documents when containment is not matched', function () {
|
||||||
|
expect(Count::all(ThrowawayDb::TABLE))->toBe(5);
|
||||||
|
Delete::byContains(ThrowawayDb::TABLE, ['target' => 'acquired']);
|
||||||
|
expect(Count::all(ThrowawayDb::TABLE))->toBe(5);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('::byJsonPath()', function () {
|
||||||
|
test('deletes documents when path matches', function () {
|
||||||
|
expect(Count::all(ThrowawayDb::TABLE))->toBe(5);
|
||||||
|
Delete::byJsonPath(ThrowawayDb::TABLE, '$.num_value ? (@ <> 0)');
|
||||||
|
expect(Count::all(ThrowawayDb::TABLE))->toBe(1);
|
||||||
|
});
|
||||||
|
test('does not delete documents when path is not matched', function () {
|
||||||
|
expect(Count::all(ThrowawayDb::TABLE))->toBe(5);
|
||||||
|
Delete::byJsonPath(ThrowawayDb::TABLE, '$.num_value ? (@ < 0)');
|
||||||
|
expect(Count::all(ThrowawayDb::TABLE))->toBe(5);
|
||||||
|
});
|
||||||
|
});
|
45
tests/Integration/PostgreSQL/DocumentListTest.php
Normal file
45
tests/Integration/PostgreSQL/DocumentListTest.php
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use BitBadger\PDODocument\{DocumentException, DocumentList, Query};
|
||||||
|
use BitBadger\PDODocument\Mapper\DocumentMapper;
|
||||||
|
use Test\Integration\PostgreSQL\ThrowawayDb;
|
||||||
|
use Test\Integration\TestDocument;
|
||||||
|
|
||||||
|
pest()->group('integration', 'postgresql');
|
||||||
|
|
||||||
|
describe('::create()', function () {
|
||||||
|
test('creates a document list', function () {
|
||||||
|
$list = DocumentList::create(Query::selectFromTable(ThrowawayDb::TABLE), [],
|
||||||
|
new DocumentMapper(TestDocument::class));
|
||||||
|
expect($list)->not->toBeNull();
|
||||||
|
$list = null; // free database result
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('::items()', function () {
|
||||||
|
test('enumerates items in the list', function () {
|
||||||
|
$list = DocumentList::create(Query::selectFromTable(ThrowawayDb::TABLE), [],
|
||||||
|
new DocumentMapper(TestDocument::class));
|
||||||
|
expect($list)->not->toBeNull();
|
||||||
|
$count = 0;
|
||||||
|
foreach ($list->items() as $item) {
|
||||||
|
expect(['one', 'two', 'three', 'four', 'five'])->toContain($item->id);
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
expect($count)->toBe(5);
|
||||||
|
});
|
||||||
|
test('fails when the list is exhausted', function () {
|
||||||
|
$list = DocumentList::create(Query::selectFromTable(ThrowawayDb::TABLE), [],
|
||||||
|
new DocumentMapper(TestDocument::class));
|
||||||
|
expect($list)->not->toBeNull()->hasItems()->toBeTrue();
|
||||||
|
$ignored = iterator_to_array($list->items());
|
||||||
|
expect($list)->hasItems()->toBeFalse()
|
||||||
|
->and(fn () => iterator_to_array($list->items()))->toThrow(DocumentException::class);
|
||||||
|
});
|
||||||
|
});
|
|
@ -12,6 +12,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// pest()->extend(Tests\TestCase::class)->in('Feature');
|
// pest()->extend(Tests\TestCase::class)->in('Feature');
|
||||||
|
pest()->extend(Test\Integration\PgIntegrationTest::class)->in('Integration/PostgreSQL');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
|
||||||
* @license MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Test\Integration\PostgreSQL;
|
|
||||||
|
|
||||||
use BitBadger\PDODocument\{Count, Field};
|
|
||||||
use PHPUnit\Framework\Attributes\TestDox;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PostgreSQL integration tests for the Count class
|
|
||||||
*/
|
|
||||||
#[TestDox('Count (PostgreSQL integration)')]
|
|
||||||
class CountTest 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('all() succeeds')]
|
|
||||||
public function testAllSucceeds(): void
|
|
||||||
{
|
|
||||||
$count = Count::all(ThrowawayDb::TABLE);
|
|
||||||
$this->assertEquals(5, $count, 'There should have been 5 matching documents');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('byFields() succeeds for a numeric range')]
|
|
||||||
public function testByFieldsSucceedsForANumericRange(): void
|
|
||||||
{
|
|
||||||
$count = Count::byFields(ThrowawayDb::TABLE, [Field::between('num_value', 10, 20)]);
|
|
||||||
$this->assertEquals(3, $count, 'There should have been 3 matching documents');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('byFields() succeeds for a non-numeric range')]
|
|
||||||
public function testByFieldsSucceedsForANonNumericRange(): void
|
|
||||||
{
|
|
||||||
$count = Count::byFields(ThrowawayDb::TABLE, [Field::between('value', 'aardvark', 'apple')]);
|
|
||||||
$this->assertEquals(1, $count, 'There should have been 1 matching document');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('byContains() succeeds when documents match')]
|
|
||||||
public function testByContainsSucceedsWhenDocumentsMatch(): void
|
|
||||||
{
|
|
||||||
$this->assertEquals(2, Count::byContains(ThrowawayDb::TABLE, ['value' => 'purple']),
|
|
||||||
'There should have been 2 matching documents');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('byContains() succeeds when no documents match')]
|
|
||||||
public function testByContainsSucceedsWhenNoDocumentsMatch(): void
|
|
||||||
{
|
|
||||||
$this->assertEquals(0, Count::byContains(ThrowawayDb::TABLE, ['value' => 'magenta']),
|
|
||||||
'There should have been no matching documents');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('byJsonPath() succeeds when documents match')]
|
|
||||||
public function testByJsonPathSucceedsWhenDocumentsMatch(): void
|
|
||||||
{
|
|
||||||
$this->assertEquals(2, Count::byJsonPath(ThrowawayDb::TABLE, '$.num_value ? (@ < 5)'),
|
|
||||||
'There should have been 2 matching documents');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('byJsonPath() succeeds when no documents match')]
|
|
||||||
public function testByJsonPathSucceedsWhenNoDocumentsMatch(): void
|
|
||||||
{
|
|
||||||
$this->assertEquals(0, Count::byJsonPath(ThrowawayDb::TABLE, '$.num_value ? (@ > 100)'),
|
|
||||||
'There should have been no matching documents');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,138 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
|
||||||
* @license MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Test\Integration\PostgreSQL;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PostgreSQL integration tests for the Custom class
|
|
||||||
*/
|
|
||||||
#[TestDox('Custom (PostgreSQL integration)')]
|
|
||||||
class CustomTest extends TestCase
|
|
||||||
{
|
|
||||||
/** @var string Database name for throwaway database */
|
|
||||||
private string $dbName;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
parent::setUp();
|
|
||||||
$this->dbName = ThrowawayDb::create();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function tearDown(): void
|
|
||||||
{
|
|
||||||
ThrowawayDb::destroy($this->dbName);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('runQuery() succeeds with a valid query')]
|
|
||||||
public function testRunQuerySucceedsWithAValidQuery(): void
|
|
||||||
{
|
|
||||||
$stmt = &Custom::runQuery('SELECT data FROM ' . ThrowawayDb::TABLE . ' LIMIT 1', []);
|
|
||||||
try {
|
|
||||||
$this->assertNotNull($stmt, 'The statement should not have been null');
|
|
||||||
} finally {
|
|
||||||
$stmt = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('runQuery() fails with an invalid query')]
|
|
||||||
public function testRunQueryFailsWithAnInvalidQuery(): void
|
|
||||||
{
|
|
||||||
$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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('list() succeeds when data is found')]
|
|
||||||
public function testListSucceedsWhenDataIsFound(): void
|
|
||||||
{
|
|
||||||
$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');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('list() succeeds when no data is found')]
|
|
||||||
public function testListSucceedsWhenNoDataIsFound(): void
|
|
||||||
{
|
|
||||||
$list = Custom::list(
|
|
||||||
Query::selectFromTable(ThrowawayDb::TABLE) . " WHERE (data->>'num_value')::numeric > :value",
|
|
||||||
[':value' => 100], new DocumentMapper(TestDocument::class));
|
|
||||||
$this->assertNotNull($list, 'The document list should not be null');
|
|
||||||
$this->assertFalse($list->hasItems(), 'There should have been no documents in the list');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('array() succeeds when data is found')]
|
|
||||||
public function testArraySucceedsWhenDataIsFound(): void
|
|
||||||
{
|
|
||||||
$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');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('array() succeeds when no data is found')]
|
|
||||||
public function testArraySucceedsWhenNoDataIsFound(): void
|
|
||||||
{
|
|
||||||
$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');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('single() succeeds when a row is found')]
|
|
||||||
public function testSingleSucceedsWhenARowIsFound(): void
|
|
||||||
{
|
|
||||||
$doc = Custom::single('SELECT data FROM ' . ThrowawayDb::TABLE . " WHERE data->>'id' = :id", [':id' => 'one'],
|
|
||||||
new DocumentMapper(TestDocument::class));
|
|
||||||
$this->assertTrue($doc->isSome(), 'There should have been a document returned');
|
|
||||||
$this->assertEquals('one', $doc->get()->id, 'The incorrect document was returned');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('single() succeeds when a row is not found')]
|
|
||||||
public function testSingleSucceedsWhenARowIsNotFound(): void
|
|
||||||
{
|
|
||||||
$doc = Custom::single('SELECT data FROM ' . ThrowawayDb::TABLE . " WHERE data->>'id' = :id",
|
|
||||||
[':id' => 'eighty'], new DocumentMapper(TestDocument::class));
|
|
||||||
$this->assertTrue($doc->isNone(), 'There should not have been a document returned');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('nonQuery() succeeds when operating on data')]
|
|
||||||
public function testNonQuerySucceedsWhenOperatingOnData(): void
|
|
||||||
{
|
|
||||||
Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []);
|
|
||||||
$remaining = Count::all(ThrowawayDb::TABLE);
|
|
||||||
$this->assertEquals(0, $remaining, 'There should be no documents remaining in the table');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('nonQuery() succeeds when no data matches WHERE clause')]
|
|
||||||
public function testNonQuerySucceedsWhenNoDataMatchesWhereClause(): void
|
|
||||||
{
|
|
||||||
Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE . " WHERE (data->>'num_value')::numeric > :value",
|
|
||||||
[':value' => 100]);
|
|
||||||
$remaining = Count::all(ThrowawayDb::TABLE);
|
|
||||||
$this->assertEquals(5, $remaining, 'There should be 5 documents remaining in the table');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('scalar() succeeds')]
|
|
||||||
public function testScalarSucceeds(): void
|
|
||||||
{
|
|
||||||
$value = Custom::scalar("SELECT 5 AS it", [], new CountMapper());
|
|
||||||
$this->assertEquals(5, $value, 'The scalar value was not returned correctly');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,88 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
|
||||||
* @license MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Test\Integration\PostgreSQL;
|
|
||||||
|
|
||||||
use BitBadger\PDODocument\{Custom, Definition, DocumentException, DocumentIndex};
|
|
||||||
use BitBadger\PDODocument\Mapper\ExistsMapper;
|
|
||||||
use PHPUnit\Framework\Attributes\TestDox;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PostgreSQL integration tests for the Definition class
|
|
||||||
*/
|
|
||||||
#[TestDox('Definition (PostgreSQL integration)')]
|
|
||||||
class DefinitionTest extends TestCase
|
|
||||||
{
|
|
||||||
/** @var string Database name for throwaway database */
|
|
||||||
private string $dbName;
|
|
||||||
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
parent::setUp();
|
|
||||||
$this->dbName = ThrowawayDb::create(withData: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function tearDown(): void
|
|
||||||
{
|
|
||||||
ThrowawayDb::destroy($this->dbName);
|
|
||||||
parent::tearDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does the given named object exist in the database?
|
|
||||||
*
|
|
||||||
* @param string $name The name of the object whose existence should be verified
|
|
||||||
* @return bool True if the object exists, false if not
|
|
||||||
* @throws DocumentException If any is encountered
|
|
||||||
*/
|
|
||||||
private function itExists(string $name): bool
|
|
||||||
{
|
|
||||||
return Custom::scalar('SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = :name)',
|
|
||||||
[':name' => $name], new ExistsMapper());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('ensureTable() succeeds')]
|
|
||||||
public function testEnsureTableSucceeds(): void
|
|
||||||
{
|
|
||||||
$this->assertFalse($this->itExists('ensured'), 'The table should not exist already');
|
|
||||||
$this->assertFalse($this->itExists('idx_ensured_key'), 'The key index should not exist already');
|
|
||||||
Definition::ensureTable('ensured');
|
|
||||||
$this->assertTrue($this->itExists('ensured'), 'The table should now exist');
|
|
||||||
$this->assertTrue($this->itExists('idx_ensured_key'), 'The key index should now exist');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('ensureFieldIndex() succeeds')]
|
|
||||||
public function testEnsureFieldIndexSucceeds(): void
|
|
||||||
{
|
|
||||||
$this->assertFalse($this->itExists('idx_ensured_test'), 'The index should not exist already');
|
|
||||||
Definition::ensureTable('ensured');
|
|
||||||
Definition::ensureFieldIndex('ensured', 'test', ['name', 'age']);
|
|
||||||
$this->assertTrue($this->itExists('idx_ensured_test'), 'The index should now exist');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('ensureDocumentIndex() succeeds for Full')]
|
|
||||||
public function testEnsureDocumentIndexSucceedsForFull(): void
|
|
||||||
{
|
|
||||||
$docIdx = 'idx_' . ThrowawayDb::TABLE . '_document';
|
|
||||||
Definition::ensureTable(ThrowawayDb::TABLE);
|
|
||||||
$this->assertFalse($this->itExists($docIdx), 'The document index should not exist');
|
|
||||||
Definition::ensureDocumentIndex(ThrowawayDb::TABLE, DocumentIndex::Full);
|
|
||||||
$this->assertTrue($this->itExists($docIdx), 'The document index should now exist');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('ensureDocumentIndex() succeeds for Optimized')]
|
|
||||||
public function testEnsureDocumentIndexSucceedsForOptimized(): void
|
|
||||||
{
|
|
||||||
$docIdx = 'idx_' . ThrowawayDb::TABLE . '_document';
|
|
||||||
Definition::ensureTable(ThrowawayDb::TABLE);
|
|
||||||
$this->assertFalse($this->itExists($docIdx), 'The document index should not exist');
|
|
||||||
Definition::ensureDocumentIndex(ThrowawayDb::TABLE, DocumentIndex::Optimized);
|
|
||||||
$this->assertTrue($this->itExists($docIdx), 'The document index should now exist');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,99 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
|
||||||
* @license MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Test\Integration\PostgreSQL;
|
|
||||||
|
|
||||||
use BitBadger\PDODocument\{Count, Delete, Field};
|
|
||||||
use PHPUnit\Framework\Attributes\TestDox;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PostgreSQL integration tests for the Delete class
|
|
||||||
*/
|
|
||||||
#[TestDox('Delete (PostgreSQL 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('byId() 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('byId() 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');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('byFields() succeeds when documents are deleted')]
|
|
||||||
public function testByFieldsSucceedsWhenDocumentsAreDeleted(): void
|
|
||||||
{
|
|
||||||
$this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents to start');
|
|
||||||
Delete::byFields(ThrowawayDb::TABLE, [Field::notEqual('value', 'purple')]);
|
|
||||||
$this->assertEquals(2, Count::all(ThrowawayDb::TABLE), 'There should have been 2 documents remaining');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('byFields() succeeds when documents are not deleted')]
|
|
||||||
public function testByFieldsSucceedsWhenDocumentsAreNotDeleted(): void
|
|
||||||
{
|
|
||||||
$this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents to start');
|
|
||||||
Delete::byFields(ThrowawayDb::TABLE, [Field::equal('value', 'crimson')]);
|
|
||||||
$this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents remaining');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('byContains() succeeds when documents are deleted')]
|
|
||||||
public function testByContainsSucceedsWhenDocumentsAreDeleted(): void
|
|
||||||
{
|
|
||||||
$this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents to start');
|
|
||||||
Delete::byContains(ThrowawayDb::TABLE, ['value' => 'purple']);
|
|
||||||
$this->assertEquals(3, Count::all(ThrowawayDb::TABLE), 'There should have been 3 documents remaining');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('byContains() succeeds when documents are not deleted')]
|
|
||||||
public function testByContainsSucceedsWhenDocumentsAreNotDeleted(): void
|
|
||||||
{
|
|
||||||
$this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents to start');
|
|
||||||
Delete::byContains(ThrowawayDb::TABLE, ['target' => 'acquired']);
|
|
||||||
$this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents remaining');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('byJsonPath() succeeds when documents are deleted')]
|
|
||||||
public function testByJsonPathSucceedsWhenDocumentsAreDeleted(): void
|
|
||||||
{
|
|
||||||
$this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents to start');
|
|
||||||
Delete::byJsonPath(ThrowawayDb::TABLE, '$.num_value ? (@ <> 0)');
|
|
||||||
$this->assertEquals(1, Count::all(ThrowawayDb::TABLE), 'There should have been 1 document remaining');
|
|
||||||
}
|
|
||||||
|
|
||||||
#[TestDox('byJsonPath() succeeds when documents are not deleted')]
|
|
||||||
public function testByJsonPathSucceedsWhenDocumentsAreNotDeleted(): void
|
|
||||||
{
|
|
||||||
$this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents to start');
|
|
||||||
Delete::byJsonPath(ThrowawayDb::TABLE, '$.num_value ? (@ < 0)');
|
|
||||||
$this->assertEquals(5, Count::all(ThrowawayDb::TABLE), 'There should have been 5 documents remaining');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -37,6 +37,20 @@ class ThrowawayDb
|
||||||
Configuration::resetPDO();
|
Configuration::resetPDO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load data into the test table
|
||||||
|
*
|
||||||
|
* @throws DocumentException If any is encountered
|
||||||
|
*/
|
||||||
|
public static function loadData(): void
|
||||||
|
{
|
||||||
|
Document::insert(self::TABLE, new TestDocument('one', 'FIRST!', 0));
|
||||||
|
Document::insert(self::TABLE, new TestDocument('two', 'another', 10, new SubDocument('green', 'blue')));
|
||||||
|
Document::insert(self::TABLE, new TestDocument('three', '', 4));
|
||||||
|
Document::insert(self::TABLE, new TestDocument('four', 'purple', 17, new SubDocument('green', 'red')));
|
||||||
|
Document::insert(self::TABLE, new TestDocument('five', 'purple', 18));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a throwaway PostgreSQL database
|
* Create a throwaway PostgreSQL database
|
||||||
*
|
*
|
||||||
|
@ -51,13 +65,10 @@ class ThrowawayDb
|
||||||
Custom::nonQuery("CREATE DATABASE $dbName WITH OWNER " . Configuration::$username, []);
|
Custom::nonQuery("CREATE DATABASE $dbName WITH OWNER " . Configuration::$username, []);
|
||||||
self::configure($dbName);
|
self::configure($dbName);
|
||||||
|
|
||||||
if ($withData) {
|
|
||||||
Definition::ensureTable(self::TABLE);
|
Definition::ensureTable(self::TABLE);
|
||||||
Document::insert(self::TABLE, new TestDocument('one', 'FIRST!', 0));
|
|
||||||
Document::insert(self::TABLE, new TestDocument('two', 'another', 10, new SubDocument('green', 'blue')));
|
if ($withData) {
|
||||||
Document::insert(self::TABLE, new TestDocument('three', '', 4));
|
self::loadData();
|
||||||
Document::insert(self::TABLE, new TestDocument('four', 'purple', 17, new SubDocument('green', 'red')));
|
|
||||||
Document::insert(self::TABLE, new TestDocument('five', 'purple', 18));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $dbName;
|
return $dbName;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user