diff --git a/composer.json b/composer.json index 8d8f33f9..8c32b1c9 100644 --- a/composer.json +++ b/composer.json @@ -124,15 +124,15 @@ "test:db": "@parallel test:db:sqlite:ci test:db:mysql test:db:maria test:db:postgres test:db:ms", "test:db:sqlite": "APP_ENV=test php vendor/bin/phpunit --order-by=random --colors=always --testdox -c phpunit-db.xml", "test:db:sqlite:ci": "@test:db:sqlite --coverage-php build/coverage-db.cov", - "test:db:mysql": "DB_DRIVER=mysql composer test:db:sqlite", - "test:db:maria": "DB_DRIVER=maria composer test:db:sqlite", - "test:db:postgres": "DB_DRIVER=postgres composer test:db:sqlite", - "test:db:ms": "DB_DRIVER=mssql composer test:db:sqlite", + "test:db:mysql": "DB_DRIVER=mysql composer test:db:sqlite -- $*", + "test:db:maria": "DB_DRIVER=maria composer test:db:sqlite -- $*", + "test:db:postgres": "DB_DRIVER=postgres composer test:db:sqlite -- $*", + "test:db:ms": "DB_DRIVER=mssql composer test:db:sqlite -- $*", "test:api": "bin/test/run-api-tests.sh", - "test:api:sqlite": "DB_DRIVER=sqlite composer test:api", - "test:api:mysql": "DB_DRIVER=mysql composer test:api", - "test:api:maria": "DB_DRIVER=maria composer test:api", - "test:api:mssql": "DB_DRIVER=mssql composer test:api", + "test:api:sqlite": "DB_DRIVER=sqlite composer test:api -- $*", + "test:api:mysql": "DB_DRIVER=mysql composer test:api -- $*", + "test:api:maria": "DB_DRIVER=maria composer test:api -- $*", + "test:api:mssql": "DB_DRIVER=mssql composer test:api -- $*", "test:api:ci": "GENERATE_COVERAGE=yes composer test:api && vendor/bin/phpcov merge build/coverage-api --php build/coverage-api.cov && rm build/coverage-api/*.cov", "test:api:pretty": "GENERATE_COVERAGE=yes composer test:api && vendor/bin/phpcov merge build/coverage-api --html build/coverage-api/coverage-html && rm build/coverage-api/*.cov", "test:cli": "APP_ENV=test DB_DRIVER=maria TEST_ENV=cli php vendor/bin/phpunit --order-by=random --colors=always --testdox -c phpunit-cli.xml", diff --git a/module/Core/src/ShortUrl/Repository/ShortUrlListRepository.php b/module/Core/src/ShortUrl/Repository/ShortUrlListRepository.php index 323ecb10..e66bbdc2 100644 --- a/module/Core/src/ShortUrl/Repository/ShortUrlListRepository.php +++ b/module/Core/src/ShortUrl/Repository/ShortUrlListRepository.php @@ -46,6 +46,8 @@ class ShortUrlListRepository extends EntitySpecificationRepository implements Sh 'DISTINCT s AS shortUrl', '(' . $buildVisitsSubQuery('v', excludingBots: false) . ') AS ' . OrderableField::VISITS->value, '(' . $buildVisitsSubQuery('v2', excludingBots: true) . ') AS ' . OrderableField::NON_BOT_VISITS->value, + // This is added only to have a consistent order by title between database engines + 'COALESCE(s.title, \'\') AS title', ) ->setMaxResults($filtering->limit) ->setFirstResult($filtering->offset) @@ -62,15 +64,17 @@ class ShortUrlListRepository extends EntitySpecificationRepository implements Sh private function processOrderByForList(QueryBuilder $qb, ShortUrlsListFiltering $filtering): void { $fieldName = $filtering->orderBy->field; - $order = $filtering->orderBy->direction; - - match (true) { + $direction = $filtering->orderBy->direction; + [$sort, $order] = match (true) { // With no explicit order by, fallback to dateCreated-DESC - $fieldName === null => $qb->orderBy('s.dateCreated', 'DESC'), + $fieldName === null => ['s.dateCreated', 'DESC'], $fieldName === OrderableField::VISITS->value, - $fieldName === OrderableField::NON_BOT_VISITS->value => $qb->orderBy($fieldName, $order), - default => $qb->orderBy('s.' . $fieldName, $order), + $fieldName === OrderableField::NON_BOT_VISITS->value, + $fieldName === OrderableField::TITLE->value => [$fieldName, $direction], + default => ['s.' . $fieldName, $direction], }; + + $qb->orderBy($sort, $order); } public function countList(ShortUrlsCountFiltering $filtering): int diff --git a/module/Rest/test-api/Action/ListShortUrlsTest.php b/module/Rest/test-api/Action/ListShortUrlsTest.php index c3b9b41e..e3fc49a6 100644 --- a/module/Rest/test-api/Action/ListShortUrlsTest.php +++ b/module/Rest/test-api/Action/ListShortUrlsTest.php @@ -201,12 +201,12 @@ class ListShortUrlsTest extends ApiTestCase self::SHORT_URL_SHLINK_WITH_TITLE, ], 'valid_api_key']; yield [['orderBy' => 'title-DESC'], [ + self::SHORT_URL_SHLINK_WITH_TITLE, self::SHORT_URL_META, self::SHORT_URL_CUSTOM_SLUG, self::SHORT_URL_DOCS, self::SHORT_URL_CUSTOM_DOMAIN, self::SHORT_URL_CUSTOM_SLUG_AND_DOMAIN, - self::SHORT_URL_SHLINK_WITH_TITLE, ], 'valid_api_key']; yield [['startDate' => Chronos::parse('2018-12-01')->toAtomString()], [ self::SHORT_URL_CUSTOM_DOMAIN,