Can function be passed as input argument to a query?

I have transacted custom function:

{
    :db/id    #db/id [:db.part/user]
    :db/ident :search.fn/getLinksByValue
    :db/doc   "Used to get link values filtering on passed values for passed attributes"
    :db/fn    #db/fn {:lang   "clojure"
                      :params [db valueAttributeIdents searchValue linkAttributeIdent]
                      :code   [[(datomic.api/q
                               "[:find [?linkValue ...] :in $ [?valueAttributeIdents ...] ?searchValue ?linkAttributeIdent
                               :where
                                   [?ex_e ?valueAttributeIdents ?searchValue]
                                   [?ex_e ?linkAttributeIdent ?linkValue]
                               ]"
                               db valueAttributeIdents searchValue linkAttributeIdent)]]}
}

I see it installed

Then in repl I’m getting function by:

(def myFuncEn (d/entity (d/db connInternal) :search.fn/getLinksByValue))
(def myFunc (.get myFuncEn :db/fn))

And the call is:

(d/q "[:find (pull ?Post [:db/id :model/type :Post/title :Post/uid])
	 :in $ $comment ?myFunc ?modelType_value_0 ?Comment_text_value_1
	 :where
		
		 [?Post :model/superTypes ?modelType_value_0]
		 (not-join [?Post ?Comment_text_value_1]
		   [(?myFunc $comment [:Comment/text] ?Comment_text_value_1 :Comment/uid) [?Comment_uid_3 ...]] 
		   [?Post :Post/comments ?Comment_uid_3]
		 )
  ]"
(d/db connInternal), (d/db connComment) 'user/myFunc "Post" "Comment 1 on post-2")

But an error is returned:

Execution error at datomic.datalog/compile-expr-clause (datalog.clj:1143).
Unable to resolve symbol: ?myFunc in this context

Could you point me where I’m doing wrong things?

P.S. I’m wondering about such case when function is passed as input argument to be able to do similar steps in java

You can call custom functions in query without installing them or passing them as arguments. They just need to be available in the VM (classloader) Peer is using. See: https://docs.datomic.com/on-prem/query.html#calling-java and https://docs.datomic.com/on-prem/query.html#calling-clojure

If you’re trying to reference an installed database function in query, but want to do so dynamically, have you tried referring to it by its ident?

have you tried referring to it by its ident

Yes, no luck

they just need to be available in the VM (classloader) Peer is using

Yeah, looks like the only way, I just thought if the doc says tbat :db/fn attribute holds datomic.functions.Fn which also implements clojure.lang.IFn for clojure users than why not to try call it in a query especially when clojure is functional language where functions can be passed as arguments to another functions and be called from there

Can you resolve your function entirely in query and d/invoke it? a la https://stackoverflow.com/questions/12474116/using-a-database-function-in-a-datomic-query

1 Like

Big thanks you Adam, works like a charm, I wish this example was added in https://docs.datomic.com/on-prem/database-functions.html, it really extends the possible way how database functions can be used. I reproach myself that I did not see https://docs.datomic.com/on-prem/clojure/index.html#datomic.api/invoke. Thank you again, you really helped me

Yeah, and I couldn’t even quite get there from the docs, but the SO example made it immediately clear. Sometimes the docs put all the pieces out there for you, but it isn’t clear how to put them together…it would be nice if they had a few more examples than they do.