Fork me on GitHub
#clojure
<
2021-03-12
>
zendevil.eth06:03:13

I’m doing a db query using the monger library like so:

(q/with-collection db "videos"
             (q/find {})
             (q/sort {:date 1})
             (q/paginate :page page :per-page 5))
However, when I do page 1, I get the following ids:
("6011a14028dacb0004d7475c"
"6011a1ea28dacb0004d7475d"
"60119fe128dacb0004d7475a"
"602a15665273b0b82c3ded1c"
"6011a0b428dacb0004d7475b")
when I do page 2, I get these:
("6011a14028dacb0004d7475c"
"60119fe128dacb0004d7475a"
"602a15665273b0b82c3ded1c"
"6011a0b428dacb0004d7475b"
"60124ed4afa8e90004ab71a0")
The problem is that there’s an overlap of ids between the two pages. I expect the pages to show ids with no overlap. How to fix this?

svt08:03:40

What would you suggest for using Graphql in Clojure?

agile_geek08:03:04

Take a look a Lacinia

borkdude12:03:15

@nilern About yesterday's discussion: I guess Clojure has the same kind of issue but smaller in scope and more apparent to a user who defines things with proxy:

user=> (ifn? (proxy [clojure.lang.APersistentMap] []))
true
So the predicate returns true, while at runtime you will get an UnsupportedOperationException when trying to call it as a function

nilern12:03:42

Oh. But much more tolerable since it is so rare and already annoying to have to use proxy.

borkdude12:03:38

yeah, and the scope for which this will give "false" positives is much smaller

restenb12:03:22

puzzle: given a vector of vectors like [[1 5 3][4 10 35 9][2 7 19]], I want to pick the one that contains the highest single value. In this case, it would be [4 10 35 9]since 35 is the highest number in any of the vectors.

javahippie12:03:19

Definitely not the most optimized version

simongray12:03:00

this is mine - also not really optimised. It does handle the case that there can be more than 1 vectors to return, though.

