alpha2 #2
@ -17,7 +17,7 @@
|
||||
"rss": "https://git.bitbadger.solutions/bit-badger/pdo-document.rss"
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.3",
|
||||
"php": ">=8.1",
|
||||
"netresearch/jsonmapper": "^4",
|
||||
"ext-pdo": "*"
|
||||
},
|
||||
|
4
composer.lock
generated
4
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "ca79f450e8e715ad61ba3581734c0fe7",
|
||||
"content-hash": "f4563891566be8872ae85552261303bd",
|
||||
"packages": [
|
||||
{
|
||||
"name": "netresearch/jsonmapper",
|
||||
@ -1697,7 +1697,7 @@
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": ">=8.3",
|
||||
"php": ">=8.1",
|
||||
"ext-pdo": "*"
|
||||
},
|
||||
"platform-dev": [],
|
||||
|
@ -26,14 +26,14 @@ class Count
|
||||
*
|
||||
* @param string $tableName The name of the table in which documents should be counted
|
||||
* @param array|Field[] $fields The field comparison to match
|
||||
* @param string $conjunction How to handle multiple conditions (optional; defaults to `AND`)
|
||||
* @param FieldMatch|null $match How to handle multiple conditions (optional; defaults to All)
|
||||
* @return int The count of documents matching the field comparison
|
||||
* @throws DocumentException If one is encountered
|
||||
*/
|
||||
public static function byFields(string $tableName, array $fields, string $conjunction = 'AND'): int
|
||||
public static function byFields(string $tableName, array $fields, ?FieldMatch $match = null): int
|
||||
{
|
||||
$namedFields = Parameters::nameFields($fields);
|
||||
return Custom::scalar(Query\Count::byFields($tableName, $namedFields, $conjunction),
|
||||
return Custom::scalar(Query\Count::byFields($tableName, $namedFields, $match),
|
||||
Parameters::addFields($namedFields, []), new CountMapper());
|
||||
}
|
||||
}
|
||||
|
@ -24,13 +24,13 @@ class Delete
|
||||
*
|
||||
* @param string $tableName The table from which documents should be deleted
|
||||
* @param array|Field[] $fields The field comparison to match
|
||||
* @param string $conjunction How to handle multiple conditions (optional; defaults to `AND`)
|
||||
* @param FieldMatch|null $match How to handle multiple conditions (optional; defaults to All)
|
||||
* @throws DocumentException If any is encountered
|
||||
*/
|
||||
public static function byFields(string $tableName, array $fields, string $conjunction = 'AND'): void
|
||||
public static function byFields(string $tableName, array $fields, ?FieldMatch $match = null): void
|
||||
{
|
||||
$namedFields = Parameters::nameFields($fields);
|
||||
Custom::nonQuery(Query\Delete::byFields($tableName, $namedFields, $conjunction),
|
||||
Custom::nonQuery(Query\Delete::byFields($tableName, $namedFields, $match),
|
||||
Parameters::addFields($namedFields, []));
|
||||
}
|
||||
}
|
||||
|
@ -27,14 +27,14 @@ class Exists
|
||||
*
|
||||
* @param string $tableName The name of the table in which document existence should be determined
|
||||
* @param Field[] $fields The field comparison to match
|
||||
* @param string $conjunction How to handle multiple conditions (optional; defaults to `AND`)
|
||||
* @param FieldMatch|null $match How to handle multiple conditions (optional; defaults to All)
|
||||
* @return bool True if any documents match the field comparison, false if not
|
||||
* @throws DocumentException If any is encountered
|
||||
*/
|
||||
public static function byFields(string $tableName, array $fields, string $conjunction = 'AND'): bool
|
||||
public static function byFields(string $tableName, array $fields, ?FieldMatch $match = null): bool
|
||||
{
|
||||
$namedFields = Parameters::nameFields($fields);
|
||||
return Custom::scalar(Query\Exists::byFields($tableName, $namedFields, $conjunction),
|
||||
return Custom::scalar(Query\Exists::byFields($tableName, $namedFields, $match),
|
||||
Parameters::addFields($namedFields, []), new ExistsMapper());
|
||||
}
|
||||
}
|
||||
|
28
src/FieldMatch.php
Normal file
28
src/FieldMatch.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument;
|
||||
|
||||
/**
|
||||
* How multiple fields should be matched
|
||||
*/
|
||||
enum FieldMatch
|
||||
{
|
||||
/** Match all provided fields (`AND`) */
|
||||
case All;
|
||||
|
||||
/** Match any provided fields (`OR`) */
|
||||
case Any;
|
||||
|
||||
/**
|
||||
* Get the SQL keyword for this enumeration value
|
||||
*
|
||||
* @return string The SQL keyword for this enumeration value
|
||||
*/
|
||||
public function toString(): string
|
||||
{
|
||||
return match ($this) {
|
||||
FieldMatch::All => 'AND',
|
||||
FieldMatch::Any => 'OR'
|
||||
};
|
||||
}
|
||||
}
|
12
src/Find.php
12
src/Find.php
@ -45,15 +45,15 @@ class Find
|
||||
* @param string $tableName The table from which documents should be retrieved
|
||||
* @param array|Field[] $fields The field comparison to match
|
||||
* @param class-string<TDoc> $className The name of the class to be retrieved
|
||||
* @param string $conjunction How to handle multiple conditions (optional; defaults to `AND`)
|
||||
* @param FieldMatch|null $match How to handle multiple conditions (optional; defaults to All)
|
||||
* @return DocumentList<TDoc> A list of documents matching the given field comparison
|
||||
* @throws DocumentException If any is encountered
|
||||
*/
|
||||
public static function byFields(string $tableName, array $fields, string $className,
|
||||
string $conjunction = 'AND'): DocumentList
|
||||
?FieldMatch $match = null): DocumentList
|
||||
{
|
||||
$namedFields = Parameters::nameFields($fields);
|
||||
return Custom::list(Query\Find::byFields($tableName, $namedFields, $conjunction),
|
||||
return Custom::list(Query\Find::byFields($tableName, $namedFields, $match),
|
||||
Parameters::addFields($namedFields, []), new DocumentMapper($className));
|
||||
}
|
||||
|
||||
@ -64,15 +64,15 @@ class Find
|
||||
* @param string $tableName The table from which the document should be retrieved
|
||||
* @param array|Field[] $fields The field comparison to match
|
||||
* @param class-string<TDoc> $className The name of the class to be retrieved
|
||||
* @param string $conjunction How to handle multiple conditions (optional; defaults to `AND`)
|
||||
* @param FieldMatch|null $match How to handle multiple conditions (optional; defaults to All)
|
||||
* @return false|TDoc The first document if any matches are found, false otherwise
|
||||
* @throws DocumentException If any is encountered
|
||||
*/
|
||||
public static function firstByFields(string $tableName, array $fields, string $className,
|
||||
string $conjunction = 'AND'): mixed
|
||||
?FieldMatch $match = null): mixed
|
||||
{
|
||||
$namedFields = Parameters::nameFields($fields);
|
||||
return Custom::single(Query\Find::byFields($tableName, $namedFields, $conjunction),
|
||||
return Custom::single(Query\Find::byFields($tableName, $namedFields, $match),
|
||||
Parameters::addFields($namedFields, []), new DocumentMapper($className));
|
||||
}
|
||||
}
|
||||
|
@ -27,14 +27,14 @@ class Patch
|
||||
* @param string $tableName The table in which documents should be patched
|
||||
* @param array|Field[] $fields The field comparison to match
|
||||
* @param array|object $patch The object with which the documents should be patched (will be JSON-encoded)
|
||||
* @param string $conjunction How to handle multiple conditions (optional; defaults to `AND`)
|
||||
* @param FieldMatch|null $match How to handle multiple conditions (optional; defaults to All)
|
||||
* @throws DocumentException If any is encountered
|
||||
*/
|
||||
public static function byFields(string $tableName, array $fields, array|object $patch,
|
||||
string $conjunction = 'AND'): void
|
||||
?FieldMatch $match = null): void
|
||||
{
|
||||
$namedFields = Parameters::nameFields($fields);
|
||||
Custom::nonQuery(Query\Patch::byFields($tableName, $namedFields, $conjunction),
|
||||
Custom::nonQuery(Query\Patch::byFields($tableName, $namedFields, $match),
|
||||
Parameters::addFields($namedFields, Parameters::json(':data', $patch)));
|
||||
}
|
||||
}
|
||||
|
@ -22,12 +22,14 @@ class Query
|
||||
* Create a WHERE clause fragment to implement a comparison on fields in a JSON document
|
||||
*
|
||||
* @param Field[] $fields The field comparison to generate
|
||||
* @param string $conjunction How to join multiple conditions (optional; defaults to AND)
|
||||
* @param FieldMatch|null $match How to join multiple conditions (optional; defaults to All)
|
||||
* @return string The WHERE clause fragment matching the given fields and parameter
|
||||
* @throws DocumentException If the database mode has not been set
|
||||
*/
|
||||
public static function whereByFields(array $fields, string $conjunction = 'AND'): string
|
||||
public static function whereByFields(array $fields, ?FieldMatch $match = null): string
|
||||
{
|
||||
return implode(" $conjunction ", array_map(fn($it) => $it->toWhere(), $fields));
|
||||
return implode(' ' . ($match ?? FieldMatch::All)->toString() . ' ',
|
||||
array_map(fn($it) => $it->toWhere(), $fields));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -35,6 +37,7 @@ class Query
|
||||
*
|
||||
* @param string $paramName The parameter name where the value of the ID will be provided (optional; default @id)
|
||||
* @return string The WHERE clause fragment to match by ID
|
||||
* @throws DocumentException If the database mode has not been set
|
||||
*/
|
||||
public static function whereById(string $paramName = ':id'): string
|
||||
{
|
||||
@ -69,6 +72,7 @@ class Query
|
||||
*
|
||||
* @param string $tableName The name of the table in which the document should be updated
|
||||
* @return string The UPDATE query for the document
|
||||
* @throws DocumentException If the database mode has not been set
|
||||
*/
|
||||
public static function update(string $tableName): string
|
||||
{
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace BitBadger\PDODocument\Query;
|
||||
|
||||
use BitBadger\PDODocument\{Field, Query};
|
||||
use BitBadger\PDODocument\{DocumentException, Field, FieldMatch, Query};
|
||||
|
||||
/**
|
||||
* Queries for counting documents
|
||||
@ -25,11 +25,12 @@ class Count
|
||||
*
|
||||
* @param string $tableName The name of the table in which documents should be counted
|
||||
* @param Field[] $fields The field comparison to match
|
||||
* @param string $conjunction How to handle multiple conditions (optional; defaults to `AND`)
|
||||
* @param FieldMatch|null $match How to join multiple conditions (optional; defaults to All)
|
||||
* @return string The query to count documents using a field comparison
|
||||
* @throws DocumentException If the database mode has not been set
|
||||
*/
|
||||
public static function byFields(string $tableName, array $fields, string $conjunction = 'AND'): string
|
||||
public static function byFields(string $tableName, array $fields, ?FieldMatch $match = null): string
|
||||
{
|
||||
return self::all($tableName) . ' WHERE ' . Query::whereByFields($fields, $conjunction);
|
||||
return self::all($tableName) . ' WHERE ' . Query::whereByFields($fields, $match);
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace BitBadger\PDODocument\Query;
|
||||
|
||||
use BitBadger\PDODocument\{Field, Query};
|
||||
use BitBadger\PDODocument\{DocumentException, Field, FieldMatch, Query};
|
||||
|
||||
/**
|
||||
* Queries to delete documents
|
||||
@ -14,6 +14,7 @@ class Delete
|
||||
*
|
||||
* @param string $tableName The name of the table from which a document should be deleted
|
||||
* @return string The DELETE statement to delete a document by its ID
|
||||
* @throws DocumentException If the database mode has not been set
|
||||
*/
|
||||
public static function byId(string $tableName): string
|
||||
{
|
||||
@ -25,11 +26,12 @@ class Delete
|
||||
*
|
||||
* @param string $tableName The name of the table from which documents should be deleted
|
||||
* @param Field[] $fields The field comparison to match
|
||||
* @param string $conjunction How to handle multiple conditions (optional; defaults to `AND`)
|
||||
* @param FieldMatch|null $match How to handle multiple conditions (optional; defaults to All)
|
||||
* @return string The DELETE statement to delete documents via field comparison
|
||||
* @throws DocumentException If the database mode has not been set
|
||||
*/
|
||||
public static function byFields(string $tableName, array $fields, string $conjunction = 'AND'): string
|
||||
public static function byFields(string $tableName, array $fields, ?FieldMatch $match = null): string
|
||||
{
|
||||
return "DELETE FROM $tableName WHERE " . Query::whereByFields($fields, $conjunction);
|
||||
return "DELETE FROM $tableName WHERE " . Query::whereByFields($fields, $match);
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace BitBadger\PDODocument\Query;
|
||||
|
||||
use BitBadger\PDODocument\{Field, Query};
|
||||
use BitBadger\PDODocument\{DocumentException, Field, FieldMatch, Query};
|
||||
|
||||
/**
|
||||
* Queries to determine document existence
|
||||
@ -26,6 +26,7 @@ class Exists
|
||||
*
|
||||
* @param string $tableName The name of the table in which document existence should be checked
|
||||
* @return string The query to determine document existence by ID
|
||||
* @throws DocumentException If the database mode has not been set
|
||||
*/
|
||||
public static function byId(string $tableName): string
|
||||
{
|
||||
@ -37,11 +38,12 @@ class Exists
|
||||
*
|
||||
* @param string $tableName The name of the table in which document existence should be checked
|
||||
* @param Field[] $fields The field comparison to match
|
||||
* @param string $conjunction How to handle multiple conditions (optional; defaults to `AND`)
|
||||
* @param FieldMatch|null $match How to handle multiple conditions (optional; defaults to All)
|
||||
* @return string The query to determine document existence by field comparison
|
||||
* @throws DocumentException If the database mode has not been set
|
||||
*/
|
||||
public static function byFields(string $tableName, array $fields, string $conjunction = 'AND'): string
|
||||
public static function byFields(string $tableName, array $fields, ?FieldMatch $match = null): string
|
||||
{
|
||||
return self::query($tableName, Query::whereByFields($fields, $conjunction));
|
||||
return self::query($tableName, Query::whereByFields($fields, $match));
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace BitBadger\PDODocument\Query;
|
||||
|
||||
use BitBadger\PDODocument\{Field, Query};
|
||||
use BitBadger\PDODocument\{DocumentException, Field, FieldMatch, Query};
|
||||
|
||||
/**
|
||||
* Queries for retrieving documents
|
||||
@ -14,6 +14,7 @@ class Find
|
||||
*
|
||||
* @param string $tableName The name of the table from which a document should be retrieved
|
||||
* @return string The SELECT statement to retrieve a document by its ID
|
||||
* @throws DocumentException If the database mode has not been set
|
||||
*/
|
||||
public static function byId(string $tableName): string
|
||||
{
|
||||
@ -25,11 +26,12 @@ class Find
|
||||
*
|
||||
* @param string $tableName The name of the table from which documents should be retrieved
|
||||
* @param Field[] $fields The field comparison to match
|
||||
* @param string $conjunction How to handle multiple conditions (optional; defaults to `AND`)
|
||||
* @param FieldMatch|null $match How to handle multiple conditions (optional; defaults to All)
|
||||
* @return string The SELECT statement to retrieve documents by field comparison
|
||||
* @throws DocumentException If the database mode has not been set
|
||||
*/
|
||||
public static function byFields(string $tableName, array $fields, string $conjunction = 'AND'): string
|
||||
public static function byFields(string $tableName, array $fields, ?FieldMatch $match = null): string
|
||||
{
|
||||
return Query::selectFromTable($tableName) . ' WHERE ' . Query::whereByFields($fields, $conjunction);
|
||||
return Query::selectFromTable($tableName) . ' WHERE ' . Query::whereByFields($fields, $match);
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace BitBadger\PDODocument\Query;
|
||||
|
||||
use BitBadger\PDODocument\{Configuration, DocumentException, Field, Mode, Query};
|
||||
use BitBadger\PDODocument\{Configuration, DocumentException, Field, FieldMatch, Mode, Query};
|
||||
|
||||
/**
|
||||
* Queries to perform partial updates on documents
|
||||
@ -44,12 +44,12 @@ class Patch
|
||||
*
|
||||
* @param string $tableName The name of the table in which documents should be patched
|
||||
* @param array|Field[] $field The field comparison to match
|
||||
* @param string $conjunction How to handle multiple conditions (optional; defaults to `AND`)
|
||||
* @param FieldMatch|null $match How to handle multiple conditions (optional; defaults to All)
|
||||
* @return string The query to patch documents via field comparison
|
||||
* @throws DocumentException If the database mode has not been set
|
||||
*/
|
||||
public static function byFields(string $tableName, array $field, string $conjunction = 'AND'): string
|
||||
public static function byFields(string $tableName, array $field, ?FieldMatch $match = null): string
|
||||
{
|
||||
return self::update($tableName, Query::whereByFields($field, $conjunction));
|
||||
return self::update($tableName, Query::whereByFields($field, $match));
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace BitBadger\PDODocument\Query;
|
||||
|
||||
use BitBadger\PDODocument\{Configuration, DocumentException, Field, Mode, Query};
|
||||
use BitBadger\PDODocument\{Configuration, DocumentException, Field, FieldMatch, Mode, Query};
|
||||
|
||||
/**
|
||||
* Queries to remove fields from documents
|
||||
@ -54,13 +54,13 @@ class RemoveFields
|
||||
* @param string $tableName The name of the table in which documents should be manipulated
|
||||
* @param array|Field[] $fields The field comparison to match
|
||||
* @param array $parameters The parameter list for the query
|
||||
* @param string $conjunction How to handle multiple conditions (optional; defaults to `AND`)
|
||||
* @param FieldMatch|null $match How to handle multiple conditions (optional; defaults to All)
|
||||
* @return string The UPDATE statement to remove fields from documents via field comparison
|
||||
* @throws DocumentException If the database mode has not been set
|
||||
*/
|
||||
public static function byFields(string $tableName, array $fields, array $parameters,
|
||||
string $conjunction = 'AND'): string
|
||||
?FieldMatch $match = null): string
|
||||
{
|
||||
return self::update($tableName, $parameters, Query::whereByFields($fields, $conjunction));
|
||||
return self::update($tableName, $parameters, Query::whereByFields($fields, $match));
|
||||
}
|
||||
}
|
||||
|
@ -28,15 +28,15 @@ class RemoveFields
|
||||
* @param string $tableName The table in which documents should have fields removed
|
||||
* @param array|Field[] $fields The field comparison to match
|
||||
* @param array|string[] $fieldNames The names of the fields to be removed
|
||||
* @param string $conjunction How to handle multiple conditions (optional; defaults to `AND`)
|
||||
* @param FieldMatch|null $match How to handle multiple conditions (optional; defaults to All)
|
||||
* @throws DocumentException If any is encountered
|
||||
*/
|
||||
public static function byFields(string $tableName, array $fields, array $fieldNames,
|
||||
string $conjunction = 'AND'): void
|
||||
?FieldMatch $match = null): void
|
||||
{
|
||||
$nameParams = Parameters::fieldNames(':name', $fieldNames);
|
||||
$namedFields = Parameters::nameFields($fields);
|
||||
Custom::nonQuery(Query\RemoveFields::byFields($tableName, $namedFields, $nameParams, $conjunction),
|
||||
Custom::nonQuery(Query\RemoveFields::byFields($tableName, $namedFields, $nameParams, $match),
|
||||
Parameters::addFields($namedFields, $nameParams));
|
||||
}
|
||||
}
|
||||
|
22
tests/unit/FieldMatchTest.php
Normal file
22
tests/unit/FieldMatchTest.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Test\Unit;
|
||||
|
||||
use BitBadger\PDODocument\FieldMatch;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Unit tests for the FieldMatch enum
|
||||
*/
|
||||
class FieldMatchTest extends TestCase
|
||||
{
|
||||
public function testToStringSucceedsForAll(): void
|
||||
{
|
||||
$this->assertEquals('AND', FieldMatch::All->toString(), 'All should have returned AND');
|
||||
}
|
||||
|
||||
public function testToStringSucceedsForAny(): void
|
||||
{
|
||||
$this->assertEquals('OR', FieldMatch::Any->toString(), 'Any should have returned OR');
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace Test\Unit\Query;
|
||||
|
||||
use BitBadger\PDODocument\{Configuration, Field, Mode};
|
||||
use BitBadger\PDODocument\{Configuration, Field, FieldMatch, Mode};
|
||||
use BitBadger\PDODocument\Query\Find;
|
||||
use PHPUnit\Framework\Attributes\TestDox;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
@ -32,7 +32,8 @@ class FindTest extends TestCase
|
||||
public function testByFieldsSucceeds(): void
|
||||
{
|
||||
$this->assertEquals("SELECT data FROM there WHERE data->>'active' = :act OR data->>'locked' = :lock",
|
||||
Find::byFields('there', [Field::EQ('active', true, ':act'), Field::EQ('locked', true, ':lock')], 'OR'),
|
||||
Find::byFields('there', [Field::EQ('active', true, ':act'), Field::EQ('locked', true, ':lock')],
|
||||
FieldMatch::Any),
|
||||
'SELECT query not generated correctly');
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace Test\Unit;
|
||||
|
||||
use BitBadger\PDODocument\{Configuration, Field, Mode, Query};
|
||||
use BitBadger\PDODocument\{Configuration, Field, FieldMatch, Mode, Query};
|
||||
use PHPUnit\Framework\Attributes\TestDox;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
@ -33,17 +33,18 @@ class QueryTest extends TestCase
|
||||
Query::whereByFields([Field::LE('test_field', '', ':it')]), 'WHERE fragment not constructed correctly');
|
||||
}
|
||||
|
||||
public function testWhereByFieldsSucceedsForMultipleFields(): void
|
||||
public function testWhereByFieldsSucceedsForMultipleFieldsAll(): void
|
||||
{
|
||||
$this->assertEquals("data->>'test_field' <= :it AND data->>'other_field' = :other",
|
||||
Query::whereByFields([Field::LE('test_field', '', ':it'), Field::EQ('other_field', '', ':other')]),
|
||||
'WHERE fragment not constructed correctly');
|
||||
}
|
||||
|
||||
public function testWhereByFieldsSucceedsForMultipleFieldsWithOr(): void
|
||||
public function testWhereByFieldsSucceedsForMultipleFieldsAny(): void
|
||||
{
|
||||
$this->assertEquals("data->>'test_field' <= :it OR data->>'other_field' = :other",
|
||||
Query::whereByFields([Field::LE('test_field', '', ':it'), Field::EQ('other_field', '', ':other')], 'OR'),
|
||||
Query::whereByFields([Field::LE('test_field', '', ':it'), Field::EQ('other_field', '', ':other')],
|
||||
FieldMatch::Any),
|
||||
'WHERE fragment not constructed correctly');
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user