|
1 | 1 | <?php
|
2 | 2 | namespace Vimeo\MysqlEngine\Processor\Expression;
|
3 | 3 |
|
| 4 | +use Closure; |
4 | 5 | use Vimeo\MysqlEngine\FakePdoInterface;
|
5 | 6 | use Vimeo\MysqlEngine\Processor\ProcessorException;
|
6 | 7 | use Vimeo\MysqlEngine\Processor\QueryResult;
|
@@ -938,26 +939,62 @@ private static function sqlConcat(
|
938 | 939 | * @param array<string, mixed> $row
|
939 | 940 | */
|
940 | 941 | private static function sqlGroupConcat(
|
941 |
| - FakePdoInterface $conn, |
942 |
| - Scope $scope, |
| 942 | + FakePdoInterface $conn, |
| 943 | + Scope $scope, |
943 | 944 | FunctionExpression $expr,
|
944 |
| - QueryResult $result |
945 |
| - ): string { |
| 945 | + QueryResult $result |
| 946 | + ): string |
| 947 | + { |
946 | 948 | $args = $expr->args;
|
947 | 949 |
|
948 | 950 | $items = [];
|
949 | 951 | foreach ($result->rows as $row) {
|
950 | 952 | $tmp_str = "";
|
| 953 | + /** @var Closure(array{direction: "ASC"|"DESC", expression: Expression}): ?scalar $func */ |
| 954 | + /** @psalm-suppress MissingClosureReturnType */ |
| 955 | + $func = function (array $order) use ($result, $row, $scope, $conn) { |
| 956 | + /** @var array{expression: Expression} $order */ |
| 957 | + return Evaluator::evaluate($conn, $scope, $order["expression"], $row, $result); |
| 958 | + }; |
| 959 | + $orders = array_map( |
| 960 | + $func, |
| 961 | + $expr->order ?? [] |
| 962 | + ); |
951 | 963 | foreach ($args as $arg) {
|
952 |
| - $val = (string) Evaluator::evaluate($conn, $scope, $arg, $row, $result); |
| 964 | + $val = (string)Evaluator::evaluate($conn, $scope, $arg, $row, $result); |
953 | 965 | $tmp_str .= $val;
|
954 | 966 | }
|
955 | 967 | if ($tmp_str !== "" && (!$expr->distinct || !isset($items[$tmp_str]))) {
|
956 |
| - $items[$tmp_str] = $tmp_str; |
| 968 | + $items[$tmp_str] = ["val" => $tmp_str, "orders" => $orders]; |
957 | 969 | }
|
958 | 970 | }
|
959 | 971 |
|
960 |
| - return implode(",", array_values($items)); |
| 972 | + usort($items, function ($a, $b) use ($expr): int { |
| 973 | + /** |
| 974 | + * @var array{val: string, orders: array<int, scalar>} $a |
| 975 | + * @var array{val: string, orders: array<int, scalar>} $b |
| 976 | + */ |
| 977 | + for ($i = 0; $i < count($expr->order ?? []); $i++) { |
| 978 | + $direction = $expr->order[$i]["direction"] ?? 'ASC'; |
| 979 | + $a_val = $a["orders"][$i]; |
| 980 | + $b_val = $b["orders"][$i]; |
| 981 | + |
| 982 | + if ($a_val < $b_val) { |
| 983 | + return ($direction === 'ASC') ? -1 : 1; |
| 984 | + } elseif ($a_val > $b_val) { |
| 985 | + return ($direction === 'ASC') ? 1 : -1; |
| 986 | + } |
| 987 | + } |
| 988 | + return 0; |
| 989 | + }); |
| 990 | + |
| 991 | + if (isset($expr->separator)) { |
| 992 | + $separator = (string)(Evaluator::evaluate($conn, $scope, $expr->separator, [], $result)); |
| 993 | + } else { |
| 994 | + $separator = ","; |
| 995 | + } |
| 996 | + |
| 997 | + return implode($separator, array_column($items, 'val')); |
961 | 998 | }
|
962 | 999 |
|
963 | 1000 | /**
|
|
0 commit comments