Changes for RC1 #6

Merged
danieljsummers merged 2 commits from beta-11 into main 2024-10-01 00:29:12 +00:00
4 changed files with 73 additions and 46 deletions

View File

@ -17,9 +17,9 @@
"rss": "https://git.bitbadger.solutions/bit-badger/pdo-document.rss", "rss": "https://git.bitbadger.solutions/bit-badger/pdo-document.rss",
"docs": "https://bitbadger.solutions/open-source/pdo-document/" "docs": "https://bitbadger.solutions/open-source/pdo-document/"
}, },
"minimum-stability": "beta", "minimum-stability": "RC",
"require": { "require": {
"php": ">=8.2", "php": "8.2 - 8.3",
"bit-badger/inspired-by-fsharp": "^1", "bit-badger/inspired-by-fsharp": "^1",
"netresearch/jsonmapper": "^4", "netresearch/jsonmapper": "^4",
"ext-pdo": "*" "ext-pdo": "*"

26
composer.lock generated
View File

@ -4,18 +4,18 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "7f9c6e825e6f0968b2dedefec770f558", "content-hash": "ec1fce1531c57de8cb1300e3d1cf2a83",
"packages": [ "packages": [
{ {
"name": "bit-badger/inspired-by-fsharp", "name": "bit-badger/inspired-by-fsharp",
"version": "v1.0.0-beta2", "version": "v1.0.0-rc1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://git.bitbadger.solutions/bit-badger/inspired-by-fsharp", "url": "https://git.bitbadger.solutions/bit-badger/inspired-by-fsharp",
"reference": "fad428a4e40b606987499b17bb2d5b7d4b04502d" "reference": "6779b2c554cf52e2eea4bd0575ea308e4ac09570"
}, },
"require": { "require": {
"php": "^8.2" "php": "8.2 - 8.3"
}, },
"require-dev": { "require-dev": {
"phpoption/phpoption": "^1", "phpoption/phpoption": "^1",
@ -49,7 +49,7 @@
"rss": "https://git.bitbadger.solutions/bit-badger/inspired-by-fsharp.rss", "rss": "https://git.bitbadger.solutions/bit-badger/inspired-by-fsharp.rss",
"source": "https://git.bitbadger.solutions/bit-badger/inspired-by-fsharp" "source": "https://git.bitbadger.solutions/bit-badger/inspired-by-fsharp"
}, },
"time": "2024-07-29T17:58:33+00:00" "time": "2024-10-01T00:14:52+00:00"
}, },
{ {
"name": "netresearch/jsonmapper", "name": "netresearch/jsonmapper",
@ -166,16 +166,16 @@
}, },
{ {
"name": "nikic/php-parser", "name": "nikic/php-parser",
"version": "v5.2.0", "version": "v5.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nikic/PHP-Parser.git", "url": "https://github.com/nikic/PHP-Parser.git",
"reference": "23c79fbbfb725fb92af9bcf41065c8e9a0d49ddb" "reference": "3abf7425cd284141dc5d8d14a9ee444de3345d1a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/23c79fbbfb725fb92af9bcf41065c8e9a0d49ddb", "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3abf7425cd284141dc5d8d14a9ee444de3345d1a",
"reference": "23c79fbbfb725fb92af9bcf41065c8e9a0d49ddb", "reference": "3abf7425cd284141dc5d8d14a9ee444de3345d1a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -218,9 +218,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/nikic/PHP-Parser/issues", "issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v5.2.0" "source": "https://github.com/nikic/PHP-Parser/tree/v5.3.0"
}, },
"time": "2024-09-15T16:40:33+00:00" "time": "2024-09-29T13:56:26+00:00"
}, },
{ {
"name": "phar-io/manifest", "name": "phar-io/manifest",
@ -1844,12 +1844,12 @@
} }
], ],
"aliases": [], "aliases": [],
"minimum-stability": "beta", "minimum-stability": "RC",
"stability-flags": [], "stability-flags": [],
"prefer-stable": false, "prefer-stable": false,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {
"php": ">=8.2", "php": "8.2 - 8.3",
"ext-pdo": "*" "ext-pdo": "*"
}, },
"platform-dev": [], "platform-dev": [],

View File

