diff --git a/CHANGELOG.md b/CHANGELOG.md index e4b7ac3..7f4438f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # Changes * 2.5.next in progress - * Address [#515](https://github.com/seancorfield/honeysql/issues/515) in part by quoting entities that start with a digit but are otherwise alphanumeric. Note that entities that are all digits (optionally including underscores) will still not be quoted as in previous releases. + * Address [#515](https://github.com/seancorfield/honeysql/issues/515) in part by quoting entities that start with a digit but are otherwise alphanumeric. Note that entities that are all digits (optionally including underscores) will still not be quoted as in previous releases. In addition, a new `:quoted-always` option allows users to specify a regex that matches entities that should always be quoted (stropped) regardless of the value of `:quoted`. * Address [#513](https://github.com/seancorfield/honeysql/issues/513) by ignoring `:file`, `:line`, `:column`, `:end-line`, and `:end-column` metadata keys and providing an `:ignored-metadata` option to allow additional keys to be ignored. * 2.5.1091 -- 2023-10-28 diff --git a/doc/options.md b/doc/options.md index dd213ea..398973a 100644 --- a/doc/options.md +++ b/doc/options.md @@ -23,6 +23,7 @@ All options may be omitted. The default behavior of each option is described in * `:numbered` -- a Boolean indicating whether to generate numbered placeholders in the generated SQL (`$1`, `$2`, etc) or positional placeholders (`?`); the default is `false` (positional placeholders); this option was added in 2.4.962, * `:params` -- a hash map providing values for named parameters, identified by names (keywords or symbols) that start with `?` in the DSL; the default is that any such named parameters will have `nil` values, * `:quoted` -- a Boolean indicating whether or not to quote (strop) SQL entity names (table and column names); the default is `nil` -- alphanumeric SQL entity names are not quoted but (as of 2.3.928) "unusual" SQL entity names are quoted; a `false` value turns off all quoting, +* `:quoted-always` -- an optional regex that matches SQL entity names that should always be quoted (stropped) regardless of the value of `:quoted`; the default is `nil` -- no SQL entity names are always quoted, * `:quoted-snake` -- a Boolean indicating whether or not quoted and string SQL entity names should have `-` replaced by `_`; the default is `false` -- quoted and string SQL entity names are left exactly as-is, * `:values-default-columns` -- a sequence of column names that should have `DEFAULT` values instead of `NULL` values if used in a `VALUES` clause with no associated matching value in the hash maps passed in; the default behavior is for such missing columns to be given `NULL` values. @@ -131,7 +132,10 @@ selected dialect. If `:quoted false`, SQL entity names that represent tables and columns will not be quoted. If those SQL entity names are reserved words in -SQL, the generated SQL will be invalid. +SQL, the generated SQL will be invalid. You can use the `:quoted-always` +option to specify a regex, to identify SQL entity names that should +always be quoted (stropped) regardless of the value of `:quoted`, e.g., +reserved words that you happen to use as table or column names. The quoting (stropping) is dialect-dependent: * `:ansi` -- uses double quotes diff --git a/src/honey/sql.cljc b/src/honey/sql.cljc index 7b1343f..fdf7f2f 100644 --- a/src/honey/sql.cljc +++ b/src/honey/sql.cljc @@ -120,6 +120,7 @@ ; should become defonce (def ^:private default-dialect (atom (:ansi @dialects))) (def ^:private default-quoted (atom nil)) +(def ^:private default-quoted-always (atom nil)) (def ^:private default-quoted-snake (atom nil)) (def ^:private default-inline (atom nil)) (def ^:private default-checking (atom :none)) @@ -130,6 +131,7 @@ ;; functions harder than necessary: (def ^:private ^:dynamic *clause-order* default-clause-order) (def ^:private ^:dynamic *quoted* @default-quoted) +(def ^:private ^:dynamic *quoted-always* @default-quoted-always) (def ^:private ^:dynamic *quoted-snake* @default-quoted-snake) (def ^:private ^:dynamic *inline* @default-inline) (def ^:private ^:dynamic *params* nil) @@ -277,10 +279,18 @@ ;; characters in entity, then quote it: (nil? *quoted*) (fn opt-quote [part] - (cond (re-find alphanumeric part) + (cond (and *quoted-always* + (re-find *quoted-always* part)) + (dialect-q part) + (re-find alphanumeric part) part :else (dialect-q part))) + *quoted-always* + (fn always-quote [part] + (if (re-find *quoted-always* part) + (dialect-q part) + part)) :else identity) parts-fn (or (:parts-fn *dialect*) @@ -2055,6 +2065,9 @@ true :else @default-quoted) + *quoted-always* (if (contains? opts :quoted-always) + (:quoted-always opts) + @default-quoted-always) *quoted-snake* (if (contains? opts :quoted-snake) (:quoted-snake opts) @default-quoted-snake) @@ -2097,6 +2110,7 @@ * :inline * :numbered * :quoted + * :quoted-always * :quoted-snake Note that calling `set-dialect!` can override the default for `:quoted`." [opts] @@ -2113,6 +2127,8 @@ (reset! default-numbered (:numbered opts))) (when (contains? opts :quoted) (reset! default-quoted (:quoted opts))) + (when (contains? opts :quoted-always) + (reset! default-quoted-always (:quoted-always opts))) (when (contains? opts :quoted-snake) (reset! default-quoted-snake (:quoted-snake opts)))))