diff options
author | scgilardi <scgilardi@gmail.com> | 2008-07-22 06:23:10 +0000 |
---|---|---|
committer | scgilardi <scgilardi@gmail.com> | 2008-07-22 06:23:10 +0000 |
commit | d2cfb3ff67a2ca4774928664758a5f8880cf285c (patch) | |
tree | 5b77c03fce628fae5bec41e8520a882690a55424 | |
parent | 40aae31f03c00834cd4d356f829eb7fb0e7e9215 (diff) |
provide namespace directories and contents for def and sql
-rw-r--r-- | def/def.clj | 74 | ||||
-rw-r--r-- | sql/sql.clj | 126 |
2 files changed, 200 insertions, 0 deletions
diff --git a/def/def.clj b/def/def.clj new file mode 100644 index 00000000..1708eb94 --- /dev/null +++ b/def/def.clj @@ -0,0 +1,74 @@ +;; Copyright (c) Stephen C. Gilardi. All rights reserved. +;; The use and distribution terms for this software are covered by the +;; Common Public License 1.0 (http://opensource.org/licenses/cpl.php) +;; which can be found in the file CPL.TXT at the root of this distribution. +;; By using this software in any fashion, you are agreeing to be bound by +;; the terms of this license. +;; You must not remove this notice, or any other, from this software. +;; +;; File: def.clj +;; +;; def.clj provides variants of def that make including doc strings and +;; making private definitions more succinct. +;; +;; scgilardi (gmail) +;; 17 May 2008 + +(clojure/in-ns 'clojure-contrib.def) +(clojure/refer 'clojure) + +(defmacro init-once + "Initializes a var exactly once. The var must already exist." + [var init] + `(let [v# (resolve '~var)] + (when-not (.isBound v#) + (.bindRoot v# ~init)))) + +(defmacro defvar + "Defines a var with an optional intializer and doc string" + ([name] + (list `def name)) + ([name init] + (list `def name init)) + ([name init doc] + (list `def (with-meta name (assoc (meta name) :doc doc)) init))) + +(defmacro defunbound + "Defines an unbound var with optional doc string" + ([name] + (list `def name)) + ([name doc] + (list `def (with-meta name (assoc (meta name) :doc doc))))) + +(defmacro defmacro- + "Same as defmacro but yields a private definition" + [name & decls] + (list* `defmacro (with-meta name (assoc (meta name) :private true)) decls)) + +(defmacro defvar- + "Same as defvar but yields a private definition" + [name & decls] + (list* `defvar (with-meta name (assoc (meta name) :private true)) decls)) + +(defmacro defunbound- + "Same as defunbound but yields a private definition" + [name & decls] + (list* `defunbound (with-meta name (assoc (meta name) :private true)) decls)) + +(defmacro defstruct- + "Same as defstruct but yields a private definition" + [name & decls] + (list* `defstruct (with-meta name (assoc (meta name) :private true)) decls)) + +(defmacro defalias + "Defines an alias for a var: a new var with the same value and metadata + as another with the exception of :namespace, :name, :file, :line, and + optionally :doc which are those of new var." + ([name orig] + `(let [v# (def ~name ~orig)] + (. v# (setMeta (merge (meta #'~orig) (meta #'~name)))) + v#)) + ([name orig doc] + `(let [v# (def ~name ~orig)] + (. v# (setMeta (merge (meta #'~orig) (assoc (meta #'~name) :doc ~doc)))) + v#))) diff --git a/sql/sql.clj b/sql/sql.clj new file mode 100644 index 00000000..6b32efd6 --- /dev/null +++ b/sql/sql.clj @@ -0,0 +1,126 @@ +;; Copyright (c) Stephen C. Gilardi. All rights reserved. +;; The use and distribution terms for this software are covered by the +;; Common Public License 1.0 (http://opensource.org/licenses/cpl.php) +;; which can be found in the file CPL.TXT at the root of this distribution. +;; By using this software in any fashion, you are agreeing to be bound by +;; the terms of this license. +;; You must not remove this notice, or any other, from this software. +;; +;; sql.clj +;; +;; A Clojure interface to sql databases via jdbc +;; +;; scgilardi (gmail) +;; 23 April 2008 + +(clojure/in-ns 'clojure-contrib.sql) +(clojure/refer 'clojure) + +(import '(java.sql DriverManager Connection PreparedStatement ResultSet)) + +(defn get-connection + "Attempts to get a connection to a database via a jdbc URL" + [subprotocol db-name] + (let [url (str "jdbc:" subprotocol ":" db-name)] + (.getConnection DriverManager url))) + +(defmacro with-connection + "Evaluates body in the context of a connection to a database. Any updates + are committed as one transaction after evaluating body or rolled back on + any uncaught exception." + [con init & body] + `(with-open ~con ~init + (try + (.setAutoCommit ~con false)) + ~@body + (.commit ~con) + (catch Exception e# + (.rollback ~con) + (throw (Exception. "transaction rolled back" e#))))) + +(defn execute-commands + "Executes a sequence of SQL commands that do not return results" + [con commands] + (with-open stmt (.createStatement con) + (doseq cmd commands + (.addBatch stmt cmd)) + (.executeBatch stmt))) + +(defn execute-prepared-statement + "Executes a prepared statement with a sequence of parameter sets" + [con sql sets] + (with-open stmt (.prepareStatement con sql) + (doseq set sets + (doseq [index value] (map vector (iterate inc 1) set) + (.setObject stmt index value)) + (.addBatch stmt )) + (.executeBatch stmt))) + +(defmacro with-query-results + "Executes a query and then evaluates body repeatedly with rec bound to + each of the generated results in turn" + [rec con sql & body] + `(with-open stmt# (.prepareStatement ~con ~sql) + (with-open rset# (.executeQuery stmt#) + (doseq ~rec (resultset-seq rset#) + ~@body)))) + +(comment + + ;; Examples + + ;; Simple tests of sql.clj using derby as a JDBC provider. + ;; + ;; Substituting a different database should only affect the definition + ;; of 'db' below (and perhaps suggest the need for more variations of + ;; get-connection). + +(clojure/in-ns 'sql-test) +(clojure/refer 'clojure) + +(lib/use sql) + +(.forName Class "org.apache.derby.jdbc.EmbeddedDriver") + +(defn db [] + (get-connection "derby" "/tmp/test-derby.db;create=true")) + +(defn db-drop [] + (with-connection con (db) + (try + (execute-commands con + ["drop table fruit"]) + (catch Exception e)))) + +(defn db-write [] + (db-drop) + (with-connection con (db) + (execute-commands con + ["create table fruit (name varchar(32), appearance varchar(32), cost int, grade real)"]) + (execute-prepared-statement con + "insert into fruit values (?, ?, ?, ?)" + [["Apple" "red" 59 87] + ["Banana" "yellow" 29 92.2] + ["Peach" "fuzzy" 139 90.0] + ["Orange" "juicy" 89 88.6]]))) + +(defn db-read [] + (with-connection con (db) + (with-query-results rec con + "select * from fruit" + (println rec)))) + +(defn db-grade-a [] + (with-connection con (db) + (with-query-results rec con + "select name, cost from fruit where grade >= 90" + (println rec)))) + +(defn db-exception [] + (with-connection con (db) + (execute-prepared-statement con + "insert into fruit (name, appearance) values (?, ?)" + [["Grape" "yummy"] + ["Pear" "bruised"]]) + (throw (Exception. "an exception")))) +) |