lobos1.0.0-SNAPSHOTA library to create and manipulate SQL database schemas. dependencies
dev dependencies
| (this space intentionally left almost blank) | ||||||||||||||||||||||||
The To find out more about Lobos, check out: | (ns lobos.core {:author "Nicolas Buduroi"} (:refer-clojure :exclude [alter defonce drop]) (:require (lobos [compiler :as compiler] [connectivity :as conn] [migration :as mig] [schema :as schema])) (:use (clojure.tools [macro :only [name-with-attributes]]) (clojure [pprint :only [pprint]]) lobos.internal lobos.utils)) | ||||||||||||||||||||||||
Helpers | |||||||||||||||||||||||||
(defmacro without-migration [& body] `(binding [mig/*record* nil] ~@body)) | |||||||||||||||||||||||||
Debugging Interface | |||||||||||||||||||||||||
Set the current debugging level. The level argument can be one of
| (defn set-debug-level [level] (swap! debug-level (constantly level))) | ||||||||||||||||||||||||
Prints useful information on the given combination protocol method
and schema (or elements). For the available methods, see the
| (defn debug [method object-or-fn & [args connection-info level]] (let [level (or level @debug-level :sql) object (if (fn? object-or-fn) (object-or-fn) object-or-fn) db-spec (conn/get-db-spec connection-info) ast (when-not (= :schema level) (apply method object (conj args db-spec)))] (case level :sql (println (compiler/compile ast)) :ast (do (println (type ast)) (pprint ast)) :schema (do (println (type object)) (pprint object))))) | ||||||||||||||||||||||||
Lobos Action | |||||||||||||||||||||||||
Action Macro | |||||||||||||||||||||||||
Defines an action applicable to an optional abstract schema or
database connection. Actions are simply a special kind of
functions. They will have an augmented argument list, which is the
given one prepended by the optional All actions must return a built statement (or list of statements) using one of the protocol method available. The defined actions will have access to two extra local variables. The
| (defmacro defaction {:arglists '([name doc-string? attr-map? [params*] & body])} [name & args] (let [params (seq (first (filter vector? args))) name* (symbol (str name \*)) [name args] (name-with-attributes name args) [params* & body] args] `(do (defn ~name* [self# & params#] (let [[~'db-spec ~'schema ~params*] (optional-cnx-or-schema params#)] (execute (do ~@body) ~'db-spec) (mig/record self#))) (defmacro ~name [~'& args#] `(~~name* (quote ~~'&form) ~@args#)) (.setMeta #'~name (merge (.meta #'~name) {:arglists '(~(vec (conj params 'cnx-or-schema?)))}))))) | ||||||||||||||||||||||||
Actions | |||||||||||||||||||||||||
Builds a create statement with the given schema element and execute
it. See the
| (defaction create [element] (schema/build-create-statement (or element schema) db-spec)) | ||||||||||||||||||||||||
Builds an alter statement with the given schema element and execute
it. There's four types of alter actions:
| (defaction alter [action element] (schema/build-alter-statement element action db-spec)) | ||||||||||||||||||||||||
Builds a drop statement with the given schema element and execute
it. It can take an optional
| (defaction drop [element & [behavior]] (schema/build-drop-statement element behavior db-spec)) | ||||||||||||||||||||||||
Execute the given statements as an action. | (defaction exec [& statements] statements) | ||||||||||||||||||||||||
Lobos Migration | |||||||||||||||||||||||||
Migration Command Macro | |||||||||||||||||||||||||
(defmacro defcommand [name & args] (let [params (seq (first (filter vector? args))) [name args] (name-with-attributes name args) [params* & body] args] `(do (defn ~name [& params#] (let [[~'db-spec ~'sname ~params*] (optional-cnx-and-sname params#)] (mig/create-migrations-table ~'db-spec ~'sname) (do ~@body))) (.setMeta #'~name (merge (.meta #'~name) {:arglists '(~(vec (conj params 'sname? 'cnx-or-schema?)))}))))) | |||||||||||||||||||||||||
Migration Commands | |||||||||||||||||||||||||
(defn print-stash [] (when (.exists mig/*stash-file*) (print (slurp mig/*stash-file*)))) | |||||||||||||||||||||||||
(defcommand print-done [] (doseq [name (mig/query-migrations-table db-spec sname)] (println name))) | |||||||||||||||||||||||||
(defcommand print-pending [] (doseq [name (mig/pending-migrations db-spec sname)] (println name))) | |||||||||||||||||||||||||
(defcommand migrate [& names] (let [names (if (empty? names) (mig/pending-migrations db-spec sname) names)] (mig/do-migrations db-spec sname :up names))) | |||||||||||||||||||||||||
(defcommand rollback [& args] (let [names (cond (empty? args) [(last (mig/query-migrations-table db-spec sname))] (= 1 (count args)) (let [arg (first args) migs (mig/query-migrations-table db-spec sname)] (cond (integer? arg) (take arg migs) (= arg :all) migs :else args)) :else args)] (mig/do-migrations db-spec sname :down names))) | |||||||||||||||||||||||||
(defcommand reset [& args] (apply rollback args) (migrate)) | |||||||||||||||||||||||||
(defcommand generate-migration [name & [msg]] (let [name (symbol (if (string? name) name (clojure.core/name name)))] (when-not name (throw (IllegalArgumentException. "Migration must be named."))) (when ((set (mig/list-migrations-names)) (str name)) (throw (IllegalArgumentException. "Migration name is already taken."))) (mig/generate-migration* db-spec sname name msg (mig/read-stash-file)) (mig/clear-stash-file))) | |||||||||||||||||||||||||
This namespace include the abstract schema data-structures, an handful of helpers to create them and the protocol to build the into an abstract syntax tree of implementation agnostic SQL statements. Abstract schema data-structures can be divided in two categories. First, schema elements which include the Then there's the table elements that serves to define tables. There's
the completly abstract | (ns lobos.schema (:refer-clojure :exclude [defonce replace bigint boolean char double float time]) (:require (lobos [ast :as ast])) (:use (clojure [walk :only [postwalk]] [set :only [union]] [string :only [replace]]) lobos.utils)) | ||||||||||||||||||||||||
(ast/import-all) | |||||||||||||||||||||||||
Protocols | |||||||||||||||||||||||||
The Alterable protocol add the possibility of building alter statements from an object implementing it. For internal use. | (defprotocol Alterable (build-alter-statement [this action db-spec])) | ||||||||||||||||||||||||
The Buildable protocol is currently used only by table elements. For internal use. | (defprotocol Buildable (build-definition [this db-spec])) | ||||||||||||||||||||||||
The Creatable protocol add the possibility of building create statements from an object implementing it. For internal use. | (defprotocol Creatable (build-create-statement [this db-spec])) | ||||||||||||||||||||||||
The Dropable protocol add the possibility of building drop statements from an object implementing it. For internal use. | (defprotocol Dropable (build-drop-statement [this behavior db-spec])) | ||||||||||||||||||||||||
Common Exception | |||||||||||||||||||||||||
Throws an IllegalArgumentException when the given name is nil with a default message using the given type of elements. | (defn name-required [name etype] (when-not name (throw (IllegalArgumentException. (format "A % definition needs at least a name." etype))))) | ||||||||||||||||||||||||
Definition Predicate | |||||||||||||||||||||||||
Returns true if the given object is an abstract schema element definition. For internal use. | (defn definition? [o] (isa? (type o) ::definition)) | ||||||||||||||||||||||||
Expression Definitions | |||||||||||||||||||||||||
A set of symbol representing SQL infix operators. | (def sql-infix-operators '#{;; math operators + - * / ;; boolean operators < > <= >= = != or and in like}) | ||||||||||||||||||||||||
A set of symbol representing SQL prefix operators. | (def sql-prefix-operators '#{not}) | ||||||||||||||||||||||||
A set of symbol representing SQL functions. | (def sql-functions '#{;; string functions length lower position replace str subs trim upper ;; numeric functions abs ceil floor mod ;; datetime functions extract now current_date current_time current_timestamp}) | ||||||||||||||||||||||||
(def sql-symbols (union sql-infix-operators sql-prefix-operators sql-functions)) | |||||||||||||||||||||||||
(defrecord Expression [value] Buildable (build-definition [this db-spec] (postwalk #(do (cond (vector? %) (let [[f & n] %] (if (keyword? f) (condp contains? (-> f name symbol) sql-infix-operators (OperatorExpression. db-spec f (first n) (next n)) sql-prefix-operators (OperatorExpression. db-spec f nil n) sql-functions (FunctionExpression. db-spec f n)) %)) (and (keyword? %) (not (contains? sql-symbols (-> % name symbol)))) (IdentifierExpression. db-spec % nil) (not (keyword? %)) (ScalarExpression. db-spec %) :else %)) value))) | |||||||||||||||||||||||||
(defmacro expression [form] `(Expression. ~(postwalk #(if (and (seq? %) (sql-symbols (first %))) (apply vector (keyword (first %)) (rest %)) %) form))) | |||||||||||||||||||||||||
Index Definitions | |||||||||||||||||||||||||
(defrecord Index [iname tname columns options] Creatable Dropable (build-create-statement [this db-spec] (CreateIndexStatement. db-spec iname tname columns options)) (build-drop-statement [this behavior db-spec] (DropStatement. db-spec :index iname nil {:tname tname}))) | |||||||||||||||||||||||||
(defn index ([table columns] (index table nil columns)) ([table name columns & options] (let [tname (if (keyword? table) table (:name table)) cnames (map #(if (keyword? %) % (first %)) columns) name (or name (make-index-name tname :index cnames))] (if (keyword? table) (Index. name tname columns options) (update-in table [:indexes] conj [name (Index. name tname columns options)]))))) | |||||||||||||||||||||||||
Constraint Definitions | |||||||||||||||||||||||||
| (defrecord Constraint [cname] Buildable (build-definition [this db-spec] (ConstraintDefinition. db-spec cname))) | ||||||||||||||||||||||||
Constructs an unspecified abstract constraint definition and add it to the given table. To be used with alter action while dropping a constraint. | (defn constraint [table name] (update-in table [:constraints] conj [name (Constraint. name)])) | ||||||||||||||||||||||||
| (defrecord UniqueConstraint [cname ctype columns] Buildable (build-definition [this db-spec] (UniqueConstraintDefinition. db-spec cname ctype columns))) | ||||||||||||||||||||||||
Constructs an abstract unique (or primary-key depending on the given type) constraint definition and add it to the given table. | (defn unique-constraint [table name type columns] (let [name (or name (make-index-name table type columns))] (update-in table [:constraints] conj [name (UniqueConstraint. name type (vec columns))]))) | ||||||||||||||||||||||||
Constructs an abstract primary key constraint definition and add it to the given table. If the name isn't specified, this constraint will be named using its specification. | (defn primary-key ([table columns] (primary-key table nil columns)) ([table name columns] (unique-constraint table name :primary-key columns))) | ||||||||||||||||||||||||
Constructs an abstract unique constraint definition and add it to the given table. If the name isn't specified, this constraint will be named using its specification. | (defn unique ([table columns] (unique table nil columns)) ([table name columns] (unique-constraint table name :unique columns))) | ||||||||||||||||||||||||
| (defrecord ForeignKeyConstraint [cname columns parent-table parent-columns match triggered-actions] Buildable (build-definition [this db-spec] (ForeignKeyConstraintDefinition. db-spec cname columns parent-table parent-columns match triggered-actions))) | ||||||||||||||||||||||||
Constructs an abstract foreign key constraint definition and add it
to the given table. The The You can specify If the name isn't specified, this constraint will be named using its specification. | (defn foreign-key {:arglists '([table name? columns parent-table parent-columns? match? & triggered-actions])} [table & args] (let [[constraint-name args] (optional keyword? args) columns (first args) parent-table (second args) args (nnext args) [parent-columns args] (optional vector? args) parent-columns (or parent-columns columns) [match args] (optional #{:full :partial :simple} args) triggered-actions (apply hash-map args) constraint-name (or constraint-name (make-index-name table "fkey" columns))] (update-in table [:constraints] conj [constraint-name (ForeignKeyConstraint. constraint-name columns parent-table parent-columns match triggered-actions)]))) | ||||||||||||||||||||||||
| (defrecord CheckConstraint [cname condition] Buildable (build-definition [this db-spec] (CheckConstraintDefinition. db-spec cname (build-definition condition db-spec)))) | ||||||||||||||||||||||||
Constructs an abstract check constraint definition and add it to the
given table. The | (defn check* [table constraint-name condition] (name-required constraint-name "check constraint") (update-in table [:constraints] conj [constraint-name (CheckConstraint. constraint-name condition)])) | ||||||||||||||||||||||||
Constructs an abstract check constraint definition and add it to the given table. | (defmacro check [table constraint-name condition] `(check* ~table ~constraint-name (expression ~condition))) | ||||||||||||||||||||||||
Data-type Definition | |||||||||||||||||||||||||
| (defrecord DataType [dtype args options]) | ||||||||||||||||||||||||
Constructs an abstract data-type definition using the given keyword
| (defn data-type [dtype & [args options]] (DataType. dtype (vec args) (merge {:time-zone nil :collate nil :encoding nil} options))) | ||||||||||||||||||||||||
Column Definition | |||||||||||||||||||||||||
If the given default value, it will be replaced by the standard function returning the current time, date or timestamp depending on the specified data-type. For internal use. | (defn datetime-now-alias [dtype default] (let [value (:value default)] (if (= value [:now]) (Expression. (or ({:date [:current_date] :time [:current_time] :timestamp [:current_timestamp]} dtype) value)) default))) | ||||||||||||||||||||||||
| (defrecord Column [cname data-type default auto-inc not-null others] Buildable (build-definition [this db-spec] (let [{:keys [dtype args options]} data-type] (ColumnDefinition. db-spec cname (DataTypeClause. db-spec dtype args options) (if (= default :drop) :drop (when default (build-definition (datetime-now-alias dtype default) db-spec))) (when auto-inc (AutoIncClause. db-spec)) not-null others)))) | ||||||||||||||||||||||||
(defmacro default [form] `[:default (expression ~form)]) | |||||||||||||||||||||||||
Constructs an abstract column definition. It'll parse the column
specific options. See the | (defn column* [column-name data-type options] (let [{:keys [default encoding collate]} (into {} (filter vector? options)) data-type (when data-type (update-in data-type [:options] (partial merge-with #(or %1 %2)) {:encoding encoding :collate collate :time-zone ((set options) :time-zone)})) others (vec (filter string? options)) option-set (set options) not-null (clojure.core/boolean (:not-null option-set)) auto-inc (clojure.core/boolean (:auto-inc option-set))] (Column. column-name data-type default auto-inc not-null others))) | ||||||||||||||||||||||||
Constructs an abstract column definition and add it to the given table. Also creates and add the appropriate column constraints when these are specified as options. Here's a list of available options:
| (defn column {:arglists '([table column-name data-type? & options])} [table column-name & options] (name-required column-name "column") (let [[data-type options] (optional #(instance? DataType %) options) reference? #(and (vector? %) (= (first %) :refer)) [ptable pcol & others] (->> options (filter reference?) first next) options (filter (comp not reference?) options) option-set (when (seq? options) (set options)) add-constraint #(cond (:primary-key option-set) (primary-key % [column-name]) (:unique option-set) (unique % [column-name]) ptable (apply foreign-key % [column-name] ptable (when pcol [pcol]) others) :else %)] (add-constraint (update-in table [:columns] conj [column-name (case (first options) :to (Column. column-name nil nil false false (second options)) :drop-default (Column. column-name nil :drop false false []) (column* column-name data-type options))])))) | ||||||||||||||||||||||||
Typed Column Definitions | |||||||||||||||||||||||||
Instead of calling the | |||||||||||||||||||||||||
Typed Column Helpers | |||||||||||||||||||||||||
Helper for macros that create typed columns definitions. It takes a
sequence of names and define a function for each of them, a vector of
arguments for those functions, | (defn def-typed-columns* [names args dargs options & [docs]] `(do ~@(for [n names] `(defn ~n ~(format (str "Constructs an abstract %s column definition and" " add it to the given table." docs) (name n)) ~args (let [dargs# ~dargs options# ~options] (apply column ~'table ~'column-name (data-type ~(keyword n) dargs#) options#)))))) | ||||||||||||||||||||||||
Defines typed columns for simple data-types taking no arguments. For internal use. | (defmacro def-simple-typed-columns [& names] (def-typed-columns* names '[table column-name & options] '[] 'options)) | ||||||||||||||||||||||||
Defines numeric-like typed columns. These typed column funcitons can
take an optional | (defmacro def-numeric-like-typed-columns [& names] (def-typed-columns* names '[table column-name & [precision scale & options]] '(-> [] (conj-when (integer? precision) precision) (conj-when (integer? scale) scale)) '(-> options (conj-when (not (integer? precision)) precision) (conj-when (not (integer? scale)) scale)) " Takes an optional `precision` and `scale` arguments.")) | ||||||||||||||||||||||||
Defines typed columns with optional precision. Used by | (defmacro def-optional-precision-typed-columns [& names] (def-typed-columns* names '[table column-name & [precision & options]] '(conj-when [] (integer? precision) precision) '(conj-when options (not (integer? precision)) precision) " Takes an optional `precision` argument.")) | ||||||||||||||||||||||||
Defines optionally length-bounded typed columns. Used by binary and character types. For internal use. | (defmacro def-optional-length-typed-columns [& names] (def-typed-columns* names '[table column-name & [length & options]] '(conj-when [] (integer? length) length) '(conj-when options (not (integer? length)) length) " Takes an optional `length` argument.")) | ||||||||||||||||||||||||
Defines length-bounded typed columns. Used by variable binary and character types. For internal use. | (defmacro def-length-bounded-typed-columns [& names] (def-typed-columns* names '[table column-name length & options] '(conj-when [] (integer? length) length) '(conj-when options (not (integer? length)) length) " The `length` arguemnt is mandatory.")) | ||||||||||||||||||||||||
Numeric Types | |||||||||||||||||||||||||
Constructs an abstract smallint column definition and add it to the given table. | (def-simple-typed-columns smallint integer bigint) | ||||||||||||||||||||||||
Constructs an abstract numeric column definition and add it to the given table. Takes an optional | (def-numeric-like-typed-columns numeric decimal) | ||||||||||||||||||||||||
Constructs an abstract real column definition and add it to the given table. | (def-simple-typed-columns real double-precision) | ||||||||||||||||||||||||
(def double double-precision) | |||||||||||||||||||||||||
Constructs an abstract float column definition and add it to the given table. Takes an optional | (def-optional-precision-typed-columns float) | ||||||||||||||||||||||||
Character Types | |||||||||||||||||||||||||
Constructs an abstract char column definition and add it to the given table. Takes an optional | (def-optional-length-typed-columns char nchar clob nclob) | ||||||||||||||||||||||||
(def text clob) | |||||||||||||||||||||||||
(def ntext nclob) | |||||||||||||||||||||||||
Constructs an abstract varchar column definition and add it to the given table. The | (def-length-bounded-typed-columns varchar nvarchar) | ||||||||||||||||||||||||
Binary Types | |||||||||||||||||||||||||
Constructs an abstract binary column definition and add it to the given table. Takes an optional | (def-optional-length-typed-columns binary blob) | ||||||||||||||||||||||||
Constructs an abstract varbinary column definition and add it to the given table. The | (def-length-bounded-typed-columns varbinary) | ||||||||||||||||||||||||
Boolean Type | |||||||||||||||||||||||||
Constructs an abstract boolean column definition and add it to the given table. | (def-simple-typed-columns boolean) | ||||||||||||||||||||||||
Data/time Types | |||||||||||||||||||||||||
Constructs an abstract date column definition and add it to the given table. | (def-simple-typed-columns date) | ||||||||||||||||||||||||
Constructs an abstract time column definition and add it to the given table. Takes an optional | (def-optional-precision-typed-columns time timestamp) | ||||||||||||||||||||||||
Table Definition | |||||||||||||||||||||||||
(defn- build-table-elements [db-spec method & elements] (->> (apply concat elements) (map #(when (second %) (method (second %) db-spec))) (filter identity))) | |||||||||||||||||||||||||
| (defrecord Table [name columns constraints indexes] Alterable Creatable Dropable (build-alter-statement [this action db-spec] (let [elements (build-table-elements db-spec build-definition columns constraints)] (for [element elements] (AlterTableStatement. db-spec name action element)))) (build-create-statement [this db-spec] (conj (build-table-elements db-spec build-create-statement indexes) (CreateTableStatement. db-spec name (build-table-elements db-spec build-definition columns constraints)))) (build-drop-statement [this behavior db-spec] (DropStatement. db-spec :table name behavior nil))) | ||||||||||||||||||||||||
Constructs an abstract table definition. The | (defn table* [table-name & [columns constraints indexes]] (name-required table-name "table") (Table. table-name (or columns {}) (or constraints {}) (or indexes {}))) | ||||||||||||||||||||||||
Constructs an abstract table definition containing the given elements. Takes an arbitrary number of table elements. | (defmacro table [name & elements] `(-> (table* ~name {} {} {}) ~@(reverse elements))) | ||||||||||||||||||||||||
Schema Definition | |||||||||||||||||||||||||
| (defrecord Schema [sname elements options] Creatable Dropable (build-create-statement [this db-spec] (CreateSchemaStatement. db-spec sname (flatten (map #(build-create-statement (second %) db-spec) elements)))) (build-drop-statement [this behavior db-spec] (DropStatement. db-spec :schema sname behavior nil))) | ||||||||||||||||||||||||
Returns true if the given object is a Schema. | (defn schema? [o] (isa? (type o) Schema)) | ||||||||||||||||||||||||
Constructs an abstract schema definition. | (defn schema {:arglists '([schema-name options? & elements])} [schema-name & args] (name-required schema-name "schema") (let [[options elements] (optional (comp not definition?) args)] (Schema. schema-name (into (sorted-map) (map #(vector (:name %) %) elements)) (or options {})))) | ||||||||||||||||||||||||
Definitions Hierarchy | |||||||||||||||||||||||||
The definition hierarchy makes it easy to test if an object represent
an abstract schema element definition. See the | (derive Index ::definition) (derive Constraint ::definition) (derive UniqueConstraint ::definition) (derive ForeignKeyConstraint ::definition) (derive CheckConstraint ::definition) (derive DataType ::definition) (derive Column ::definition) (derive Table ::definition) (derive Schema ::definition) | ||||||||||||||||||||||||
A set of connectivity functions. | (ns lobos.connectivity (:refer-clojure :exclude [defonce]) (:require (clojure.java.jdbc [internal :as sqlint])) (:use lobos.utils)) | ||||||||||||||||||||||||
Globals | |||||||||||||||||||||||||
This atom contains a map of all opened global connections. | (defonce global-connections (atom {})) | ||||||||||||||||||||||||
Helpers | |||||||||||||||||||||||||
(def find-connection sqlint/find-connection*) | |||||||||||||||||||||||||
(def connection sqlint/connection*) | |||||||||||||||||||||||||
Returns the associated db-spec or itself. For internal use. | (defn get-db-spec [& [connection-info]] (let [connection-info (or connection-info :default-connection)] (or (:db-spec sqlint/*db*) (if (keyword? connection-info) (-> @global-connections connection-info :db-spec) connection-info)))) | ||||||||||||||||||||||||
Replaces | (defn ^{:dynamic true} *get-cnx* [db-spec] (let [db-spec (dissoc db-spec :schema)] (sqlint/get-connection db-spec))) | ||||||||||||||||||||||||
Checks if the given argument is a named connection or a db-spec. As a db-spec is just a map, any map return true. For internal use. | (defn connection? [cnx] (or ((set (keys @global-connections)) cnx) (map? cnx))) | ||||||||||||||||||||||||
Global Connections | |||||||||||||||||||||||||
Supplied with a keyword identifying a global connection, that connection is closed and the reference dropped. If a truthful silent argument is supplied, don't throw an execption if there's no such connection. | (defn close-global [& [connection-name silent]] (let [connection-name (or connection-name :default-connection) cnx (connection-name @global-connections)] (if cnx (do (.close (:connection cnx)) (swap! global-connections dissoc connection-name) true) (when-not silent (throw (Exception. (format "No global connection by that name is open: %s" connection-name))))))) | ||||||||||||||||||||||||
(defn- open-global* [connection-name db-spec] (let [cnx (*get-cnx* db-spec)] (when-let [ac (-> db-spec :auto-commit)] (.setAutoCommit cnx ac)) (swap! global-connections assoc (or connection-name :default-connection) {:connection cnx :db-spec db-spec}))) | |||||||||||||||||||||||||
Opens a global connection to the database specified by If a global connection by that name already exists and the db-spec is safe (see below), then an exeption will be thrown. When the db-spec is unsafe it will be closed if the old db-spec is different and the original connection is left untouched. A safe db-spec is a map that does not contain an :unsafe key set to a truthful value. | (defn open-global ([db-spec] (open-global :default-connection db-spec)) ([connection-name db-spec] (if-let [cnx (connection-name @global-connections)] (if (:unsafe (:db-spec cnx)) (when-not (= (:db-spec cnx) db-spec) (close-global connection-name) (open-global* connection-name db-spec)) (throw (Exception. (format "A global connection by that name already exists (%s)" connection-name)))) (open-global* connection-name db-spec)))) | ||||||||||||||||||||||||
With Connections | |||||||||||||||||||||||||
Evaluates func in the context of a named global connection to a database. | (defn with-named-connection [connection-name func] (io! (if-let [cnx (@global-connections connection-name)] (binding [sqlint/*db* (assoc sqlint/*db* :connection (:connection cnx) :level 0 :rollback (atom false) :db-spec (:db-spec cnx))] (func)) (throw (Exception. (format "No such global connection currently open: %s, only got %s" connection-name (vec (keys @global-connections)))))))) | ||||||||||||||||||||||||
Evaluates func in the context of a new connection to a database then closes the connection. | (defn with-spec-connection [db-spec func] (with-open [cnx (*get-cnx* db-spec)] (binding [sqlint/*db* (assoc sqlint/*db* :connection cnx :level 0 :rollback (atom false) :db-spec db-spec)] (when-let [ac (-> db-spec :auto-commit)] (.setAutoCommit cnx ac)) (func)))) | ||||||||||||||||||||||||
Evaluates body in the context of a new connection or a named global connection to a database then closes the connection if it's a new one. The connection-info parameter can be a keyword denoting a global connection or a map containing values for one of the following parameter sets:
| (defmacro with-connection [connection-info & body] `(let [connection-info# (or ~connection-info :default-connection)] ((if (keyword? connection-info#) with-named-connection with-spec-connection) connection-info# (fn [] ~@body)))) | ||||||||||||||||||||||||
Returns the default connection if it exists. | (defn default-connection [] (try (with-named-connection :default-connection connection) (catch Exception _ nil))) | ||||||||||||||||||||||||