Fork me on GitHub
#beginners
<
2022-01-08
>
jimmysit000:01:49

How can I read the content of a channel chan ?

hiredman00:01:44

<! or <!! or take!

jimmysit000:01:31

How would I do it using take, could you send an example?

hiredman00:01:03

You can read the doc string in your repl

jimmysit000:01:44

I pretty much know the difference between <!, and <!!. Although it isn't really clear how can I use them to read something, when their use case is completely different. From my understanding < stands for put. And take well, the name is pretty descriptive

jimmysit000:01:04

Do you mean take! as >?

hiredman03:01:12

You have the meaning of your > flipped

hiredman03:01:36

The way to remember is the arrow indicates the direction dataflows, >! (put) is towards the channel, <! (take) is away from the channel

❤️ 1
hiredman00:01:44

<! works in go blocks, <!! works on blockable threads, take! takes a callback

tabidots03:01:14

I need to figure out what DB to use for a web app I’ve just started working on, but I am a bit overwhelmed by all the options out there. (I used Mongo once, a long time ago, and that’s it—I don’t know much about DBs) • I want to deploy to Heroku • Data is a huge hash-map of information (not state) 3-4 nesting levels deep, to be loaded once and only read by users, never written to • Not sure of final data size yet but will probably be well under 25MB, maybe even under 10MB. I don’t need any fancy querying capabilities beyond core Clojure functions, so something like XTDB or Datahike seems like overkill. In-memory seems like the way to go, so H2 and Redis looked like possibilities, but I would like to keep everything as close to Clojure as possible. Enduro (going the file-backed route) seems like an interesting possibility—would that be a good choice? Or is it only possible to use Enduro on Heroku with PostgreSQL?

phronmophobic04:01:40

> • Data is a huge hash-map of information (not state) 3-4 nesting levels deep, to be loaded once and only read by users, never written to Read by users how? Are you planning on providing the full data set to every user that loads the page? If the full db is going to be made available and you only need clojure functions, then you could just encode the full data set using something like https://github.com/cognitect/transit-clj.

phronmophobic04:01:40

If you're not sending the full data set, then you could just store the data locally as edn (transit isn't meant for persisting data) and read the file into memory on startup.

phronmophobic04:01:58

If you're deploying your web app as a jar, then you could include the edn file as a resource that can be read using . Jars are compressed, so the edn data should compress reasonably.

1
tabidots04:01:27

It’s a database of natural-language word data (a dictionary, more or less). Lookups will be one word at a time, but I want it to return available results instantaneously as the user types, without having to press a submit button

tabidots04:01:31

Sounds like a simple and effective solution! I had been reading about using .edn files for this purpose but wasn’t sure if it was suitable for production. Thanks!

👍 1
phronmophobic04:01:48

depending on your users, there are several trade-off you can consider. • sending the full dataset to each web app user will generally increase page load time, but make search-as-you-type more responsive • sending results on demand will generally decrease page load time, but make search-as-you-type less responsive • there are many middle-ground options that require more/less effort and can tailor the experience towards users based on their usage and network speeds

tabidots04:01:22

Hmm, I didn’t really consider sending the full dataset at once. I figured the practical limit on the size of the data would be too restrictive (with regard to page load time)

tabidots04:01:08

I think I should prototype it first with the easiest-to-implement option (send on demand) and evaluate the performance then

phronmophobic04:01:22

well, depending on the size of the dataset, it might be easiest to just load all the data as an ajax call. If it's 10Mb uncompressed, it might be much smaller compressed.

tabidots04:01:08

Hmm. So I can read the .edn file in CLJS? If the file ends up being small enough I might not even need a backend

phronmophobic04:01:34

10Mb is already in the range of a large jpeg file.

phronmophobic04:01:53

Yes, you could read edn data directly in cljs.

1
tabidots04:01:13

Perfect! This approach sounds like a winner. Thank you 🙏:skin-tone-2:

phronmophobic04:01:18

You could potentially even consider creating a static html file with the data embedded within a script tag

wow 1
tabidots04:01:06

Oh, that’s also pretty interesting. So the script tag would contain the huge hash-map (as-is) and my app would just require the name I give it?

phronmophobic04:01:56

Well, you would probably assign the huge hash map to a global variable and then reference that variable from your cljs code.

tabidots04:01:42

