Add an alternative Ring session store that uses Clojure reader serialization

This way libraries like Friend, that use namespaced keywords (::identity) and other
Clojure-specific data structures will work well with Monger.

Current store will strip off namespace information from namespaced keywords
because clojure.core/name work that way. For example: (name ::identity).

Reported by Julio Barros.
This commit is contained in:
Michael S. Klishin 2012-06-27 19:02:11 +04:00
parent 828e7981f0
commit 43349f65ae
2 changed files with 97 additions and 0 deletions

View file

@ -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

View file

@ -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)))))