Mercurial > lasercutter
view src/clojure/contrib/sql.clj @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
line wrap: on
line source
1 ;; Copyright (c) Stephen C. Gilardi. All rights reserved. The use and2 ;; distribution terms for this software are covered by the Eclipse Public3 ;; License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which can4 ;; be found in the file epl-v10.html at the root of this distribution. By5 ;; using this software in any fashion, you are agreeing to be bound by the6 ;; terms of this license. You must not remove this notice, or any other,7 ;; from this software.8 ;;9 ;; sql.clj10 ;;11 ;; A Clojure interface to sql databases via jdbc12 ;;13 ;; See clojure.contrib.sql.test for an example14 ;;15 ;; scgilardi (gmail)16 ;; Created 2 April 200818 (ns19 ^{:author "Stephen C. Gilardi",20 :doc "A Clojure interface to sql databases via jdbc."21 :see-also [["http://github.com/richhickey/clojure-contrib/blob/master/src/test/clojure/clojure/contrib/test_sql.clj"22 "Example code"]]}23 clojure.contrib.sql24 (:use (clojure.contrib25 [def :only (defalias)]26 [string :only (as-str)])27 clojure.contrib.sql.internal))29 (defalias find-connection find-connection*)30 (defalias connection connection*)32 (defmacro with-connection33 "Evaluates body in the context of a new connection to a database then34 closes the connection. db-spec is a map containing values for one of the35 following parameter sets:37 Factory:38 :factory (required) a function of one argument, a map of params39 (others) (optional) passed to the factory function in a map41 DriverManager:42 :classname (required) a String, the jdbc driver class name43 :subprotocol (required) a String, the jdbc subprotocol44 :subname (required) a String, the jdbc subname45 (others) (optional) passed to the driver as properties.47 DataSource:48 :datasource (required) a javax.sql.DataSource49 :username (optional) a String50 :password (optional) a String, required if :username is supplied52 JNDI:53 :name (required) a String or javax.naming.Name54 :environment (optional) a java.util.Map"55 [db-spec & body]56 `(with-connection* ~db-spec (fn [] ~@body)))58 (defmacro transaction59 "Evaluates body as a transaction on the open database connection. Any60 nested transactions are absorbed into the outermost transaction. By61 default, all database updates are committed together as a group after62 evaluating the outermost body, or rolled back on any uncaught63 exception. If set-rollback-only is called within scope of the outermost64 transaction, the entire transaction will be rolled back rather than65 committed when complete."66 [& body]67 `(transaction* (fn [] ~@body)))69 (defn set-rollback-only70 "Marks the outermost transaction such that it will rollback rather than71 commit when complete"72 []73 (rollback true))75 (defn is-rollback-only76 "Returns true if the outermost transaction will rollback rather than77 commit when complete"78 []79 (rollback))81 (defn do-commands82 "Executes SQL commands on the open database connection."83 [& commands]84 (with-open [stmt (.createStatement (connection))]85 (doseq [cmd commands]86 (.addBatch stmt cmd))87 (transaction88 (seq (.executeBatch stmt)))))90 (defn do-prepared91 "Executes an (optionally parameterized) SQL prepared statement on the92 open database connection. Each param-group is a seq of values for all of93 the parameters."94 [sql & param-groups]95 (with-open [stmt (.prepareStatement (connection) sql)]96 (doseq [param-group param-groups]97 (doseq [[index value] (map vector (iterate inc 1) param-group)]98 (.setObject stmt index value))99 (.addBatch stmt))100 (transaction101 (seq (.executeBatch stmt)))))103 (defn create-table104 "Creates a table on the open database connection given a table name and105 specs. Each spec is either a column spec: a vector containing a column106 name and optionally a type and other constraints, or a table-level107 constraint: a vector containing words that express the constraint. All108 words used to describe the table may be supplied as strings or keywords."109 [name & specs]110 (do-commands111 (format "CREATE TABLE %s (%s)"112 (as-str name)113 (apply str114 (map as-str115 (apply concat116 (interpose [", "]117 (map (partial interpose " ") specs))))))))119 (defn drop-table120 "Drops a table on the open database connection given its name, a string121 or keyword"122 [name]123 (do-commands124 (format "DROP TABLE %s" (as-str name))))126 (defn insert-values127 "Inserts rows into a table with values for specified columns only.128 column-names is a vector of strings or keywords identifying columns. Each129 value-group is a vector containing a values for each column in130 order. When inserting complete rows (all columns), consider using131 insert-rows instead."132 [table column-names & value-groups]133 (let [column-strs (map as-str column-names)134 n (count (first value-groups))135 template (apply str (interpose "," (replicate n "?")))136 columns (if (seq column-names)137 (format "(%s)" (apply str (interpose "," column-strs)))138 "")]139 (apply do-prepared140 (format "INSERT INTO %s %s VALUES (%s)"141 (as-str table) columns template)142 value-groups)))144 (defn insert-rows145 "Inserts complete rows into a table. Each row is a vector of values for146 each of the table's columns in order."147 [table & rows]148 (apply insert-values table nil rows))150 (defn insert-records151 "Inserts records into a table. records are maps from strings or152 keywords (identifying columns) to values."153 [table & records]154 (doseq [record records]155 (insert-values table (keys record) (vals record))))157 (defn delete-rows158 "Deletes rows from a table. where-params is a vector containing a string159 providing the (optionally parameterized) selection criteria followed by160 values for any parameters."161 [table where-params]162 (let [[where & params] where-params]163 (do-prepared164 (format "DELETE FROM %s WHERE %s"165 (as-str table) where)166 params)))168 (defn update-values169 "Updates values on selected rows in a table. where-params is a vector170 containing a string providing the (optionally parameterized) selection171 criteria followed by values for any parameters. record is a map from172 strings or keywords (identifying columns) to updated values."173 [table where-params record]174 (let [[where & params] where-params175 column-strs (map as-str (keys record))176 columns (apply str (concat (interpose "=?, " column-strs) "=?"))]177 (do-prepared178 (format "UPDATE %s SET %s WHERE %s"179 (as-str table) columns where)180 (concat (vals record) params))))182 (defn update-or-insert-values183 "Updates values on selected rows in a table, or inserts a new row when no184 existing row matches the selection criteria. where-params is a vector185 containing a string providing the (optionally parameterized) selection186 criteria followed by values for any parameters. record is a map from187 strings or keywords (identifying columns) to updated values."188 [table where-params record]189 (transaction190 (let [result (update-values table where-params record)]191 (if (zero? (first result))192 (insert-values table (keys record) (vals record))193 result))))195 (defmacro with-query-results196 "Executes a query, then evaluates body with results bound to a seq of the197 results. sql-params is a vector containing a string providing198 the (optionally parameterized) SQL query followed by values for any199 parameters."200 [results sql-params & body]201 `(with-query-results* ~sql-params (fn [~results] ~@body)))