Gotcha. Haven’t done front-end in years and also never tried to do something like this (the last web app I did had a pretty conventional REST API setup)

phronmophobic04:01:57

I've done stuff like this for a few projects that want either very low server costs or very low ongoing maintenance and it's hard to beat just serving static assets.

1
tabidots05:01:46

I’m relieved to know that this app might not even require a backend. Doing a CLJS web app is already new territory for me, so not having to learn Heroku and how to interact with DBs in Clojure simplifies things a lot. Thanks again!

kenj04:01:26

Why not just load your data into a var in your app?

2
1
👍 1
tabidots04:01:28

@risinglight yep, I think I’m going to just dump it to an .edn file and load that in on startup. Was definitely overthinking it. Thanks!

seancorfield05:01:53

Some folks in the early Agile camp talk about building several production systems that ended up still using flat files for storage -- a decision that was made for the earliest MVP when they hadn't decided which database to use (or, indeed, whether to use a database at all).

wow 3
tabidots05:01:46

@seancorfield Very cool. I like that simplicity! @smith.adriane just gave me the (mind-blowing, to me) idea of skipping the backend entirely and serving the entire .edn as a static asset… which I assume would be done as in the snippets here: https://stackoverflow.com/questions/15423136/how-can-i-pass-edn-to-clojurescript-from-clojure-without-making-ajax-request-i

phronmophobic07:01:38

The only extra thing I would add is that this technique works best for data you control. I don't think it applies here, but if you want to embed user generated data, there are some extra precautions to avoid xss vulnerabilities. See comments under https://stackoverflow.com/a/21022656.

fearnoeval15:01:17

Not XSS (at least by itself), but opening HTML comments (`<!--`) inside of an embedded JSON string can also bite you inside of that context.

tabidots14:01:42

Oh, good to know. Yeah, I won’t have to worry about it for this project but for future ones I’ll keep that in mind.

tabidots14:01:10

Btw, @smith.adriane @seancorfield, I got the embedded EDN working and it is awesome. I can fetch just a handful of Wiktionary pages at a time, process/dump a little bit of data to work with as a test, and make progress before spending hours pulling all the Wiktionary pages I need and committing the final data… all without a database. Thanks for the idea!

🎉 1
seancorfield05:01:23

Yeah, it's kind of amazing how much can be done directly in the browser these days and the volume of data that can be loaded and manipulated...

popeye12:01:03

i am using linux and I have defined below in my project.clj , But this only running less auto , and not starting the server ? my co worked is using windows and both server and lein auto is running, Is there any issues with OS? Also I have referred https://stackoverflow.com/questions/47075245/run-more-than-one-lein-task-at-the-same-time

:aliases {"watch" ["pdo" ["figwheel" "dev-run"]
                         ["less" "auto"]]}

Timofey Sitnikov19:01:38

Hello all, when I run an sql query, my result is super flat like so:

