This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-05-14
Channels
- # beginners (74)
- # boot (1)
- # cider (6)
- # clj-kondo (8)
- # cljs-dev (30)
- # clojure (195)
- # clojure-ecuador (1)
- # clojure-europe (2)
- # clojure-italy (51)
- # clojure-nl (47)
- # clojure-spec (9)
- # clojure-sweden (27)
- # clojure-uk (63)
- # clojurescript (84)
- # cursive (41)
- # datascript (17)
- # datomic (16)
- # docker (1)
- # emacs (10)
- # events (2)
- # graalvm (2)
- # graphql (37)
- # juxt (2)
- # nrepl (20)
- # nyc (2)
- # off-topic (26)
- # onyx (3)
- # pedestal (4)
- # perun (19)
- # planck (1)
- # reagent (9)
- # reitit (4)
- # shadow-cljs (208)
- # spacemacs (6)
- # tools-deps (4)
@andrea.imparato se vuoi evitare di fare 108 require
mentre stai prototipando ricordati che tutto ciò che sta dentro Clojure + il classpath lo puoi usare con clojure.data/diff
, io spesso per clojure.string
faccio così e se alla fine l'ho usato solo 1-2 volte in tutto non sto a fare require
occhio, che questo vale solo per namespace che sono gia` stati require
'd, che e` il caso per clojure.string
(usato da clojure.repl
) ma non per clojure.data
A questo proposito, esiste un modo (con Emacs o altro) per far prendere a :require
nella definizione del namespace tutti i singoli :refer
in automatico? Cioè da (:require [clojure.string :as s])
a (:require [clojure.string :refer [(le funzioni che uso nel namespace)] :as s])
?
c'è l'opposto qui: https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-stop-referring#sr-stop-referring 🙂
Questo è uno di quei (pochi) casi in cui anche l'esatto contrario è più che accettabile 😄
occhio, che questo vale solo per namespace che sono gia` stati require
'd, che e` il caso per clojure.string
(usato da clojure.repl
) ma non per clojure.data
@justalanm se sposi la filosofia che i namespaced names (e.g. (str/join ...)
) sono meglio dei :refer
'ed ones (e.g. (join ...)
), una volta installato cljr-refactor
di norma appena scrivi lo slash in (str/)
ti prova ad aggiornare la ns
declaration (non estremamente preciso, comunque C-h f cljr-slash
e C-h f cljr-magic-require-namespaces
)
Questo è uno di quei (pochi) casi in cui anche l'esatto contrario è più che accettabile 😄
buongiorno, io chiedo allora, è sempre buona pratica mettere il :refer
nei require? è così brutto lasciarli senza?
@andrea.imparato Come dicevano anche gli altri il top sarebbe [org.library :as lib]
, seguito da singoli [org.library :refer [fn1 fn2]]
e di solito si evita [org.library :refer :all]
Però mentre nella community Python le librerie più usate ormai hanno alias standard (pandas as pd, numpy as np, tensorflow as tf, etc) ho notato che in Clojure c'è molta più libertà e fantasia a riguardo
io onestamente preferisco non usare mai :refer
, usando il namespace di ogni symbol come visual hint di "WARNING: funzione esterna, AKA dependency, AKA robba architetturale"
Io lo uso in maniera soggettiva (e limitata). 1. se il significato della funzione e’ ovvio 2. se mi servono solo 1 o 2 fns e 3. se aumenta la leggibilita’ del codice in una sezione dove e’ usata di frequente.
un esempio di funzioni per le quali uso il :refer
nonostante la guideline di non usarli mai e' clojure.pprint/pprint
: e' sufficientemente self-explanatory da non necessitare un namespace alias
oppure nel classico dev.clj
che e' in classpath solo in development, allora la' vado di libertinismo
So che e’ forzare un po’ la mano, ma il rompicapo di oggi e’:
user=> (def ^:const A (fn [_] A))
#'user/A
user=> (A 1)
#object[user$A 0x315f43d5 "user$A@315f43d5"]
user=> (def ^:const B (constantly B))
#'user/B
user=> (B 1)
IllegalArgumentException No matching ctor found for class clojure.core$constantly$fn__5394 clojure.lang.Reflector.invokeConstructor (Reflector.java:163)
alternativa che esplicita il problema
user=> (def ^:const c (let [c c] (fn [_] c)))
#'user/c
user=> (c 1)
Execution error (IllegalArgumentException) at user$eval146/<clinit> (REPL:1).
No matching ctor found for class user$fn__142$fn__143
necessito consiglio, come posso generate a partire da un vector, una stringa che poi posso usare per fare binding con una query sql? Mi spiego:
(query! "select * from table where field in ($1)" parameters)
parameters è un vector ovviamente
Qualcuno di voi ha mai fatto qualcosa di simile?
ho provato honeysql
però non capisco perchè questa mappa non mi genera correttamente la query che voglio 😕
(def sqlmap {:select [:*]
:from [:table]
:where [:in :field [ "1" "2" ]]})
quindi dato che mi serve veramente fare solo 1 query volevo provare a generarmela “a mano”
per farmi l’escaping delle stringhe?
se faccio il binding il driver del db mi fa l’escaping, giusto?
(almeno penso io)
la mappa che hai messo prima, con HoneySQL mi genera:
> (hc/format sqlmap)
;; => ["SELECT * FROM table WHERE (field in (?, ?))" "1" "2"]
che mi pare corretta infatti,ma quando la uso con https://github.com/alaisi/postgres.async mi sputa fuori un’eccezione 😕
Class: java.lang.String
Value: "#error {\n :cause \"ERROR: SQLSTATE=42601, MESSAGE=syntax error at or near \\\",\\\"\"\n :via\n [{:type com.github.pgasync.SqlException\n :message \"ERROR: SQLSTATE=42601, MESSAGE=syntax error at or near \\\",\\\"\"\n :at [com.github.pgasync.impl.netty.NettyPgProtocolStream toSqlException \"NettyPgProtocolStream.java\" 223]}]\n :trace\n [[com.github.pgasync.impl.netty.NettyPgProtocolStream toSqlException \"NettyPgProtocolStream.java\" 223]\n [com.github.pgasync.impl.netty.NettyPgProtocolStream access$300 \"NettyPgProtocolStream.java\" 46]\n [com.github.pgasync.impl.netty.NettyPgProtocolStream$1 onNext \"NettyPgProtocolStream.java\" 197]\n [com.github.pgasync.impl.netty.NettyPgProtocolStream$5 channelRead \"NettyPgProtocolStream.java\" 304]\n [io.netty.channel.AbstractChannelHandlerContext invokeChannelRead \"AbstractChannelHandlerContext.java\" 348]\n [io.netty.channel.AbstractChannelHandlerContext invokeChannelRead \"AbstractChannelHandlerContext.java\" 334]\n [io.netty.channel.AbstractChannelHandlerContext fireChannelRead \"AbstractChannelHandlerContext.java\" 326]\n [io.netty.handler.codec.ByteToMessageDecoder fireChannelRead \"ByteToMessageDecoder.java\" 293]\n [io.netty.handler.codec.ByteToMessageDecoder channelRead \"ByteToMessageDecoder.java\" 267]\n [io.netty.channel.AbstractChannelHandlerContext invokeChannelRead \"AbstractChannelHandlerContext.java\" 348]\n [io.netty.channel.AbstractChannelHandlerContext invokeChannelRead \"AbstractChannelHandlerContext.java\" 334]\n [io.netty.channel.AbstractChannelHandlerContext fireChannelRead \"AbstractChannelHandlerContext.java\" 326]\n [io.netty.handler.codec.ByteToMessageDecoder fireChannelRead \"ByteToMessageDecoder.java\" 293]\n [io.netty.handler.codec.ByteToMessageDecoder fireChannelRead \"ByteToMessageDecoder.java\" 280]\n [io.netty.handler.codec.ByteToMessageDecoder callDecode \"ByteToMessageDecoder.java\" 396]\n [io.netty.handler.codec.ByteToMessageDecoder channelRead \"ByteToMessageDecoder.java\" 248]\n [io.netty.channel.AbstractChannelHandlerContext invokeChannelRead \"AbstractChannelHandlerContext.java\" 348]\n [io.netty.channel.AbstractChannelHandlerContext invokeChannelRead \"AbstractChannelHandlerContext.java\" 334]\n [io.netty.channel.AbstractChannelHandlerContext fireChannelRead \"AbstractChannelHandlerContext.java\" 326]\n [io.netty.channel.DefaultChannelPipeline$HeadContext channelRead \"DefaultChannelPipeline.java\" 1320]\n [io.netty.channel.AbstractChannelHandlerContext invokeChannelRead \"AbstractChannelHandlerContext.java\" 348]\n [io.netty.channel.AbstractChannelHandlerContext invokeChannelRead \"AbstractChannelHandlerContext.java\" 334]\n [io.netty.channel.DefaultChannelPipeline fireChannelRead \"DefaultChannelPipeline.java\" 905]\n [io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe read \"AbstractNioByteChannel.java\" 123]\n [io.netty.channel.nio.NioEventLoop processSelectedKey \"NioEventLoop.java\" 563]\n [io.netty.channel.nio.NioEventLoop processSelectedKeysOptimized \"NioEventLoop.java\" 504]\n [io.netty.channel.nio.NioEventLoop processSelectedKeys \"NioEventLoop.java\" 418]\n [io.netty.channel.nio.NioEventLoop run \"NioEventLoop.java\" 390]\n [io.netty.util.concurrent.SingleThreadEventExecutor$5 run \"SingleThreadEventExecutor.java\" 742]\n [io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator run \"DefaultThreadFactory.java\" 145]\n [java.lang.Thread run \"Thread.java\" 748]]}"
oh non conoscevo hikaricp, sembra molto + potente di postgres.async
provalo, perché così su 2 piedi a me la query sembra giusta, ma non conoscendo postgres.async non so che cosa succede sotto. 🙂
più concretamente, io qui uso postgres+hikari+honeysql: https://github.com/manuel-uberti/boodle/blob/master/src/clj/boodle/services/postgresql.clj
in realtà, honeysql va bene su questo progetto che è relativamente semplice per quanto riguarda l'interazione col DB. Ma quanto le query hanno sub-query, alias, e si fanno un po' più complesse, HugSQL è un'opzione migliore.
meh. c'e' sempre un trade off: HoneySQL scala bene con la dinamicita' delle queries mentre scala male con la complessita' non-standardness dell'idioma SQL utilizzato, HugSQL scala viceversa. Avendo avuto crisi di rigetto da ORM, ero partigiano di soluzioni plain-sql come HugSQL. Oggigiorno HoneySQL lo trovo un default migliore visto che non ho mai avuto un progetto senza query dinamiche
e per interagire in async con il db cosa mi consigliate di fare?
per adesso faccio (async/<!! query! query-string)
ma non so quanto corretto sia