2012-07-13 01:50:13 +00:00
|
|
|
# Honey SQL
|
|
|
|
|
|
2012-07-13 13:57:47 +00:00
|
|
|
SQL as Clojure data structures.
|
|
|
|
|
|
|
|
|
|
**Work in progress**
|
2012-07-13 01:50:13 +00:00
|
|
|
|
|
|
|
|
## Usage
|
|
|
|
|
|
2012-07-13 13:57:47 +00:00
|
|
|
```clj
|
2012-07-13 14:53:19 +00:00
|
|
|
(require '[honeysql.core :as sql :refer [select from where limit merge-select
|
|
|
|
|
merge-where]])
|
2012-07-13 13:57:47 +00:00
|
|
|
|
|
|
|
|
;; Everything is centered around maps representing SQL queries
|
|
|
|
|
(def sqlmap {:select [:a :b :c]
|
|
|
|
|
:from [:foo]
|
|
|
|
|
:where [:= :f.a "baz"]})
|
|
|
|
|
|
|
|
|
|
;; format-sql turns maps into clojure.java.jdbc-compatible, parameterized SQL
|
2012-07-13 14:53:19 +00:00
|
|
|
(sql/format sqlmap)
|
2012-07-13 13:57:47 +00:00
|
|
|
=> ["SELECT a, b, c FROM foo WHERE (f.a = ?)" ["baz"]]
|
|
|
|
|
|
|
|
|
|
;; The sql function is a helper for building query maps
|
|
|
|
|
(= sqlmap
|
2012-07-13 14:53:19 +00:00
|
|
|
(sql/sql :select [:a :b :c]
|
|
|
|
|
:from :foo
|
|
|
|
|
:where [:= :f.a "baz"]))
|
2012-07-13 13:57:47 +00:00
|
|
|
=> true
|
|
|
|
|
|
2012-07-13 14:53:19 +00:00
|
|
|
;; You can also use clause-specific helper functions, if you prefer. They
|
|
|
|
|
;; compose together nicely.
|
|
|
|
|
(= sqlmap
|
|
|
|
|
(-> (select :a :b :c)
|
|
|
|
|
(from :foo)
|
|
|
|
|
(where [:= :f.a "baz"])))
|
|
|
|
|
=> true
|
|
|
|
|
|
|
|
|
|
;; Providing a map as the first argument to sql or clause helper functions will
|
|
|
|
|
;; use that map as a base, with the new clauses replacing old ones
|
|
|
|
|
(sql/format (sql/sql sqlmap :select :* :limit 10))
|
|
|
|
|
=> ["SELECT * FROM foo WHERE (f.a = ?) LIMIT 10" ["baz"]]
|
|
|
|
|
(sql/format (-> sqlmap (select :*) (limit 10)))
|
2012-07-13 13:57:47 +00:00
|
|
|
=> ["SELECT * FROM foo WHERE (f.a = ?) LIMIT 10" ["baz"]]
|
|
|
|
|
|
2012-07-13 14:53:19 +00:00
|
|
|
;; To add to clauses instead of replacing them, use merge-sql, or merge-select,
|
|
|
|
|
;; merge-from, etc.
|
|
|
|
|
(sql/format
|
|
|
|
|
(sql/merge-sql sqlmap :select [:d :e] :where [:> :b 10]))
|
|
|
|
|
=> ["SELECT a, b, c, d, e FROM foo WHERE ((f.a = ?) AND (b > 10))" ["baz"]]
|
|
|
|
|
(sql/format
|
|
|
|
|
(-> sqlmap (merge-select :d :e) (merge-where [:> :b 10])))
|
2012-07-13 13:57:47 +00:00
|
|
|
=> ["SELECT a, b, c, d, e FROM foo WHERE ((f.a = ?) AND (b > 10))" ["baz"]]
|
|
|
|
|
|
|
|
|
|
;; Queries can be nested
|
2012-07-13 14:53:19 +00:00
|
|
|
(sql/format
|
|
|
|
|
(sql/sql :select :*
|
|
|
|
|
:from :foo
|
|
|
|
|
:where [:in :foo.a (sql/sql :select :a :from :bar)]))
|
2012-07-13 13:57:47 +00:00
|
|
|
=> ["SELECT * FROM foo WHERE (foo.a IN (SELECT a FROM bar))"]
|
|
|
|
|
|
|
|
|
|
;; There are helper functions and data literals for handling SQL function
|
|
|
|
|
;; calls and raw SQL fragments
|
2012-07-13 14:53:19 +00:00
|
|
|
(sql/sql :select [(sql/call :count :*) (sql/raw "@var := foo.bar")]
|
|
|
|
|
:from :foo)
|
|
|
|
|
=> {:from (:foo), :select (#sql/call [:count :*] #sql/raw "@var := foo.bar")}
|
2012-07-13 13:57:47 +00:00
|
|
|
|
2012-07-13 14:53:19 +00:00
|
|
|
(sql/format *1)
|
2012-07-13 13:57:47 +00:00
|
|
|
=> ["SELECT COUNT(*), @var := foo.bar FROM foo"]
|
|
|
|
|
```
|
2012-07-13 01:50:13 +00:00
|
|
|
|
|
|
|
|
## License
|
|
|
|
|
|
|
|
|
|
Copyright © 2012 Justin Kramer
|
|
|
|
|
|
|
|
|
|
Distributed under the Eclipse Public License, the same as Clojure.
|