clojurehugsqlvscode-calvaclj-kondo

How to avoid unresolved symbol with clj-kond when using hugSQL def-db-fns macro?


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;

Solution

  • 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.