I write Clojure using the VS Code Calva extension, which uses clj-kondo to perform static analysis of my code.
I'm using HugSQL to create Clojure functions from SQL queries and statements.
I'm aware that I could handle the database connection and the HugSQL integration with a library like conman, infact I used it in the past and I like it, but this time I wanted to keep things vanilla and talk to HugSQL myself.
HugSQL's def-db-fns
macro takes a SQL file and creates Clojure functions based on the SQL queries and statements contained in that file.
My code below works, but clj-kondo complains that seed-mytable!
is an unresolved symbol.
(ns my-app.db
"This namespace represents the bridge between the database world and the clojure world."
(:require [environ.core :refer [env]]
[hugsql.core :as hugsql]
[nano-id.core :refer [nano-id]]))
;; This create the function seed-mytable!, but clj-kondo doesn't (cannot?) know it.
(hugsql/def-db-fns "sql/mytable.sql")
;; The functions created by HugSQL can accept a db-spec, a connection, a connection pool,
;; or a transaction object. Let's keep it simple and use a db-spec for a SQLite database.
(def db-spec {:classname "org.sqlite.JDBC"
:subprotocol "sqlite"
:subname (env :database-subname)})
(defn db-seed
"Populate the table with some fakes."
[]
(let [fakes [[(nano-id) "First fake title" "First fake content"]
[(nano-id) "Second fake title" "Second fake content"]]]
;; clj-kondo complains that seed-my-table! is an unresolved symbol
(seed-mytable! db-spec {:fakes fakes})))
I understand why clj-kondo complains: seed-mytable!
is not defined anywhere, it's "injected" in this namespace when calling the def-db-fns
macro.
Is there a way to tell clj-kondo that after calling the hugsql/def-db-fns
macro the symbol does indeed exist?
Probably it's not that useful, but this is the SQL file I'm loading with HugSQL.
-- :name seed-mytable!
-- :command :execute
-- :result :affected
-- :doc Seed the `mytable` table with some fakes.
INSERT INTO mytable (id, title, content)
VALUES :t*:fakes;
From the clj-kondo documentation:
Sometimes vars are introduced by executing macros, e.g. when using HugSQL's def-db-fns
. You can suppress warnings about these vars by using declare
. Example:
(ns hugsql-example
(:require [hugsql.core :as hugsql]))
(declare select-things)
;; this will define a var #'select-things:
(hugsql/def-db-fns "select_things.sql")
(defn get-my-things [conn params]
(select-things conn params))
If the amount of symbols introduced by HugSQL becomes too unwieldy, consider
introducing a separate namespace in which HugSQL generates the vars:
foo.db.hugsql
. You can then refer to this namespace from foo.db
with
(require '[foo.db.hugsql :as sql]) (sql/insert! ...)
and clj-kondo will not
complain about this. If it does, you can add {:linters {:unresolved-var {:exclude [my-hugsql.functions-ns]}}}
to your config.