| 398 | |
| 399 | template <typename Sortable> |
| 400 | void SQLParser::parseOrderBy(Tokenizer& parser, Sortable& sortable) { |
| 401 | // Just skip token (BY) |
| 402 | std::ignore = peekSqlToken(parser, BySqlToken); |
| 403 | parser.SkipToken(); |
| 404 | Token tok, nameWithCase; |
| 405 | for (;;) { |
| 406 | nameWithCase = peekSqlToken(parser, FieldNameSqlToken, false); |
| 407 | if (nameWithCase.Type() != TokenName && nameWithCase.Type() != TokenString) { |
| 408 | const auto range = parser.Where(nameWithCase); |
| 409 | throw SqlParserError(range, "Expected name, but found '{}' in query, {}", nameWithCase.Text(), range); |
| 410 | } |
| 411 | tok = parser.NextToken(Tokenizer::Flags::InOrderBy); |
| 412 | std::string sortExpression(tok.Text()); |
| 413 | if (sortExpression.empty()) { |
| 414 | const auto range = parser.Where(tok); |
| 415 | throw SqlParserError(range, "Order by expression should not be empty, {}", range); |
| 416 | } |
| 417 | tok = peekSqlToken(parser, SortDirectionSqlToken); |
| 418 | std::vector<Variant> forcedSortOrder; |
| 419 | if (tok.Text() == "("sv && iequals(nameWithCase.Text(), "field"sv)) { |
| 420 | if constexpr (std::is_same_v<Sortable, AggregateEntry>) { |
| 421 | const auto range = parser.Where(tok); |
| 422 | throw SqlParserError(range, "Forced sort order is not available in aggregation sort"); |
| 423 | } |
| 424 | parser.SkipToken(); |
| 425 | nameWithCase = peekSqlToken(parser, FieldNameSqlToken, false); |
| 426 | if (nameWithCase.Type() != TokenName) { |
| 427 | const auto range = parser.Where(nameWithCase); |
| 428 | throw SqlParserError(range, "Expected name, but found '{}' in query, {}", nameWithCase.Text(), range); |
| 429 | } |
| 430 | sortExpression = nameWithCase.Text(); |
| 431 | tok = parser.NextToken(Tokenizer::Flags::NoFlags); |
| 432 | for (;;) { |
| 433 | tok = parser.NextToken(); |
| 434 | if (tok.Text() == ")"sv) { |
| 435 | break; |
| 436 | } |
| 437 | if (tok.Text() != ","sv) { |
| 438 | const auto range = parser.Where(tok); |
| 439 | throw SqlParserError(range, "Expected ')' or ',', but found '{}' in query, {}", tok.Text(), range); |
| 440 | } |
| 441 | tok = parser.NextToken(); |
| 442 | forcedSortOrder.push_back(Token2kv(tok, parser, CompositeAllowed_True, FieldAllowed_False, NullAllowed_False)); |
| 443 | } |
| 444 | tok = parser.PeekToken(); |
| 445 | } |
| 446 | |
| 447 | bool desc = false; |
| 448 | if (tok.Text() == "asc"sv || tok.Text() == "desc"sv) { |
| 449 | desc = tok.Text() == "desc"sv; |
| 450 | parser.SkipToken(); |
| 451 | } |
| 452 | if constexpr (std::is_same_v<Sortable, AggregateEntry>) { |
| 453 | sortable.Sort(std::move(sortExpression), desc); |
| 454 | } else { |
| 455 | sortable.Sort(std::move(sortExpression), desc, std::move(forcedSortOrder)); |
| 456 | } |
| 457 |
nothing calls this directly
no test coverage detected