Changes for beta10 #5

Merged
danieljsummers merged 7 commits from beta10 into main 2024-09-27 02:15:01 +00:00
14 changed files with 140 additions and 37 deletions
Showing only changes of commit a3ad158dfe - Show all commits

View File

@ -38,9 +38,9 @@ class Count
*/
public static function byFields(string $tableName, array $fields, ?FieldMatch $match = null): int
{
$namedFields = Parameters::nameFields($fields);
return Custom::scalar(Query\Count::byFields($tableName, $namedFields, $match),
Parameters::addFields($namedFields, []), new CountMapper());
Parameters::nameFields($fields);
return Custom::scalar(Query\Count::byFields($tableName, $fields, $match), Parameters::addFields($fields, []),
new CountMapper());
}
/**

View File

@ -35,9 +35,8 @@ class Delete
*/
public static function byFields(string $tableName, array $fields, ?FieldMatch $match = null): void
{
$namedFields = Parameters::nameFields($fields);
Custom::nonQuery(Query\Delete::byFields($tableName, $namedFields, $match),
Parameters::addFields($namedFields, []));
Parameters::nameFields($fields);
Custom::nonQuery(Query\Delete::byFields($tableName, $fields, $match), Parameters::addFields($fields, []));
}
/**

View File

@ -39,9 +39,9 @@ class Exists
*/
public static function byFields(string $tableName, array $fields, ?FieldMatch $match = null): bool
{
$namedFields = Parameters::nameFields($fields);
return Custom::scalar(Query\Exists::byFields($tableName, $namedFields, $match),
Parameters::addFields($namedFields, []), new ExistsMapper());
Parameters::nameFields($fields);
return Custom::scalar(Query\Exists::byFields($tableName, $fields, $match), Parameters::addFields($fields, []),
new ExistsMapper());
}
/**

View File

@ -60,9 +60,9 @@ class Find
public static function byFields(string $tableName, array $fields, string $className,
?FieldMatch $match = null): DocumentList
{
$namedFields = Parameters::nameFields($fields);
return Custom::list(Query\Find::byFields($tableName, $namedFields, $match),
Parameters::addFields($namedFields, []), new DocumentMapper($className));
Parameters::nameFields($fields);
return Custom::list(Query\Find::byFields($tableName, $fields, $match), Parameters::addFields($fields, []),
new DocumentMapper($className));
}
/**
@ -110,9 +110,9 @@ class Find
public static function firstByFields(string $tableName, array $fields, string $className,
?FieldMatch $match = null): Option
{
$namedFields = Parameters::nameFields($fields);
return Custom::single(Query\Find::byFields($tableName, $namedFields, $match),
Parameters::addFields($namedFields, []), new DocumentMapper($className));
Parameters::nameFields($fields);
return Custom::single(Query\Find::byFields($tableName, $fields, $match),
Parameters::addFields($fields, []), new DocumentMapper($className));
}
/**

View File

@ -52,7 +52,7 @@ enum Op
Op::NotEqual => "<>",
Op::Between => "BETWEEN",
Op::In => "IN",
Op::InArray => "?|",
Op::InArray => "??|", // The actual operator is ?|, but needs to be escaped by doubling
Op::Exists => "IS NOT NULL",
Op::NotExists => "IS NULL",
};

View File

@ -59,15 +59,13 @@ class Parameters
/**
* Fill in parameter names for any fields missing one
*
* @param Field[] $fields The fields for the query
* @return Field[] The fields, all with non-blank parameter names
* @param Field[] $fields The fields for the query (entries with no names will be modified)
*/
public static function nameFields(array $fields): array
public static function nameFields(array &$fields): void
{
array_walk($fields, function (Field $field, int $idx) {
if (empty($field->paramName)) $field->paramName =":field$idx";
});
return $fields;
}
/**

View File

@ -39,9 +39,9 @@ class Patch
public static function byFields(string $tableName, array $fields, array|object $patch,
?FieldMatch $match = null): void
{
$namedFields = Parameters::nameFields($fields);
Custom::nonQuery(Query\Patch::byFields($tableName, $namedFields, $match),
Parameters::addFields($namedFields, Parameters::json(':data', $patch)));
Parameters::nameFields($fields);
Custom::nonQuery(Query\Patch::byFields($tableName, $fields, $match),
Parameters::addFields($fields, Parameters::json(':data', $patch)));
}
/**

View File

@ -41,9 +41,9 @@ class RemoveFields
?FieldMatch $match = null): void
{
$nameParams = Parameters::fieldNames(':name', $fieldNames);
$namedFields = Parameters::nameFields($fields);
Custom::nonQuery(Query\RemoveFields::byFields($tableName, $namedFields, $nameParams, $match),
Parameters::addFields($namedFields, $nameParams));
Parameters::nameFields($fields);
Custom::nonQuery(Query\RemoveFields::byFields($tableName, $fields, $nameParams, $match),
Parameters::addFields($fields, $nameParams));
}
/**

View File

@ -0,0 +1,35 @@
<?php
/**
* @author Daniel J. Summers <daniel@bitbadger.solutions>
* @license MIT
*/
declare(strict_types=1);
namespace Test\Integration;
/**
* A document with an array of values
*/
class ArrayDocument
{
/**
* @param string $id The ID of the document
* @param string[] $values The values for the document
*/
public function __construct(public string $id = '', public array $values = []) { }
/**
* A set of documents used for integration tests
*
* @return ArrayDocument[] Test documents for InArray tests
*/
public static function testDocuments(): array
{
return [
new ArrayDocument('first', ['a', 'b', 'c']),
new ArrayDocument('second', ['c', 'd', 'e']),
new ArrayDocument('third', ['x', 'y', 'z'])
];
}
}

