sqljdbcclojurehugsql

Force hugsql query functions to throw an error when they return the wrong number of results


Using Clojure and hugsql. I define my queries as such.

-- :name query-should-return-one-but-returns-multiple
-- :result one
-- :command :query
SELECT v.id FROM some_table v;

After using def-db-fns, this will create a function query-should-return-one-but-returns-multiple in my namespace.

However, if I have more than one row in some_table, this function will simply return an arbitrary row, and will not signal an error.

How could I force query functions defined to return :one to throw an exception if the database returned more than one result?


Solution

  • -- :result :one simply takes the first row of the returned result set of your query, so there is no verification that your query returns exactly 1 record (hashmap).

    However, HugSQL uses Clojure multimethods to define its result types, so you can create your own or override existing methods to fit your needs.

    We define a function result-exactly-one that will throw an exception when the count of the result is not one. We then define the hugsql-result-fn multimethod with the :exactly-one keyword. Please note the quoted, namespaced (user in this case) symbol referring to the function we've created.

    (require '[hugsql.core :as hugsql]
             '[hugsql.adapter])
    
    (defn result-exactly-one
      [this result options]
      (let [rs (hugsql.adapter/result-many this result options)]
        (if (= 1 (count rs)) 
            rs 
            (throw (ex-info "Oops!" {})))))
    
    (defmethod hugsql/hugsql-result-fn :exactly-one [sym] 'user/result-exactly-one)
    
    -- :name return-exactly-one
    -- :result :exactly-one
    -- :command :query
    SELECT v.id FROM t1 v;
    

    And the result when 0 or more than one records are returned:

    user=> (return-exactly-one db)
    
    ExceptionInfo Oops!  clojure.core/ex-info (core.clj:4617)