add ability to manually provide table name hints for unparseable sql
an important backup to allow SQL that JSqlParser cannot handle still be used in the views system. JSqlParser is still actively maintained and will get better over time, but it cannot handle everything thrown at it.
This commit is contained in:
parent
d82702d946
commit
a86d4eef17
|
@ -81,11 +81,21 @@
|
|||
result#))))
|
||||
|
||||
(defn- execute-sql!
|
||||
[db [sql & params :as sqlvec]]
|
||||
(let [info (query-info sql)]
|
||||
(if (:returning? info)
|
||||
(jdbc/query db sqlvec)
|
||||
(jdbc/execute! db sqlvec))))
|
||||
[db [sql & params :as sqlvec] returning?]
|
||||
(if returning?
|
||||
(jdbc/query db sqlvec)
|
||||
(jdbc/execute! db sqlvec)))
|
||||
|
||||
(defn- vexec!*
|
||||
[db [sql & params :as sqlvec] {:keys [parse? namespace tables returning?] :as options}]
|
||||
(let [tables (if parse? (query-tables sql) tables)
|
||||
returning? (if parse? (:returning? (query-info sql)) returning?)
|
||||
results (execute-sql! db sqlvec returning?)
|
||||
hint (views/hint namespace tables hint-type)]
|
||||
(if-let [tx-hints (:views-sql/hints db)]
|
||||
(swap! tx-hints conj hint)
|
||||
(views/put-hints! [hint]))
|
||||
results))
|
||||
|
||||
(defn vexec!
|
||||
"Used to run any SQL insert/update/delete query on the database while ensuring
|
||||
|
@ -96,15 +106,30 @@
|
|||
|
||||
Arguments are:
|
||||
- db: a clojure.java.jdbc database connection
|
||||
- namespace (optional): a namespace that will be included in the hints sent out
|
||||
- sqlvec: a JDBC-style vector containing a SQL query string followed by any
|
||||
parameters for the query."
|
||||
([db namespace [sql & params :as sqlvec]]
|
||||
(let [results (execute-sql! db sqlvec)
|
||||
hint (views/hint namespace (query-tables sql) hint-type)]
|
||||
(if-let [tx-hints (:views-sql/hints db)]
|
||||
(swap! tx-hints conj hint)
|
||||
(views/put-hints! [hint]))
|
||||
results))
|
||||
([db [sql & params :as sqlvec]]
|
||||
(vexec! db nil sqlvec)))
|
||||
parameters for the query.
|
||||
|
||||
Options are:
|
||||
- namespace: a namespace that will be included in the hints sent out
|
||||
|
||||
NOTE:
|
||||
If the SQL being run cannot be parsed (e.g. due to use of database-specific
|
||||
extensions, or other limitations of JSqlParser), you will need to manually
|
||||
specify the list of table names (as keywords) that the SQL query will affect
|
||||
as the optional tables argument. In addition, if the SQL query includes a
|
||||
RETURNING clause, you should specify :returning true in the options given
|
||||
to vexec!, since automatic detection of this will not work if the SQL cannot
|
||||
be parsed."
|
||||
{:arglists '([db sqlvec & options]
|
||||
[db sqlvec tables & options])}
|
||||
[db sqlvec & options]
|
||||
(let [[first-option & [other-options]] options]
|
||||
(if (or (nil? options)
|
||||
(map? first-option))
|
||||
(vexec!* db sqlvec (-> first-option
|
||||
(assoc :parse? true)
|
||||
(dissoc :returning?)))
|
||||
(vexec!* db sqlvec (assoc other-options
|
||||
:tables (set first-option)
|
||||
:parse? false)))))
|
||||
|
||||
|
|
|
@ -23,21 +23,50 @@
|
|||
(when (>= time 1000) (warn id "took" time "msecs"))
|
||||
data))
|
||||
(relevant? [_ namespace parameters hints]
|
||||
(let [[sql & sqlparams] (apply query-fn parameters)
|
||||
tables (query-tables sql)
|
||||
nhints (filter #(and (= namespace (:namespace %))
|
||||
(= hint-type (:type %))) hints)]
|
||||
(let [[sql & _] (apply query-fn parameters)
|
||||
tables (if (:parse? options)
|
||||
(query-tables sql)
|
||||
(:tables options))
|
||||
nhints (filter #(and (= namespace (:namespace %))
|
||||
(= hint-type (:type %))) hints)]
|
||||
(boolean (some #(not-empty (intersection (:hint %) tables)) nhints)))))
|
||||
|
||||
(defn- view*
|
||||
[id db-or-db-fn sql-fn {:keys [row-fn result-set-fn tables]
|
||||
:or {row-fn identity
|
||||
result-set-fn doall}
|
||||
:as options}]
|
||||
(SQLView. id db-or-db-fn sql-fn options))
|
||||
|
||||
(defn view
|
||||
"Creates a SQL view that uses a JDBC database configuration.
|
||||
|
||||
db-or-db-fn - either a database connection map, or a function that will get passed
|
||||
a namespace and should return a database connection map
|
||||
sql-fn - a function that returns a JDBC-style vector containing a SELECT query
|
||||
followed by any parameters. this query will be run whenever this view
|
||||
needs to be refreshed."
|
||||
[id db-or-db-fn sql-fn & {:keys [row-fn result-set-fn] :as options
|
||||
:or {row-fn identity
|
||||
result-set-fn doall}}]
|
||||
(SQLView. id db-or-db-fn sql-fn options))
|
||||
Arguments are:
|
||||
- id: an id for this view that is unique within the view system
|
||||
- db-or-db-fn: either a database connection map, or a function that will get
|
||||
passed a namespace and should return a database connection map
|
||||
- sql-fn: a function that returns a JDBC-style vector containing a SELECT
|
||||
query followed by any parameters. this query will be run whenever
|
||||
this view needs to be refreshed.
|
||||
|
||||
Options are:
|
||||
- row-fn: a function that if specified will be run against each row in the
|
||||
view's result set before returning it.
|
||||
- result-set-fn: a function that will be run against the entire view's result
|
||||
set before returning it.
|
||||
|
||||
NOTE:
|
||||
If the SQL being run cannot be parsed (e.g. due to use of database-specific
|
||||
extensions, or other limitations of JSqlParser), you will need to manually
|
||||
specify the list of table names (as keywords) that the SQL query will affect
|
||||
as the optional tables argument."
|
||||
{:arglists '([id db-or-db-fn sql-fn & options]
|
||||
[id db-or-db-fn sql-fn tables & options])}
|
||||
[id db-or-db-fn sql-fn & options]
|
||||
(let [[first-option & [other-options]] options]
|
||||
(if (or (nil? options)
|
||||
(map? first-option))
|
||||
(view* id db-or-db-fn sql-fn (assoc first-option :parse? true))
|
||||
(view* id db-or-db-fn sql-fn (assoc other-options
|
||||
:tables (set first-option)
|
||||
:parse? false)))))
|
||||
|
|
Loading…
Reference in a new issue