Clojure & SQLite

С базами данных я не работал уже лет… 10 наверное. Само собой, мой старый опыт это ODBC, C++ обертки над ним и прочие реально страшные штуки. И тут я столкнулся с современными способами взаимодействия с базами данных и не в монстроподобном C++, а в изящной Clojure и обомлел! Все так просто, изящно, правда, потенциально, тормознуто Но про тормознутость это не более чем теория вызванная тяжелым C++ опытом, когда подозреваешь в плохой оптимизации все, что автоматически генерирует какие-либо сущности.

На мой неискушенный взгляд, поддержка баз данных в Clojure замечательная. Я ограничился довольно скромным набором состоящим из ядра org.clojure/java.jdbc, драйвера для SQLite org.xerial/sqlite-jdbc и библиотечки для работы с SQL в Clojure-стиле java-jdbc/dsl.

Мой случай, пока что, совсем уж простой: две таблицы, пара индексов да внешний ключ. Вспоминая об ужасах 10 летней давности, ожидал что даже данный пункт окажется не простым. Внезапно все оказалось сильно иначе.

(defn init-db []
  (jdbc/db-do-commands db
                       (jdbc/create-table-ddl :authors
                                              [:author_id :integer "primary key"]
                                              [:follow :boolean]
                                              [:follow_date :datetime])
                       (jdbc/create-table-ddl :images
                                              [:image_id :integer "primary key"]
                                              [:author_id :integer "references authors (author_id)"]
                                              [:commented :boolean]
                                              [:liked :boolean])

                       "CREATE UNIQUE INDEX image_id ON images(image_id)"
                       "CREATE UNIQUE INDEX author_id ON authors(author_id)"))

Что не менее восхитительно – так это возможность вынести обработку ошибок из функции с логикой. В данном примере функция db-do-commands легко может выкинуть исключение SQLException если база данных уже существует. При этом, никакой необходимости усложнять логику функции init-db нет, ведь обработчик вполне можно написать отдельно:

(with-handler! #'init-db
               java.lang.Exception
               (fn [e & args]
                 (log/warn "init-db: " e)))

Моя реализация обработки крайне простая и примитивная. При этом ничто не мешает добавить, например, удаление/восстановление базы, создание отсутствующей директории и т.п. в зависимости от перехваченного исключения с последующим перезапуском db-do-commands.

Каким образом удобнее писать запросы я как-то не определился. С одной стороны, можно мудрить и написать SQL-запрос на самом SQL. Быстро, просто, понятно.

(defn image-info [id]
  (jdbc/query db ["select * from images where image_id = ?" id]))

Можно воспользоваться DSL из java-jdbc/dsl. В качестве плюсов видится использование keyword-ов (коллеги, как правильно на русский перевести? Ключевые слова очень не к месту, как мне кажется), что облегчает автоподстановку со стороны IDE, а значит и минимизирует вероятность ошибки. В качестве минусов вылезает более громоздкая конструкция.

(defn author-info [id]
  (jdbc/query db
              (sql/select [:*] :authors
                          (sql/where {:author_id id})))
  )

Прогресс очень далеко шагнул, хотя, не удивлюсь если в мире C++ и баз данных всё тот же ODBC рулит. Проект “поиграться” тут.

3 Comments Clojure & SQLite

  1. Yauheni Akhotnikau

    Такое ощущение, что если бы ты в 2005 увидел, что позволяет делать ActiveRecord в Ruby-On-Rails, у тебя бы вообще шаблоны разорвало в клочья

    PS. По поводу C++ и ODBC. Тут как у кого. Если человек не может пользоваться Google, то да, только хардкор. Если может, то пользуется чем-то вроде OTL или SOCI, на худой конец простейшими обертками вроде Poco::Db. А для SQLite в свое время была очень удобная библиотечка sqlite++, заброшенная авторами, но ее несложно было подкрутить под свои нужды.

    PPS. Вместо keywords здесь, возможно, уместно было бы зарезервированные слова.

    Reply
    1. Alexander Stavonin

      То был 2002, я думаю. Тогда, вроде бы и гугла не было
      А почему ключевые слова? Ты же сам их вводишь… У мен с ключевыми словами скорее if/for ассоциируются.

      Reply
      1. Yauheni Akhotnikau

        OTL существует очень давно, даже OTL 4.0 была выпущена в 2001-м: http://otl.sourceforge.net/otl3_hist.htm
        В 2002-м был Yahoo, да и Google уже начинался и был, имхо, даже лучше, чем сейчас. Правда, в 2002-м я сам велосипедил свою обертку над ODBS, но в конце-концов забабахался и выбросил ее, перейдя на OTL.

        > А почему ключевые слова?

        Не ключевые, а зарезервированные слова. Ты же сам написал, что перевод keywords как “ключевые слова” тебе не нравится в данном контексте. Если не “ключевые”, тогда напрашиваются “зарезервированные”.

        Reply

Leave a Reply