<commit_before><commit_msg>feat: add sort parser to build ORDER BY clause<commit_after><?php namespace Zephyrus\Database\Components;

use Zephyrus\Database\QueryBuilder\OrderByClause;
use Zephyrus\Network\RequestFactory;

class SortParser
{
    public const URL_PARAMETER = 'sorts';

    private OrderByClause $orderByClause;
    private array $defaultSorts;
    private bool $ascNullLast = true;
    private bool $descNullLast = false;

    public function __construct(array $defaultSorts = [])
    {
        $this->defaultSorts = $defaultSorts;
    }

    public function setAscNullLast(bool $nullLast)
    {
        $this->ascNullLast = $nullLast;
    }

    public function setDescNullLast(bool $nullLast)
    {
        $this->descNullLast = $nullLast;
    }

    /**
     * Parses the request parameters to build a corresponding ORDER BY clause. The parameters should be given following
     * the public constants:
     *
     *     example.com?sorts[column] = asc|desc
     *
     * If no sorts are given, the configured default sorts will be used. The NULLs ordering is defined by the
     * setAscNullLast and setDescNullLast methods.
     *
     * @param array $columnConversion
     * @return OrderByClause
     */
    public function parse(array $columnConversion = []): OrderByClause
    {
        $request = RequestFactory::read();
        $sortColumns = $request->getParameter(self::URL_PARAMETER, $this->defaultSorts);
        $this->orderByClause = new OrderByClause();
        foreach ($sortColumns as $column => $order) {
            // Invalid order are evaluated as asc sorting (default)
            match ($order) {
                'desc' => $this->orderByClause->desc($columnConversion[$column] ?? $column, !$this->descNullLast),
                default => $this->orderByClause->asc($columnConversion[$column] ?? $column, $this->ascNullLast),
            };
        }
        return $this->orderByClause;
    }
}
{'fraction_non_alphanumeric': 0.10594315245478036, 'fraction_numerical': 0.0, 'mean_word_length': 2.926977687626775, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6015311', 'n_tokens_mistral': 544, 'n_tokens_neox': 543, 'n_words': 141}