<commit_before><?php

abstract class RecordsRequestHandler extends RequestHandler
{
    // configurables
    public static $recordClass;
    public static $accountLevelRead = false;
    public static $accountLevelComment = 'User';
    public static $accountLevelBrowse = 'Staff';
    public static $accountLevelWrite = 'Staff';
    public static $accountLevelAPI = false;
    public static $browseOrder = false;
    public static $browseConditions = false;
    public static $browseLimitDefault = false;
    public static $editableFields = false;
    public static $searchConditions = false;
    public static $browseCalcFoundRows = true;

    public static $calledClass = __CLASS__;
    public static $responseMode = 'html';
    public static $userResponseModes = array(
        'application/json' => 'json'
        ,'text/csv' => 'csv'
    );

    public static function handleRequest()
    {
        // save static class
        static::$calledClass = get_called_class();

        switch (static::peekPath()) {
            case 'csv':
            case 'json':
            case 'pdf':
                static::$responseMode = static::shiftPath();
                break;
        }

        return static::handleRecordsRequest();
    }


    public static function handleRecordsRequest($action = false)
    {
        switch ($action ? $action : $action = static::shiftPath()) {
            case 'save':
            {
                return static::handleMultiSaveRequest();
            }

            case 'destroy':
            {
                return static::handleMultiDestroyRequest();
            }

            case 'create':
            {
                return static::handleCreateRequest();
            }

            case '*fields':
            {
                return static::handleFieldsRequest();
            }

            case '':
            case false:
            {
                if (count(static::getPath())) {
                    // throw an error for URLs like /collection//foo
                    return static::throwInvalidRequestError();
                }

                return static::handleBrowseRequest();
            }

            default:
            {
                try {
                    $Record = static::getRecordByHandle(urldecode($action));
                } catch (UserUnauthorizedException $e) {
                    return static::throwUnauthorizedError();
                }

                if ($Record) {
                    if (!static::checkReadAccess($Record)) {
                        return static::throwUnauthorizedError();
                    }

                    return static::handleRecordRequest($Record);
                } else {
                    return static::throwRecordNotFoundError($action);
                }
            }
        }
    }

    public static function getRecordByHandle($handle)
    {
        $className = static::$recordClass;

        if (ctype_digit($handle) || is_int($handle)) {
            return $className::getByID($handle);
        } elseif (method_exists($className, 'getByHandle')) {
            return $className::getByHandle($handle);
        } else {
            return null;
        }
    }

    public static function handleQueryRequest($query, $conditions = array(), $options = array(), $responseID = null, $responseData = array(), $mode = 'AND')
    {
        $className = static::$recordClass;
        $tableAlias = $className::getTableAlias();
        $terms = preg_split('/\s+/', $query);

        $options = array_merge(array(
            'limit' =>  !empty($_REQUEST['limit']) && is_numeric($_REQUEST['limit']) ? $_REQUEST['limit'] : static::$browseLimitDefault
            ,'offset' => !empty($_REQUEST['offset']) && is_numeric($_REQUEST['offset']) ? $_REQUEST['offset'] : false
        ), $options);

        $select = array($tableAlias.'.*');
        $joins = array();
        $having = array();
        $matchers = array();

        foreach ($terms AS $term) {
            $n = 0;
            $qualifier = 'any';
            $split = explode(':', $term, 2);

            if (empty($term)) {
                continue;
            }

            if (count($split) == 2) {
                $qualifier = strtolower($split[0]);
                $term = $split[1];
            }
<commit_msg>Added support for quoted search queries<commit_after><?php

abstract class RecordsRequestHandler extends RequestHandler
{
    // configurables
    public static $recordClass;
    public static $accountLevelRead = false;
    public static $accountLevelComment = 'User';
    public static $accountLevelBrowse = 'Staff';
    public static $accountLevelWrite = 'Staff';
    public static $accountLevelAPI = false;
    public static $browseOrder = false;
    public static $browseConditions = false;
    public static $browseLimitDefault = false;
    public static $editableFields = false;
    public static $searchConditions = false;
    public static $browseCalcFoundRows = true;

    public static $calledClass = __CLASS__;
    public static $responseMode = 'html';
    public static $userResponseModes = array(
        'application/json' => 'json'
        ,'text/csv' => 'csv'
    );

    public static function handleRequest()
    {
        // save static class
        static::$calledClass = get_called_class();

        switch (static::peekPath()) {
            case 'csv':
            case 'json':
            case 'pdf':
                static::$responseMode = static::shiftPath();
                break;
        }

        return static::handleRecordsRequest();
    }


    public static function handleRecordsRequest($action = false)
    {
        switch ($action ? $action : $action = static::shiftPath()) {
            case 'save':
            {
                return static::handleMultiSaveRequest();
            }

            case 'destroy':
            {
                return static::handleMultiDestroyRequest();
            }

            case 'create':
            {
                return static::handleCreateRequest();
            }

            case '*fields':
            {
                return static::handleFieldsRequest();
            }

            case '':
            case false:
            {
                if (count(static::getPath())) {
                    // throw an error for URLs like /collection//foo
                    return static::throwInvalidRequestError();
                }

                return static::handleBrowseRequest();
            }

            default:
            {
                try {
                    $Record = static::getRecordByHandle(urldecode($action));
                } catch (UserUnauthorizedException $e) {
                    return static::throwUnauthorizedError();
                }

                if ($Record) {
                    if (!static::checkReadAccess($Record)) {
                        return static::throwUnauthorizedError();
                    }

                    return static::handleRecordRequest($Record);
                } else {
                    return static::throwRecordNotFoundError($action);
                }
            }
        }
    }

    public static function getRecordByHandle($handle)
    {
        $className = static::$recordClass;

        if (ctype_digit($handle) || is_int($handle)) {
            return $className::getByID($handle);
        } elseif (method_exists($className, 'getByHandle')) {
            return $className::getByHandle($handle);
        } else {
            return null;
        }
    }

    public static function handleQueryRequest($query, $conditions = array(), $options = array(), $responseID = null, $responseData = array(), $mode = 'AND')
    {
        $className = static::$recordClass;
        $tableAlias = $className::getTableAlias();
        $terms = str_getcsv($query, ' ');

        $options = array_merge(array(
            'limit' =>  !empty($_REQUEST['limit']) && is_numeric($_REQUEST['limit']) ? $_REQUEST['limit'] : static::$browseLimitDefault
            ,'offset' => !empty($_REQUEST['offset']) && is_numeric($_REQUEST['offset']) ? $_REQUEST['offset'] : false
        ), $options);

        $select = array($tableAlias.'.*');
        $joins = array();
        $having = array();
        $matchers = array();

        foreach ($terms AS $term) {
            $n = 0;
            $qualifier = 'any';
            $split = explode(':', $term, 2);

            if (empty($term)) {
                continue;
            }

            if (count($split) == 2) {
                $qualifier = strtolower($split[0]);
                $term = $split[1];
            }

{'fraction_non_alphanumeric': 0.12183801346019958, 'fraction_numerical': 0.0011603620329542817, 'mean_word_length': 1.7484056122448979, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 11, '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': '4616111', 'n_tokens_mistral': 2192, 'n_tokens_neox': 2068, 'n_words': 478}