diff --git a/src/views/db.clj b/src/views/db.clj index 092e57a..625bf73 100644 --- a/src/views/db.clj +++ b/src/views/db.clj @@ -11,7 +11,7 @@ [clojure.java.jdbc :as j] [clojure.tools.logging :refer [debug]] [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 "Get a primary key for a table." @@ -468,7 +468,7 @@ calculate for them and associated with the hash-maps (appropriately called views-with-deltas)." [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)] (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)] diff --git a/src/views/subscriptions.clj b/src/views/subscriptions.clj index 6c3a458..08960b9 100644 --- a/src/views/subscriptions.clj +++ b/src/views/subscriptions.clj @@ -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 ...}}} @@ -18,20 +20,26 @@ (conj view-subs 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! - ([subscriber-key view-sig] - (swap! subscribed-views #(update-in % [view-sig] (add-subscriber-key subscriber-key)))) - ([subscriber-key view-sig prefix] - (swap! subscribed-views #(update-in % [prefix view-sig] (add-subscriber-key subscriber-key))))) + ([subscriber-key view-sig templates] + (swap! subscribed-views #(update-in % [view-sig] (add-subscriber-key subscriber-key))) + (add-compiled-view! view-sig templates)) + ([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! - ([subscriber-key view-sigs] - (add-subscriptions! subscriber-key view-sigs nil)) - ([subscriber-key view-sigs prefix] + ([subscriber-key view-sigs templates] + (add-subscriptions! subscriber-key view-sigs templates nil)) + ([subscriber-key view-sigs templates prefix] (doseq [vs view-sigs] (if prefix - (add-subscription! subscriber-key vs prefix) - (add-subscription! subscriber-key vs))))) + (add-subscription! subscriber-key vs templates prefix) + (add-subscription! subscriber-key vs templates))))) (defn subscribed-to ([view-sig] @@ -53,9 +61,10 @@ updated (update-in subbed-views path disj subscriber-key)] (if (seq (get-in updated path)) updated - (if prefix - (update-in updated [prefix] dissoc view-sig) - (dissoc updated view-sig)))))) + (do (swap! compiled-views dissoc view-sig) ; remove the compiled view as well + (if prefix + (update-in updated [prefix] dissoc view-sig) + (dissoc updated view-sig))))))) (defn remove-subscription! ([subscriber-key view-sig] @@ -63,3 +72,7 @@ ([subscriber-key view-sig prefix] (when (subscribed-to? subscriber-key view-sig (if prefix prefix)) (swap! subscribed-views (remove-key-or-view subscriber-key view-sig prefix))))) + +(defn compiled-view-for + [view-sig] + (get @compiled-views view-sig)) diff --git a/test/views/db/core_test.clj b/test/views/db/core_test.clj index e379c64..60d5bd4 100644 --- a/test/views/db/core_test.clj +++ b/test/views/db/core_test.clj @@ -2,26 +2,12 @@ (:require [clojure.test :refer [use-fixtures deftest is]] [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] [clojure.string :refer [upper-case]])) (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 [] {[:users] {:view-map ((get-in templates [:users :fn]))}}) diff --git a/test/views/fixtures.clj b/test/views/fixtures.clj index 038028c..64d45fa 100644 --- a/test/views/fixtures.clj +++ b/test/views/fixtures.clj @@ -52,3 +52,17 @@ (dotimes [n n] (user-fixture! (dg/string #(rand-nth (seq "abcdefghijklmnopqrstuwvxyz"))))) (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}}) diff --git a/test/views/subscriptions_test.clj b/test/views/subscriptions_test.clj index 3702b98..b4b1db2 100644 --- a/test/views/subscriptions_test.clj +++ b/test/views/subscriptions_test.clj @@ -1,6 +1,7 @@ (ns views.subscriptions-test (:require [clojure.test :refer [use-fixtures deftest is]] + [views.fixtures :refer [templates user-posts-tmpl]] [views.subscriptions :as vs])) (defn- reset-subscribed-views! @@ -11,49 +12,55 @@ (use-fixtures :each reset-subscribed-views!) (deftest adds-a-subscription - (let [key 1, view-sig [:view 1]] - (vs/add-subscription! key view-sig) + (let [key 1, view-sig [:user-posts 1]] + (vs/add-subscription! key view-sig templates) (is (vs/subscribed-to? key view-sig)))) (deftest can-use-prefix - (let [prefix1 1, prefix2 2, key 1, view-sig [:view 1]] - (vs/add-subscription! key view-sig prefix1) - (vs/add-subscription! key view-sig prefix2) + (let [prefix1 1, prefix2 2, key 1, view-sig [:user-posts 1]] + (vs/add-subscription! key view-sig templates prefix1) + (vs/add-subscription! key view-sig templates prefix2) (is (vs/subscribed-to? key view-sig prefix1)) (is (vs/subscribed-to? key view-sig prefix2)))) (deftest removes-a-subscription - (let [key 1, view-sig [:view 1]] - (vs/add-subscription! key view-sig) + (let [key 1, view-sig [:user-posts 1]] + (vs/add-subscription! key view-sig templates) (vs/remove-subscription! key view-sig) (is (not (vs/subscribed-to? key view-sig))))) (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))) (deftest removes-a-subscription-with-prefix - (let [prefix1 1, prefix2 2, key 1, view-sig [:view 1]] - (vs/add-subscription! key view-sig prefix1) - (vs/add-subscription! key view-sig prefix2) + (let [prefix1 1, prefix2 2, key 1, view-sig [:user-posts 1]] + (vs/add-subscription! key view-sig templates prefix1) + (vs/add-subscription! key view-sig templates prefix2) (vs/remove-subscription! key view-sig prefix1) (is (not (vs/subscribed-to? key view-sig prefix1))) (is (vs/subscribed-to? key view-sig prefix2)))) (deftest removes-unsubscribed-to-view-from-subscribed-views - (let [key 1, view-sig [:view 1]] - (vs/add-subscription! key view-sig) + (let [key 1, view-sig [:user-posts 1]] + (vs/add-subscription! key view-sig templates) (vs/remove-subscription! key view-sig) (is (= {} @vs/subscribed-views)))) (deftest adds-multiple-views-at-a-time - (let [key 1, view-sigs [[:view 1] [:view 2]]] - (vs/add-subscriptions! key view-sigs) + (let [key 1, view-sigs [[:user-posts 1] [:user-posts 2]]] + (vs/add-subscriptions! key view-sigs templates) (is (vs/subscribed-to? key (first view-sigs))) (is (vs/subscribed-to? key (last view-sigs))))) -;; (deftest subscribing-compiles-and-stores-view-maps -;; (let [key 1, view-sig [:view 1]] -;; (vs/add-subscriptions! key view-sigs) -;; (is (vs/subscribed-to? key (first view-sigs))) -;; (is (vs/subscribed-to? key (last view-sigs))))) +(deftest subscribing-compiles-and-stores-view-maps + (let [key 1, view-sig [:user-posts 1]] + (vs/add-subscription! key view-sig templates) + (is (= (:view (vs/compiled-view-for [:user-posts 1])) + (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])))))