Fork me on GitHub
#code-reviews
<
2020-07-03
>
adam02:07:25

Hey guys. How does this function look (generating some fixture data):

(defn- insert-classes! [datasource]
  (let [teachers (db/find-by-keys datasource :user {:role (db/enum (:teacher user/roles))} {:columns [:id] :limit 2})]
    (doseq [t teachers]
      (db/insert-multi!
        datasource
        :class
        [:name :school :description :archived :teacher_id]
        (take 5 (repeatedly #(seq
                               [(first (names))
                                (first (co-names))
                                (join " " (take 3 (sentences)))
                                (rand-nth [true false])
                                (:user/id t)])))))
    (println "Inserted  classes")))
Particularly the (take 5 (repeatedly #(seq part. Is it alright or it can be simplified? Still new to lazy seqs.

seancorfield02:07:34

So the (names), (co-names) etc are all zero-arg side-effecting functions that do ... what?

noisesmith02:07:22

OK yeah this isn't how lazy-seqs work at all

noisesmith02:07:57

on each call you are generating a lazy stream of names, and only consuming one, and on the next call you make a new stream

adam03:07:03

What I can do about that when it’s an external library and I only need one name?

seancorfield03:07:24

See what I posted in the main channel.

seancorfield02:07:10

And why are you calling seq on the vector?

adam02:07:02

Because this works for me:

(take 5 (repeatedly #(seq [1 2])))
And this doesn’t:
(take 5 (repeatedly [1 2]))

seancorfield03:07:17

(repeatedly #(vector 1 2))

👍 3
seancorfield02:07:42

@somedude314 Can you provide a bit more background on what exactly you're trying to do here?

adam02:07:59

I am basically trying to populate the vector inline for insert-multi!

seancorfield03:07:38

Looks like you should map over the various lazy fakers and make a vector: (map vector (names) (co-names) (map #(str/join " " %) (partition 3 (sentences))) ...)

seancorfield03:07:11

Then (partition 5 ...) over that to get groups of five rows each.

seancorfield03:07:22

(repeatedly #(rand-nth [true false])) would give you the generator for the archived values in that (map vector ...)

seancorfield03:07:18

I'd probably create the teacher ID series with (mapcat #(repeat 5 %) (map :user/id teachers)) and that would be the last sequence in that (map vector ...) -- the fifth and final of the sequence arguments.

seancorfield03:07:35

That would also cause the number of teachers to control how many groups of 5 rows you got, so it would automatically grow as you changed the :limit to different values.

seancorfield03:07:01

and finally (doseq [row-group (partition 5 (map vector (names) ...))] (jdbc/insert-multi! datasource :class [:name :school :description :archived :teacher_id] row-group)

seancorfield03:07:56

So the key here is to take a series of (infinite) lazy sequences and use map vector to take corresponding elements from all of them and put them together in rows -- so this in turn would be an (infinite) lazy sequence of rows.

seancorfield03:07:34

The (partition 5 ...) and the #(repeat 5 %) (inside the mapcat over the teachers) are related so pulling the 5 out of both as a local binding to class-size or something similar would make sure they stay in sync.

seancorfield03:07:26

So you can see what I'm taking about on a small scale:

user=> (defn names [] (cycle ["Sean" "Adam"]))
#'user/names
user=> (defn co-names [] (cycle ["ACME" "Saint Mary's" "Collyer's"]))
#'user/co-names
user=> (take 2 (partition 5 (map vector (names) (co-names))))
((["Sean" "ACME"] ["Adam" "Saint Mary's"] ["Sean" "Collyer's"] ["Adam" "ACME"] ["Sean" "Saint Mary's"]) (["Adam" "Collyer's"] ["Sean" "ACME"] ["Adam" "Saint Mary's"] ["Sean" "Collyer's"] ["Adam" "ACME"]))
user=>

adam03:07:25

Thanks for the detailed input! Will try to put this together and see what I can come up with.

seancorfield03:07:13

Here's the above with fake sentences added:

user=> (defn sentences [] (cycle (str/split "The quick brown fox jumped over the lazy dog" #" ")))
#'user/sentences
user=> (take 2 (partition 5 (map vector (names) (co-names) (map #(str/join " " %) (partition 3 (sentences))))))
((["Sean" "ACME" "The quick brown"] ["Adam" "Saint Mary's" "fox jumped over"] ["Sean" "Collyer's" "the lazy dog"] ["Adam" "ACME" "The quick brown"] ["Sean" "Saint Mary's" "fox jumped over"]) (["Adam" "Collyer's" "the lazy dog"] ["Sean" "ACME" "The quick brown"] ["Adam" "Saint Mary's" "fox jumped over"] ["Sean" "Collyer's" "the lazy dog"] ["Adam" "ACME" "The quick brown"]))
user=>

👌 3
adam14:07:58

(defn- insert-classes! [datasource]
  (let [teachers (db/find-by-keys datasource :user {:role (db/enum (:teacher user/roles))} {:columns [:id :email] :limit 2})
        class-size 5]
    (doseq [row-group (partition
                        class-size
                        (map vector
                             (names)
                             (co-names)
                             (map #(join " " %) (partition 3 (sentences)))
                             (repeatedly #(rand-nth [true false]))
                             (mapcat #(repeat class-size %) (map :user/id teachers))))]
      (db/insert-multi! datasource :class [:name :school :description :archived :teacher_id] row-group)))
  (println "Inserted  classes"))
Learned a lot, truly appreciated.

3