dscarpetti / codax

An idiomatic transactional embedded database for clojure
Eclipse Public License 1.0
179 stars 9 forks source link

with-write-transaction #9

Closed dbushenko closed 6 years ago

dbushenko commented 6 years ago

I'm doing like this:

(defn init-db [ db ] (c/with-write-transaction [db tx] (when-not (c/get-at tx [:counters :user-id]) (c/assoc-at tx [:counters :user-id] 1))))

This is for the one-time DB initialization. As you see, if the DB was already initialized, the body of the when-not will not be evaluated, nothing is written to DB. This leads to NullPointerException clojure.lang.RT.longCast (RT.java:1259)

dscarpetti commented 6 years ago

The final expression of a with-write-transaction body must evaluate to a transaction. Since transactions are immutable (each operation on a transaction returns a new transaction) the with-write-transaction macro must have a final transaction in order to perform a commit. If there is not a transaction an error is thrown because silently aborting the transaction would likely result in data unintentionally not being committed.

That said, it's a pretty common error and the error message should be improved. Also, the docs should be updated to clarify this aspect. I will close this issue once that is taken care of.

More to the point, you can handle your initialization use-case like so:

(defn init-db [ db ]
  (c/with-write-transaction [db tx]
    (if-not (c/get-at tx [:counters :user-id])
      (c/assoc-at tx [:counters :user-id] 1)
      tx)))
dbushenko commented 6 years ago

Thanks for the explanations! Yes, if you add this to README and other docs -- would be really helpful!