Add in/inArray tests
- Make nameFields void (modifies array by ref)
This commit is contained in:
parent
9a2cf4c204
commit
a3ad158dfe
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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, []));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
12
src/Find.php
12
src/Find.php
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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",
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
35
tests/integration/ArrayDocument.php
Normal file
35
tests/integration/ArrayDocument.php
Normal 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'])
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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')]
|
||||||
|
|
|
@ -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');
|
||||||
|
|
Loading…
Reference in New Issue
Block a user