Оболочка функции SQL CakePHP 4 для минимального и максимального значений, возвращающая неправильный тип данных

У меня проблемы с обработчиком функций sql в CakePHP 4. Я использую SQLite 3 и Cakephp 4.2.3 Strawberry. В моей таблице базы данных есть поле TEXT под названием «дата». Наименьшее и наибольшее значения в «дате»: «2020-01-15» и «2020-12-31». У меня есть простой запрос:

$query = $this->find();
$query->select(['minDate' => $query->func()->min('date'),
                'maxDate' => $query->func()->max('date')])
      ->where(['date <>' => ''])
      ->enableHydration(false);
       
$results = $query->toList();

$maxDate = $results[0]['maxDate'];
$minDate = $results[0]['minDate'];

Что генерирует SQL, который я хочу:

SELECT (MIN(date)) AS minDate, (MAX(date)) AS maxDate FROM temp_income TempIncome WHERE date <> :c0

Однако код возвращает значения с плавающей запятой для $minDate и $maxDate:

$minDate = 2020
$maxDate = 2020

Если я запускаю этот оператор непосредственно в SQLite Studio, я получаю правильный результат (ввод '' вместо: c0)

minDate = '2020-01-15' 
maxDate = '2020-12-31'

Если я запущу запрос в CakePHP с помощью Connection Manager и того же SQL, я получу правильный ответ.

$connection = ConnectionManager::get('default');
$results = $connection->execute("SELECT min(date) as minDate, max(date) as maxDate from temp_income where date <> ''")->fetchAll('assoc');


minDate = '2020-01-15'
maxDate = '2020-12-31'

Оболочка функции торта func()->min(‘date’) выполняет нежелательное преобразование типов.

Копнув глубже, внутри vendor/cakephp/cakephp/src/database/FunctionsBuilder.php компоновщики для min и max настроены на возврат «float», если не определен другой тип, что, по-видимому, не в данном случае. Я не знаю почему. Я еще не копал так далеко.

public function max($expression, $types = []): AggregateExpression
{
    return $this->aggregate('MAX', $this->toLiteralParam($expression), $types, current($types) ?: 'float');
}


public function min($expression, $types = []): AggregateExpression
{
    return $this->aggregate('MIN', $this->toLiteralParam($expression), $types, current($types) ?: 'float');
}

Правильное поведение для min() и max(), по крайней мере, в Oracle и SQL Server, и явно в SQLite, поскольку необработанный запрос работает нормально, состоит в том, чтобы возвращать тип данных аргумента.

Это ошибка в обёртке функции CakePHP? Или я что-то упускаю?

Спасибо!


person SMac    schedule 16.03.2021    source источник
comment
Функции min и max принимают второй параметр, представляющий собой массив типов. Я не могу найти пример использования этого в документации, я думаю, ->min('date', ['date'])?   -  person Greg Schmidt    schedule 16.03.2021


Ответы (1)


Грег Шмидт прав. min() и max() принимают аргумент типа. Вам нужно изучить документацию по классу FunctionsBuilder, чтобы найти его: https://api.cakephp.org/4.1/class-Cake.Database.FunctionsBuilder.html#min

В моем случае:

  $query->select(['minDate' => $query->func()->min('date', ['text']),
                  'maxDate' => $query->func()->max('date', ['text'])])

Оглядываясь назад, это ясно из объявлений функций, которые я опубликовал ранее:

public function max($expression, $types = []): AggregateExpression

Приведенный выше код решил проблему.

person SMac    schedule 16.03.2021