[{:problem/id #uuid "017e10f",
  :problem/summary_id #uuid "017e10f",
  :problem/detail_id #uuid "017e10f",
  :problem/account_id #uuid "017e1042",
  :problem/created_at #inst "2021-12-31T14:50:35.595503000-00:00",
  :solution/id #uuid "017e344f",
  :solution/problem_id #uuid "017e10f"}
 {:problem/id #uuid "017e10f",
  :problem/summary_id #uuid "017e10f",
  :problem/detail_id #uuid "017e10f",
  :problem/account_id #uuid "017e1042",
  :problem/created_at #inst "2021-12-31T14:50:35.595503000-00:00",
  :solution/id #uuid "017e3479",
  :solution/problem_id #uuid "017e10f"}
 {:problem/id #uuid "017e1610",
  :problem/summary_id #uuid "017e1610",
  :problem/detail_id #uuid "017e1610",
  :problem/account_id #uuid "017e1042",
  :problem/created_at #inst "2022-01-01T14:35:00.445598000-00:00",
  :solution/id nil,
  :solution/problem_id nil}]J
I would like it to be more like this:
{"017e10f8" {:problem/id #uuid "017e10f8",
             :problem/summary_id #uuid "017e10f8",
             :problem/detail_id #uuid "017e10f8",
             :problem/account_id #uuid "017e1042",
             :problem/created_at #inst "2021-12-31T14:50:35.595503000-00:00",
             :problem/solutions {["017e344f" {:solution/id #uuid "017e344f",
                                              :solution/problem_id #uuid "017e10f8"}
                                  "017e3479" {:solution/id #uuid "017e3479",
                                              :solution/id #uuid "017e3479",}]}}
 "017e1610" {:problem/id #uuid "017e1610",
             :problem/summary_id #uuid "017e1610",
             :problem/detail_id #uuid "017e1610",
             :problem/account_id #uuid "017e1042",
             :problem/created_at #inst "2022-01-01T14:35:00.445598000-00:00",
             :problem/solutions {}}}
I do use next.jdbc and I am getting all that data through a single fetch like so:
(defn home-problems [ds]
  (jdbc/execute! ds ["   SELECT p.id,p.summary_id,p.detail_id,p.account_id,
                                p.created_at,s.id,s.problem_id
                           FROM problem p
                      LEFT JOIN solution s
                             ON p.id=s.problem_id"]))
What is the easiest, efficient way of arranging the data into the clojure data structure?

seancorfield19:01:02

Since the desired structure is going to be domain-specific, you'll have to write your own code to reduce over the results and produce the structure you want.

1
seancorfield19:01:31

Once you have a specific structure in mind, you can probably write something fairly generic that uses namespace and name on the keys and looks for a "primary" namespace (`problem` in the case above) and treats other namespaces as secondary -- solution in your case.

seancorfield19:01:40

(but, as the author of next.jdbc and maintainer of both clojure.java.jdbc and HoneySQL, I tend to push back on folks who want to turn flat maps with namespace keys into nested maps)

seancorfield19:01:49

A simple place to start, BTW, would be (into {} (map (juxt :problem/id identity)) results) -- that will produce a hash map keyed by the :problem/id values mapping to the records.

Timofey Sitnikov20:01:26

OK, this gives me a good direction. I had no idea if there was a more or less a common way of doing, but it sounds like you just have to work through data. The points about using into and juxt are helpful as well.

maziar rumiani22:01:23

Hi guys, I have some questions in Clojure: 1- How can I run a function in a special namespace with repl? The repl is in that namespace now but I can't call that function 2- I have an input and I update the value with on-change event. I want to update another state synonymously. for example, if I type "Hello word" I want to be shown in another div (another component) below the input. Do you know how can I do this with Clojure? 3- What is the efficient way to run a function after 300 ms?

emccue02:01:37

1. Depends on your editor. You should have a shortcut to load the contents of the current file into the repl and a shortcut to switch to the ns of the current file. 2. Well, you need to share the state. I am assuming you are talking about reagent in ClojureScript, in which case this would sorta do it, but if you want to “solve” that problem in general you might want to look to re-frame

(defn comp-1 [text on-edit]
  [:input {:on-change (fn [e] (on-edit (.. e -target -value)))
           :value text}])

(defn comp-2 [text]
  [:h1 text])

(defn comp-3
  (let [text-atom (r/atom "")]
    [:div
      [comp-1 @text-atom #(reset text-atom %)]
      [comp-2 @text-atom]]))
3. In ClojureScript or Clojure (JVM)? In clojurescript js/setTimeout . In JVM Clojure the answer is more complicated since threads are more expensive, but ScheduledExecutorService would be the place to look

Muhammad Hamza Chippa22:01:45

I have using this function but the problem is that ajax call is keep on calling and don't stop how can I make that ajax call is called one time ? I can't use the ajax call outside the function.

(defn view-event-panel []
  (let [event-response (reagent/atom {})]
    (fn []
      (ajax/get-json-header url
                     {:content-type "application/json"
                      :password "123"}
                     (fn [response]
                       (if (empty? response)
                         (notify 102 "No results")
                         (swap! event-response assoc :event-response response))))
      [:div.form-horizontal
       [:legend [:h3 "View Event"]]
       [:p (str @event-response)]
       ])))

emccue01:01:49

(defn view-event-panel []
  (let [event-response (reagent/atom {})]
        ajax-call (delay (ajax/get-json-header url
                           {:content-type "application/json"
                            :password "123"}
                           (fn [response]
                             (if (empty? response)
                               (notify 102 "No results")
                               (swap! event-response assoc :event-response response))))
    (fn []
      @ajax-call
      [:div.form-horizontal
       [:legend [:h3 "View Event"]]
       [:p (str @event-response)]
       ])))

emccue01:01:08

if you truly can’t make the call outside of that inner function - then a delay will work