Add :record-timestamps to dbi-store for recording created_at & updated_at.

This commit is contained in:
Eitarow Fukamachi 2016-08-23 22:01:50 +09:00
parent ac68b5c167
commit 17d15c7102
2 changed files with 79 additions and 5 deletions

View file

@ -27,6 +27,7 @@
(deserializer (lambda (data) (deserializer (lambda (data)
(unmarshal (read-from-string (unmarshal (read-from-string
(utf-8-bytes-to-string (base64-string-to-usb8-array data)))))) (utf-8-bytes-to-string (base64-string-to-usb8-array data))))))
(record-timestamps nil :type boolean)
(table-name "sessions")) (table-name "sessions"))
(defmethod fetch-session ((store dbi-store) sid) (defmethod fetch-session ((store dbi-store) sid)
@ -45,6 +46,13 @@
nil)) nil))
nil))) nil)))
(defun current-timestamp ()
(multiple-value-bind (sec min hour date month year)
(decode-universal-time (get-universal-time))
(format nil "~D-~2,'0D-~2,'0DT~2,'0D:~2,'0D:~2,'0D"
year month date
hour min sec)))
(defmethod store-session ((store dbi-store) sid session) (defmethod store-session ((store dbi-store) sid session)
(let ((conn (funcall (dbi-store-connector store))) (let ((conn (funcall (dbi-store-connector store)))
(serialized-session (funcall (dbi-store-serializer store) session))) (serialized-session (funcall (dbi-store-serializer store) session)))
@ -58,14 +66,19 @@
((equal current-session serialized-session)) ((equal current-session serialized-session))
;; Session exists and is going to be changed ;; Session exists and is going to be changed
(current-session (current-session
(dbi:do-sql conn (format nil "UPDATE ~A SET session_data = ? WHERE id = ?" (dbi:do-sql conn
(dbi-store-table-name store)) (format nil "UPDATE ~A SET session_data = ?~:[~*~;, updated_at = '~A'~] WHERE id = ?"
(dbi-store-table-name store)
(dbi-store-record-timestamps store)
(current-timestamp))
serialized-session serialized-session
sid)) sid))
;; New session ;; New session
(t (t
(dbi:do-sql conn (format nil "INSERT INTO ~A (id, session_data) VALUES (?, ?)" (dbi:do-sql conn (format nil "INSERT INTO ~A (id, session_data~:[~;, created_at, updated_at~]) VALUES (?, ?~:*~:[~*~;, '~A', ~:*'~A'~])"
(dbi-store-table-name store)) (dbi-store-table-name store)
(dbi-store-record-timestamps store)
(current-timestamp))
sid sid
serialized-session))))))) serialized-session)))))))

View file

@ -8,7 +8,7 @@
:prove)) :prove))
(in-package :t.lack.session.store.dbi) (in-package :t.lack.session.store.dbi)
(plan 3) (plan 4)
(defvar *test-db* (asdf:system-relative-pathname :lack "data/test.db")) (defvar *test-db* (asdf:system-relative-pathname :lack "data/test.db"))
(when (probe-file *test-db*) (when (probe-file *test-db*)
@ -83,6 +83,67 @@
(is (getf session :|count|) 2 (is (getf session :|count|) 2
"'sessions' has two records")) "'sessions' has two records"))
(dbi:disconnect *conn*)
(delete-file *test-db*)
(setf *conn*
(dbi:connect :sqlite3 :database-name *test-db*))
;;
;; record-timestamps t
(dbi:do-sql *conn*
"CREATE TABLE sessions (id CHAR(72) PRIMARY KEY, session_data TEXT, created_at DATETIME, updated_at DATETIME)")
(subtest "session middleware"
(let ((app
(builder
(:session
:store (make-dbi-store
:connector (lambda () *conn*)
:record-timestamps t))
(lambda (env)
(unless (gethash :counter (getf env :lack.session))
(setf (gethash :counter (getf env :lack.session)) 0))
`(200
(:content-type "text/plain")
(,(format nil "Hello, you've been here for ~Ath times!"
(incf (gethash :counter (getf env :lack.session)))))))))
session
now)
(diag "1st request")
(destructuring-bind (status headers body)
(funcall app (generate-env "/"))
(is status 200)
(setf session (parse-lack-session headers))
(ok session)
(is body '("Hello, you've been here for 1th times!")))
(let ((records (dbi:fetch-all
(dbi:execute
(dbi:prepare *conn* "SELECT * FROM sessions")))))
(is (length records) 1)
(is (getf (first records) :|id|) session)
(setf now (getf (first records) :|created_at|))
(is (getf (first records) :|updated_at|) now))
(sleep 2)
(diag "2nd request")
(destructuring-bind (status headers body)
(funcall app (generate-env "/" :cookies `(("lack.session" . ,session))))
(declare (ignore headers))
(is status 200)
(is body '("Hello, you've been here for 2th times!")))
(let ((records (dbi:fetch-all
(dbi:execute
(dbi:prepare *conn* "SELECT * FROM sessions")))))
(is (length records) 1)
(is (getf (first records) :|id|) session)
(is (getf (first records) :|created_at|) now)
(isnt (getf (first records) :|updated_at|) now))))
(dbi:disconnect *conn*) (dbi:disconnect *conn*)
(finalize) (finalize)