# clojure-sql A DSL for [Clojure][1] to compose queries using the constructs of [Relational Algebra][2]. The RA constructs are then compiled into an SQL query to be run on a DBMS. `clojure-sql` doesn't connect to a database itself, but can be configured to perform an action when a query is to be executed. `clojure-sql` provides some utility functions beyond strict RA to allow for data to be inserted, updated and deleted. `clojure-sql` provides no mechanism to create database schemas. [1]: http://clojure.org/ [2]: http://en.wikipedia.org/wiki/Relational_Algebra ## Leiningen information Just add the following to your `project.clj` to get started with `clojure-sql`. [clojure-sql "0.1.0"] ## Database support `clojure-sql` aims to have an extensible compiler. Compilation of queries is performed by multimethods which dispatch on an arbitrary (and otherwise unused) `db` parameter. This allows the compilation of queries to be special-cased per database. By default `clojure-sql` will produce SQL for PostgreSQL (work on other databases may be undertaken in future). ## Usage In `clojure-sql` expressions it is generally assumed that: * Clojure keywords represent *column names* (exception: the `table` function) * Clojure symbols represent *SQL functions* and *SQL operators* * Clojure strings represent *literal strings* * Clojure numbers represent *literal numbers* Thus: `(and (= :name "Barry") (= (length :username) 10))` compiles into an SQL expression equivalent to `("name" = 'Barry' AND "length"("username") = 10)`. A few more query examples: (require '[clojure-sql.core :as s]) ;; this is only shown as a demonstration ;; a query like this is not advised for general use (s/table :users) ;; => ["SELECT * FROM \"users\" AS \"users1715\""] ;; it is recommended that a query be projected first to provide ;; clojure-sql with field information (-> (s/table :users) ;; tables are automatically given internal aliases (s/project [:id :username])) ;; => ["SELECT \"users3205\".\"id\" AS \"id\", \"users3205\".\"username\" AS \"username\" FROM \"users\" AS \"users3205\""] (-> (s/table :users) (s/project [:id :username]) (s/rename {:id :uid}) (s/join (-> (s/table :people) (s/project {:id :pid, :fname :first}) (s/select '(= :first "Henry"))) :on '(= :uid :pid)) (s/project [:username])) ;; => ["SELECT \"users3430\".\"username\" AS \"username\" FROM (\"users\" AS \"users3430\" INNER JOIN \"people\" AS \"people3432\" ON (\"users3430\".\"id\" = \"people3432\".\"id\")) WHERE (\"people3432\".\"fname\" = ?)" "Henry"] ### clojure.java.jdbc [`clojure.java.jdbc`][3] support is provided, but must be included explicitly. `clojure-sql` does not depend on `clojure.java.jdbc`. (require '[clojure-sql.jdbc :as jdbc]) (jdbc/use-jdbc! "postgres://user:pass@localhost:5432/db") ;; => nil (deref (-> (s/table :users) (s/project [:id :username]))) ;; => [{:id 5, :username "username"}] Results are returned from queries in an eager vector. [3]: https://github.com/clojure/java.jdbc ### Other query executors If `clojure.java.jdbc` support is not what you're looking for (or if you're looking for more control of how `clojure.java.jdbc` is executed) then you can register a query executor with `clojure-sql.core/set-query-executor!`. A query executor is a function which is used to run a query when it is executed. When a query is executed the executor is passed two things: the type of query being executed, and the compiled query (as vector of `[query-string & query-args]`). The query executor's return value will be the return value of the associated query function call (`deref`, `insert!`, `update!` or `delete!`). ## Generated queries In general, `clojure-sql` will try to avoid creating subqueries. For any of the RA primitives (`select`, `join`, `project`, `rename`) no subqueries will be introduced. The use of non-RA operations (`group`, `sort`, `take`/`drop`) may introduce a subquery. The particular operations which will create a subquery are: * `join`ing a query which has been `group`ed * `sort`ing a query which has been `take`n or `drop`ped from * `group`ing a query which has been previously `group`ed ## License Copyright © 2013 Carlo Zancanaro Distributed under the Eclipse Public License, the same as Clojure.