diff options
author | Carlo Zancanaro <carlo@clearboxsystems.com.au> | 2013-05-23 18:26:46 +1000 |
---|---|---|
committer | Carlo Zancanaro <carlo@clearboxsystems.com.au> | 2013-05-23 18:26:46 +1000 |
commit | 5ccaca496f4babb4fef2d34e272b8772e077fa25 (patch) | |
tree | 39503109047318559e806372668bdfc092dbb1a6 /src/clojure_sql/writer.clj | |
parent | 626ab0234ad2e578992d128ced35c2003902e90f (diff) |
Simplify the compiler, better subquery support
The compiler's been simplified a bit by breaking out the `writer` stuff into
its own namespace and by generally making the monadic stuff better. It's all
hidden behind a nice, simple, `clojure-sql.compiler/compile` function now. Call
that and you'll get back what you need. (Internally it's a writer monad which
is really modelled as a state monad with the only operation able to be
performed on the state being `tell`.)
Subqueries are now handled by the DSL in such a way as to not blow up
everything. Subqueries have no support for referencing values in the
superquery, though, so their utility is quite limited at present. Thinking
about how to do subqueries properly may be difficult.
Diffstat (limited to 'src/clojure_sql/writer.clj')
-rw-r--r-- | src/clojure_sql/writer.clj | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/src/clojure_sql/writer.clj b/src/clojure_sql/writer.clj new file mode 100644 index 0000000..5f4250b --- /dev/null +++ b/src/clojure_sql/writer.clj @@ -0,0 +1,69 @@ +(ns clojure-sql.writer + (:refer-clojure :exclude [sequence])) + + +;; A small writer monad implementation, for what we need +(defn return [x] + (fn [s] [x s])) + +(defn bind [mv f] + {:pre [(not (nil? mv))]} + (fn [s] + (let [[x s2] (mv s)] + ((f x) s2)))) + +(defn tell [val] + (fn [s] [nil (conj s val)])) + +(defn join [mv] + (bind mv identity)) + +(defn sequence + ([] (return nil)) + ([mv & mvs] + {:pre [(not (nil? mv))]} + (bind mv + (fn [x] + (bind (apply sequence mvs) + (fn [xs] + (return (cons x xs)))))))) + +(defn lift [f] + (fn [& args] + (bind (apply sequence args) + (fn [s] + (return (apply f s)))))) + +(defn p-lift [f & args] + (lift (apply partial f args))) + +(defn >> + ([arg] + arg) + ([arg1 & args] + (bind arg1 + (fn [x] + (apply >> args))))) + +(defn do-m* + ([] (throw (ex-info "No." {}))) + ([& args] + (or (if (nil? (next args)) + (first args)) + (if (= (first args) :let) + `(let ~(second args) + ~(apply do-m* (nnext args)))) + (if (= (name (second args)) "<-") + (let [[var <- val & others] args] + `(bind ~val + (fn [~var] + ~(apply do-m* others))))) + `(bind ~(first args) + (fn [_#] + ~(apply do-m* (next args))))))) + +(defmacro do-m [& args] + (apply do-m* args)) + +(defmacro do [& args] + (apply do-m* args)) |