diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/clojure_sql/compiler.clj | 2 | ||||
| -rw-r--r-- | src/clojure_sql/core.clj | 39 | ||||
| -rw-r--r-- | src/clojure_sql/dsl.clj | 18 | ||||
| -rw-r--r-- | src/clojure_sql/jdbc.clj | 37 | ||||
| -rw-r--r-- | src/clojure_sql/query.clj | 24 | 
5 files changed, 69 insertions, 51 deletions
| diff --git a/src/clojure_sql/compiler.clj b/src/clojure_sql/compiler.clj index 87899f9..50c14af 100644 --- a/src/clojure_sql/compiler.clj +++ b/src/clojure_sql/compiler.clj @@ -254,7 +254,7 @@ -(defn compile-insert [db {:keys [fields tables joins]} & records] +(defn compile-insert [db {:keys [fields tables joins]} records]    (assert (= (count tables) 1) "Cannot insert into a multiple-table query")    (let [fields-order (map key fields)          wrap #(str "INSERT INTO " diff --git a/src/clojure_sql/core.clj b/src/clojure_sql/core.clj index 2a9e77f..415c7f4 100644 --- a/src/clojure_sql/core.clj +++ b/src/clojure_sql/core.clj @@ -22,40 +22,27 @@        select        group        sort take drop -      union intersection) - - -(def ^:private ^:dynamic *database-type* nil) -(defn set-database-type! [new-type] -  (alter-var-root #'*database-type* (constantly new-type)) -  nil) - -(def ^:private ^:dynamic *query-executor* (comp second vector)) -(defn set-query-executor! [exec-fn] -  (alter-var-root #'*query-executor* (constantly exec-fn)) -  nil) - - +      union intersection +      set-default-query-executor!)  (defmethod print-method clojure_sql.query.Query [query writer]    (binding [*out* writer] -    (pr (c/compile-select *database-type* query)))) +    (pr (c/compile-select nil query))))  (defn run-query    "Run a select query. Return value is determined by query executor."    [query] -  (assert *query-executor* "Cannot execute a query without a query executor") -  (*query-executor* :select (c/compile-select *database-type* query))) +  (assert (:executor query) "Cannot execute a query without a query executor") +  (q/query (:executor query) query))  (defn insert!    "Insert a number of records into a table, setting each column to the    corresponding value from the record. Return value is determined by    query executor."    [query & records] -  (assert *query-executor* "Cannot execute a query without a query executor") -  (let [compiled (apply c/compile-insert *database-type* query records)] -    (*query-executor* :insert compiled))) +  (assert (:executor query) "Cannot execute a query without a query executor") +  (q/insert! (:executor query) query records))  (defn update!    "Update everything which would have been selected by the query, @@ -67,16 +54,12 @@    with `project` before calling `update!`."    [query partial-record] -  (assert *query-executor* "Cannot execute a query without a query executor") -  (let [compiled (c/compile-update *database-type* query partial-record)] -    (*query-executor* :update compiled))) +  (assert (:executor query) "Cannot execute a query without a query executor") +  (q/update! (:executor query) query partial-record))  (defn delete!    "Delete everything which would have been selected by the    query. Return value is determined by query executor."    [query] -  (assert *query-executor* "Cannot execute a query without a query executor") -  (let [compiled (c/compile-delete *database-type* query)] -    (*query-executor* :delete compiled))) - -(q/set-query-deref-behaviour! run-query) +  (assert (:executor query) "Cannot execute a query without a query executor") +  (q/delete! (:executor query) query)) diff --git a/src/clojure_sql/dsl.clj b/src/clojure_sql/dsl.clj index 413b9c0..2a22eea 100644 --- a/src/clojure_sql/dsl.clj +++ b/src/clojure_sql/dsl.clj @@ -85,14 +85,21 @@          (keyword? expression) (resolve-field tables aliases expression)          :else expression)) +(def ^:dynamic *default-executor* nil) +(defn set-default-query-executor! [executor] +  (alter-var-root #'*default-executor* (constantly executor))) +(defmacro with-default-query-executor [executor & body] +  `(binding [*default-executor* ~executor] ~@body)) +  (defn table    "Create a query on a database table. If `table` is itself a query it    will be wrapped, otherwise `table` will be used as the table name." -  [table] +  [table & [executor]]    (q/map->Query (let [table-name (if (u/named? table) (name table) "table")                        table-keyword (keyword (gensym table-name))]                    {:tables {table-keyword table} -                   :joins [table-keyword]}))) +                   :joins [table-keyword] +                   :executor (or executor *default-executor*)})))  (defn ^:private into-map-duplicate-error [coll error-fn]    (reduce (fn [acc [k v]] @@ -229,6 +236,7 @@    outer join is considered a LEFT outer join. To achieve a right outer    join reverse the query arguments."    [left right & {:keys [on type]}] +  (assert (= (:executor left) (:executor right)) "Cannot join queries with different executors.")    (let [left (make-join-subquery left)          right (rename-all-tables (make-join-subquery right))          merged-tables (merge (:tables left) (:tables right)) @@ -387,7 +395,8 @@  (defn ^:private union-compatible? [& queries]    (and (every? (comp seq keys :fields) queries) -       (apply = (map (comp set keys :fields) queries)))) +       (apply = (map (comp set keys :fields) queries)) +       (apply = (map :executor queries))))  (defn union    "Combine the results of two queries. @@ -407,4 +416,5 @@    {:pre [(apply union-compatible? queries)]}    (convert-to-subquery (q/map->Query {:set-operation :intersect                                        :queries queries -                                      :fields (zipmap (keys (:fields (first queries))) (repeat nil))}))) +                                      :fields (zipmap (keys (:fields (first queries))) (repeat nil)) +                                      :executor (:executor (first queries))}))) diff --git a/src/clojure_sql/jdbc.clj b/src/clojure_sql/jdbc.clj index 44ed55e..5a3a55d 100644 --- a/src/clojure_sql/jdbc.clj +++ b/src/clojure_sql/jdbc.clj @@ -1,6 +1,8 @@  (ns clojure-sql.jdbc    (:require [clojure.java.jdbc :as jdbc] -            [clojure-sql.core :refer [set-query-executor!]] +            [clojure-sql.query :refer [QueryExecutor fn->QueryExecutor]] +            [clojure-sql.compiler :as compiler] +            ;;[clojure-sql.core :refer [set-query-executor!]]              [clojure.string :as string]))  (defn ^:private dotted-to-nested-map-one [obj] @@ -16,13 +18,26 @@  (defn ^:private dotted-to-nested-maps [objs]    (mapv dotted-to-nested-map-one objs)) -(defn use-jdbc! [connection-string] -  (set-query-executor! (fn [type query]  -                         (jdbc/with-connection connection-string -                           (case type -                             :select (jdbc/with-query-results results query -                                       (dotted-to-nested-maps results)) -                             :insert (jdbc/do-prepared-return-keys (first query) (next query)) -                             :update (jdbc/do-prepared-return-keys (first query) (next query)) -                             :delete (first (jdbc/do-prepared (first query) (next query))) -                             (assert false (str "Unknown query type: " type))))))) +(defn jdbc-executor [connection-string] +  (let [[_ db-type] (re-find #"^jdbc:([^:]+)" connection-string)] +    (reify QueryExecutor +      (query [_ query] +        (let [compiled (compiler/compile-select db-type query)] +          (jdbc/with-connection connection-string +            (jdbc/with-query-results results compiled +              (dotted-to-nested-maps results))))) + +      (insert! [_ query records] +        (let [compiled (compiler/compile-insert db-type query records)] +          (jdbc/with-connection connection-string +            (jdbc/do-prepared-return-keys (first query) (next query))))) + +      (update! [_ query partial-record] +        (let [compiled (compiler/compile-update db-type query partial-record)] +          (jdbc/with-connection connection-string +            (jdbc/do-prepared-return-keys (first query) (next query))))) + +      (delete! [_ query] +        (let [compiled (compiler/compile-delete db-type query)] +          (jdbc/with-connection connection-string +            (first (jdbc/do-prepared (first query) (next query))))))))) diff --git a/src/clojure_sql/query.clj b/src/clojure_sql/query.clj index 218ae7a..113e748 100644 --- a/src/clojure_sql/query.clj +++ b/src/clojure_sql/query.clj @@ -1,13 +1,23 @@  (ns clojure-sql.query) -(def ^:private ^:dynamic *query-deref-behaviour* identity) -(defn set-query-deref-behaviour! [f] -  (alter-var-root #'*query-deref-behaviour* (constantly f)) -  nil) +(defprotocol QueryExecutor +  (query [_ query] +    "Retrieve information from the database.") +  (insert! [_ query records] +    "Insert a number of records into a table, setting each column to the corresponding value in its record.") +  (update! [_ query partial-record]  +    "Update every row which this query would select by setting each field to the corresponding value in partial-record.") +  (delete! [_ query] +    "Delete every row which this query would select.")) -(defrecord ^:private Query [] +(defn fn->QueryExecutor [f] +  (reify QueryExecutor +    (query [_ query] ()))) + +(defrecord ^:private Query [executor]    clojure.lang.IDeref -  (deref [this] (*query-deref-behaviour* this))) +  (deref [this] +    (assert executor "Cannot deref a query without a query executor") +    (query executor this)))  (def query? (partial instance? Query)) - | 
