Bitbucket is a code hosting site with unlimited public and private repositories. We're also free for small teams!

Close

-- markdown --

Clj-DBSpec v0.3

Clj-DBSpec is a common configuration spec for dealing with relational databases e.g. data source, connection, conversion of schema/tables/columns/indices names between the database and Clojure.

Usage

Maven/Leiningen dependency details are here: http://clojars.org/org.bituf/clj-dbspec

Examples for usage can be found in the tutorial below:

Building/Installation

You will need Maven 2 to build from sources. Execute the following:

$ mvn clean package  # packages up a JAR in "target" dir
$ mvn install        # to install to your local Maven repo
$ mvn clojure:gendoc # generate Clojure API documentation

License

Copyright (C) 2011 Shantanu Kumar (kumar.shantanu at gmail dot com)

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this software except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Documentation

Clj-DBSpec can be used after including the following in your namespace:

(ns example.app
  (:require [org.bituf.clj-dbspec :as spec]))

Feel free to browse the documentation and source code/unit tests for details.

Quickstart

Dynamic var for database configuration keys

spec/*dbspec*

This var is bound to a map containing well known keys and corresponding values. Those keys are:

:datasource    (javax.sql.DataSource, default: nil)
                1. When you rebind this var with :datasource you SHOULD also
                   include a cached :dbmetadata value.
                2. Everytime a connection is taken from the datasource you
                   SHOULD re-bind this var to include the :connection object.
:connection    (java.sql.Connection, default: nil)
                1. If the connection is not taken from a datasource you SHOULD
                   include a cached :dbmetadata value while re-binding.
:dbmetadata    (map, default: empty map)
                1. This is usually result of dbmeta function.
:catalog       (Clojure form - String, Keyword etc.; default nil)
                1. Catalog name - SHOULD be converted using db-iden
:schema        (Clojure form - String, Keyword etc.; default nil)
                1. Schema name - SHOULD be converted using db-iden
:read-only     (boolean, default: false)
                1. When true, declares that write operations to be disallowed
:show-sql      (boolean, default true)
                1. If true, SQL statements should be printed.
:show-sql-fn   (function, default: fn that prints SQL using `println`)
                You may like to rebind this to fn that prints via a logger
:clj-to-db     (function, default: to string, replace '-' => '_')
                1. Dictates how should identifiers be converted from
                   Clojure to the Database.
                2. The default value is the least common denominator that
                   works with most databases. Override as necessary.
:db-to-clj     (function, default: to lower-case keyword, replace '_' => '-')
                1. Dictates how should identifiers be converted from the
                   Database to Clojure.
                2. The default value is the least common denominator that
                   works with most databases. Override as necessary.
:fetch-size    (Integer, default: 1000)
                1. Number of rows to fetch per DB roundtrip. Helps throttle
                   as well as optimize large DB reads. 0 means unlimited.
:query-timeout (Integer, default: 0)
                1. Number of seconds to wait for query to execute, after
                   which timeout occurs raising SqlException. Not all JDBC
                   drivers support this so check driver manual before use.

Libraries MAY expose their own API to re-bind this var to new values - they MUST NOT alter the type/semantics of the well-defined keys. They MAY introduce custom keys with unique prefixes e.g. :com.foo.xlib.conn-pool-name (in order to prevent name collision), which may be useful to interoperate with other libraries.

The idiomatic use of this var is to write middleware to alter the values of certain keys. Some pre-built middleware are:

wrap-dbspec
wrap-datasource
wrap-datasource-conn
wrap-connection

Create raw database connection

Important: You must include the JDBC drivers on the classpath on your own.

;; without username/password
(spec/make-connection
  ;; driver-classname - for H2 database
  "org.h2.Driver"
  ;; JDBC URL - for in-memory H2 database
  "jdbc:h2:mem:db1")

;; with username/password
(spec/make-connection
  ;; driver-classname - for H2 database
  "org.h2.Driver"
  ;; JDBC URL - for in-memory H2 database
  "jdbc:h2:mem:db1"
  ;; username
  "sa"
  ;; password
  "")

Work with a DataSource

;; assuming we are using Clj-DBCP for creating data source
(let [ds (dbcp/h2-memory-datasource)
      g  (spec/wrap-datasource ds
           #(with-open [conn (.getConnection (:datasource spec/*dbspec*))]
              (-> (.createStatement conn)
                (.executeQuery "SELECT 1;"))))]
  (g))

Work with a Connection obtained from a DataSource

;; assuming we are using Clj-DBCP for creating data source
(let [ds (dbcp/h2-memory-datasource)
      g  (spec/wrap-datasource-conn ds
           #(-> (.createStatement (:connection spec/*dbspec*))
              (.executeQuery "SELECT 1;")))]
  (g))

Convert Clojure name to database name (name of table/column/column-type etc.)

Let us see the default behavior:

(spec/db-iden :Emp-Name) ; returns "emp_name"

You can modify the behavior as follows:

(let [g (wrap-dbspec {:clj-to-db  (fn [iden]
                                    (if (string? iden) iden
                                      (apply str (replace {\- "xx"}
                                                   (name iden)))))}
          ;; returns "EMPxxNAME"
          #(spec/db-iden :Emp-Name))]
  (g))

Convert database name to Clojure name (name of table/column/column-type etc.)

Let us see the default behavior:

(spec/clj-iden "Emp_Name") ; returns :emp-name

You can modify the behavior by reassigning a convertor function to the key :db-to-clj (as shown in Clojure-to-database name example above.)

Reference

Please check The Bitumen Framework Handbook https://bitbucket.org/kumarshantanu/bituf-handbook/src

Recent activity

Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.