Fork me on GitHub
#beginners
<
2022-08-09
>
quan xing01:08:07

I wrote the function get two sql statement and return. but It's return [] now. should I use atom saves the result or some easy way? like this remember the middle variable

(defn return-sql
  [table-name remote-rows local-rows where]
  (println "remote-count:" (count remote-rows) " local-count:" (count local-rows))

  (let [execute-sqls []]
    (if-not (empty? local-rows)
      (conj execute-sqls
                 (-> {:delete-from table-name
                      :where where}
                     (hsql/format))))
   
    (conj execute-sqls
          (-> {:insert-into [table-name]
               :values  remote-rows}
              (hsql/format {:pretty true})))))

quan xing01:08:31

or like this?

(defn return-sql
  [table-name remote-rows local-rows where]
  (println "remote-count:" (count remote-rows) " local-count:" (count local-rows))

  (if-not (empty? local-rows)
    [(-> {:delete-from table-name
          :where where}
         (hsql/format))

     (-> {:insert-into [table-name]
          :values  remote-rows}
         (hsql/format {:pretty true}))]
    [(-> {:insert-into [table-name]
          :values  remote-rows}
         (hsql/format {:pretty true}))]))

(return-sql :bz_project_item [{:id 100 :name "1#"} {:id 101 :name "2#"}],[{:id 100 :name "3#"} {:id 101 :name "4#"}] [:= :project_id 8892])
=> [["DELETE FROM bz_project_item WHERE project_id = ?" 8892]
 ["\nINSERT INTO bz_project_item\n(id, name) VALUES (?, ?), (?, ?)\n" 100 "1#" 101 "2#"]]