@ -143,6 +143,44 @@ class Query
return "UPDATE $tableName SET data = :data WHERE " . self::whereById(); return "UPDATE $tableName SET data = :data WHERE " . self::whereById();
} }
/**
* Transform a field to an ORDER BY clause segment
*
* @param Field $field The field by which ordering should be implemented
* @return string The ORDER BY fragment for the given field
* @throws Exception If the database mode has not been set
*/
private static function mapToOrderBy(Field $field): string
{
$mode = Configuration::mode('render ORDER BY clause');
if (str_contains($field->fieldName, ' ')) {
$parts = explode(' ', $field->fieldName);
$field->fieldName = array_shift($parts);
$direction = ' ' . implode(' ', $parts);
} else {
$direction = '';
}
if (str_starts_with($field->fieldName, 'n:')) {
$field->fieldName = substr($field->fieldName, 2);
$value = match ($mode) {
Mode::PgSQL => '(' . $field->path() . ')::numeric',
Mode::SQLite => $field->path()
};
} elseif (str_starts_with($field->fieldName, 'i:')) {
$field->fieldName = substr($field->fieldName, 2);
$value = match ($mode) {
Mode::PgSQL => 'LOWER(' . $field->path() . ')',
Mode::SQLite => $field->path() . ' COLLATE NOCASE'
};
} else {
$value = $field->path();
}
return (empty($field->qualifier) ? '' : "$field->qualifier.") . $value . $direction;
}
/** /**
* Create an `ORDER BY` clause ('n:' treats field as number, 'i:' does case-insensitive ordering) * Create an `ORDER BY` clause ('n:' treats field as number, 'i:' does case-insensitive ordering)
* *
@ -152,36 +190,6 @@ class Query
*/ */
public static function orderBy(array $fields): string public static function orderBy(array $fields): string
{ {
if (empty($fields)) return ""; return empty($fields) ? "" : ' ORDER BY ' . implode(', ', array_map(self::mapToOrderBy(...), $fields));
$mode = Configuration::mode('render ORDER BY clause');
$sqlFields = array_map(function (Field $it) use ($mode) {
if (str_contains($it->fieldName, ' ')) {
$parts = explode(' ', $it->fieldName);
$it->fieldName = array_shift($parts);
$direction = ' ' . implode(' ', $parts);
} else {
$direction = '';
}
if (str_starts_with($it->fieldName, 'n:')) {
$it->fieldName = substr($it->fieldName, 2);
$value = match ($mode) {
Mode::PgSQL => '(' . $it->path() . ')::numeric',
Mode::SQLite => $it->path()
};
} elseif (str_starts_with($it->fieldName, 'i:')) {
$it->fieldName = substr($it->fieldName, 2);
$value = match ($mode) {
Mode::PgSQL => 'LOWER(' . $it->path() . ')',
Mode::SQLite => $it->path() . ' COLLATE NOCASE'
};
} else {
$value = $it->path();
}
return $value . $direction;
}, $fields);
return ' ORDER BY ' . implode(', ', $sqlFields);
} }
} }

View File

@ -253,6 +253,25 @@ class QueryTest extends TestCase
'ORDER BY not constructed correctly'); 'ORDER BY not constructed correctly');
} }
#[TestDox('orderBy() succeeds with one qualified field for PostgreSQL')]
public function testOrderBySucceedsWithOneQualifiedFieldForPostgreSQL(): void
{
Configuration::overrideMode(Mode::PgSQL);
$field = Field::named('TestField');
$field->qualifier = 'qual';
$this->assertEquals(" ORDER BY qual.data->>'TestField'", Query::orderBy([$field]),
'ORDER BY not constructed correctly');
}
#[TestDox('orderBy() succeeds with one qualified field for SQLite')]
public function testOrderBySucceedsWithOneQualifiedFieldForSQLite(): void
{
$field = Field::named('TestField');
$field->qualifier = 'qual';
$this->assertEquals(" ORDER BY qual.data->>'TestField'", Query::orderBy([$field]),
'ORDER BY not constructed correctly');
}
#[TestDox('orderBy() succeeds with multiple fields and direction for PostgreSQL')] #[TestDox('orderBy() succeeds with multiple fields and direction for PostgreSQL')]
public function testOrderBySucceedsWithMultipleFieldsAndDirectionForPostgreSQL(): void public function testOrderBySucceedsWithMultipleFieldsAndDirectionForPostgreSQL(): void
{ {