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 public static function byFields(string $tableName, array $fields, ?FieldMatch $match = null): int
{ {
$namedFields = Parameters::nameFields($fields); Parameters::nameFields($fields);
return Custom::scalar(Query\Count::byFields($tableName, $namedFields, $match), return Custom::scalar(Query\Count::byFields($tableName, $fields, $match), Parameters::addFields($fields, []),
Parameters::addFields($namedFields, []), new CountMapper()); new CountMapper());
} }
/** /**

View File

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

View File

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

View File

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

View File

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

View File

@ -59,15 +59,13 @@ class Parameters
/** /**
* Fill in parameter names for any fields missing one * Fill in parameter names for any fields missing one
* *
* @param Field[] $fields The fields for the query * @param Field[] $fields The fields for the query (entries with no names will be modified)
* @return Field[] The fields, all with non-blank parameter names
*/ */
public static function nameFields(array $fields): array public static function nameFields(array &$fields): void
{ {
array_walk($fields, function (Field $field, int $idx) { array_walk($fields, function (Field $field, int $idx) {
if (empty($field->paramName)) $field->paramName =":field$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, public static function byFields(string $tableName, array $fields, array|object $patch,
?FieldMatch $match = null): void ?FieldMatch $match = null): void
{ {
$namedFields = Parameters::nameFields($fields); Parameters::nameFields($fields);
Custom::nonQuery(Query\Patch::byFields($tableName, $namedFields, $match), Custom::nonQuery(Query\Patch::byFields($tableName, $fields, $match),
Parameters::addFields($namedFields, Parameters::json(':data', $patch))); Parameters::addFields($fields, Parameters::json(':data', $patch)));
} }
/** /**

View File

@ -41,9 +41,9 @@ class RemoveFields
?FieldMatch $match = null): void ?FieldMatch $match = null): void
{ {
$nameParams = Parameters::fieldNames(':name', $fieldNames); $nameParams = Parameters::fieldNames(':name', $fieldNames);
$namedFields = Parameters::nameFields($fields); Parameters::nameFields($fields);
Custom::nonQuery(Query\RemoveFields::byFields($tableName, $namedFields, $nameParams, $match), Custom::nonQuery(Query\RemoveFields::byFields($tableName, $fields, $nameParams, $match),
Parameters::addFields($namedFields, $nameParams)); 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; 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\Attributes\TestDox;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Test\Integration\{NumDocument, TestDocument}; use Test\Integration\{ArrayDocument, NumDocument, TestDocument};
/** /**
* PostgreSQL integration tests for the Find class * PostgreSQL integration tests for the Find class
@ -81,11 +81,22 @@ class FindTest extends TestCase
#[TestDox('byFields() succeeds when documents are found')] #[TestDox('byFields() succeeds when documents are found')]
public function testByFieldsSucceedsWhenDocumentsAreFound(): void 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'); $this->assertNotNull($docs, 'There should have been a document list returned');
$count = 0; $count = 0;
foreach ($docs->items() as $ignored) $count++; 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')] #[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'); $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')] #[TestDox('byContains() succeeds when documents are found')]
public function testByContainsSucceedsWhenDocumentsAreFound(): void public function testByContainsSucceedsWhenDocumentsAreFound(): void
{ {

View File

@ -8,9 +8,10 @@ declare(strict_types=1);
namespace Test\Integration\SQLite; 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\Attributes\TestDox;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Test\Integration\ArrayDocument;
use Test\Integration\TestDocument; use Test\Integration\TestDocument;
/** /**
@ -80,11 +81,22 @@ class FindTest extends TestCase
#[TestDox('byFields() succeeds when documents are found')] #[TestDox('byFields() succeeds when documents are found')]
public function testByFieldsSucceedsWhenDocumentsAreFound(): void 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'); $this->assertNotNull($docs, 'There should have been a document list returned');
$count = 0; $count = 0;
foreach ($docs->items() as $ignored) $count++; 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')] #[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'); $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')] #[TestDox('byContains() fails')]
public function testByContainsFails(): void public function testByContainsFails(): void
{ {

View File

@ -349,7 +349,7 @@ class FieldTest extends TestCase
Configuration::overrideMode(Mode::PgSQL); Configuration::overrideMode(Mode::PgSQL);
try { try {
$field = Field::inArray('even', 'tbl', [2, 4, 6, 8], ':it'); $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'); 'WHERE fragment not generated correctly');
} finally { } finally {
Configuration::overrideMode(null); Configuration::overrideMode(null);

View File

@ -69,7 +69,7 @@ class OpTest extends TestCase
#[TestDox('toSQL() succeeds for InArray')] #[TestDox('toSQL() succeeds for InArray')]
public function testToSQLSucceedsForInArray(): void 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')] #[TestDox('toSQL() succeeds for Exists')]

View File

@ -84,8 +84,8 @@ class ParametersTest extends TestCase
#[TestDox('nameFields() succeeds')] #[TestDox('nameFields() succeeds')]
public function testNameFieldsSucceeds(): void public function testNameFieldsSucceeds(): void
{ {
$named = Parameters::nameFields( $named = [Field::equal('it', 17), Field::equal('also', 22, ':also'), Field::equal('other', 24)];
[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->assertCount(3, $named, 'There should be 3 parameters in the array');
$this->assertEquals(':field0', $named[0]->paramName, 'Parameter 1 not named correctly'); $this->assertEquals(':field0', $named[0]->paramName, 'Parameter 1 not named correctly');
$this->assertEquals(':also', $named[1]->paramName, 'Parameter 2 not named correctly'); $this->assertEquals(':also', $named[1]->paramName, 'Parameter 2 not named correctly');