subscribing stores compiled views

This commit is contained in:
Dave Della Costa 2014-06-06 20:34:51 +09:00
parent e901e70057
commit 3dc546e192
5 changed files with 70 additions and 50 deletions

View file

@ -11,7 +11,7 @@
[clojure.java.jdbc :as j] [clojure.java.jdbc :as j]
[clojure.tools.logging :refer [debug]] [clojure.tools.logging :refer [debug]]
[views.honeysql :as vh] [views.honeysql :as vh]
[views.subscribed-views :refer [get-subscribed-views broadcast-deltas]])) [views.subscribed-views :refer [subscribed-views broadcast-deltas]]))
(defn get-primary-key (defn get-primary-key
"Get a primary key for a table." "Get a primary key for a table."
@ -468,7 +468,7 @@
calculate for them and associated with the hash-maps (appropriately calculate for them and associated with the hash-maps (appropriately
called views-with-deltas)." called views-with-deltas)."
[schema db action-map subscribed-views] [schema db action-map subscribed-views]
(let [subbed-views (get-subscribed-views subscribed-views db) (let [subbed-views (subscribed-views subscribed-views db)
transaction-fn #(do-view-transaction schema db subbed-views action-map)] transaction-fn #(do-view-transaction schema db subbed-views action-map)]
(if-let [deltas (:deltas db)] ;; inside a transaction we just collect deltas and do not retry (if-let [deltas (:deltas db)] ;; inside a transaction we just collect deltas and do not retry
(let [{:keys [views-with-deltas result-set]} (transaction-fn)] (let [{:keys [views-with-deltas result-set]} (transaction-fn)]

View file

@ -1,4 +1,6 @@
(ns views.subscriptions) (ns views.subscriptions
(:require
[views.db :as vdb]))
;; ;;
;; {[:view-sig 1 "arg2"] {:keys [1 2 3 4 ... ] :view-map {:view ...}}} ;; {[:view-sig 1 "arg2"] {:keys [1 2 3 4 ... ] :view-map {:view ...}}}
@ -18,20 +20,26 @@
(conj view-subs subscriber-key) (conj view-subs subscriber-key)
#{subscriber-key}))) #{subscriber-key})))
(defn- add-compiled-view!
[view-sig templates]
(swap! compiled-views #(assoc % view-sig (vdb/view-map (get-in templates [(first view-sig) :fn]) view-sig))))
(defn add-subscription! (defn add-subscription!
([subscriber-key view-sig] ([subscriber-key view-sig templates]
(swap! subscribed-views #(update-in % [view-sig] (add-subscriber-key subscriber-key)))) (swap! subscribed-views #(update-in % [view-sig] (add-subscriber-key subscriber-key)))
([subscriber-key view-sig prefix] (add-compiled-view! view-sig templates))
(swap! subscribed-views #(update-in % [prefix view-sig] (add-subscriber-key subscriber-key))))) ([subscriber-key view-sig templates prefix]
(swap! subscribed-views #(update-in % [prefix view-sig] (add-subscriber-key subscriber-key)))
(add-compiled-view! view-sig templates)))
(defn add-subscriptions! (defn add-subscriptions!
([subscriber-key view-sigs] ([subscriber-key view-sigs templates]
(add-subscriptions! subscriber-key view-sigs nil)) (add-subscriptions! subscriber-key view-sigs templates nil))
([subscriber-key view-sigs prefix] ([subscriber-key view-sigs templates prefix]
(doseq [vs view-sigs] (doseq [vs view-sigs]
(if prefix (if prefix
(add-subscription! subscriber-key vs prefix) (add-subscription! subscriber-key vs templates prefix)
(add-subscription! subscriber-key vs))))) (add-subscription! subscriber-key vs templates)))))
(defn subscribed-to (defn subscribed-to
([view-sig] ([view-sig]
@ -53,9 +61,10 @@
updated (update-in subbed-views path disj subscriber-key)] updated (update-in subbed-views path disj subscriber-key)]
(if (seq (get-in updated path)) (if (seq (get-in updated path))
updated updated
(if prefix (do (swap! compiled-views dissoc view-sig) ; remove the compiled view as well
(update-in updated [prefix] dissoc view-sig) (if prefix
(dissoc updated view-sig)))))) (update-in updated [prefix] dissoc view-sig)
(dissoc updated view-sig)))))))
(defn remove-subscription! (defn remove-subscription!
([subscriber-key view-sig] ([subscriber-key view-sig]
@ -63,3 +72,7 @@
([subscriber-key view-sig prefix] ([subscriber-key view-sig prefix]
(when (subscribed-to? subscriber-key view-sig (if prefix prefix)) (when (subscribed-to? subscriber-key view-sig (if prefix prefix))
(swap! subscribed-views (remove-key-or-view subscriber-key view-sig prefix))))) (swap! subscribed-views (remove-key-or-view subscriber-key view-sig prefix)))))
(defn compiled-view-for
[view-sig]
(get @compiled-views view-sig))

View file

@ -2,26 +2,12 @@
(:require (:require
[clojure.test :refer [use-fixtures deftest is]] [clojure.test :refer [use-fixtures deftest is]]
[honeysql.core :as hsql] [honeysql.core :as hsql]
[views.fixtures :as vf :refer [gen-n-users! database-fixtures!]] [views.fixtures :as vf :refer [gen-n-users! database-fixtures! templates]]
[views.db.core :as vdb] [views.db.core :as vdb]
[clojure.string :refer [upper-case]])) [clojure.string :refer [upper-case]]))
(use-fixtures :each database-fixtures!) (use-fixtures :each database-fixtures!)
(defn users-tmpl
[]
(hsql/build :select [:id :name :created_on] :from :users))
(defn user-posts-tmpl
[user_id]
(hsql/build :select [:u.user_id :u.name :p.title :p.body :p.created_on]
:from {:posts :p}
:join [[:users :u][:= :user_id user_id]]))
(def templates
{:users {:fn #'users-tmpl}
:user-posts {:fn #'user-posts-tmpl}})
(defn subscribed-views (defn subscribed-views
[] []
{[:users] {:view-map ((get-in templates [:users :fn]))}}) {[:users] {:view-map ((get-in templates [:users :fn]))}})

View file

@ -52,3 +52,17 @@
(dotimes [n n] (dotimes [n n]
(user-fixture! (dg/string #(rand-nth (seq "abcdefghijklmnopqrstuwvxyz"))))) (user-fixture! (dg/string #(rand-nth (seq "abcdefghijklmnopqrstuwvxyz")))))
(j/query db ["SELECT * FROM users"])) (j/query db ["SELECT * FROM users"]))
(defn users-tmpl
[]
(hsql/build :select [:id :name :created_on] :from :users))
(defn user-posts-tmpl
[user_id]
(hsql/build :select [:u.user_id :u.name :p.title :p.body :p.created_on]
:from {:posts :p}
:join [[:users :u][:= :user_id user_id]]))
(def templates
{:users {:fn #'users-tmpl}
:user-posts {:fn #'user-posts-tmpl}})

View file

@ -1,6 +1,7 @@
(ns views.subscriptions-test (ns views.subscriptions-test
(:require (:require
[clojure.test :refer [use-fixtures deftest is]] [clojure.test :refer [use-fixtures deftest is]]
[views.fixtures :refer [templates user-posts-tmpl]]
[views.subscriptions :as vs])) [views.subscriptions :as vs]))
(defn- reset-subscribed-views! (defn- reset-subscribed-views!
@ -11,49 +12,55 @@
(use-fixtures :each reset-subscribed-views!) (use-fixtures :each reset-subscribed-views!)
(deftest adds-a-subscription (deftest adds-a-subscription
(let [key 1, view-sig [:view 1]] (let [key 1, view-sig [:user-posts 1]]
(vs/add-subscription! key view-sig) (vs/add-subscription! key view-sig templates)
(is (vs/subscribed-to? key view-sig)))) (is (vs/subscribed-to? key view-sig))))
(deftest can-use-prefix (deftest can-use-prefix
(let [prefix1 1, prefix2 2, key 1, view-sig [:view 1]] (let [prefix1 1, prefix2 2, key 1, view-sig [:user-posts 1]]
(vs/add-subscription! key view-sig prefix1) (vs/add-subscription! key view-sig templates prefix1)
(vs/add-subscription! key view-sig prefix2) (vs/add-subscription! key view-sig templates prefix2)
(is (vs/subscribed-to? key view-sig prefix1)) (is (vs/subscribed-to? key view-sig prefix1))
(is (vs/subscribed-to? key view-sig prefix2)))) (is (vs/subscribed-to? key view-sig prefix2))))
(deftest removes-a-subscription (deftest removes-a-subscription
(let [key 1, view-sig [:view 1]] (let [key 1, view-sig [:user-posts 1]]
(vs/add-subscription! key view-sig) (vs/add-subscription! key view-sig templates)
(vs/remove-subscription! key view-sig) (vs/remove-subscription! key view-sig)
(is (not (vs/subscribed-to? key view-sig))))) (is (not (vs/subscribed-to? key view-sig)))))
(deftest doesnt-fail-or-create-view-entry-when-empty (deftest doesnt-fail-or-create-view-entry-when-empty
(vs/remove-subscription! 1 [:view 1]) (vs/remove-subscription! 1 [:user-posts 1])
(is (= {} @vs/subscribed-views))) (is (= {} @vs/subscribed-views)))
(deftest removes-a-subscription-with-prefix (deftest removes-a-subscription-with-prefix
(let [prefix1 1, prefix2 2, key 1, view-sig [:view 1]] (let [prefix1 1, prefix2 2, key 1, view-sig [:user-posts 1]]
(vs/add-subscription! key view-sig prefix1) (vs/add-subscription! key view-sig templates prefix1)
(vs/add-subscription! key view-sig prefix2) (vs/add-subscription! key view-sig templates prefix2)
(vs/remove-subscription! key view-sig prefix1) (vs/remove-subscription! key view-sig prefix1)
(is (not (vs/subscribed-to? key view-sig prefix1))) (is (not (vs/subscribed-to? key view-sig prefix1)))
(is (vs/subscribed-to? key view-sig prefix2)))) (is (vs/subscribed-to? key view-sig prefix2))))
(deftest removes-unsubscribed-to-view-from-subscribed-views (deftest removes-unsubscribed-to-view-from-subscribed-views
(let [key 1, view-sig [:view 1]] (let [key 1, view-sig [:user-posts 1]]
(vs/add-subscription! key view-sig) (vs/add-subscription! key view-sig templates)
(vs/remove-subscription! key view-sig) (vs/remove-subscription! key view-sig)
(is (= {} @vs/subscribed-views)))) (is (= {} @vs/subscribed-views))))
(deftest adds-multiple-views-at-a-time (deftest adds-multiple-views-at-a-time
(let [key 1, view-sigs [[:view 1] [:view 2]]] (let [key 1, view-sigs [[:user-posts 1] [:user-posts 2]]]
(vs/add-subscriptions! key view-sigs) (vs/add-subscriptions! key view-sigs templates)
(is (vs/subscribed-to? key (first view-sigs))) (is (vs/subscribed-to? key (first view-sigs)))
(is (vs/subscribed-to? key (last view-sigs))))) (is (vs/subscribed-to? key (last view-sigs)))))
;; (deftest subscribing-compiles-and-stores-view-maps (deftest subscribing-compiles-and-stores-view-maps
;; (let [key 1, view-sig [:view 1]] (let [key 1, view-sig [:user-posts 1]]
;; (vs/add-subscriptions! key view-sigs) (vs/add-subscription! key view-sig templates)
;; (is (vs/subscribed-to? key (first view-sigs))) (is (= (:view (vs/compiled-view-for [:user-posts 1]))
;; (is (vs/subscribed-to? key (last view-sigs))))) (user-posts-tmpl 1)))))
(deftest removing-last-view-sub-removes-compiled-view
(let [key 1, view-sig [:user-posts 1]]
(vs/add-subscription! key view-sig templates)
(vs/remove-subscription! key view-sig)
(is (nil? (vs/compiled-view-for [:user-posts 1])))))