connection.select_value возвращает строки только в postgres с pg gem

Я конвертирую приложение rails с использования mysql (mysql2 gem) в postgres (pg gem).

В mysql вызовы ActiveRecord::Base.connection.select_value возвращают значения, типизированные в соответствии с данными, например:

> ActiveRecord::Base.connection.select_value("SELECT COUNT(*) FROM errors")
=> 86
> ActiveRecord::Base.connection.select_value("SELECT exception FROM errors where id=565")
=> "TechTalk.Genome.SqlExecutionException"
> ActiveRecord::Base.connection.select_value("SELECT id FROM errors where id=565")
=> 565

Однако с postgres connection.select_value всегда возвращает строку:

> ActiveRecord::Base.connection.select_value("SELECT COUNT(*) FROM errors")
=> "1"
> ActiveRecord::Base.connection.select_value("SELECT id FROM errors")
=> "1"
> ActiveRecord::Base.connection.select_value("SELECT source FROM errors limit 1")
=> "webapp"

Это сломало несколько модульных тестов, и хотя их можно исправить, я уверен, что у нас есть другой код, полагающийся на эти возвращаемые значения. Есть ли способ получить правильно типизированные возвращаемые значения из connection.select_value при использовании postgres?


person Monica Woods    schedule 24.09.2012    source источник


Ответы (2)


Короткий ответ: нет. Драйвер «pg» намеренно обеспечивает как можно более тонкий слой поверх родного драйвера «libpq». Он не выполняет приведение типов, так как за это отвечают библиотеки более высокого уровня, которые имеют некоторое представление о предметной области, в которой будут использоваться результаты. Обоснование этого решения задокументировано на PostgreSQL Wiki, и я был бы рад обсудить это с вами далее в списке рассылки.

person Michael Granger    schedule 24.09.2012
comment
Худший лучший ответ! ;) Спасибо. - person Monica Woods; 28.09.2012
comment
как можно более тонкий слой поверх родного драйвера libpq. проблема в том, что выделение строк в ruby ​​на самом деле довольно дорого, кажется таким расточительным - person Sam Saffron; 16.01.2013
comment
Я думаю, что это вопрос обстоятельств, будет ли более расточительно выделять строки для каждого столбца или пытаться отображать типы PostgreSQL в Ruby по умолчанию. Если все ваши типы столбцов имеют точные числовые производные (не BigNum) эквиваленты в Ruby, вероятно, расточительно представлять их все как строки. Тем не менее, мне кажется безответственным реализовать то, что может быть только частично полной системой сопоставления типов, основанной на потенциальной трате памяти в этом сравнительно редком случае. - person Michael Granger; 25.01.2013
comment
Я согласен с идеей, выраженной Майклом, но в контексте Rails мне кажется, что драйвер должен выводить тип данных в соответствии со своей таблицей 'native_database_types'. - person gamov; 13.10.2014

Для тех, кто попадает сюда в поисках атрибутов активной записи (Rails), конкретный ответ: я провел несколько тестов (https://gist.github.com/gamov/8fe38733012931eb3360) и обнаружил, что:

RequestedItem.where(id: 1).select(*, 10 AS tq).first.tq.class

возвращает String с Rails ‹ 4 и Fixnum с Rails >= 4.

Адаптер Postgres будет пересылать типы из БД в модуль Persistence, чтобы можно было выполнять приведение типов прозрачно.

person gamov    schedule 15.10.2014