(defn max-vecs
    [coll]
    (let [n (apply max (flatten coll))]
      (filter (partial some #{n}) coll)))

👍 3
simongray12:03:13

or the code golf version:

(defn max-vecs
    [coll]
    (filter (partial some #{(apply max (flatten coll))}) coll))

borkdude13:03:06

Weird naming

restenb13:03:52

thanks for all the replies guys! I didn't know about max-key either, that one is quite elegant.

vanelsas13:03:29

Late to the party, this takes the input as requested and delivers the output too (not optimised)

(defn max-vec [v] 
  (let [res (map #(vector (apply max %) %) v)  
        m (into {} res)] (get m (apply max (keys m)))))

Joe15:03:51

How about

(last (sort-by #(apply max %) [[1 5 3] [4 10 35 9] [2 7 19]]))

restenb12:03:59

there are ways to do it with a couple of let-bindings and .indexOfat the end, but ...

borkdude13:03:42

@restenb

user=> (max-key #(apply max %) [1 5 3] [4 10 35 9] [2 7 19])
[4 10 35 9]

raspasov15:03:36

Safe version (also makes sure the original input vector is not empty, which also fails.

(when-let [coll (not-empty (remove empty? [[1 5 3][4 10 35 9][2 7 19]]))]
  (apply max-key #(apply max %) coll))

borkdude15:03:29

You can also fold the empty? check into the predicate

borkdude13:03:37

beware of empty collections, since max requires at least one arg

👆 6
Jeremy Cronk15:03:09

I have a weird issue coming up when I try to test a generated class that uses a gen-interface. The interface has a method that’s overloaded a few times, but the one in question is supposed to take and return a string. If I go into the REPL and create an instance of the class, then call the method with a string, everything’s totally fine and it gives me the right result. But for some reason when I run a test that does, as far as I can tell, the exact same thing, I get an AbstractMethodError and it’s saying giving the method signature as (Ljava/lang/String;)Ljava/lang/String, which I don’t understand at all. Maybe this is my inexperience with Java showing, but I just don’t understand what it’s doing differently between the test and calling it from the REPL. Is there something obvious going on here that a Java person might pick up on immediately?

noisesmith15:03:56

that L prefix means it wants an array of string, which can be implicit if the method takes varargs

noisesmith15:03:08

you probably need to share your code (or a simplified version), but another issue is that gen-interface doesn't reload like normal clojure code, so your repl might not reflect the current code even if you reloaded the code

Jeremy Cronk15:03:47

Hm, okay. I don’t have my Leiningen REPL set up right, so it doesn’t reload correctly and I always end up exiting it and starting it again when I try testing it like this.

Jeremy Cronk15:03:36

My entire gen-interface is here:

(gen-interface
  :name XSLTTransformer
  :methods [[transform [java.io.File java.io.File] void]
            [transform [javax.xml.transform.Source java.io.File] void]
            [transform [java.io.File] String]
            [transform [javax.xml.transform.Source] String]
            [transform [String] String]
            [updateConfiguration [java.util.Map] void]
            [getConfiguration [] java.util.Map]
            [setConfiguration [java.util.Map] void]])
I have the signature set as String, so I don’t get why it would be looking for an array of strings

noisesmith15:03:15

also gen-interface is a weird corner of the language, I've never needed it, there could be gotchas that I'm unaware of still. what's your use case - you need java code to use your lib via an interface?

noisesmith15:03:05

or a java lib is written such that it takes an interface as a parameter?

noisesmith15:03:04

I don't see how any of those methods would end up taking or returning an array

Jeremy Cronk15:03:11

Well, I ended up creating this in a Java-ish way, but basically I have two XSLT transformers that I need to wrap with a consistent API that will be used from Java.

noisesmith15:03:31

I have a hunch this would be much easier using a gen-class, plus a implementation object that extends a clojure protocol

noisesmith15:03:00

(in clojure land, each instance of the object would own as member data an implementation of the protocol)

Jeremy Cronk15:03:06

Oh, okay, something weird is happening because I’m trying to delegate. This is probably a stupid approach, but I didn’t have a lot of time to get it done. Basically there are two gen-classes that implement the interface and then there’s a third class that implements the interface and uses its constructor to choose one of the other two classes to delegate to.

Jeremy Cronk15:03:25

Ah, okay, so I’d want a protocol like “Transformable” or something, then define the methods from there?

noisesmith15:03:27

right, you can still do the delegation with protocols, but protocols play nicer with the rest of clojure I think -the big gotcha here is that protocols don't differentiate methods for dispatch based on type, only name plus arg count

noisesmith15:03:47

(I don't have proof that gen-interface doesn't have the same issue...)

Jeremy Cronk15:03:52

Interesting, thanks. I’ll have to reread the documentation for protocols - I’ve used them a bit, but I don’t have the experience to necessarily know when/why to use them. I still need to figure out what’s going wrong with my delegation for now, but what you’re suggesting seems like a better direction that’s more Clojure-ish.

noisesmith15:03:40

the docs say that if you aren't compiling gen-interface is a no-op, are you using a separate aot step?

Jeremy Cronk15:03:10

Yeah, I have the classes set to aot in my project file

noisesmith16:03:19

I feel a bit irresponsible trying to weigh in here when I haven't used it (and also know it will be weird), but I don't think there are many people who use the function so I hope some answer is better than none

Jeremy Cronk16:03:26

Aha, replacing the gen-interface with a protocol seems to have fixed the immediate issue - I’ll have to go back later and try to rearrange things to take better advantage of the protocol, but this gets me to where I need to be. Thanks!

noisesmith16:03:16

consider writing a doc on http://clojuredocs.org or a blog post if you figure out how to make gen-interface work- it feels like a dark corner of the language currently

👍 3
borkdude15:03:33

Is there an example of an abstract class in the Java stdlib that takes arguments in the constructor?

p-himik16:03:24

java.lang.AbstractStringBuilder

p-himik16:03:35

java.lang.VirtualMachineError, if you need a public constructor.

borkdude16:03:09

cool, I wondered if the args to the super contructor can be dynamic and they can be:

(defn foo [m]
  (proxy [java.lang.VirtualMachineError] [(:msg m)]))

(prn (.getMessage (foo {:msg "bar"})))

👍 3
Alex Miller (Clojure team)16:03:07

maybe somewhere in swing

mafcocinco21:03:35

Wasn’t sure if there was a channel for core.match. Had one very specific question: Is it possible to dynamically generate patterns from data at runtime (i.e. what is contained in the match form) or would it require some macro magic? All the examples that I have seen look to be static/“hard coded” into the source code.

borkdude21:03:59

@mafcocinco core.match/match is a macro. the only way to make this more dynamic is to use eval

borkdude21:03:44

$ bb -e "(defn dyn-match [pat & clauses] (eval \`(clojure.core.match/match ~pat ~@clauses))) (dyn-match [(+ 1 2 3)] [(+ 1 2 3)] :yo)"
:yo

mafcocinco21:03:24

yeah, that is what I figured. Doable but kind of a bummer that we have to know the patterns ahead of time (or use eval). Would be cool if core.match had a data driven interface.

borkdude21:03:43

I think the main reason it's a macro is that the pattern can be compiled to something efficient

borkdude21:03:08

Take a look at matchete if you need something more basic and fn-driven: https://github.com/xapix-io/matchete

borkdude21:03:29

or maybe even malli

mafcocinco21:03:19

the usage of the patterns is going to be time sensitive, so I would like the benefit of the efficient compilation. If eval works, I would be fine with it as I run the compilation “offline”.

mafcocinco21:03:41

I will check out your other suggestions too and see if one of those might be a better fit.

borkdude21:03:45

Also #meander has an interpreter which accepts data instead of compile time patterns (it does both)

borkdude22:03:57

With malli:

user=> (m/parse [:catn [:a [:= 1]] [:b :any] [:c [:= 3]]] '[1 2 3])
{:a 1, :b 2, :c 3}

richiardiandrea21:03:09

Hi there, I have a question, if I have an implementation like this

(s/fdef delete-by-id!
  :args (s/cat :impl any?
               :file-id ::id)
  :ret number?)

(defn delete-by-id!
  [impl file-id]
  (...)

(defmethod ig/init-key ::impl [_ {:keys [db]}]
  (with-meta
    {:db db}
    {`interfaces.file-repository/append-files append-files!
     `interfaces.file-repository/find-info-by-id file-info-by-id
     `interfaces.file-repository/find-content-by-id file-content-by-id
     `interfaces.file-repository/delete-file delete-by-id!}))
Should I expect the instrumented delete-by-id! to throw (cause it does not)

p-himik21:03:02

AFAIK s/fdef will be checked against only if the corresponding function have been instrumented: https://clojure.org/guides/spec#_instrumentation

richiardiandrea23:03:56

@U2FRKM4TW yeah the function is instrumented