From 417104096654ed282d0a27a830db373eb685a62f Mon Sep 17 00:00:00 2001 From: "Daniel J. Summers" Date: Sun, 29 Sep 2024 12:30:26 -0400 Subject: [PATCH 1/2] Add qualifier support for ORDER BY --- src/Query.php | 70 ++++++++++++++++++++++------------------ tests/unit/QueryTest.php | 19 +++++++++++ 2 files changed, 58 insertions(+), 31 deletions(-) diff --git a/src/Query.php b/src/Query.php index ebe6211..66c39b6 100644 --- a/src/Query.php +++ b/src/Query.php @@ -143,6 +143,44 @@ class Query 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) * @@ -152,36 +190,6 @@ class Query */ public static function orderBy(array $fields): string { - if (empty($fields)) return ""; - - $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); + return empty($fields) ? "" : ' ORDER BY ' . implode(', ', array_map(self::mapToOrderBy(...), $fields)); } } diff --git a/tests/unit/QueryTest.php b/tests/unit/QueryTest.php index 66eb63f..75606a4 100644 --- a/tests/unit/QueryTest.php +++ b/tests/unit/QueryTest.php @@ -253,6 +253,25 @@ class QueryTest extends TestCase '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')] public function testOrderBySucceedsWithMultipleFieldsAndDirectionForPostgreSQL(): void { -- 2.45.1 From 66e8e571fa6c9e0d388a3a638321b27e9d62f458 Mon Sep 17 00:00:00 2001 From: "Daniel J. Summers" Date: Mon, 30 Sep 2024 20:27:00 -0400 Subject: [PATCH 2/2] Update required PHP version --- composer.json | 4 ++-- composer.lock | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/composer.json b/composer.json index 133d40b..f25554f 100644 --- a/composer.json +++ b/composer.json @@ -17,9 +17,9 @@ "rss": "https://git.bitbadger.solutions/bit-badger/pdo-document.rss", "docs": "https://bitbadger.solutions/open-source/pdo-document/" }, - "minimum-stability": "beta", + "minimum-stability": "RC", "require": { - "php": ">=8.2", + "php": "8.2 - 8.3", "bit-badger/inspired-by-fsharp": "^1", "netresearch/jsonmapper": "^4", "ext-pdo": "*" diff --git a/composer.lock b/composer.lock index 6331c2e..75a8b3a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,18 +4,18 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7f9c6e825e6f0968b2dedefec770f558", + "content-hash": "ec1fce1531c57de8cb1300e3d1cf2a83", "packages": [ { "name": "bit-badger/inspired-by-fsharp", - "version": "v1.0.0-beta2", + "version": "v1.0.0-rc1", "source": { "type": "git", "url": "https://git.bitbadger.solutions/bit-badger/inspired-by-fsharp", - "reference": "fad428a4e40b606987499b17bb2d5b7d4b04502d" + "reference": "6779b2c554cf52e2eea4bd0575ea308e4ac09570" }, "require": { - "php": "^8.2" + "php": "8.2 - 8.3" }, "require-dev": { "phpoption/phpoption": "^1", @@ -49,7 +49,7 @@ "rss": "https://git.bitbadger.solutions/bit-badger/inspired-by-fsharp.rss", "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", @@ -166,16 +166,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.2.0", + "version": "v5.3.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "23c79fbbfb725fb92af9bcf41065c8e9a0d49ddb" + "reference": "3abf7425cd284141dc5d8d14a9ee444de3345d1a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/23c79fbbfb725fb92af9bcf41065c8e9a0d49ddb", - "reference": "23c79fbbfb725fb92af9bcf41065c8e9a0d49ddb", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3abf7425cd284141dc5d8d14a9ee444de3345d1a", + "reference": "3abf7425cd284141dc5d8d14a9ee444de3345d1a", "shasum": "" }, "require": { @@ -218,9 +218,9 @@ ], "support": { "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", @@ -1844,12 +1844,12 @@ } ], "aliases": [], - "minimum-stability": "beta", + "minimum-stability": "RC", "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=8.2", + "php": "8.2 - 8.3", "ext-pdo": "*" }, "platform-dev": [], -- 2.45.1