View File

@ -8,10 +8,10 @@ declare(strict_types=1);
namespace Test\Integration\PostgreSQL;
use BitBadger\PDODocument\{Custom, Delete, Document, Field, Find};
use BitBadger\PDODocument\{Custom, Delete, Document, Field, FieldMatch, Find};
use PHPUnit\Framework\Attributes\TestDox;
use PHPUnit\Framework\TestCase;
use Test\Integration\{NumDocument, TestDocument};
use Test\Integration\{ArrayDocument, NumDocument, TestDocument};
/**
* PostgreSQL integration tests for the Find class
@ -81,11 +81,22 @@ class FindTest extends TestCase
#[TestDox('byFields() succeeds when documents are found')]
public function testByFieldsSucceedsWhenDocumentsAreFound(): void
{
$docs = Find::byFields(ThrowawayDb::TABLE, [Field::greater('num_value', 15)], TestDocument::class);
$docs = Find::byFields(ThrowawayDb::TABLE, [Field::in('value', ['blue', 'purple']), Field::exists('sub')],
TestDocument::class, FieldMatch::All);
$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');
$this->assertEquals(1, $count, 'There should have been 1 document in the list');
}
#[TestDox('byFields() succeeds when documents are found using IN with numeric field')]
public function testByFieldsSucceedsWhenDocumentsAreFoundUsingInWithNumericField()
{
$docs = Find::byFields(ThrowawayDb::TABLE, [Field::in('num_value', [2, 4, 6, 8])], TestDocument::class);
$this->assertNotNull($docs, 'There should have been a document list returned');
$count = 0;
foreach ($docs->items() as $ignored) $count++;
$this->assertEquals(1, $count, 'There should have been 1 document in the list');
}
#[TestDox('byFields() succeeds when no documents are found')]
@ -96,6 +107,30 @@ class FindTest extends TestCase
$this->assertFalse($docs->hasItems(), 'There should have been no documents in the list');
}
#[TestDox('byFields() succeeds for inArray when matching documents exist')]
public function testByFieldsSucceedsForInArrayWhenMatchingDocumentsExist(): void
{
Delete::byFields(ThrowawayDb::TABLE, [Field::notExists('absentField')]);
foreach (ArrayDocument::testDocuments() as $doc) Document::insert(ThrowawayDb::TABLE, $doc);
$docs = Find::byFields(ThrowawayDb::TABLE, [Field::inArray('values', ThrowawayDb::TABLE, ['c'])],
ArrayDocument::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');
}
#[TestDox('byFields() succeeds for inArray when no matching documents exist')]
public function testByFieldsSucceedsForInArrayWhenNoMatchingDocumentsExist(): void
{
Delete::byFields(ThrowawayDb::TABLE, [Field::notExists('absentField')]);
foreach (ArrayDocument::testDocuments() as $doc) Document::insert(ThrowawayDb::TABLE, $doc);
$docs = Find::byFields(ThrowawayDb::TABLE, [Field::inArray('values', ThrowawayDb::TABLE, ['j'])],
ArrayDocument::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('byContains() succeeds when documents are found')]
public function testByContainsSucceedsWhenDocumentsAreFound(): void
{

View File

@ -8,9 +8,10 @@ declare(strict_types=1);
namespace Test\Integration\SQLite;
use BitBadger\PDODocument\{Custom, Document, DocumentException, Field, Find};
use BitBadger\PDODocument\{Custom, Delete, Document, DocumentException, Field, FieldMatch, Find};
use PHPUnit\Framework\Attributes\TestDox;
use PHPUnit\Framework\TestCase;
use Test\Integration\ArrayDocument;
use Test\Integration\TestDocument;
/**
@ -80,11 +81,22 @@ class FindTest extends TestCase
#[TestDox('byFields() succeeds when documents are found')]
public function testByFieldsSucceedsWhenDocumentsAreFound(): void
{
$docs = Find::byFields(ThrowawayDb::TABLE, [Field::greater('num_value', 15)], TestDocument::class);
$docs = Find::byFields(ThrowawayDb::TABLE, [Field::in('value', ['blue', 'purple']), Field::exists('sub')],
TestDocument::class, FieldMatch::All);
$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');
$this->assertEquals(1, $count, 'There should have been 1 document in the list');
}
#[TestDox('byFields() succeeds when documents are found using IN with numeric field')]
public function testByFieldsSucceedsWhenDocumentsAreFoundUsingInWithNumericField()
{
$docs = Find::byFields(ThrowawayDb::TABLE, [Field::in('num_value', [2, 4, 6, 8])], TestDocument::class);
$this->assertNotNull($docs, 'There should have been a document list returned');
$count = 0;
foreach ($docs->items() as $ignored) $count++;
$this->assertEquals(1, $count, 'There should have been 1 document in the list');
}
#[TestDox('byFields() succeeds when no documents are found')]
@ -95,6 +107,30 @@ class FindTest extends TestCase
$this->assertFalse($docs->hasItems(), 'There should have been no documents in the list');
}
#[TestDox('byFields() succeeds for inArray when matching documents exist')]
public function testByFieldsSucceedsForInArrayWhenMatchingDocumentsExist(): void
{
Delete::byFields(ThrowawayDb::TABLE, [Field::notExists('absentField')]);
foreach (ArrayDocument::testDocuments() as $doc) Document::insert(ThrowawayDb::TABLE, $doc);
$docs = Find::byFields(ThrowawayDb::TABLE, [Field::inArray('values', ThrowawayDb::TABLE, ['c'])],
ArrayDocument::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');
}
#[TestDox('byFields() succeeds for inArray when no matching documents exist')]
public function testByFieldsSucceedsForInArrayWhenNoMatchingDocumentsExist(): void
{
Delete::byFields(ThrowawayDb::TABLE, [Field::notExists('absentField')]);
foreach (ArrayDocument::testDocuments() as $doc) Document::insert(ThrowawayDb::TABLE, $doc);
$docs = Find::byFields(ThrowawayDb::TABLE, [Field::inArray('values', ThrowawayDb::TABLE, ['j'])],
ArrayDocument::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('byContains() fails')]
public function testByContainsFails(): void
{

View File

@ -349,7 +349,7 @@ class FieldTest extends TestCase
Configuration::overrideMode(Mode::PgSQL);
try {
$field = Field::inArray('even', 'tbl', [2, 4, 6, 8], ':it');
$this->assertEquals("data->'even' ?| ARRAY[:it_0, :it_1, :it_2, :it_3]", $field->toWhere(),
$this->assertEquals("data->'even' ??| ARRAY[:it_0, :it_1, :it_2, :it_3]", $field->toWhere(),
'WHERE fragment not generated correctly');
} finally {
Configuration::overrideMode(null);

View File

@ -69,7 +69,7 @@ class OpTest extends TestCase
#[TestDox('toSQL() succeeds for InArray')]
public function testToSQLSucceedsForInArray(): void
{
$this->assertEquals('?|', Op::InArray->toSQL(), 'InArray SQL operator incorrect');
$this->assertEquals('??|', Op::InArray->toSQL(), 'InArray SQL operator incorrect');
}
#[TestDox('toSQL() succeeds for Exists')]

View File

@ -84,8 +84,8 @@ class ParametersTest extends TestCase
#[TestDox('nameFields() succeeds')]
public function testNameFieldsSucceeds(): void
{
$named = Parameters::nameFields(
[Field::equal('it', 17), Field::equal('also', 22, ':also'), Field::equal('other', 24)]);
$named = [Field::equal('it', 17), Field::equal('also', 22, ':also'), Field::equal('other', 24)];
Parameters::nameFields($named);
$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');