I use the jdbc/with-transcation show errors:
(let [sqls (return-sql :bz_project_item [{:id 100 :name "1#"} {:id 101 :name "2#"}],[{:id 100 :name "3#"} {:id 101 :name "4#"}] [:= :project_id 8892])]
     (jdbc/with-transaction [tx local-conn]
       (for [sql sqls]
         (jdbc/execute! tx sql)))

; Error printing return value (SQLException) at com.zaxxer.hikari.pool.ProxyConnection$ClosedConnection/lambda$getClosedConnection$0 (ProxyConnection.java:515).
; Connection is closed

rolt06:08:06

something like:

(cond->> [insert-sql]
  (empty? local-rows) (cons delete-sql))
for the second part, the problem is that for is lazy, so the transaction is closed before the for is realized. You could replace by doseq if you don't care about the return, or wrap the for in doall

quan xing04:08:00

I use the next.jdbc/connection/->pool com.zaxxer.hikari.HikariDataSource create pool with jdbc/with-logging return object:

{:connectable #object[com.zaxxer.hikari.HikariDataSource 0x30f2d2d8 "HikariDataSource (HikariPool-1)"],
 :sql-logger #function[xing.data.common/sql-logger],
 :result-logger #function[xing.data.common/sql-result-logger]}
now I call .close to close the connection, show error:
(.close conn)
; Execution error (IllegalArgumentException) at app.data-recover.core/eval11609 (REPL:6496).
; No matching field found: close for class next.jdbc.sql_logging.SQLLogging
I use (.close (:connectable remote-conn)) It's closed. About jdbc connection pool. Whether it should be closed manually after use

David08:08:24

Quick question, (tangentially Clojure-related): I'm developing on windows, and want to tinker with the seesaw library. When I try to download dependencies with Lein, I get an error and the solution seems to be to add an http_proxy to environment variables. What I'm wondering is to what url should I set this?

Bart Kleijngeld08:08:20

That depends. Typically the need for such a proxy occurs at the workplace because of security concerns, so you would have to consult within your company. I assume that's your situation (more or less)?

rolt08:08:57

if there are java developpers in the company you should be able to use the same url as the one defined in .m2/settings.xml (iirc, you could just set up this file, without touching lein)

David08:08:04

@U03BYUDJLJF no this is my home computer!

Bart Kleijngeld08:08:03

Hmm alright. Can you share the output of your error? And how did you conclude that the proxy env vars seem to be a solution?

rolt08:08:19

just use https instead of http

Bart Kleijngeld08:08:01

Exactly. It seems Stuart Sierra's repository supports it: https://stuartsierra.com/maven2 (source: https://stuartsierra.com/software/maven)

rolt08:08:14

there is a trick to use http repositories but it's not recommended

David08:08:40

@U02F0C62TC1 got it, that said I'm just using lein deps, how can I specify to use https vs http?

rolt08:08:29

that's the first time i see a repository defined in a lib, can you try upgrading seesaw to 1.5.0 ?

rolt08:08:29

otherwise you can do the http repo trick: add

(require 'cemerick.pomegranate.aether)
(cemerick.pomegranate.aether/register-wagon-factory!
 "http"
 #(org.apache.maven.wagon.providers.http.HttpWagon.))

rolt08:08:55

at the beggining of your project.clj file

David08:08:53

OMG I think upgrading to 1.5 did it

muje hoxe08:08:31

Looking for a programming buddy/mentor if anyone is interested

Bart Kleijngeld13:08:21

I'm trying out clojure.test and I'm a bit surprised by the output. For example:

; expected:
(= 0 1)
; actual:
(not (= 0 1))
I was curious if more people found this counter-intuitive and not as helpful as it could be by providing what the actual value is, instead of just prepending not before the expected value.

Bart Kleijngeld13:08:47

I've come across this library: https://github.com/pjstadig/humane-test-output So I know I'm not entirely alone. I was just wondering if people know the reason behind this design choice, and what are nice ways to change it (including perhaps this library). Most notably I would feel helped if I can get the Calva test runner to display neater results

Ed13:08:19

That's not all it's doing. If you wrote something more complex, for example

(deftest thing
  (let [a 1
        b 2]
    (is (= a b))))
you'd see that expected is (= a b) and actual is (not (= 1 2)) so the first one is telling you what forms you ran and the second one tells you what values you got.

lread13:08:31

See https://github.com/lambdaisland/kaocha and https://github.com/weavejester/eftest as other examples of test runners with that produce easy to read test results.

Bart Kleijngeld13:08:03

@U01AKQSDJUX, right, that's fair. I still feel a bit underwhelmed when comparing to the example output in the library mentioned above (or something like pytest in Python).

Bart Kleijngeld13:08:00

@UE21H2HHD I intend to look into different test runners for sure! Currently I'm looking for something to run against a running REPL (ideally from within Calva) during development

lread13:08:49

@U03BYUDJLJF be sure to check out #calva if you get stuck, you'll find a super helpful group over there.

👍 1
Ed14:08:09

I use cider (and I'm under the impression that calva uses the same nrepl + middleware tooling that cider uses, though I'm not a vs code user so prepared to be corrected on this 😉 ) but given a more complex test case such as

(deftest thing
  (let [a {:a 1 :b 2 :c 3}
        b {:a 1 :b 2 :c 1}]
    (is (= a b))))
by default I now get
expected: {:a 1, :b 2, :c 3}

  actual: {:a 1, :b 2, :c 1}          
    diff: - {:c 3}          
          + {:c 1}            
which I would expect calva to do to. There are a bunch of alternative test systems available that a lot of people seem to like, but I've never felt it was worth the effort to switch.

Bart Kleijngeld14:08:09

That looks nice! I'm also pretty confident there's some shared tooling between Calva and Cider, but judging from my output using your test example there's some differences as well:

expected: {:a 1, :b 2, :c 3}
  actual: {:a 1, :b 2, :c 1}

Ran 1 tests containing 1 assertions.
1 failures, 0 errors.
{:test 1, :pass 0, :fail 1, :error 0, :type :summary}
Although, to my surprise, it does show the actual value. Anyways, Calva doesn't support customizing this, so I'm going to accept if for now 🙂. I am also trying out Doom Emacs with Cider. Lots of positives so far, but it takes some time to get used to everything.

lepistane14:08:05

How do i kill a process programatically that was started with clojure.java.shell ? i have a code that (sh "ffmpeg"...) saves a stream locally but i want to chunk it in bits.

rolt15:08:30

doesn't look like it, well except (sh "kill" ...) 😅 however you could write your own function that handle it, starting from (source sh)

(with-open [stdout (.getInputStream proc)
                stderr (.getErrorStream proc)]
     (future
      (try
      (let [out (future (stream-to-enc stdout out-enc))
            err (future (stream-to-string stderr))
            exit-code (.waitFor proc)]
        {:exit exit-code :out @out :err @err})
      (catch InterruptedException e (.destroy proc))))
(parentheses are most likely wrong) you'd now get a future, which you can future-cancel Are you sure killing the process is the right way of doing it though ? ffmpeg may have an option for chunking

lepistane17:08:09

Hey! I figured out that ffmpeg has duration so i am gonna use that 🙂 Thanks for this

JoshLemer15:08:24

Is there some kind of control structure in clojure I could use for this kind of method in java which goes through a few expensive-to-compute results and conditionally returns the first that satisfies a condition?

public int foo() {
  int i = expensiveComputation();
  if (someCondition(i)) {
    return i;
  }
  i = expensiveOtherComputation();
  if (someOtherCondition(i)) {
    return i;
  }
  i = expensiveThirdComputation();
  if (thirdCondition(i)) {
    return i;
  }
  //...
}
I would naturally lean on cond but that doesn't let you reuse things in the condition and the return value so you'd be doing double work
(defn foo []
  (cond
    (some-condition (expensive-computation)) (expensive-computation)
    (some-condition2 (expensive-computation2)) (expensive-computation2)
    (some-condition3 (expensive-computation3)) (expensive-computation3)
    ;;...
    ))

Ben Sless15:08:45

Some variation thereof It's not terrible to write a macro for such cases

JoshLemer15:08:26

perhaps reducing over a vector of compute, condition and result functions is easiest

(defn foo []
  (reduce (fn [_ [com con res]]
            (let [value (com)]
              (if (con value) (reduced (result value)) nil)))
          nil
          [[compute1 condition1 result1] [compute2 condition2 result2] [compute3 condition3 result3]]))

afleck15:08:16

you could have someCondition return i and then make it or

(or (someCondition (expensiveComputation))
      (someOtherCondition (otherComputation)))
etc

tschady15:08:47

perhaps use laziness? map i through a collection of expensive functions fs , then do something similar to run them through conditions, take the first true.

JoshLemer15:08:12

oh ya afleck this works nicely

(or 
  (let [i (some-computation)] (when (some-condition i) i))
  (let [i (other-computation)] (when (other-condition i) i)))

JoshLemer15:08:22

@U1Z392WMQ unfortunately then you get into territory of having to make sure you aren't using chunked sequences which will go through a whole 32-chunk of your expensive or io-laden branches

tschady15:08:45

sounds like an implementation detail 😂

2
Ed15:08:31

you could also use a delay

(let [x (delay (prn 'expensive 'calculation) (+ 1 2))
        y (delay (prn 'not 'run) (+ 3 4))]
    (cond (= 3 @x) @x
          :else    @y))
This will run the computation only once when it is defrefed and would allow you to chain the computations if you need to

❤️ 1
pppaul17:08:41

you may want to look into cond-> cond->>

pppaul17:08:10

oh sorry, i only saw the last code block in your message

pppaul17:08:37

you may want to look into manifold https://github.com/clj-commons/manifold if you run into async stuff like this a lot. it has control structures for this type of logic, mainly let-flow https://cljdoc.org/d/manifold/manifold/0.2.4/api/manifold.deferred#let-flow

❤️ 1
Mario C.17:08:32

How about

(defn compute-and-check
    [[compute & computes] [condition & conditions] input]
    (when (and (function? compute)
               (function? condition))
      (let [result (compute input)]
        (if (condition result)
          [result [compute condition input]]
          #(compute-and-check computes conditions input)))))

  (trampoline compute-and-check computations conditions input)

ale21:08:39

My 2cents:

(def computations-with-checks
  [[computation1 predicate1]
   [computation2 predicate2]
   ; etc.
   ])
(defn computes-ok [[computation ok?]]
  (let [result (computation)]
    (when (ok? result) result)))
(some computes-ok computations-with-checks)

David18:08:40

Follow-on to last night's issue: Trying to use Seesaw to play with UIs, when I run build in lein , get an error that x11 Display is not set. Been doing a bunch of reading, and seems like it is an issue with "headless" versions of java that use java.awt library. That said, I can't figure out how to solve / get around this, resetting display in the terminal doesn't work (e.g. export DISPLAY=:0 , etc.); I've tried uninstalling and resinstalling Java itself, and I'm not sure how to set a headless mode inside of a Clojure app (or if that would even work). Any thoughts?

phronmophobic18:08:12

I believe the headless version applies to the jvm itself. How did you install java/the jvm?

phronmophobic18:08:54

A workaround is to run it with something like xvfb, but obviously it won't pop up any windows.

phronmophobic18:08:36

Are you trying to run your GUI over ssh?

phronmophobic18:08:52

What is your dev setup like?

hiredman18:08:55

if you have a headless jvm build, then the classes / code needed to do guis are missing, and you need to install a non-headless jvm

hiredman18:08:44

on linux you may also be on wayland and x11 (in theory wayland has some kind of fallback story, but I dunno)

David19:08:52

Believe I used apt via a linux distro (on WSL, i.e. Linux for windows). Can send my env and java build in a bit

David20:08:38

here are the errors. first without setting DISPLAY=:0

David20:08:41

And with DISPLAY set:

David20:08:24

Incredibly strangely, if I just import java.swing and create a UI using that (and not Seesaw), it works...

hiredman20:08:04

is that jvm running in wsl?

hiredman20:08:10

(where it works)

hiredman20:08:09

you may need to make sure any gui apps work in wsl before looking at java gui apps (https://docs.microsoft.com/en-us/windows/wsl/tutorials/gui-apps)

David20:08:47

Excellent, thank you. I'll read into that, appreciate the help!

pppaul20:08:05

what don't you understnad?

pppaul20:08:33

do you not understand map or % or # or something else?

RAJKUMAR20:08:22

I don't understand (+ % 1) 1 becomes 2

RAJKUMAR20:08:35

I can understand map

pppaul20:08:46

#( + 1) is a partial

pppaul20:08:04

same as (partial + 1)

hiredman20:08:33

user=> '#(+ 1 %)
(fn* [p1__2#] (+ 1 p1__2#))
user=>

pppaul20:08:50

% is an anon variable, they can be numbered % %1 %2

hiredman20:08:09

user=> ((fn [x] (+ x 1)) 1)
2
user=>

pppaul20:08:45

anon variables are sorta like regex capture groups

RAJKUMAR20:08:24

I thought % is remainder of something

RAJKUMAR20:08:31

thats my confustion

RAJKUMAR20:08:27

could you please explain how is this working

Drew Verlee20:08:01

your "map"ing over the list [ 1 1 ...] and applying the function #(+ % 1) to each value to get the output [2 2 ...]. It's like a for loop It's like doing 1 + 1 = 2 1 + 1 = 2

👍 1
Drew Verlee20:08:22

try (map inc [0 1]) for similar results

Drew Verlee20:08:54

i just saw that everyone replied under "HI". lol

RAJKUMAR20:08:29

(def c [ 1 1 2 2 3 3 4 4 1 1])
 (map #(+ % 1) c)

RAJKUMAR20:08:53

> (2 2 3 3 4 4 5 5 2 2)