Fork me on GitHub

We have a function similar to clob-to-string here:

(defn declob
  "Turn a clob into a String"
  (when clob
      (with-open [rdr (BufferedReader. (.getCharacterStream clob))]
;;; missing \n?
        (string/join (line-seq rdr)))))
What I can't quite understand why it's joining lines without using \n separator. I think it should (always) be :
(defn declob
  "Turn a clob into a String"
  (when clob
      (with-open [rdr (BufferedReader. (.getCharacterStream clob))]
       ;; Note the separator here
        (string/join "\n" (line-seq rdr)))))


Exactly 🙂


(it's a real issue we've found when showing description stored in the db in the browser - missing new lines)


Reading that code, I think they are deliberately producing a single line string and they want the newlines removed.


(I deleted my first answer because I want sure if I was reading your question correctly)


If you want the newlines retained, why even use line-seq at all?


That's a good question. I'd say just a quick fix of the function that has been around for a long time. I think they copied it from somewhere without really thinking much 🙂.


Glad you mentioned that. I think I'm going with just (slurp rdr)


My aforementoined solution has another disadvantage - it removes a new line at the end of the string.


This is the new implementation:

(defn declob
  "Turn a clob into a String"
  (when clob
    (with-open [rdr (BufferedReader. (.getCharacterStream clob))]
      (slurp rdr))))


And I guess that with-open shouldn't be needed at all (not sure if it closes properly)


It does seem to close the reader properly so it's just this:

(defn declob
  "Turn a clob into a String"
  (when clob
    (slurp (.getCharacterStream clob))))


There ya go! So nice and simple!


has anyone ever extended the protocol with, essentially, a mock? I have some code that runs in a transaction (via the with-db-transaction macro) and i’m with-redefs-ing all the database queries, but i can’t redef the macro. I want it to do nothing.


maybe this is a silly idea. My database connection is a mount state which doesn’t get started, so I tried this:

    (add-connection [db _] db)
    (get-level [_] 1))


and I get a stack track about trying to assoc to the notstartedstate, presumably happening somewhere deeper inside with-db-transaction


(defn- fake-transaction
  (with-redefs [jdbc/db-transaction* (fn [_ func] (func nil))]
good enough for my purposes


@ccann That feels like a code smell to me -- I'd look at teasing apart any business logic from any database persistence there if you can. Mocking out JDBC calls isn't something you should need to do in well-structured code, IMO.


yeah, definitely


I’m torn because I have a series of queries and updates I need to do under 1 postgres transaction (because I’m doing row-level concurrency locking via SELECT … FOR UPDATE ) and I haven’t figured out how to factor that behind a protocol as weavejester recommends in his duct concept of Boundaries


I have my SQL defined via HugSQL and I have shim functions in the ns that loads the SQL. So I’d have to put all the functionality in those shims but that feels wrong


Would simply making your test rollback the transaction be sufficient? i.e., wrap the whole test in a transaction set to rollback?


I have tilted at such a windmill in the past and found the most happiness when I had a set of business components that could close over something clojure.jdbc treated as a db connection, and within the context of a db transaction, I constructed components on the transaction value yielded by with-db-transaction.


the system under test here actually mocks out the database commands and I test the DB interface separately (for speed and separation of concerns)


Hmm, sounds like the wrong level of abstraction to me but I'd probably have to see the full code and the tests to offer better suggestions...


yeah i’m finding it really hard to explain in the abstract


Testing around persistence can be tricky. Sometimes just swapping the disk-based DB for a memory-based DB is sufficient to make the full tests viable without mocks. Sometimes you can just wrap tests in a rollback transaction and that's still fast enough. But if you're aiming for "separation of concerns" and you're still mocking out low-level JDBC calls... that doesn't sound very "separate" to me 🙂


yeah, you make a great point


mocking them felt silly


I was trying to avoid writing tests that go from HTTP request to database and back, preferring to test the HTTP interface with a fake database and the database functions without the noise of the web stuff


If all that DB stuff is wrapped up in a function that your handler calls, you could just mock that function when testing the handler. Then write separate tests for that function (with real DB operations).


that’s essentially what’s going on, except it’s functions not function


But I'd say the solution here is to introduce a nicely mockable layer between your handler logic and your persistence logic.


agreed, and I’ll have to find a way to push the transaction down behind that mock


The transaction level operation is a single function, surely? (that calls a bunch of other stuff)


yeah it is, and the content of that function is basically 3 function calls, 2 are db commands and 1 is business logic, and I’d like to not push that business logic behind the mock


so I could have the mockable layer expose a function which takes my business logic function as an argument


☝️:skin-tone-2: Yup, that was going to be my next suggestion -- separating persistence and business logic.

👍 8

thanks for all the help 🙂