|
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