diff --git a/src/clojure/monger/ring/session_store.clj b/src/clojure/monger/ring/session_store.clj index ef08e39..5db10be 100644 --- a/src/clojure/monger/ring/session_store.clj +++ b/src/clojure/monger/ring/session_store.clj @@ -18,6 +18,49 @@ ;; API ;; +;; this session store stores Clojure data structures using Clojure reader. It will correctly store every +;; data structure Clojure reader can serialize and read but won't make the data useful to applications +;; in other languages. + +(defrecord ClojureReaderBasedMongoDBSessionStore [^String collection-name]) + +(extend-protocol ringstore/SessionStore + ClojureReaderBasedMongoDBSessionStore + + (read-session [store key] + #_ (if-let [m (and key + (mc/find-one-as-map (.collection-name store) {:_id key}))] + m + {}) + (if key + (if-let [m (mc/find-one-as-map (.collection-name store) {:_id key})] + (read-string (:value m)) + {}) + {})) + + (write-session [store key data] + (let [date (Date.) + key (or key (str (UUID/randomUUID))) + value (binding [*print-dup* true] + (pr-str (assoc data :date date :_id key)))] + (mc/save (.collection-name store) {:_id key :date date :value value}) + key)) + + (delete-session [store key] + (mc/remove-by-id (.collection-name store) key) + nil)) + + +(defn session-store + ([] + (ClojureReaderBasedMongoDBSessionStore. default-session-store-collection)) + ([^String s] + (ClojureReaderBasedMongoDBSessionStore. s))) + + +;; this session store won't store namespaced keywords correctly but stores results in a way +;; that applications in other languages can read. DO NOT use it with Friend. + (defrecord MongoDBSessionStore [^String collection-name]) (extend-protocol ringstore/SessionStore diff --git a/test/monger/test/ring/clojure_session_store_test.clj b/test/monger/test/ring/clojure_session_store_test.clj new file mode 100644 index 0000000..f5a0ae2 --- /dev/null +++ b/test/monger/test/ring/clojure_session_store_test.clj @@ -0,0 +1,54 @@ +(ns monger.test.ring.session-store-test + (:require [monger core util] + [monger.collection :as mc] + [monger.test.helper :as helper]) + (:use clojure.test + ring.middleware.session.store + monger.ring.session-store)) + + +(helper/connect!) + +(defn purge-sessions + [f] + (mc/remove "web_sessions") + (mc/remove "sessions") + (f) + (mc/remove "web_sessions") + (mc/remove "sessions")) + +(use-fixtures :each purge-sessions) + + +(deftest test-reading-a-session-that-does-not-exist + (let [store (session-store)] + (is (= {} (read-session store "a-missing-key-1228277"))))) + + +(deftest test-reading-a-session-that-does-exist + (let [store (session-store) + sk (write-session store nil {:library "Monger"}) + m (read-session store sk)] + (is sk) + (is (and (:_id m) (:date m))) + (is (= (dissoc m :_id :date) + {:library "Monger"})))) + + +(deftest test-updating-a-session + (let [store (session-store "sessions") + sk1 (write-session store nil {:library "Monger"}) + sk2 (write-session store sk1 {:library "Ring"}) + m (read-session store sk2)] + (is (and sk1 sk2)) + (is (and (:_id m) (:date m))) + (is (= sk1 sk2)) + (is (= (dissoc m :_id :date) + {:library "Ring"})))) + + +(deftest test-deleting-a-session + (let [store (session-store "sessions") + sk (write-session store nil {:library "Monger"})] + (is (nil? (delete-session store sk))) + (is (= {} (read-session store sk)))))