Fork me on GitHub
#beginners
<
2018-12-03
>
Daouda00:12:38

hey guys. how can i achieve this (s/defschema Person {:age s/Num > 0 & < 200}), please?

Ben Grabow00:12:34

I don't know much about Plumatic and schema, but you can define an anonymous function literal to bounds check a number like this: #(< 0 % 200)

👍 4
Daouda00:12:08

@ben.grabow that is exactly what i did 🙂

👍 4
Daouda00:12:40

thank you very much @ben.grabow 🙂

jaide00:12:25

Is there a better way to write this?

(map #(hash-map :value %) [:a :b :c])
;; =>
({:value :a} {:value :b} {:value :c})

jaide00:12:43

Oooh may have figured it out.

(map hash-map (repeat :value) [1 2 3])

Daouda00:12:21

can you guys tell me how you format your snippet code this way ☝️, please?

Daouda00:12:24

Testing 1 2 3

jaide00:12:33

Yep you got it 🙂

Daouda00:12:47

ooooooohhhhhhh thank you @jayzawrotny 🙂

ackerleytng01:12:16

is there a naming convention for the function that actually does stuff? like in the linux kernel they have maybe divide, which does some prep on the data and calls do_divide which actually does the division

ackerleytng01:12:34

i think the equivalent in python is divide and _divide?

andy.fingerhut01:12:58

There are several pairs of things in clojure.core like that, e.g. let and let*, fn and fn*, where the one with * at the end actually does the things, although that isn't a completely accurate characterization, since the one without the * is often doing something active, too, e.g. using a macro to change destructuring into simpler bindings.

andy.fingerhut01:12:35

I myself have on occasion created foo and foo-helper, but that is by no means a common convention that I am aware of.

ackerleytng02:12:36

i see, thanks!

clojure beginner04:12:17

defrecord getBasis behaves differently when used to look up record fields

clojure beginner04:12:57

(defrecord Person [name age company]) (def p1 {:name "foo", :age 27, :company :bar}) (map #(% p1) (keys p1)) ("foo" 27 :bar) user=> (map #(% p1) (Person/getBasis)) (nil nil nil nil) user=> (map #(class %) (Person/getBasis)) (clojure.lang.Symbol clojure.lang.Symbol clojure.lang.Symbol clojure.lang.Symbol) I dont wish to use keys on the record instance since the instance might be missing some fields in the record

clojure beginner04:12:01

How do i get (map #(% p1) (Person/getBasis))

seancorfield04:12:30

Based on the (map class (Person/getBasis)), you're seeing that you're getting Symbol types back...

seancorfield04:12:56

...but in p1 you have keywords for keys -- and that's also what you get in records.

seancorfield04:12:30

So when you use symbols to lookup in p1, you get nil because they don't match -- keywords are not symbols.

clojure beginner04:12:12

Thanks @seancorfield. How do i dynamically come up with generic look ups like these (:name p1) where :name is inferred at runtime from the record definition itself. May be the answer to this will help me understand the different between keywords and symbols.

seancorfield05:12:06

I'm not sure why you don't want to use keys?

seancorfield05:12:01

The declared fields of the record can never be missing -- but you might have additional fields. So (keys some-person) is always going to have at least (:name :age :company) but some may be nil and there may be other fields.

seancorfield05:12:00

FWIW @gayathrik (map keyword (Person/getBasis)) will give you a sequence of keywords...

clojure beginner05:12:59

@seancorfield cool thanks. For some reason I overlooked when trying on repl. I thought keys would not return all the fields of an instance if not present on the instance to begin with. Also thanks for map #((keyword %) p2) (Person/getBasis))

Daouda05:12:47

hey guys, can i put several deftest in my fixtures ?

seancorfield05:12:27

@quieterkali Not sure what you mean -- fixtures execute outside any deftest code

Daouda05:12:45

let me put a snippet code here

seancorfield05:12:53

@gayathrik You don't need the #(f %) -- that's just f

seancorfield05:12:53

It would definitely be easier to read (map p2 (map keyword (Person/getBasis))) for example...

seancorfield05:12:17

(a hash map can be used as a function to lookup things in itself)

Daouda05:12:26

i am new in those clojure stuff so please, feel free to correct my poor code understand please

Daouda05:12:40

(ns nukr.profile-test
    (:require [cheshire.core :as cheshire]
              [clojure.test :refer :all]
              [nukr.profile :refer :all]))

(deftest create-profile 
  (let [profile-one {:firstname "Maflany"
                      :lastname "Traore"
                      :visibility true}
        created-profile-one {:id (+ @id-seq 1)
                              :firstname "Maflany"
                              :lastname "Traore"
                              :visibility true
                              :connections #{}}]
       (is (= created-profile-one (add! profile-one)) "Add new profile test failed")))

(deftest get-profile-from
  (let [profile {:id @id-seq
                  :firstname "Maflany"
                  :lastname "Traore"
                  :visibility true
                  :connections #{}}]
       (is (= profile (get-profile @id-seq)))))


(defn nukr-features [get-profile]
  (create-profile)
  (get-profile))

(use-fixtures :once nukr-features)

Daouda05:12:41

after running lein test here is the output:

Daouda05:12:06

lein test nukr.core-test

lein test nukr.profile-test

Ran 4 tests containing 9 assertions.
0 failures, 0 errors.

seancorfield05:12:37

@quieterkali That doesn't make any sense I'm afraid -- fixtures are intended to set up an "environment" in which to run tests.

Daouda05:12:43

oops sorry the output is from others test too

seancorfield05:12:47

Fixtures do not include tests.

Daouda05:12:22

please teach the right way

Daouda05:12:36

any example will be very welcome 🙂

seancorfield05:12:45

I don't understand what you're trying to do.

seancorfield05:12:00

deftest defines a (sequence of) tests.

seancorfield05:12:26

Fixtures are only needed if you have code that needs to execute before/after your tests.

Daouda05:12:39

i want to execute (get-profile) after (create-profile) been executed

seancorfield05:12:15

You should not have dependencies between your tests.

seancorfield05:12:50

Each deftest should be self-contained and should be able to execute in any order.

Daouda05:12:27

so the right way will be write afunction that will do the first one and the i call my deftest

seancorfield05:12:57

You don't call the deftest functions -- the test framework does that.

Daouda05:12:44

like this example `(def add-to-profile) (deftest get-profile) (defn nukr-features [get-profile] (add-to-profile) (get-profile))

Daouda05:12:26

(ns nukr.profile-test
    (:require [cheshire.core :as cheshire]
              [clojure.test :refer :all]
              [nukr.profile :refer :all]))

(def add-to-profile)  

(deftest get-profile) 

(defn nukr-features [get-profile]
  (add-to-profile)
  (get-profile))

(use-fixtures :once nukr-features)

Daouda05:12:40

can be this way?

seancorfield05:12:55

It's not how you use fixtures.

seancorfield05:12:33

You just don't need fixtures here.

seancorfield05:12:00

get-profile could simply call add-to-profile as part of its body here

Daouda05:12:17

ooooooooooooooh

Daouda05:12:41

i though every function sould be test apart

seancorfield05:12:01

But add-to-profile is not a test.

seancorfield05:12:09

It's just a function.

Daouda05:12:41

but actually i have a function which already to that and i need to test it too

seancorfield05:12:59

Right, so write separate tests.

seancorfield05:12:08

And keep test logic and setup logic separate.

Daouda05:12:22

add-profile and get-profile are two function i have

Daouda05:12:28

but to test get-profile ineed first to have something in my atom

Daouda05:12:59

so that is why i wanted to run add and after get

seancorfield05:12:37

Sounds like you need two tests add-profile-test and get-profile-test and it just so happens that both call add-profile as part of their code.

seancorfield05:12:08

Also, the fact that you're jumping to an atom suggests you are depending on side effects and you might be writing non-idiomatic code here.

seancorfield05:12:32

You really want functions to be pure where possible without mutable state.

seancorfield05:12:57

Mutable state, like atom, makes tests harder to write and generally makes your code hard to work with.

Daouda05:12:38

but in a program in some point you need to achieve I/O

Daouda05:12:44

store stuffs in db

seancorfield05:12:06

Sure, but you push that out to the edges as much as possible.

Daouda05:12:09

so i can test function which willdo that?

Daouda05:12:34

i understand

Daouda05:12:46

so if i have a function which only get a data in an atom or database, it is under side effect.

Daouda05:12:27

so they don't have to be test?

Daouda05:12:46

sorry for my questions hahaha

Daouda05:12:57

i like to ask too much questions

seancorfield05:12:07

There are some very basic operations that aren't worth testing.

seancorfield05:12:42

Writing a record to DB -- it's not worth testing that the result gives you an extra :id field to be honest.

Daouda05:12:06

but let say i have a function calling another one

seancorfield05:12:08

Simple side effects are both hard to test and somewhat pointless to test.

Daouda05:12:24

the first one being pure and the second one not being

Daouda05:12:42

is that means the first one stop being pure function?

Daouda05:12:11

oh myyyyyyyyy

Daouda05:12:34

so this way the whole project is under side effect!!!!!

seancorfield05:12:41

Better to have a third function call both. Then you can write tests for the pure function. And ensure the side effecting function does nothing but the side effect (which isn't worth testing).

jaihindhreddy-duplicate05:12:49

It's like this. If you mark functions with side effects in your codebase, they should be a tiny proportion of all functions. Because they are harder to test, and reason about.

Daouda05:12:04

guys i don't know if i should laugh or cry hehehehe

Daouda05:12:24

i think i got you both

Daouda05:12:42

but in my understanding it's like if i make only one call to a side effect function and there are some other 30 functions call after that, all of them become side effect function, unpure function

seancorfield05:12:44

Don't worry -- it's a big shift when you come to Clojure, trying to get the hang of separating out pure functions, immutable data, and side effect!

Daouda05:12:10

then i ask myself how to right a really pur function 😢

seancorfield05:12:58

If you have 30 pure functions and one impure function, write the 32nd function that calls the 30 pure ones and the impure one.

seancorfield05:12:10

Now you have 30 pure functions that are easy to test.

seancorfield05:12:37

If your impure one is simple enough, it probably doesn't need testing.

seancorfield05:12:02

You can also test your combination function by mocking the impure function (`with-redefs` for example).

Daouda05:12:48

i understood

Daouda05:12:14

so if i need a data from the database, it's better to retrieve it once and then pass other others functions

Daouda05:12:22

something like that

Daouda05:12:57

then i will have only one accessing the database and the others one will only work with the data

Daouda06:12:44

hey guys, it's me again

Daouda06:12:15

can i have a function that i will use for unpure function calling?

Daouda06:12:26

i mean when i see that i am about to call an unpure function, use that func, passs to it the function and params, then it will do the call for me and give me back the result

Daouda06:12:41

is that make sense to you?

lispyclouds06:12:15

@quieterkali you can do something like this. I use it in my code:

(defmacro unsafe!
  "Wrap around potentially side effecting expression(s).
  Either it catches the exception if thrown returns it as a value
  or the result of the computation if successful."
  [& body]
  `(try
     ~@body
     (catch Exception e# e#)))

lispyclouds06:12:10

Can be used like (unsafe! (/ 4 0)) it will return the exception rather than throwing them. Otherwise returns the result like (unsafe! (/4 2)) => 2

lispyclouds06:12:41

works wil any number of forms inside the (unsafe! ...) block

lispyclouds06:12:22

You can check if it failed like this:

(instance? Exception (unsafe! (/ 4 0)))
=> true

Daouda06:12:36

hunn i see

Daouda06:12:18

so in this case body will be any function you need to call

Daouda06:12:28

i mean any side effect one?

andy.fingerhut06:12:42

You want this "wrapper" around an impure function call, for documentation purposes?

Daouda06:12:27

i want it to protect all my function to become side effect

lispyclouds06:12:35

yes. body can be any form

andy.fingerhut06:12:37

protect in what way?

andy.fingerhut06:12:10

Do you mean, you want to prevent impure functions from being called, unless you call them by using this new function?

Daouda06:12:26

let say i have 2 functions

andy.fingerhut06:12:27

If so, I don't know any way to do that in Clojure. Haskell, perhaps.

Daouda06:12:45

one is pure and the another one unpure

Daouda06:12:07

and the pure one come to call the unpure one, that will turn it unpure also

Daouda06:12:56

so i ask, what about having a function that i will use in the middle to hanlde those call to unpure function?

Daouda06:12:11

to avoid direct contat with them

Daouda06:12:44

you know i am new in the functional programming and things are really strange to me

andy.fingerhut06:12:00

So function P is a pure function, IMP is impure. You want to know if there is a way to write a function "IMPURE-ARMOR" such that if P calls (IMPURE-ARMOR IMP ... args for IMP here ...), then you get an error message?

andy.fingerhut06:12:14

Or that IMP's side effects don't happen?

Daouda06:12:15

when i think i got the whole picture then i realise that i know nothing yet 😞

Daouda06:12:36

EXACTLYYYYYYYY

Daouda06:12:55

i don't get

Daouda06:12:06

i want to know if that make sense

andy.fingerhut06:12:22

I don't think that is possible in general. It is impossible to write an algorithm that can determine with 100% certainty, for all possible code you could write, whether that function is pure or not.

lispyclouds06:12:39

I guess what youre looking for is a Monad, which is not really idiomatic in Clojure. Here the side effect throw exceptions like in Java. The one i sent is an approximation of a Monad in Haskell.

andy.fingerhut06:12:40

For some special cases you could do it.

lispyclouds06:12:19

The genral way is to throw exceptions from a side effect and let it bubble up. like @andy.fingerhut said its not that clean to to write one in clojure

Daouda06:12:15

i am sorry but i don't get it riht when you say throw error from side effect

andy.fingerhut06:12:58

@rahul080327 If you call libraries written by others, and they didn't write their code so that it optionally throws an exception when a side effect occurs (and most people don't write code that way), then that technique would only work for you own code, written using that style, and if you forget to throw an exception on some side effects, then that case won't be caught.

andy.fingerhut06:12:31

I am not saying it cannot be done -- it just seems very fragile.

lispyclouds06:12:47

youre right @andy.fingerhut. This is not very common in idiomatic clojure

andy.fingerhut06:12:48

On the positive side, people typically will document which of their library functions can have side effects, and which are pure functions.

andy.fingerhut06:12:19

Or at least sometimes that is mentioned, but more often perhaps "expected to be understood if you understand the library"

lispyclouds06:12:47

@quieterkali so when a side-effect occurs its something that is outside of the usual program flow and is abnormal like a file being missing, or no network etc. These are situations where its not possbile for the code to return normally. hence we throw and exception denoting that something abmormal has happened

andy.fingerhut06:12:22

@rahul080327 Is there some earlier code you are referring to that has the name side-effect in it?

lispyclouds06:12:30

no i try writing functions with a ! at the end of the names to denote a possible side effect

andy.fingerhut06:12:52

Your statement above confuses me. Are you saying that you consider the term "side effects" to only include situations where abnormal things are occurring?

Daouda06:12:55

guys, it's me again

andy.fingerhut06:12:59

Because I think most people use 'side effects' to a situation like: a function writes output to a file on disk, or receives input from a network socket, even when nothing abnormal occurs

Daouda06:12:15

my question can sounds stupid but i need to make sure

lispyclouds06:12:17

I meant situations where things apart from the intended flow happen which may lead to external problems. sorry for being vague

Daouda06:12:33

what is referential transparency?

andy.fingerhut07:12:32

The definition of 'referential transparency' I think kind of depends upon who you ask to define it. Some people use the phrase 'this function is referentially transparent' to mean the same thing as 'this function has no side effects, i.e. is a pure function'

Daouda07:12:37

doesn't mean that if i have a function being called in another one and i just take it away and put the value it is suppose to return, the whoe thing should still work perfectly?

andy.fingerhut07:12:54

Yes, that is a pretty common definition of the term.

Daouda07:12:18

or there is not baut?

andy.fingerhut07:12:42

I have an article I have written about referential transparency, which while doing research on it I found some definitions that I don't fully understand, but seem like they may be subtly different. Here is a link to that article, if you are interested in reading it: https://github.com/jafingerhut/thalia/blob/master/doc/other-topics/referential-transparency.md

Daouda07:12:26

sure, i am interested

Daouda07:12:32

thank you very much

andy.fingerhut07:12:46

I think it is usually safe to assume that "referential transparency" and "pure functional programs" are often intended to mean the same thing.

Daouda07:12:11

another question

andy.fingerhut07:12:19

At least in computer programming. Not sure about philosophy.

Daouda07:12:28

hahahahaha

Daouda07:12:48

so lest say i need some data from data base, but i don't acess it directly

andy.fingerhut07:12:51

Philosophy seems to be where the term originated.

Daouda07:12:05

i write a function to ask the data and provide it to me

andy.fingerhut07:12:50

You can edit your earlier messages content if you want.

Daouda07:12:01

hehehehehe

andy.fingerhut07:12:07

At least with web interface for Slack.

Daouda07:12:32

so back to my question, i make a funtion to call database, and i use it in another funtion

Daouda07:12:05

is that function referentially transparent?

Daouda07:12:03

i mean since can just put the data instead of the function calling the database

andy.fingerhut07:12:07

No, because the return value cannot be determined solely by the arguments.

lispyclouds07:12:02

how ive come to understand referential transperency is that if the outcome also depends on something other than your code like in your case the database connection, data availabilty, File IO errors etc, its not referentially transparent

andy.fingerhut07:12:17

That isn't a very satisfyingly clear answer I wrote there, but I think it is because the meaning of referential transparency isn't simply that you can replace a function call with its return value.

Daouda07:12:38

i nocticed that

Daouda07:12:54

it's deeper than that

Daouda07:12:19

if anything that make your output change or broke because of something else, then you don't have referencial transparency

Daouda07:12:12

i mean for the same input

andy.fingerhut07:12:16

Here is a definition copied from a book referenced on the Wikipedia page for referential transparency: “A [programming] language is referentially transparent if we may replace one expression with another of equal value anywhere in a program without changing the meaning of the program. This is a property of pure functional languages.” The book is "Concepts in Programming Languages" by John Mitchell

andy.fingerhut07:12:26

It seems to me that for a function call that reads from a database or a file, there is no constant expression you could put there that would not change the meaning of the program, in the general case that the database or file contents could be different.

Daouda07:12:29

fair enough

Daouda07:12:25

refactoring everything in my code

Daouda07:12:28

hahahahahahahaha

Daouda07:12:19

that is what happen when you deal with concept you don't really understand

andy.fingerhut08:12:52

As long as you can laugh at it and enjoy the process of learning, you are good 🙂

👍 4
Ali Ebadian08:12:12

Hey all, Hope you're all well. Does anyone know whats the most popular CMS written in Clojure?

nikola11:12:16

how can I get a list of pairs of items from a list, such that [1 2 3 4] turns into [[1 2] [1 3] [1 4] [2 3] [2 4] [3 4]]?

bronsa11:12:05

check the math.combinatorics library

nikola11:12:06

if I can pair up, I can put into a set which will give me all unique pairs?

nikola11:12:20

@bronsa oke, let me look into that

bronsa11:12:38

permutations should be what you want

bronsa11:12:05

actually, combinations rather

danielneal11:12:00

or the brute way

(into #{} (for [a [1 2 3 4]
                b [1 2 3 4]
                :when (not= a b)]
            [a b]))

Daouda12:12:45

heys guys, let's say i have a hashmap and a collection of keys, is there a way to get all the corresponding value from the hashmap at once?

potetm12:12:09

(seq my-map)

potetm12:12:31

well… actually, I’m not certain what you’re asking

potetm12:12:44

(vals my-map) returns just the values

potetm12:12:03

seq returns key-value pairs

Daouda12:12:20

#{1 a 2 b 3 c 4 d 5 e}

keys: (1 2 3) => (a b c) in one call

Daouda12:12:18

but don't want to do a for or map or any kind of iteration to get those values, just pass thoses keys and voilá it should give me back the corresponding values 😄

Daouda12:12:27

is it possible?

Daouda12:12:58

woooooooooww guys i think i've found what i was looking for hahahaha

Daouda12:12:12

(vals (select-keys {:a 1 :b 2 :c 3} [:a :c]))

Daouda12:12:39

output (1 3)

leonoel13:12:51

@quieterkali maps are functions. (map {:a 1 :b 2 :c 3} [:a :c]) is much more idiomatic

Daouda13:12:09

that's why i like this community, full of smart people, you right. i'll definitely use map

Daouda13:12:32

thank you very much @leonoel 🙂

pvillegas1213:12:04

I’m having trouble creating a java File from a string, any pointers?

Noah Bogart13:12:32

like, a file that can be compiled into a java program?

pvillegas1213:12:23

In clojure I want (defn str->file) which returns a java.io.File

pvillegas1213:12:49

I’ve tried to spit and read it back from the file system but some data gets lost in that translation

Chris Bidler13:12:48

Hm, well if you’re getting all the way to and from the filesystem with spit and slurp (or however you’re reading the file) then the issue is likely not your use of spit, but it’s hard to say for sure without a clearer picture of what > some data gets lost in that translation means

pvillegas1213:12:47

I’m manipulating .p12 certificates

pvillegas1213:12:08

and downstream when java processes the file object it complains with :cause DerInputStream.getLength(): lengthTag=111, too big.

Chris Bidler13:12:13

That seems likely to me to be an encoding issue, e.g., spit is likely outputting the .toString of bytes when a DerInputStream expects the binary representation, etc.

Chris Bidler14:12:02

My experience with PKCS is that it’s super fiddly to get right and what I would recommend is to find a known-working example of your workflow, ideally an example from a nearby repo that already talks to the services you’re working with, and just cravenly steal their code via Java interop. 😇

pvillegas1214:12:03

hahahhaa, yeah, my problem is that with a certificate I have in memory, passing the (io/file certificate) works perfectly. When talking through an api with another service, the certificate is sent as an encoded string

pvillegas1214:12:08

that’s where my problems begin

Daouda14:12:02

heys folks, any way to set constrained between two keys of the same schema?

dev.4openID15:12:17

pvillegas12, are setting file to be UT8 when you open file? It may be the reason you "lose" data?

grierson15:12:19

How do I pass a list into JDBC? (jdbc/query conn ["SELECT Id FROM table WHERE Name IN ?" ("Alice" "Bob" Charlie"))

cklaou15:12:59

@grierson You need to quote it in order to prevent clj from evaluating it as a form '("Alice" "Bob" "Charlie")

grierson15:12:24

@chris.klaou I'm actually using a symbol to the name list. How do a quote the symbol?

grierson15:12:01

(def names (list "Alice" "Bob" "Charlie"))

cklaou15:12:29

Doesn't this (jdbc/query conn ["SELECT Id FROM table WHERE Name IN ?" names]) work?

grierson15:12:32

Conversion from UNKNOWN to UNKNOWN is unsupported.

manutter5115:12:25

I'd guess it's probably because you're trying to map multiple values to a single ? placeholder. I haven't done the jdbc stuff for a while though

cklaou15:12:35

(jdbc/query conn ["SELECT Id FROM table WHERE Name IN (?,?,?)" "Alice" "Bob" "Charlie"]) ?

grierson15:12:27

@chris.klaou That does work, but I simplified my question; the name list is actually a parameter.

manutter5115:12:41

I think I remember using something like this once upon a time.

❤️ 4
manutter5115:12:22

Which I thought was horribly ugly 😉

manutter5115:12:19

Whoops, typo (fixed)

manutter5115:12:24

Should have repl’ed it before posting, now it looks better.

cklaou15:12:49

Yeah I think that you need to provide the exact number of ? in the sqlvec string. If you want to make it somewhat more dynamic you have to resort to a solution like @manutter51's

manutter5115:12:17

I’m going back to HugSQL now

grierson15:12:42

@chris.klaou Maybe (repeat "?," (count names))

manutter5115:12:42

Not quite, you’ll have an extra comma at the end that way

donaldball16:12:00

FWIW honeysql and hugsql both have reasonable, contrasting solutions to this problem of constructing dynamic sql queries

👆 4
Noah Bogart17:12:00

honeysql is very nice, hugsql felt very verbose and weighty to me

Daouda17:12:13

@potetm by 30 minutes. am i right?

kazesberger17:12:37

hi, making some babysteps in cljs (having zero xp with JavaScript). i'm trying to make an ajax-call (using cljs-ajax) to my clj compojure backend service that returns a simple plain/text response. i can call my service like this:

$ curl -v 
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 9500 (#0)
> GET /scramble HTTP/1.1
> Host: localhost:9500
> User-Agent: curl/7.47.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Mon, 03 Dec 2018 17:40:14 GMT
< Content-Type: application/octet-stream
< Cache-Control: no-cache
< Content-Length: 4
< Server: Jetty(9.2.21.v20170120)
< 
* Connection #0 to host localhost left intact
TRUE
my cljs call returns a valid response it seems. i get a valid response, cljs-ajax logs to js/console "CLJS-AJAX response: TRUE", and i can log an object instance 'goog.net.XhrIo' which i seemingly can inspect in chrome, but i have no clue how to "discover" valid attributes/functions:

kazesberger17:12:33

and on learning cljs in general: is it good advice to do something like https://javascript30.com/ first?

potetm17:12:02

@quieterkali yeah, ~12min now 🙂

noisesmith17:12:08

the XhrIo object is something that is useful in chaining a callback on completion, as you don't want to block your only thread on IO

Daouda17:12:22

waiting here https://www.twitch.tv/timpote, droping the link here if anyone want to participate

noisesmith17:12:40

@klaus.azesberger also MDN, the javascript site from mozilla, is a good resource once you identify a datatype or function from js https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest https://developer.mozilla.org/en-US/docs/Web/Guide/AJAX/Getting_Started

noisesmith17:12:41

@klaus.azesberger and for the specific wrapper object it handed you - that's a google extension https://google.github.io/closure-library/api/goog.net.XhrIo.html

noisesmith17:12:24

but that's underdocumented and seems to assume you understand the content of the MDN docs linked above

kazesberger17:12:47

thanks a lot @noisesmith! this now the second time you help me 🙂 very much appreciated!

jaide18:12:26

I can’t seem to get my test to pass. I think it’s because I set my ID to SERIAL so each entry gets a new id. Is there a better way to write that test so it doesn’t break if each insert gets a unique id?

Chris18:12:45

@jayzawrotny which assertions fail?

jaide18:12:27

(is (= {:id 1 :payload {:message "Hello World"}}
       (db/get-webhook t-conn {:id 1})))

Chris18:12:19

You get a different payload? Have you tried using a clean in-memory db for your tests?

jaide18:12:50

I’m using a docker postgres and lein test-refresh

jaide18:12:34

The issue is that the return from db/get-webhook is nil

jaide18:12:58

Because the id of the entry may not be 1

hiredman18:12:18

or because you are passing in the number 1 and the type of your column 1 is varchar, which sometimes jdbc drivers or the database will do the conversation for you, but I wouldn't depend on it

Chris18:12:42

I don’t know lein-refresh, but if your db is clean every test run and you only insert one webhook then getting id 1 should work

jaide18:12:55

In my table the type of my id is SERIAL

jaide18:12:31

It probably isn’t clear that I’m not using any of the auto generated code

jaide18:12:57

Was just including it for reference because those tests pass. I think I found a possible solution though: https://www.hugsql.org/#using-insert

jaide18:12:33

I can use one of those options to get the newest item id from the insert

👍 4
jaide19:12:25

Ok found a good solution to get the last row inserted which I can then test against. What’s a recommended way to test a map if it contains a sub map or a series of specific key-value pairs?

jaide19:12:18

For instance I don’t care about testing the created_at value which will be an auto-generated timestamp.

Chris19:12:45

select-keys could work

jaide19:12:52

I see so something like

(is (= {:payload {:message "Hello World"}} 
       (select-keys result [:payload}])))

Chris Bidler19:12:22

and for “sub-map” get-in is your friend:

boot.user> (get-in {:a "b" :c {:d "e" :f {:g "h"}}} [:c :f :g])
"h"
boot.user> (get-in {:a "b" :c {:d "e" :f {:g "h"}}} [:c])
{:d "e", :f {:g "h"}}
boot.user> 

jaide19:12:58

Ack. Sorry I wasn’t clear, I meant more for like (contains? {:a 1 :b 2 :c 3} {:a 1 :b 2}) => true

Chris Bidler19:12:57

ah, so there I think every?:

jumpnbrownweasel19:12:59

(= s2 (select-keys s1 (keys s2)))

Chris Bidler19:12:01

(let [correct-kvs {:a 1 :b 2}
                 test-kvs    {:a 1 :b 2 :c 3}]
             (every? #(= (get % correct-kvs) (get % test-kvs)) (keys correct-kvs)))

Chris Bidler19:12:22

or the much cleaner thing @UBRMX7MT7 just said. ^_^;

jaide20:12:23

Perfect, thanks!

jaide20:12:01

Also found

(defn submap?
  "Checks whether m contains all entries in sub."
  [^java.util.Map m ^java.util.Map sub]
  (.containsAll (.entrySet m) (.entrySet sub)))
from https://stackoverflow.com/questions/20421405/how-to-check-if-a-map-is-a-subset-of-another-in-clojure

jumpnbrownweasel20:12:22

Seems like a good one if you're not using clojurescript.

👍 4
jstaab19:12:30

Hey does anyone know how to prevent control characters from showing up in my repl? I'm using rlwrap ./node_modules/.bin/shadow-cljs node-repl and every time I hit up to browse history, it adds "[A" to the beginning of my line, which borks up cursor position. It's driving me nuts. This only happens after navigating left or right with my arrow keys.

jstaab19:12:34

I'm in tmux, in case that's relevant

noisesmith19:12:46

rlwrap should be eliminating that problem, unless your terminal is misconfigured or there's unusual delay in a remote connection

jstaab20:12:39

It's possible, I have a pretty loose grasp of how terminal input/output works. This is unique to shadow-cljs though; for example the python repl works fine.

jaide19:12:16

(deftest test-webhooks
  (jdbc/with-db-transaction [t-conn *db*]
    (jdbc/db-set-rollback-only! t-conn)
    (let [webhook (db/save-webhook! t-conn {:payload {:message "Hello World"}})]
      (is (= {:payload {:message "Hello World"}}
             (select-keys webhook
                          [:payload])))
      (is (= {:payload {:message "Hello World"}}
             (select-keys (db/get-webhook t-conn {:id (:id webhook)})
                          [:payload]))))))

jaide19:12:48

Is this a reasonable way to test that the db fns work correctly?

jaide21:12:44

java -cp target/uberjar/app.jar clojure.main -m app.core
Also, is there a way to run a built jar in a way where I get errors? My app is immediately exiting when I run that.

noisesmith21:12:15

what is the return code? - you can use clojure.main to start a repl from your jar

Alex Miller (Clojure team)21:12:20

one common problem is to make your main call a lazy function without realizing it (and thus lazily doing nothing)

Alex Miller (Clojure team)21:12:39

sorry, a function that returns a lazy seq I should say

Lennart Buit21:12:48

(there is run! for that right)

Alex Miller (Clojure team)21:12:02

that’s one of many ways to solve that

noisesmith21:12:04

if it's returning 1 there should be some error message / stack trace

jaide21:12:30

Unfortunately not seeing any stack traces

jaide21:12:36

Trying lein run

Lennart Buit21:12:05

it has bitten me at some point yeah, where I was trying to each over a collection and clojure promptly decided it had to do nothing at all :’)

jaide21:12:33

It’s a luminus template not saying that couldn’t be the case but I don’t think that’s the issue.

jaide21:12:22

Oh! I see 😅 it dies if postgres can not be connected to and I’m running postgres in a container but running the uberjar outside of it.

noisesmith21:12:31

that would do it

jaide21:12:50

I should probably uberjar it in the docker container I intend to run it from right?

noisesmith21:12:18

you can uberjar as part of constructing the container

noisesmith21:12:33

then you have the advantage of not needing lein inside the container

noisesmith21:12:49

also issues with caching deps are mitigated

jaide21:12:45

Hmm may need to make a separate docker file\container for that then. The one I’m using is for development with a postgres instance. The production version will be deployed to heroku.

noisesmith21:12:35

running lein inside the Docker container is also an option, but that means you are rebuilding your app when restarting effectively

noisesmith21:12:11

and either you pre-propagate your deps in a cache for the container, or you have to download the whole world on every restart...

jaide21:12:18

Ah, I do have it running lein deps as part of the build process for this development container

jaide21:12:39

version: '3'

services:
  db:
    image: postgres:latest
    volumes:
      - "dbdata:/var/lib/postgresql/data"
  repl:
    build: .
    tty: true
    stdin_open: true
    command: lein repl :headless :host 0.0.0.0 :port 7000
    ports:
      - "3030:3000"
      - "7000:7000"
    depends_on:
      - db
    volumes:
      - .:/opt/webapp

volumes:
  dbdata:

jaide21:12:46

That’s the docker-compose file

jaide21:12:07

FROM clojure

EXPOSE 3000
EXPOSE 7000

RUN mkdir /opt/webapp
WORKDIR /opt/webapp

ADD project.clj .

RUN ["lein", "deps"]

jaide21:12:09

Docker file

jaide21:12:29

If I add the uberjar step to the dockerfile that means I’d have to rebuild the image every time I want to run uberjar before making a deploy though right?

noisesmith21:12:06

how does docker get your current code?

jaide21:12:31

I’m mounting the source as a volume

noisesmith21:12:48

in that case you could as easily put an uberjar in there too

noisesmith21:12:04

unless it only gets that source via git?

jaide21:12:18

Nope, the docker setup is currently for development purposes. The code is a git managed dir on my host mac and then I run the docker containers with postgres and the clojure image with the source mounted volume running lein repl.

jaide21:12:17

After running lein with-profile uberjar run to run the server in a production-like environment I get:

Error encountered performing task 'run' with profile(s): 'uberjar' Suppressed exit```

noisesmith21:12:08

using the uberjar profile to run seems weird

jaide21:12:54

Ah, though it does seem to mimic the behavior of running the jar that exits immediately.

jaide21:12:04

Which is also happening in the docker image with access to the db.

jaide21:12:52

Gonna take a lunch break. Still just nothing when I execute this jar. Any better ways to run lein run in a prod like environment?

jaide22:12:04

Ah-hah! The jar reading the production config variables. Am I supplying it incorrectly:

java -jar target/uberjar/ts-api-explorer.jar -Dconf=prod-config.edn

noisesmith22:12:51

you want -Dconf before the -jar

jaide22:12:01

Placed it before, still get an early exit. But if I use export PORT=… and such manually it works.

jaide22:12:16

Nevermind, typo.

jaide22:12:02

Thanks a ton for all your help. I think I’m finally ready to deploy this thing!