Как получить BOOLEANS с помощью пользовательского SQL-запроса в Rails 3 + Postgres? - PullRequest
0 голосов
/ 09 сентября 2011

В моей модели я сделал этот пользовательский SQL-запрос:

SELECT
    training_courses.id,
    training_courses.training_id,
    training_courses.course_id,
    training_courses.is_pre_test, 
    training_courses.order_by,
    training_course_histories.id AS training_course_history_id, 
    training_course_histories.finished_at,
    training_course_histories.score,
    CAST(coalesce(user_training_courses.id, 0) as BOOLEAN) as purchased
FROM
    training_courses
    LEFT OUTER JOIN training_course_histories
        ON training_course_histories.training_course_id = training_courses.id AND training_course_histories.id = (
            SELECT th1.id
            FROM training_course_histories th1      
            WHERE th1.training_course_id = training_courses.id
              AND th1.finished_at IS NOT NULL
              AND th1.user_id = 1
            ORDER BY th1.finished_at DESC LIMIT 1
        )
    LEFT OUTER JOIN user_training_courses
        ON user_training_courses.training_course_id = training_courses.id AND user_training_courses.id = (
            SELECT th2.id
            FROM user_training_courses th2          
            WHERE th2.training_course_id = training_courses.id 
              AND th2.user_id = 1
        )
WHERE (training_courses.training_id = 1)
GROUP BY
    training_courses.id,
    training_courses.id,
    training_courses.training_id,
    training_courses.course_id,
    training_courses.is_pre_test, 
    training_courses.order_by,
    training_course_histories.id,
    training_course_histories.finished_at,
    training_course_histories.score, 
    user_training_courses.id
ORDER BY 
    order_by ASC, 
    id ASC, 
    training_courses.order_by ASC, 
    training_courses.id ASC

Раньше я пользовался базой данных Mysql, так что никаких проблем, запрос был такой: ISNULL(user_training_courses.id) as purchased

Но сейчас я использую Postgres, и у меня должно быть CAST(coalesce(user_training_courses.id, 0) as BOOLEAN) as purchased

Проблема: для Rails куплено = 't' или 'f' (строки)

Что я хочу: куплено = true или false (логическое значение)

Возможно ли это?

Thx.

Ответы [ 2 ]

1 голос
/ 12 сентября 2011

Наконец, в моей модели, скорее, есть средство доступа для этого случая.

def purchased
  ![false, 'false', 'f', 'FALSE', 'F', 0, '0'].include?(self[:purchased])
end
0 голосов
/ 09 сентября 2011

Драйвер Rails PostgreSQL понимает, что логические значения PostgreSQL имеют вид 't' и 'f' и обычно переводит их правильно.Ваш CAST:

CAST(coalesce(user_training_courses.id, 0) as BOOLEAN)

также должен быть в порядке:

psql=> select cast(11 as boolean), cast(1 as boolean), cast(0 as boolean);
 bool | bool | bool 
------+------+------
 t    | t    | f

Так что я предполагаю, что Rails просто не знает тип столбца вашего CAST.Например:

rails > ActiveRecord::Base.connection.select_rows('select cast(1 as boolean), 11 = 11')
 => [["t", "t"]]

Вы можете самостоятельно преобразовать 't' и 'f' в логические значения, используя константы Set в ActiveRecord::ConnectionAdapters::Column:

TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE'].to_set
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE'].to_set

или вы можете использовать ActiveRecord::ConnectionAdapters::Column.value_to_boolean:

rails > ActiveRecord::Base.connection.select_rows('select cast(1 as boolean), 11 = 11').map { |r| r.map { |b| ActiveRecord::ConnectionAdapters::Column.value_to_boolean(b) } }
 => [[true, true]] 

Но вам все равно придется знать, к каким типам относятся все ваши столбцы, и разобраться во всем, если вы собираетесь использовать низкоуровневый интерфейс SQL.Аналогичные проблемы относятся к целым числам, датам и любым другим не строковым типам, которые вы возвращаете.

...