Skip to content

Commit

Permalink
fix #419 by adding InlineValue protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
seancorfield committed Aug 7, 2022
1 parent e6654f7 commit 99e955f
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Changes

* 2.3.next in progress
* Address [#419](https://github.com/seancorfield/honeysql/issues/419) by adding `honey.sql.protocols` and `InlineValue` with a `sqlize` function.
* Address [#413](https://github.com/seancorfield/honeysql/issues/413) by flagging a lack of `WHERE` clause for `DELETE`, `DELETE FROM`, and `UPDATE` when `:checking :basic` (or `:checking :strict`).

* 2.3.911 -- 2022-07-29
Expand Down
17 changes: 17 additions & 0 deletions doc/extending-honeysql.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,23 @@ many more. Built in operators include: `:=`, `:+`, `:mod`.
Built in functions (special syntax) include: `:array`, `:case`,
`:cast`, `:inline`, `:raw` and many more.

## Extending what `:inline` can do

By default, the `:inline` option can convert a fairly
basic set of values/types to SQL strings:
* `nil`
* strings
* keywords and symbols
* vectors
* UUIDs (Clojure only)

Everything is naively converted by calling `str`.

You can extend `honey.sql.protocols/InlineValue` to
other types and defining how the `sqlize` function
should behave. It takes a single argument, the value
to be inlined (converted to a SQL string).

## Registering a New Clause Formatter

`honey.sql/register-clause!` accepts a keyword (or a symbol)
Expand Down
2 changes: 2 additions & 0 deletions doc/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ was wrapped in `[:inline `..`]`:
* keywords and symbols become SQL keywords (uppercase, with `-` replaced by a space),
* everything else is just turned into a string (by calling `str`) and added to the SQL string.

> Note: you can provide additional inline formatting by extending the `InlineValue` protocol from `honey.sql.protocols` to new types.
## `:params`

The `:params` option provides a mapping from named parameters
Expand Down
31 changes: 20 additions & 11 deletions src/honey/sql.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
* `sql-kw` -- turns a Clojure keyword (or symbol) into SQL code (makes
it uppercase and replaces - with space). "
(:refer-clojure :exclude [format])
(:require [clojure.string :as str]))
(:require [clojure.string :as str]
[honey.sql.protocols :as p]))

;; default formatting for known clauses

Expand Down Expand Up @@ -263,16 +264,24 @@
(keyword (name s)))
s))

(defn- sqlize-value [x]
(cond
(nil? x) "NULL"
(string? x) (str \' (str/replace x "'" "''") \')
(ident? x) (sql-kw x)
(vector? x) (str "[" (str/join ", " (map #'sqlize-value x)) "]")
;; issue 385: quoted UUIDs for PostgreSQL/ANSI
#?(:clj (instance? java.util.UUID x) :cljs false)
(str \' x \') ; UUID cannot contain quotes
:else (str x)))
(extend-protocol p/InlineValue
nil
(sqlize [_] "NULL")
String
(sqlize [x] (str \' (str/replace x "'" "''") \'))
#?(:clj clojure.lang.Keyword :cljs Keyword)
(sqlize [x] (sql-kw x))
#?(:clj clojure.lang.Symbol :cljs Symbol)
(sqlize [x] (sql-kw x))
#?(:clj clojure.lang.IPersistentVector :cljs PersistentVector)
(sqlize [x] (str "[" (str/join ", " (map p/sqlize x)) "]"))
#?@(:clj [java.util.UUID
;; issue 385: quoted UUIDs for PostgreSQL/ANSI
(sqlize [x] (str \' x \'))])
Object
(sqlize [x] (str x)))

(defn- sqlize-value [x] (p/sqlize x))

(defn- param-value [k]
(if (contains? *params* k)
Expand Down
8 changes: 8 additions & 0 deletions src/honey/sql/protocols.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
;; copyright (c) 2022 sean corfield, all rights reserved

(ns honey.sql.protocols
"InlineValue -- a protocol that defines how to inline
values; (sqlize x) produces a SQL string for x.")

(defprotocol InlineValue :extend-via-metadata true
(sqlize [this] "Render value inline in a SQL string."))

0 comments on commit 99e955f

Please sign in to comment.