Session

Сессия - сеанс работы с системой. Сохраняет данные между запросами. Наши сценарии используют сессию, чтобы отслеживать вошел ли пользователь в систему.

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

(ns publicator.use-cases.abstractions.session
  (:refer-clojure :exclude [get set!]))

(defprotocol Session
  (-get [this k])
  (-set! [this k v]))

(declare ^:dynamic *session*)

(defn get [k]
  (-get *session* k))

(defn set! [k v]
  (-set! *session* k v))

Для тестирования будем использовать тривиальную реализацию, хранящую состояние в атоме:

(ns publicator.use-cases.test.fakes.session
  (:require
   [publicator.use-cases.abstractions.session :as session]))

(deftype FakeSession [storage]
  session/Session
  (-get [_ k] (get @storage k))
  (-set! [_ k v] (swap! storage assoc k v)))

(defn binding-map []
  {#'session/*session* (FakeSession. (atom {}))})

Сама сессия дает только низкоуровневый интерфейс. Поэтому сделаем службу для работы с сессией пользователя:

(ns publicator.use-cases.services.user-session
  (:require
   [publicator.use-cases.abstractions.session :as session]
   [publicator.use-cases.abstractions.storage :as storage]))

(defn user-id []
  (session/get ::id))

(defn logged-in? []
  (boolean (user-id)))

(defn logged-out? []
  (not (logged-in?)))

(defn log-in! [user]
  (session/set! ::id (:id user)))

(defn log-out! []
  (session/set! ::id nil))

(defn user []
  (when-let [id (user-id)]
    (storage/tx-get-one id)))

(defn iuser [t]
  (when-let [id (user-id)]
    (storage/get-one t id)))

Абстракцию storage рассмотрим в следующем параграфе.