diff --git a/README.md b/README.md index 53d3d3d..82ec07c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ # views -Eventually consistent external materialized views for SQL databases. +Eventually consistent external materialized views. + +*Notice: despite being 1.x.x, this is incomplete. Version 2.0.0 will be + the first release version.* ## Design @@ -12,28 +15,11 @@ TODO ## Testing -You will need to set up the test db to run the tests: - -```bash -$ psql -Upostgres < test/views/test_db.sql -CREATE ROLE -CREATE DATABASE -$ -``` - -This will create a role `views_user` and a database owned by that user called `views_test`. - -(You can change the database settings if you'd like by editing that file and checking the config in `test/views/fixtures.clj`.) - -Then, to run all tests: - -```bash -$ lein with-profile test test -``` +TODO ## License -Copyright © 2014 DiligenceEngine +Copyright © 2015 DiligenceEngine Authors Dave Della Costa (https://github.com/ddellacosta) and Alexander Hudek (https://github.com/akhudek) diff --git a/project.clj b/project.clj index f59a7fb..b038991 100644 --- a/project.clj +++ b/project.clj @@ -1,5 +1,5 @@ (defproject views "1.0.0" - :description "You underestimate the power of the SQL side" + :description "A view to the past helps navigate the future." :url "https://github.com/diligenceengine/views" @@ -9,10 +9,7 @@ :dependencies [[org.clojure/clojure "1.6.0"] [org.clojure/tools.logging "0.2.6"] [org.clojure/core.async "0.1.303.0-886421-alpha"] - [org.clojure/java.jdbc "0.3.3"] [honeysql "0.4.3"] - [edl "0.1.0"] - [org.postgresql/postgresql "9.2-1003-jdbc4"] [clj-logging-config "1.9.10"] [zip-visit "1.0.2"] [prismatic/plumbing "0.3.5"] diff --git a/src/views/core.clj b/src/views/core.clj index 06d8995..0b3578a 100644 --- a/src/views/core.clj +++ b/src/views/core.clj @@ -1,7 +1,8 @@ (ns views.core (:require [views.protocols :refer [IView id data relevant?]] - [plumbing.core :refer [swap-pair!]])) + [plumbing.core :refer [swap-pair!]] + [clojure.tools.logging :refer [debug]])) ;; The view-system data structure has this shape: ;; @@ -27,9 +28,9 @@ (defn subscribe! [view-system namespace view-id parameters subscriber-key] (if-let [view (get-in @view-system [:views view-id])] - (let [vdata (data view namespace parameters)] + (let [vdata (data view namespace parameters)] (swap! view-system subscribe-view! [namespace view-id parameters] subscriber-key (hash vdata)) - ((get @view-system :send-fn) subscriber-key vdata)))) + ((get @view-system :send-fn) subscriber-key [[view-id parameters] vdata])))) (defn remove-from-subscribers [view-system view-sig subscriber-key] @@ -61,7 +62,7 @@ hdata (hash vdata)] (when-not (= hdata (get-in @view-system [:hashes view-sig])) (doseq [s (get-in @view-system [:subscribers view-sig])] - ((:send-fn @view-system) s vdata)) + ((:send-fn @view-system) s [[view-id parameters] vdata])) (swap! view-system assoc-in [:hashes view-sig] hdata)))))) (defn subscribed-views @@ -78,6 +79,7 @@ "Given a collection of hints, find all dirty views." [view-system] (let [hints (pop-hints! view-system)] + (debug "refresh hints:" hints) (mapv #(refresh-view! view-system hints %) (subscribed-views @view-system)) (swap! view-system assoc :last-update (System/currentTimeMillis)))) @@ -89,19 +91,30 @@ [last-update min-refresh-interval] (Thread/sleep (max 0 (- min-refresh-interval (- (System/currentTimeMillis) last-update))))) -(defn start-update-watcher! +(defn update-watcher! "A single threaded view update mechanism." [view-system min-refresh-interval] (swap! view-system assoc :last-update 0) - (.start (Thread. (fn [] (let [last-update (:last-update @view-system)] - (if (can-refresh? last-update min-refresh-interval) - (do (refresh-views! view-system) (recur)) - (do (wait last-update min-refresh-interval) (recur)))))))) + (.start (Thread. (fn [] (let [last-update (:last-update @view-system)] + (if (can-refresh? last-update min-refresh-interval) + (refresh-views! view-system) + (wait last-update min-refresh-interval)) + (recur)))))) + +(defn hint + "Create a hint." + [namespace hint] + {:namespace namespace :hint hint}) (defn add-hint! "Add a hint to the system." - [view-system namespace hint] - (swap! view-system update-in [:hints] (fnil conj #{}) {:namespace namespace :hint hint})) + [view-system hint] + (swap! view-system update-in [:hints] (fnil conj #{}) hint)) + +(defn add-views! + "Add a collection of views to the system." + [view-system views] + (swap! view-system update-in [:views] (fnil into {}) (map vector (map id views) views))) (comment (defrecord SQLView [id query-fn] diff --git a/src/views/honey_sql/util.clj b/src/views/honeysql/util.clj similarity index 98% rename from src/views/honey_sql/util.clj rename to src/views/honeysql/util.clj index 4d3a285..def464b 100644 --- a/src/views/honey_sql/util.clj +++ b/src/views/honeysql/util.clj @@ -1,4 +1,4 @@ -(ns views.honey-sql.util +(ns views.honeysql.util (:require [honeysql.core :as hsql] [honeysql.helpers :as hh]