How to call variadic function with some parameters before variadic parameter using hy? - hy

I am trying to write something similar to:
#classmethod
def write(cls, records, values, *args):
return super(Hello, cls).write(records, values, *args)
But I have issues with passing the *args back.
I tried using apply (but cannot pass the record and values).
I also tried to use apply with partial without success.
Current not working code in hylang:
(with-decorator classmethod
(defn write [cls records values &rest args]
(.write (super Hello cls) records values args)
))
In clojure normally I would write:
(apply .write (super Hello cls) records values args)
But it seems apply in hy doesn't support arguments before *args.
How can I write the original python code in hy?

I updated to latest version of hy
pip install git+https://github.com/hylang/hy.git
In this latest version apply has been replaced with #*
apply has been replaced with Python-style unpacking operators #* and
#** (e.g., (f #* args #** kwargs))
On the new version of hy the code can be written as:
(with-decorator classmethod
(defn write [cls records values &rest args]
(.write (super Hello cls) records values #* args)
))

Related

Find all entities that are missing a particular attribute

In my schema I have the attribute :base/type that is supposed to exist for every entity created. To check that this is indeed true, I'm trying to find entities where it is missing:
[:find [?entities ...]
:in $ :where
[(missing? $ ?entities :base/type)]]
Unfortunately this gives me back:
Execution error (Exceptions$IllegalArgumentExceptionInfo) at datomic.error/arg (error.clj:57).
:db.error/insufficient-binding [?entities] not bound in expression clause: [(missing? $ ?entities :base/type)]
How should this query be constructed?
This is because your query is too general. You need at least one positive clause in where statement if you use query API. You can access raw index to get the result, though. If you have enough RAM, you can:
(def snapshot (d/db connection)) ; your db snapshot
(def all-datoms (d/datoms snapshot :eavt))
(def base-type-id (:db/id (d/entity snapshot :base/type))
(def entities (group-by #(.e %) all-datoms))
(def entities-without-base-type (map
(comp #(into {} %) (partial d/entity snapshot) first)
(filter (fn [[k l]]
(empty? (filter #(= base-type-id (.a %))
l)))
entities)))
(def only-relevant-entities (filter #(not (or (:db/ident %) (:db/txInstant %))) entities-without-base-type))
only-relevant-entities
The last filter is to get rid of attribute definitions and transactions (they are stored as datoms in the db as well!).
If you have too many entities you can chunk datoms using the async atoms API.
Using ::singer/songs as an example attribute, this is how to do the query:
[:find [?entities ...]
:in $ :where
[?entities ::singer/songs ?s]
[(missing? $ ?entities :base/type)]]
Unfortunately (in my answer) many such queries would be required until the whole database has been covered. So another query with ::song/composers, etc...

:result-set-fn in clojure jdbc return error "The result set is closed." Why?

Often I need load huge data size from database server. Sometimes it have million rows and more. So I try to download data lazily. That what I want to do: I want get a lazy-sequence and pull data partial from server, i.e if row count is more than 500, I want primarily get with help of that lazy-sequence first 500 elements, then by another request i want receive next 500 elements and so on until i recieve all data from server.
But I have a problem. Clojure jdbc realize entire lazy-sequence, but I want obtain data from it partially.
I research that question and find good reply about similar problem:
clojure.java.jdbc lazy query
I took this example and wrote this:
(defn get_data
[arg1 arg2]
(let [full-db-spec (get ...)
sql_query (get ...)
row-n (atom 0)
prepared-statement (-> full-db-spec
(jdbc/get-connection)
(jdbc/prepare-statement sql_query {:fetch-size 3}))]
(jdbc/with-db-transaction [tx full-db-spec]
(jdbc/query full-db-spec [prepared-statement arg1 arg2]
{:fetch-size 3
:row-fn (fn [r] (do (prn "r" #row-n) (swap! row-n inc) r))
:result-set-fn identity}))))
Here I want to get a lazy-sequence to further extract data partially from this lazy-sequence. But when :result-set-fn is contain identity or (take 500 ...) the code return error: The result set is closed. Why? But when I change :result-set-fn to first or doall or last It works fine but it realize full lazy-sequence!
I use:
ms sql [com.microsoft.sqlserver/mssql-jdbc "6.3.3.jre8-preview"] (yet I test it on postgresql [org.postgresql/postgresql "9.4.1212.jre7"]. Same result)
[org.clojure/java.jdbc "0.7.3"]
That lazy sequence is reading values from your connection, but the connection is closed outside of the with-db-transaction scope. You need to realize/do further processing inside of that scope.

Django query filter using large array of ids in Postgres DB

I want to pass a query in Django to my PostgreSQL database. When I filter my query using a large array of ids, the query is very slow and goes up to 70s.
After looking for an answer I saw this post which gives a solution to my problem, simply change the ARRAY [ids] in IN statement by VALUES (id1), (id2), ....
I tested the solution with a raw query in pgadmin, the query goes from 70s to 300ms...
How can I do the same command (i.e. not using an array of ids but a query with VALUES) in Django?
I found a solution building on #erwin-brandstetter answer using a custom lookup
from django.db.models import Lookup
from django.db.models.fields import Field
#Field.register_lookup
class EfficientInLookup(Lookup):
lookup_name = "ineff"
def as_sql(self, compiler, connection):
lhs, lhs_params = self.process_lhs(compiler, connection)
rhs, rhs_params = self.process_rhs(compiler, connection)
params = lhs_params + rhs_params
return "%s IN (SELECT unnest(%s))" % (lhs, rhs), params
This allows to filter like this:
MyModel.objects.filter(id__ineff=<list-of-values>)
The trick is to transform the array to a set somehow.
Instead of (this form is only good for a short array):
SELECT *
FROM tbl t
WHERE t.tbl_id = ANY($1);
-- WHERE t.tbl_id IN($1); -- equivalent
$1 being the array parameter.
You can still pass an array like you had it, but unnest and join. Like:
SELECT *
FROM tbl t
JOIN unnest($1) arr(id) ON arr.id = t.tbl_id;
Or you can keep your query, too, but replace the array with a subquery unnesting it:
SELECT * FROM tbl t
WHERE t.tbl_id = ANY (SELECT unnest($1));
Or:
SELECT * FROM tbl t
WHERE t.tbl_id IN (SELECT unnest($1));
Same effect for performance as passing a set with a VALUES expression. But passing the array is typically much simpler.
Detailed explanation:
IN vs ANY operator in PostgreSQL
How to use ANY instead of IN in a WHERE clause with Rails?
Optimizing a Postgres query with a large IN
Is this an example of the first thing you're asking?
relation_list = list(ModelA.objects.filter(id__gt=100))
obj_query = ModelB.objects.filter(a_relation__in=relation_list)
That would be an "IN" command because you're first evaluating relation_list by casting it to a list, and then using it in your second query.
If instead you do the exact same thing, Django will only make one query, and do SQL optimization for you. So it should be more efficient that way.
You can always see the SQL command you'll be executing with obj_query.query if you're curious what's happening under the hood.
Hope that answers the question, sorry if it doesn't.
I had lots of trouble to make the custom lookup 'ineff' work.
I may have solved it, but would love some validation from Django and Postgres experts.
1) Using it 'directly' on a ForeignKey field (ModelB)
ModelA.objects.filter(ModelB__ineff=queryset_ModelB)
Throws the following exception:
"Related Field got invalid lookup: ineff"
ForeignKey fields cannot be used with custom lookups.
A similar issue is reported here:
Custom lookup is not being registered in Django
2) Using it 'indirectly' on the pk field of related model (ModelB.id)
ModelA.objects.filter(ModelB__id__ineff=queryset_ModelB.values_list('id', flat=True))
Throws the following exception:
"can only concatenate list (not "tuple") to list"
Looking at Django Traceback, I noticed that rhs_params is a tuple.
Yet we try to add it to lhs_params (a list) in our custom lookup.
Hence I changed:
params = lhs_params + rhs_params
into:
params = lhs_params + list(rhs_params)
3) I then got a Postgres error (at least I had passed Django ORM)
"function unnest(uuid) does not exist"
"HINT: No function matches the given name and argument types. You might need to add explicit type casts."
I apparently solved it by changing the sql:
from:
return "%s IN (SELECT unnest(%s))" % (lhs, rhs), params
to:
return "%s IN (SELECT unnest(ARRAY(%s)))" % (lhs, rhs), params
Hence my final as_sql method looks like this:
def as_sql(self, compiler, connection):
lhs, lhs_params = self.process_lhs(compiler, connection)
rhs, rhs_params = self.process_rhs(compiler, connection)
params = lhs_params + list(rhs_params)
return "%s IN (SELECT unnest(ARRAY(%s)))" % (lhs, rhs), params
It seems to work, and is indeed faster than in__ (tested with EXPLAIN ANALYZE in Postgres).
But I would love to have some validation from experts, perhaps Erwin Brandstetter?
Thanks for your input.

prolog avoiding duplicate predicates

I was wondering whether it is possible to test whether a predicate already exists (with the same information) to then avoid the user being able to input the same information again.
I have already managed to do it for a single predicate:
:- dynamic(test/2).
test(a,b).
top(X,Y) :-
(test(X,Y),
write('Yes'),!
;write('No'),!
).
This version works just fine, returning 'Yes' if the information already exists and 'No' if it doesn't.
I was wondering whether it would be possible to do this for multiple prediactes, not just for 'test/2';
I have tried to replace the predicate 'test' with a variable Pred but unfortunately I get a syntax error when I try to compile it.
Here is my attempt:
main(Pred,X,Y) :-
(Pred(X,Y),
write('Yes'),!
;write('No'),!
).
Is it even possible to do something like this and if it is how would it be possible?
Btw I am using GNU Prolog if it helps.
Thank you very much for your help :D !!
You want call/2, to call a dynamic goal with arguments, evaluated at runtime. In your case, it would be call(Pred,X,Y):
main(Pred,X,Y) :-
(
call(Pred,X,Y),
write('Yes'),!
)
;
(
write('No'),!
).
Do note that Pred/2 must resolve to an actual predicate at runtime, and you will need to build a different rule for each number of arguments.
#Tomas-By's answer, using (=..)/2 lets you create a single rule, with a list of args, but with the same caveats regarding predicates existing, albeit with an extra line:
main(Pred,L) :- % where L is a list of args [X,Y|...]
Term =.. [Pred | L],
(
Term,
write('Yes'),!
)
;
(
write('No'),!
).
And, as pointed out in the comments by #lurker, in either instance, using (->)/2:
(call(Pred,X,Y) -> write('Yes') ; write('No'))
or
(Term -> write('Yes') ; write('No'))
may be preferable as the destruction of choice points is limited to the if->then;else structure.
There is an operator =.. for constructing terms, as in:
Term =.. [Op,V1,V2]
not sure if that is in Gnu Prolog.
Using Sicstus:
xxx(1,2).
check(Pred,X,Y) :-
Term =.. [Pred,X,Y],
( Term ->
write('Yes')
; write('No') ).
and after loading the file:
| ?- check(xxx,1,2).
Yes

Howto Pass In Datomic functions (for Clojure API)

Using Clojure's Datomic APi, I have an architecture where I'd like to pass in a transact function, to be executed. However, trying to call the passed in transact function doesn't work. The repl recognizes it as a Symbol. And it evaluates, but no data is committed, and no future is returned, meaning, there's no returned transaction ID.
However, directly calling (datomic.api/transact conn [adatom]), works as expected. How can I make the abouve scenario work?
(defn some-fn[conn mapped-fn adatom]
(datomic.api/transact conn [adatom]) ;; works
#_(mapped-fn conn [adatom]) ;; does not work - evaluates, but no data committed, no future returned, meaning, no returned transaction ID
)
Thanks
It's not very clear what you are trying to do. For example:
why not call d/transact inside some-fn?
is mapped-fn a function that will be applied to many facts (and in this case it is d/transact)?
what is an overall intent?
To just blindly follow your example, it does work and returns a "future":
user=> (use '[datomic.api :only (db) :as d])
nil
user=> (d/create-database "datomic:mem://unsure-db")
false
user=> (def c (d/connect "datomic:mem://unsure-db"))
#'user/c
user=> (defn f [conn mapped-fn fact] (mapped-fn conn fact))
#'user/f
user=> (f c d/transact [])
#<promise$settable_future$reify__4526#2da07336: {:db-before datomic.db.Db#8835fddc, :db-after datomic.db.Db#6e2a2e78, :tx-data [#Datum{:e 13194139534313 :a 50 :v #inst "2013-09-03T15:23:34.977-00:00" :tx 13194139534313 :added true}], :tempids {}}>
Make sure you have a valid connection (e.g. you are connected [to the right database]), and the database is there.

Resources