Initial commit.
This commit is contained in:
parent
4e5ee99d36
commit
abc65cec79
13
.gitignore
vendored
Normal file
13
.gitignore
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
/target
|
||||
/classes
|
||||
/checkouts
|
||||
pom.xml
|
||||
pom.xml.asc
|
||||
*.jar
|
||||
*.class
|
||||
/.lein-*
|
||||
/.nrepl-port
|
||||
.hgignore
|
||||
.hg/
|
||||
.idea
|
||||
*.iml
|
13
project.clj
13
project.clj
|
@ -1,6 +1,11 @@
|
|||
(defproject views-honeysql "0.1.0-SNAPSHOT"
|
||||
(defproject views/honeysql "0.1.0-SNAPSHOT"
|
||||
:description "FIXME: write description"
|
||||
:url "http://example.com/FIXME"
|
||||
:license {:name "Eclipse Public License"
|
||||
:url "http://www.eclipse.org/legal/epl-v10.html"}
|
||||
:dependencies [[org.clojure/clojure "1.6.0"]])
|
||||
:license {:name "MIT License"
|
||||
:url "http://opensource.org/licenses/MIT"}
|
||||
:dependencies [[views "1.4.0-SNAPSHOT"]
|
||||
[honeysql "0.5.2"]
|
||||
[org.clojure/java.jdbc "0.3.6"]
|
||||
[org.clojure/tools.logging "0.3.1"]]
|
||||
:profiles {:dev {:dependencies
|
||||
[[org.clojure/clojure "1.6.0"]]}})
|
||||
|
|
45
src/views/honeysql/core.clj
Normal file
45
src/views/honeysql/core.clj
Normal file
|
@ -0,0 +1,45 @@
|
|||
(ns views.honeysql.core
|
||||
(:require
|
||||
[views.core :refer [hint]]
|
||||
[views.honeysql.util :refer [query-tables]]
|
||||
[honeysql.core :as hsql]
|
||||
[clojure.tools.logging :refer [error]]
|
||||
[clojure.java.jdbc :as j]))
|
||||
|
||||
(def send-hints! (atom (fn [hints] (error "send-hints! not configured"))))
|
||||
|
||||
(defmacro with-view-transaction
|
||||
"Like with-db-transaction, but sends view hints at end of transaction."
|
||||
[binding & forms]
|
||||
(let [tvar (first binding), db (second binding), args (drop 2 binding)]
|
||||
`(if (:hints ~db) ;; check if we are in a nested transaction
|
||||
(let [~tvar ~db] ~@forms)
|
||||
(let [hints# (atom [])
|
||||
result# (j/with-db-transaction [t# ~db ~@args]
|
||||
(let [~tvar (assoc ~db :hints hints#)]
|
||||
~@forms))]
|
||||
(@send-hints! @hints#)
|
||||
result#))))
|
||||
|
||||
(defn execute-honeysql!
|
||||
"Always return keys for inserts."
|
||||
[db hsql-map]
|
||||
(if-let [table (:insert-into hsql-map)]
|
||||
(if (vector? table)
|
||||
(j/execute! db (hsql/format hsql-map))
|
||||
(apply j/insert! db table (:values hsql-map)))
|
||||
(j/execute! db (hsql/format hsql-map))))
|
||||
|
||||
(defn vexec!
|
||||
"Used to perform arbitrary insert/update/delete actions on the database,
|
||||
while ensuring that view hints are sent to the view system.
|
||||
Arguments are:
|
||||
- db: a clojure.java.jdbc database with fid field
|
||||
- action-map: the HoneySQL map for the insert/update/delete action"
|
||||
[db action-map]
|
||||
(let [results (execute-honeysql! db action-map)
|
||||
hsql-hint (hint :views/honeysql (query-tables action-map))]
|
||||
(if-let [hints (:hints db)]
|
||||
(swap! hints conj hsql-hint)
|
||||
(send-hints! [hsql-hint]))
|
||||
results))
|
78
src/views/honeysql/util.clj
Normal file
78
src/views/honeysql/util.clj
Normal file
|
@ -0,0 +1,78 @@
|
|||
(ns views.honeysql.util
|
||||
(:require
|
||||
[honeysql.core :as hsql]
|
||||
[honeysql.helpers :as hh]
|
||||
[clojure.string :refer [split]]))
|
||||
;; The following is used for full refresh views where we can have CTEs and
|
||||
;; subselects in play.
|
||||
|
||||
(declare query-tables)
|
||||
|
||||
(defn- first-leaf
|
||||
"Retrieves the first leaf in a collection of collections
|
||||
|
||||
(first-leaf :table) -> :table
|
||||
(first-leaf [[:table] [& values]]) -> :table"
|
||||
[v]
|
||||
(if (coll? v) (recur (first v)) v))
|
||||
|
||||
(defn cte-tables
|
||||
[query]
|
||||
(mapcat #(query-tables (second %)) (:with query)))
|
||||
|
||||
(defn isolate-tables
|
||||
"Isolates tables from table definitions in from and join clauses."
|
||||
[c]
|
||||
(if (keyword? c) [c] (let [v (first c)] (if (map? v) (query-tables v) [v]))))
|
||||
|
||||
(defn from-tables
|
||||
[query]
|
||||
(mapcat isolate-tables (:from query)))
|
||||
|
||||
(defn every-second
|
||||
[coll]
|
||||
(map first (partition 2 coll)))
|
||||
|
||||
(defn join-tables
|
||||
[query k]
|
||||
(mapcat isolate-tables (every-second (k query))))
|
||||
|
||||
(defn collect-maps
|
||||
[wc]
|
||||
(cond
|
||||
(coll? wc) (let [maps (filterv map? wc)
|
||||
colls (filter #(and (coll? %) (not (map? %))) wc)]
|
||||
(into maps (mapcat collect-maps colls)))
|
||||
(map? wc) [wc]
|
||||
:else []))
|
||||
|
||||
(defn where-tables
|
||||
"This search for subqueries in the where clause."
|
||||
[query]
|
||||
(mapcat query-tables (collect-maps (:where query))))
|
||||
|
||||
(defn insert-tables
|
||||
[query]
|
||||
(some->> query :insert-into first-leaf vector))
|
||||
|
||||
(defn update-tables
|
||||
[query]
|
||||
(if-let [v (:update query)] [v] []))
|
||||
|
||||
(defn delete-tables
|
||||
[query]
|
||||
(if-let [v (:delete-from query)] [v] []))
|
||||
|
||||
(defn query-tables
|
||||
"Return all the tables in an sql statement."
|
||||
[query]
|
||||
(set (concat
|
||||
(cte-tables query)
|
||||
(from-tables query)
|
||||
(join-tables query :join)
|
||||
(join-tables query :left-join)
|
||||
(join-tables query :right-join)
|
||||
(where-tables query)
|
||||
(insert-tables query)
|
||||
(update-tables query)
|
||||
(delete-tables query))))
|
27
src/views/honeysql/view.clj
Normal file
27
src/views/honeysql/view.clj
Normal file
|
@ -0,0 +1,27 @@
|
|||
(ns views.honeysql.view
|
||||
(:require
|
||||
[views.protocols :refer :all]
|
||||
[views.honeysql.util :refer [query-tables]]
|
||||
[honeysql.core :as hsql]
|
||||
[clojure.set :refer [intersection]]
|
||||
[clojure.java.jdbc :as j]
|
||||
[clojure.tools.logging :refer [warn]]))
|
||||
|
||||
(defrecord HSQLView [id db query-fn post-fn]
|
||||
IView
|
||||
(id [_] id)
|
||||
(data [_ namespace parameters]
|
||||
(let [start (System/currentTimeMillis)
|
||||
data (j/query db (hsql/format (apply query-fn parameters)) :row-fn post-fn)
|
||||
time (- (System/currentTimeMillis) start)]
|
||||
(when (>= time 1000) (warn id "took" time "msecs"))
|
||||
data))
|
||||
(relevant? [_ namespace parameters hints]
|
||||
(let [tables (query-tables (apply query-fn parameters))
|
||||
nhints (filter #(= :views/honeysql (:namespace %)) hints)]
|
||||
(boolean (some #(not-empty (intersection (:hint %) tables)) nhints)))))
|
||||
|
||||
(defn view
|
||||
"Creates a Honey SQL view that uses a jdbc database configuration"
|
||||
([id db hsql-fn post-fn] (HSQLView. id db hsql-fn post-fn))
|
||||
([id db hsql-fn] (view id db hsql-fn identity)))
|
|
@ -1,6 +0,0 @@
|
|||
(ns views-honeysql.core)
|
||||
|
||||
(defn foo
|
||||
"I don't do a whole lot."
|
||||
[x]
|
||||
(println x "Hello, World!"))
|
Loading…
Reference in a new issue