Basic infrastructure working.
This commit is contained in:
parent
6d7ae24a3e
commit
afb4b91103
26
README.md
26
README.md
|
@ -1,6 +1,9 @@
|
||||||
# views
|
# 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
|
## Design
|
||||||
|
|
||||||
|
@ -12,28 +15,11 @@ TODO
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
You will need to set up the test db to run the tests:
|
TODO
|
||||||
|
|
||||||
```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
|
|
||||||
```
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Copyright © 2014 DiligenceEngine
|
Copyright © 2015 DiligenceEngine
|
||||||
|
|
||||||
Authors Dave Della Costa (https://github.com/ddellacosta) and Alexander Hudek (https://github.com/akhudek)
|
Authors Dave Della Costa (https://github.com/ddellacosta) and Alexander Hudek (https://github.com/akhudek)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
(defproject views "1.0.0"
|
(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"
|
:url "https://github.com/diligenceengine/views"
|
||||||
|
|
||||||
|
@ -9,10 +9,7 @@
|
||||||
:dependencies [[org.clojure/clojure "1.6.0"]
|
:dependencies [[org.clojure/clojure "1.6.0"]
|
||||||
[org.clojure/tools.logging "0.2.6"]
|
[org.clojure/tools.logging "0.2.6"]
|
||||||
[org.clojure/core.async "0.1.303.0-886421-alpha"]
|
[org.clojure/core.async "0.1.303.0-886421-alpha"]
|
||||||
[org.clojure/java.jdbc "0.3.3"]
|
|
||||||
[honeysql "0.4.3"]
|
[honeysql "0.4.3"]
|
||||||
[edl "0.1.0"]
|
|
||||||
[org.postgresql/postgresql "9.2-1003-jdbc4"]
|
|
||||||
[clj-logging-config "1.9.10"]
|
[clj-logging-config "1.9.10"]
|
||||||
[zip-visit "1.0.2"]
|
[zip-visit "1.0.2"]
|
||||||
[prismatic/plumbing "0.3.5"]
|
[prismatic/plumbing "0.3.5"]
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
(ns views.core
|
(ns views.core
|
||||||
(:require
|
(:require
|
||||||
[views.protocols :refer [IView id data relevant?]]
|
[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:
|
;; The view-system data structure has this shape:
|
||||||
;;
|
;;
|
||||||
|
@ -27,9 +28,9 @@
|
||||||
(defn subscribe!
|
(defn subscribe!
|
||||||
[view-system namespace view-id parameters subscriber-key]
|
[view-system namespace view-id parameters subscriber-key]
|
||||||
(if-let [view (get-in @view-system [:views view-id])]
|
(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))
|
(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
|
(defn remove-from-subscribers
|
||||||
[view-system view-sig subscriber-key]
|
[view-system view-sig subscriber-key]
|
||||||
|
@ -61,7 +62,7 @@
|
||||||
hdata (hash vdata)]
|
hdata (hash vdata)]
|
||||||
(when-not (= hdata (get-in @view-system [:hashes view-sig]))
|
(when-not (= hdata (get-in @view-system [:hashes view-sig]))
|
||||||
(doseq [s (get-in @view-system [:subscribers 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))))))
|
(swap! view-system assoc-in [:hashes view-sig] hdata))))))
|
||||||
|
|
||||||
(defn subscribed-views
|
(defn subscribed-views
|
||||||
|
@ -78,6 +79,7 @@
|
||||||
"Given a collection of hints, find all dirty views."
|
"Given a collection of hints, find all dirty views."
|
||||||
[view-system]
|
[view-system]
|
||||||
(let [hints (pop-hints! view-system)]
|
(let [hints (pop-hints! view-system)]
|
||||||
|
(debug "refresh hints:" hints)
|
||||||
(mapv #(refresh-view! view-system hints %) (subscribed-views @view-system))
|
(mapv #(refresh-view! view-system hints %) (subscribed-views @view-system))
|
||||||
(swap! view-system assoc :last-update (System/currentTimeMillis))))
|
(swap! view-system assoc :last-update (System/currentTimeMillis))))
|
||||||
|
|
||||||
|
@ -89,19 +91,30 @@
|
||||||
[last-update min-refresh-interval]
|
[last-update min-refresh-interval]
|
||||||
(Thread/sleep (max 0 (- min-refresh-interval (- (System/currentTimeMillis) last-update)))))
|
(Thread/sleep (max 0 (- min-refresh-interval (- (System/currentTimeMillis) last-update)))))
|
||||||
|
|
||||||
(defn start-update-watcher!
|
(defn update-watcher!
|
||||||
"A single threaded view update mechanism."
|
"A single threaded view update mechanism."
|
||||||
[view-system min-refresh-interval]
|
[view-system min-refresh-interval]
|
||||||
(swap! view-system assoc :last-update 0)
|
(swap! view-system assoc :last-update 0)
|
||||||
(.start (Thread. (fn [] (let [last-update (:last-update @view-system)]
|
(.start (Thread. (fn [] (let [last-update (:last-update @view-system)]
|
||||||
(if (can-refresh? last-update min-refresh-interval)
|
(if (can-refresh? last-update min-refresh-interval)
|
||||||
(do (refresh-views! view-system) (recur))
|
(refresh-views! view-system)
|
||||||
(do (wait last-update min-refresh-interval) (recur))))))))
|
(wait last-update min-refresh-interval))
|
||||||
|
(recur))))))
|
||||||
|
|
||||||
|
(defn hint
|
||||||
|
"Create a hint."
|
||||||
|
[namespace hint]
|
||||||
|
{:namespace namespace :hint hint})
|
||||||
|
|
||||||
(defn add-hint!
|
(defn add-hint!
|
||||||
"Add a hint to the system."
|
"Add a hint to the system."
|
||||||
[view-system namespace hint]
|
[view-system hint]
|
||||||
(swap! view-system update-in [:hints] (fnil conj #{}) {:namespace namespace :hint 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
|
(comment
|
||||||
(defrecord SQLView [id query-fn]
|
(defrecord SQLView [id query-fn]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
(ns views.honey-sql.util
|
(ns views.honeysql.util
|
||||||
(:require
|
(:require
|
||||||
[honeysql.core :as hsql]
|
[honeysql.core :as hsql]
|
||||||
[honeysql.helpers :as hh]
|
[honeysql.helpers :as hh]
|
Loading…
Reference in a new issue