(render "demo-variables-bind.sql" {:id 42})
SELECT * FROM users WHERE id = /*$id*/1
SELECT * FROM users WHERE id = ?
{:params [42]}
/*$ */ comments become bind variables. The sample value must be written immediately after the comment, as in /*$id*/1.
(render "demo-variables-literal.sql" {:type "BOOK"})
SELECT * FROM users WHERE type = /*^type*/'A'
SELECT * FROM users WHERE type = 'BOOK'
{:params []}
^ is rendered as a SQL literal. Strings are quoted with '.
(render "demo-variables-raw.sql" {:order-by "created_at DESC"})
SELECT * FROM users ORDER BY /*!order-by*/column_name
SELECT * FROM users ORDER BY created_at DESC
{:params []}
! is inserted into SQL as-is. It is useful for cases like ORDER BY, but it must not be fed directly from user input.
(render "demo-variables-default.sql" {:email "alice@example.com", :status bisql/DEFAULT})
INSERT INTO users (email, status)
VALUES (/*$email*/'user@example.com', /*$status*/'active')
INSERT INTO users (email, status)
VALUES (?, DEFAULT)
{:params ["alice@example.com"]}
bisql/DEFAULT is rendered as the SQL keyword DEFAULT instead of a bind parameter. This is useful in VALUES clauses.
(render "demo-variables-all.sql" {:limit bisql/ALL})
SELECT *
FROM users
LIMIT /*$limit*/10
SELECT *
FROM users
LIMIT ALL
{:params []}
bisql/ALL is rendered as the SQL keyword ALL instead of a bind parameter. This is useful in clauses such as LIMIT ALL.
(render "demo-if.sql" {:id 42})
SELECT * FROM users /*%if id */ WHERE id = /*$id*/1 /*%end*/
SELECT * FROM users WHERE id = ?
{:params [42]}
(render "demo-if-where.sql" {:active false})
SELECT *
FROM users
WHERE
/*%if active */
active = true
/*%end */
SELECT *
FROM users
{:params []}
When the condition is false, the preceding WHERE or HAVING keyword is removed automatically.
(render "demo-if-and.sql" {:active false, :status "active"})
SELECT *
FROM users
WHERE
/*%if active */
active = true
/*%end */
AND status = /*$status*/'active'
SELECT *
FROM users
WHERE
status = ?
{:params ["active"]}
When the condition is false, a following AND is removed automatically. In this case, the preceding WHERE or HAVING remains in place.
(render "demo-if-elseif-else.sql" {:active false, :pending true})
SELECT *
FROM users
WHERE
/*%if active */
active = true
/*%elseif pending */
status = 'pending'
/*%else */
status = 'inactive'
/*%end */
SELECT *
FROM users
WHERE
status = 'pending'
{:params []}
(render "demo-if-inline-elseif-else.sql" {:active false, :pending true})
SELECT *
FROM users
WHERE
/*%if active */
active = true
/*%elseif pending => status = 'pending' */
/*%else => status = 'inactive' */
/*%end */
SELECT *
FROM users
WHERE
status = 'pending'
{:params []}
else and elseif bodies can also be written inline inside the directive comment by using =>. This keeps the template closer to executable SQL.
(render "demo-for.sql" {:id 42, :items [{:name "display_name", :value "Alice"} {:name "status", :value "active"}]})
UPDATE users
SET
/*%for item in items separating , */
/*!item.name*/column_name = /*$item.value*/'sample'
/*%end */
WHERE id = /*$id*/1
UPDATE users
SET
display_name = ?,
status = ?
WHERE id = ?
{:params ["Alice" "active" 42]}
for loops can declare a separator with separating. This is useful when joining an arbitrary number of fragments with ,, AND, or OR.
(render "demo-declarations.sql" {:id 42})
/*:doc Loads a user by id. */
/*:tags
[:example
:user]
*/
/*:category :lookup */
/* This is a normal comment */
SELECT * FROM users WHERE id = /*$id*/1
/* This is a normal comment */
SELECT * FROM users WHERE id = ?
{:params [42],
:meta
{:doc "Loads a user by id.",
:tags [:example :user],
:category :lookup}}
/*: */ defines metadata entries for the generated Clojure function, keyed by keywords. /*:doc */ is a special case: unlike other declarations, it can be written as inline text instead of EDN.
(render (get (bisql/load-queries "demo-multi-queries.sql") "core.find-user-by-id") {:id 42})
/*:name find-user-by-id */
SELECT * FROM users WHERE id = /*$id*/1
SELECT * FROM users WHERE id = ?
{:params [42], :meta {:name find-user-by-id}}
A single SQL file can contain multiple templates. Each template starts with a /*:name */ directive that defines the generated function name.
(render {:sql-template "SELECT * FROM users WHERE id = /*$id*/1"} {:id 42})
SELECT * FROM users WHERE id = /*$id*/1
SELECT * FROM users WHERE id = ?
{:params [42]}
You can also pass a SQL template directly from Clojure code. This is useful for debugging or learning, but application queries should generally live in SQL files.
(render "demo-variables-bind.sql" {:ic 42})
SELECT * FROM users WHERE id = /*$id*/1
{:message "Missing query parameter: id",
:data
{:query-name "core.demo-variables-bind",
:base-path "sql",
:resource-path "sql/demo-variables-bind.sql",
:project-relative-path "scripts/sql/demo-variables-bind.sql",
:source-line 1,
:parameter :id,
:sigil "$",
:collection? false}}
(require '[bisql.core :as bisql]).Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |