Source

Clj-DBSpec / README.md

Full commit
Shantanu Kumar 1c57773 





























































Shantanu Kumar b7d325b 



















Shantanu Kumar 1c57773 









































































































Shantanu Kumar b7d325b 
-*- 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](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](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](https://bitbucket.org/kumarshantanu/bituf-handbook/src)