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#))))
|
result#))))
|
||||||
|
|
||||||
(defn- execute-sql!
|
(defn- execute-sql!
|
||||||
[db [sql & params :as sqlvec]]
|
[db [sql & params :as sqlvec] returning?]
|
||||||
(let [info (query-info sql)]
|
(if returning?
|
||||||
(if (:returning? info)
|
(jdbc/query db sqlvec)
|
||||||
(jdbc/query db sqlvec)
|
(jdbc/execute! 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!
|
(defn vexec!
|
||||||
"Used to run any SQL insert/update/delete query on the database while ensuring
|
"Used to run any SQL insert/update/delete query on the database while ensuring
|
||||||
|
@ -96,15 +106,30 @@
|
||||||
|
|
||||||
Arguments are:
|
Arguments are:
|
||||||
- db: a clojure.java.jdbc database connection
|
- 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
|
- sqlvec: a JDBC-style vector containing a SQL query string followed by any
|
||||||
parameters for the query."
|
parameters for the query.
|
||||||
([db namespace [sql & params :as sqlvec]]
|
|
||||||
(let [results (execute-sql! db sqlvec)
|
Options are:
|
||||||
hint (views/hint namespace (query-tables sql) hint-type)]
|
- namespace: a namespace that will be included in the hints sent out
|
||||||
(if-let [tx-hints (:views-sql/hints db)]
|
|
||||||
(swap! tx-hints conj hint)
|
NOTE:
|
||||||
(views/put-hints! [hint]))
|
If the SQL being run cannot be parsed (e.g. due to use of database-specific
|
||||||
results))
|
extensions, or other limitations of JSqlParser), you will need to manually
|
||||||
([db [sql & params :as sqlvec]]
|
specify the list of table names (as keywords) that the SQL query will affect
|
||||||
(vexec! db nil sqlvec)))
|
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"))
|
(when (>= time 1000) (warn id "took" time "msecs"))
|
||||||
data))
|
data))
|
||||||
(relevant? [_ namespace parameters hints]
|
(relevant? [_ namespace parameters hints]
|
||||||
(let [[sql & sqlparams] (apply query-fn parameters)
|
(let [[sql & _] (apply query-fn parameters)
|
||||||
tables (query-tables sql)
|
tables (if (:parse? options)
|
||||||
nhints (filter #(and (= namespace (:namespace %))
|
(query-tables sql)
|
||||||
(= hint-type (:type %))) hints)]
|
(:tables options))
|
||||||
|
nhints (filter #(and (= namespace (:namespace %))
|
||||||
|
(= hint-type (:type %))) hints)]
|
||||||
(boolean (some #(not-empty (intersection (:hint %) tables)) nhints)))))
|
(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
|
(defn view
|
||||||
"Creates a SQL view that uses a JDBC database configuration.
|
"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
|
Arguments are:
|
||||||
a namespace and should return a database connection map
|
- id: an id for this view that is unique within the view system
|
||||||
sql-fn - a function that returns a JDBC-style vector containing a SELECT query
|
- db-or-db-fn: either a database connection map, or a function that will get
|
||||||
followed by any parameters. this query will be run whenever this view
|
passed a namespace and should return a database connection map
|
||||||
needs to be refreshed."
|
- sql-fn: a function that returns a JDBC-style vector containing a SELECT
|
||||||
[id db-or-db-fn sql-fn & {:keys [row-fn result-set-fn] :as options
|
query followed by any parameters. this query will be run whenever
|
||||||
:or {row-fn identity
|
this view needs to be refreshed.
|
||||||
result-set-fn doall}}]
|
|
||||||
(SQLView. id db-or-db-fn sql-fn options))
|
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