Как изменить контекст в Clojure Biff?

Вопрос или проблема

Я новичок в Clojure и решил попробовать Biff. Я создаю простой блог, но решил бросить себе вызов и использовать Postgres в качестве базы данных. Я следовал руководству по Postgres Biff, но обнаружил, что ключ :example/ds из контекста возвращает nil (я также удалил все, что блогу не нужно, например, аутентификацию).

; В моем основном файле проекта...
(defn use-postgres [{:keys [biff/secret] :as ctx}]
  (let [ds (jdbc/get-datasource (secret :example/postgres-url))]
    (assoc ctx :example/ds ds)))

; ...

(def components
  [biff/use-aero-config
   biff/use-queues
   biff/use-jetty
   biff/use-chime
   biff/use-beholder
   use-postgres])

; ... В файле моего блога:


(defn blog-home [{:keys [example/ds] :as ctx} & body]
  (ui/page
   ctx
   [:h2 ""]
   [:p "Это мой блог"]
   [:.blog-list (generate-blog-entries (database/get-n-blog-posts ds 10))]
   [:h3 "Конец списка блогов"]))

(defn blog-page [{:keys [path-params] :as ctx}]
  (ui/page
   ctx
   ))

(def module
  {:routes ["/blog"
            ["/" {:get blog-home}]]})

Исключение, которое я получаю:

[qtp1087121050-39] ERROR com.biffweb.impl.middleware - Исключение при обработке запроса
java.lang.IllegalArgumentException: Не найдена реализация метода: :-execute-all протокола: #'next.jdbc.protocols/Executable для класса: nil

… и после некоторого отладки я обнаружил, что ds в blog-home всегда nil.

Я пытался добавить промежуточное ПО следующим образом:

(def module
  {:routes ["/blog" {:middleware [mid/wrap-site-defaults]}
            ["/" {:get blog-home}]]})

… но это ничего не исправило.

Кроме того, смотря в REPL, я обнаружил, что ds всегда присутствует:

(defn get-context []
  (biff/merge-context @main/system))

(defn add-fixtures []
  (let [{:keys [example/ds] :as ctx} (get-context)
        user-id (random-uuid)]
    (log/info "Полный CTX: " ctx)
    (log/info "Просто db: " (ctx :example/ds))
    (comment
      (jdbc/execute! ds ["INSERT INTO users (id, email, foo) VALUES (?, ?, ?)"
                         user-id "[email protected]" "Некое значение"])
      (jdbc/execute! ds ["INSERT INTO message (id, user_id, text) VALUES (?, ?, ?)"
                         (random-uuid) user-id "Привет"]))))

И я получаю
#object[next.jdbc.connection$url_PLUS_etc$reify__29062 0x149be200 postgresql://tester:postgres@localhost:5433/xyz]

так что я правильно настраиваю JDBC и помещаю его в системную карту, он просто не отображается в get блога.

Вот репозиторий блога на github

Ответ или решение

Чтобы правильно модифицировать контекст в Biff и устранить проблему с отсутствием значения для ключа :example/ds, вам нужно обратить внимание на порядок инициализации компонентов, а также на то, как вы передаете контекст в разные функции.

Понимание проблемы

Основная причина, по которой :example/ds возвращает nil в функции blog-home, заключается в том, что контекст, передаваемый в blog-home, не содержит ожидаемого значения для ключа :example/ds. Это может произойти, если функция, создающая datasource, не была выполнена до вызова вашего обработчика маршрута.

Шаги для решения проблемы

  1. Порядок инициализации компонентов. Убедитесь, что use-postgres добавлен в массив components до любых других компонентов, которые могут использовать его контекст.

    (def components
    [biff/use-aero-config
     biff/use-queues
     biff/use-jetty
     biff/use-chime
     biff/use-beholder
     use-postgres])  ;; `use-postgres` должен быть первым
  2. Проверка датасорса. Ваша функция use-postgres должна корректно создавать и добавлять datasource. Убедитесь, что URL вашего Postgres корректен и что база данных доступна. Проверьте, что ключ :example/postgres-url действительно содержит требуемый URL.

    (defn use-postgres [{:keys [biff/secret] :as ctx}]
     (let [ds (jdbc/get-datasource (secret :example/postgres-url))]
       (if ds
         (assoc ctx :example/ds ds)
         (throw (ex-info "Datasource could not be created" {})))))
  3. Проверка контекста в маршрутах. Убедитесь, что в рамках маршрутов вы используете правильный ключ для доступа к.datasource. Когда вы определяете функцию blog-home, строка {:keys [example/ds] :as ctx} должна быть корректной. Попробуйте, например, просто вывести весь контекст, чтобы убедиться, что он содержит все ожидаемые данные:

    (defn blog-home [{:keys [example/ds] :as ctx}]
     (log/info "Контекст в blog-home: " ctx)
     (if ds
       (ui/page
        ctx
        [:h2 ""]
        [:p "This is my blog"]
        [:.blog-list (generate-blog-entries (database/get-n-blog-posts ds 10))]
        [:h3 "End blog list"])
       (throw (ex-info "Datasource not available in blog-home" {}))))
  4. Обработка middleware. Убедитесь, что ваше middleware не удаляет нужный контекст. Если вы используете mid/wrap-site-defaults, проверьте, как это middleware взаимодействует с вашим контекстом.

Общие рекомендации

  • Логи. Обязательно логируйте ключевые моменты — это поможет вам увидеть, когда и где значения в контексте меняются.
  • Тестирование. Попробуйте запустить минимальные тесты, чтобы изолировать и проверить только функции, которые работают с контекстом.
  • Документация. Не забудьте проверить документацию Biff и Next.jdbc, чтобы быть уверенными в правильности реализации.

Заключение

Внесение изменений в контекст в Clojure Biff требует внимательности к порядку инициализации компонентов и тщательной проверки доступности данных. Следуя представленным шагам, вы сможете устранить проблему с отсутствием datasource и обеспечить корректную работу вашего блога на Postgres.

Оцените материал
Добавить комментарий

Капча загружается...