Skip to content

Commit 183a0e6

Browse files
committed
Sorting mechanism revised. The class DBExprOrderBySpec has been deprecated in favor of DBOrderSpec.
1 parent 8ee3dab commit 183a0e6

File tree

6 files changed

+103
-18
lines changed

6 files changed

+103
-18
lines changed

src/Builder/Expr/DBExprOrderBySpec.php

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
<?php
22
namespace Kir\MySQL\Builder\Expr;
33

4+
/**
5+
* @deprecated
6+
*/
47
class DBExprOrderBySpec implements OrderBySpecification {
5-
/** @var array[] */
8+
/** @var array<int, array{string, string}> */
69
private $fields = [];
7-
10+
811
/**
9-
* @param array $spec
10-
* @param array $sortFieldsSpec
12+
* @param array<string|int, string> $spec
13+
* @param array<int, array{string, string}|array<string, string>> $sortFieldsSpec
1114
*/
1215
public function __construct($spec, $sortFieldsSpec) {
1316
$expressions = [];
@@ -18,19 +21,28 @@ public function __construct($spec, $sortFieldsSpec) {
1821
$expressions[$specReference] = $dbExpr;
1922
}
2023
foreach($sortFieldsSpec as $sortFieldSpec) {
21-
if(array_key_exists(0, $sortFieldSpec) && array_key_exists($sortFieldSpec[0], $expressions)) {
22-
$direction = 'ASC';
23-
if(array_key_exists(1, $sortFieldSpec) && strtoupper($sortFieldSpec[1]) !== 'ASC') {
24-
$direction = 'DESC';
24+
if(array_key_exists(0, $sortFieldSpec)) {
25+
if(array_key_exists($sortFieldSpec[0], $expressions)) {
26+
$direction = 'ASC';
27+
if(array_key_exists(1, $sortFieldSpec) && strtoupper($sortFieldSpec[1]) !== 'ASC') {
28+
$direction = 'DESC';
29+
}
30+
$this->fields[] = [
31+
$expressions[$sortFieldSpec[0]],
32+
$direction
33+
];
34+
}
35+
} else {
36+
foreach($sortFieldSpec as $alias => $direction) {
37+
$direction = strtoupper($direction) === 'DESC' ? 'DESC' : 'ASC';
38+
if(array_key_exists($alias, $expressions)) {
39+
$this->fields[] = [$expressions[$alias], $direction];
40+
}
2541
}
26-
$this->fields[] = [
27-
$expressions[$sortFieldSpec[0]],
28-
$direction
29-
];
3042
}
3143
}
3244
}
33-
45+
3446
/**
3547
* Returns an array[], where each value is a [db-expression, sort-direction]
3648
* The sort-direction can be either ASC or DESC

src/Builder/Expr/DBOrderSpec.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
namespace Kir\MySQL\Builder\Expr;
4+
5+
use RuntimeException;
6+
7+
/**
8+
* Defines fields that are sortable. Sortable fields have an alias.
9+
* The alias can be passed as a sort specifier - along with the direction in which to sort.
10+
*/
11+
class DBOrderSpec implements DBOrderSpecInterface, OrderBySpecification {
12+
/** @var array<string, string> */
13+
private $sortSpecification;
14+
/** @var array<string, string> */
15+
private $sortingInstruction;
16+
/** @var array<string, mixed> */
17+
private $options;
18+
19+
/**
20+
* @param array<string, string> $sortSpecification
21+
* @param array<string, string> $sortingInstruction
22+
* @param array{max_sort_instructions?: positive-int} $options
23+
* @return static
24+
*/
25+
public static function from(array $sortSpecification, array $sortingInstruction, array $options = []) {
26+
return new static($sortSpecification, $sortingInstruction, $options);
27+
}
28+
29+
/**
30+
* @inheritDoc
31+
*/
32+
public function __construct(array $sortSpecification, array $sortingInstruction, array $options = []) {
33+
$this->sortSpecification = $sortSpecification;
34+
$this->sortingInstruction = $sortingInstruction;
35+
$this->options = $options;
36+
}
37+
38+
/**
39+
* @return array<int, array{string, string}>
40+
*/
41+
public function getFields() {
42+
$fields = [];
43+
$max = $this->options['max_sort_instructions'] ?? 16;
44+
foreach($this->sortingInstruction as $alias => $direction) {
45+
$direction = strtolower($direction) === 'desc' ? 'DESC' : 'ASC';
46+
if(array_key_exists($alias, $this->sortSpecification)) {
47+
$fields[] = [$this->sortSpecification[$alias], $direction];
48+
}
49+
if($max < 1) {
50+
throw new RuntimeException();
51+
}
52+
$max--;
53+
}
54+
return $fields;
55+
}
56+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
namespace Kir\MySQL\Builder\Expr;
4+
5+
/**
6+
* This interface is needed to allow new static in the deriving class
7+
*/
8+
interface DBOrderSpecInterface {
9+
/**
10+
* @param array<string, string> $sortSpecification Key = Alias, Value = DB-Expression
11+
* @param array<string, string> $sortingInstruction Key = Alias, Value = Sortdirection ("ASC" | "DESC")
12+
* @param array{max_sort_instructions?: positive-int} $options
13+
*/
14+
public function __construct(array $sortSpecification, array $sortingInstruction, array $options = []);
15+
}

src/Builder/Expr/OrderBySpecification.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33

44
interface OrderBySpecification {
55
/**
6-
* Returns an array[], where each value is a [db-expression, sort-direction]
6+
* Returns an array<int, array{string, string}>, where each value is a [db-expression, sort-direction]
77
* The sort-direction can be either ASC or DESC
88
*
9-
* @return array[]
9+
* @return array<int, array{string, string}>
1010
*/
1111
public function getFields();
1212
}

src/Builder/Value/DBOptionalValue.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55
use Kir\MySQL\Builder\Helpers\RecursiveStructureAccess;
66

77
class DBOptionalValue implements OptionalValue {
8+
/** @var object|array<string, mixed> */
89
private $data;
910
/** @var string|string[] */
1011
private $path;
1112
/** @var callable|null */
1213
private $validator;
1314

1415
/**
15-
* @param object|array<string, mixed>
16+
* @param object|array<string, mixed> $data
1617
* @param string|string[] $path
1718
* @param null|callable(): bool $validator
1819
*/

tests/Builder/SelectTest.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
use Kir\MySQL\Builder\Expr\DBExprFilter;
55
use Kir\MySQL\Builder\Expr\DBExprOrderBySpec;
6+
use Kir\MySQL\Builder\Expr\DBOrderSpec;
67
use Kir\MySQL\Builder\Expr\OptionalDBFilterMap;
78
use Kir\MySQL\Builder\Expr\RequiredDBFilterMap;
89
use Kir\MySQL\Builder\Expr\RequiredValueNotFoundException;
@@ -451,10 +452,10 @@ public function testSortSpecification() {
451452
->field('t.field1')
452453
->field('t.field2')
453454
->from('t', 'test')
454-
->orderBy(new DBExprOrderBySpec(['field1', 'field2' => 'REVERSE(t.field2)'], [['field2', 'ASC'], ['field1', 'DESC'], ['field3' => 'ASC']]))
455+
->orderBy(new DBOrderSpec(['field1' => 't.field1', 'field2' => 'REVERSE(t.field2)', 'field4' => 't.field2'], ['field3' => 'ASC', 'field1' => 'ASC', 'field2' => 'ASC', 'field4' => 'ASC']))
455456
->asString();
456457

457-
self::assertEquals("SELECT\n\tt.field1,\n\tt.field2\nFROM\n\ttest t\nORDER BY\n\tREVERSE(t.field2) ASC,\n\tfield1 DESC\n", $query);
458+
self::assertEquals("SELECT\n\tt.field1,\n\tt.field2\nFROM\n\ttest t\nORDER BY\n\tt.field1 ASC,\n\tREVERSE(t.field2) ASC,\n\tt.field2 ASC\n", $query);
458459
}
459460

460461
public function testVirtualTables() {

0 commit comments

Comments
 (0)