                         ::value (do ~@decls)})))))
 
 (defmacro deftxfn-
+  "Same as [[deftxfn]] but yielding a non-public def."
+  {:arglists '([fn-name [dialect db-spec & args] & body]
+               [fn-name doc-string [dialect db-spec & args] & body])}
   [fn-name & body]
   `(deftxfn ~(with-meta fn-name (assoc (meta fn-name) :private true))
      ~@body))

  (reduce (fn [a s] (conj a (emit-tx-step s))) [] bindings))

(defmacro tx->
  [& bindings]
  (assert (even? (count bindings))
          "Need an even number of bindings!")

         ~@(emit-tx-steps reordered-bindings))))

(defn tx-exec
  "Execute the transaction `tx` in the database represented by `db-spec`.
  The `dialect` is added for convenience since some database functions need it
  to perform their tasks (this might not be a good idea, in which case I'll
  remove the dialect)."
  [dialect db-spec tx]
  (jdbc/with-db-transaction [con db-spec]
    (::value ((:op tx) dialect con))))

(defmacro tx-exec->
  "Like [[tx->]] but immediately call [[tx-exec]] on the result."
  [dialect db-spec & bindings]
  `(tx-exec ~dialect ~db-spec (tx-> ~@bindings)))
