This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-12-15
Channels
- # adventofcode (80)
- # beginners (94)
- # biff (19)
- # cider (74)
- # clj-kondo (11)
- # cljs-dev (7)
- # clojure (110)
- # clojure-austin (3)
- # clojure-australia (1)
- # clojure-belgium (1)
- # clojure-china (1)
- # clojure-europe (83)
- # clojure-filipino (1)
- # clojure-hk (1)
- # clojure-indonesia (1)
- # clojure-japan (1)
- # clojure-korea (1)
- # clojure-my (1)
- # clojure-nl (1)
- # clojure-norway (4)
- # clojure-sg (1)
- # clojure-taiwan (1)
- # clojure-uk (2)
- # cursive (3)
- # data-science (8)
- # datalevin (8)
- # emacs (18)
- # etaoin (5)
- # graalvm (1)
- # holy-lambda (3)
- # honeysql (1)
- # jackdaw (10)
- # java (10)
- # jobs (3)
- # luminus (9)
- # malli (106)
- # off-topic (88)
- # polylith (8)
- # portal (2)
- # re-frame (50)
- # reagent (11)
- # reitit (74)
- # remote-jobs (1)
- # shadow-cljs (46)
- # tools-deps (26)
- # xtdb (49)
Java time is hard to navigate; I am using https://cljdoc.org/d/tick/tick/0.5.0-RC5/doc/readme, how do I mutate the date? I am looking to update the date.
It looks like tick is based on java time. I think just about everything in java time is immutable, so you would produce a new value rather than mutate an existing date.
Java time becomes easier if you understand the relation between LocalDateTime <=> OffsetDateTime <=> ZonedDateTime and Instant
What is must-have DB (postgresql) library to use in any production commercial project?
What do you use in your real projects?
Is it just org.clojure/java.jdbc
or something with higher level of DSL?
https://github.com/seancorfield/next-jdbc provides database connections via a ranges of database drivers and functions for SQL queries to the database. Keys can also be automatically converted to/from kebab-case
https://github.com/seancorfield/honeysql provides a way to define database queries in Clojure rather than SQL and can be used with next.jdbc for database connection
The documentation for these projects are very detailed and worth reading. https://practical.li/clojure-web-services/relational-databases-and-sql/ also covers examples of practical application of next.jdbc which have been used in numerous commercial production projects
@U05254DQM thank you man
If you look at the options and waver, I'll just say that (resultset-seq) in clojure.core is a pretty good 85% solution, in one fell swoop lifting the most awful burdens of JDBC. If you must use SQL at all, that one function pays the price of admission to Clojure.
What do you mean? Just use resultset-seq
instead of result-set/as-unqualified-lower-maps
? Or what? Sorry dont understand your message π
Just pointing out that the JDBC situation in Clojure is quite different from Java. In Java, JDBC is so hard to use that Hibernate seemed reasonable and Spring on top of that and your question about a must-have library could easily be answered with "Hibernate and Spring and everything in the kitchen sink." But Clojure showed that the hardship was Java's fault, not JDBC's. In Clojure, you might not need any SQL library at all. JDBC is a breeze. Java interop to prepare and run statements, plus the resultset-seq function in clojure.core, might be sufficient. The libraries add various value and elevate the tone, but depending on what you need beyond your own automation of JDBC, it's your choice.
do you use it in real web project? Isn't it too low level for that?
I don't use it in a real web project - nothing big. Not exactly sure what you mean by too low level though. Clojure is quite against ORMs and stuff so you'd have to explain. I just use it in tandem with honeysql in various tools.
@U04BRV8JQKE We use next.jdbc
heavily in production, powering 40 online dating sites with millions of users and a huge MySQL database. We also use HoneySQL to construct complex queries when we need to compose SQL fragments conditionally.
We still use clojure.java.jdbc
as well and the original 1.x of HoneySQL since our codebase in over a decade old in places (134,000 lines of code now).
@U04V70XH6 yeah, I see. I am already adding next.jdbs + honeysql to my pet project. They are very simple to understand, thank you! Specially honeysql DSL for complex queries
Is there a case when "symbol" honeysql
helpers are better than "keyword"? Or I can write any complex queries via "keyword" helpers like :select
?
It's personal preference, with a couple of very minor exceptions (that you hardly ever need to worry about).
If you look in the tests (and docs), you'll see examples of both, but most are keyword style.
Folks who like datalog style queries will often prefer the symbol forms.
I love clojure homoiconic so want to use only keywords
If you don't need symbols evaluated in a query, a quoted symbol form is less typing π
What do you mean?
'(select * from table where (= col ?param))
[:select :* :from :table :where [:= :col :?param]]
Ah I see)
But to get a habbit and practice I will write all my queries via keywords for now
I think it makes sense
Am I right I cant create database via honeysql
?
So I just need to use plain-text SQL via next.jdbc
?
I did not found any :create-database
SQL clause in honeysql docs
@U04BRV8JQKE you donβt need honeysql for table creation:
@UC1DTFY1G nice example, thanks. What is about database creation? Then I need to create it not from clojure layer at all? So I need to create it from system layer (docker)
also I probably need to create at least 2 databases: for dev and for tests
Yeah I think its better to manage dbs via system tools
(jdbc/execute! ds ["create database if not exists foo"])
-- it's a pretty simple SQL command so you don't need HoneySQL for that really.
No one has asked for that to be added to HoneySQL yet π
I think its not required there ) Plain text is enough
At work, we use plain .sql
files for all our DB migrations. We read them in and run them with next.jdbc
.
I just thinking what is better, to manage databases from docker-compose file (just add another section for additional database) or from clojure
> plain .sql
files for all our DB migrations
so there are database creation AND all tables creation code?
It's all just DDL.
Do you mean just CREATE/ALTER/DROP queries?
At this point we have about 950 .sql
files representing the "migration" up from a completely empty Percona instance started with Docker to four full test databases.
Yes. All the DDL is in .sql
files that we read and execute.
ah so you separate it to many .sql
files not just 1
We do automated SQL migrations to QA and production as well, the same way. We have a table in the DB containing the highest migration applied and then automatically apply any missing migrations as part of our automated deployment.
looks very relative to rails migration way where I come from here π
Libraries like Migratus help automate this. We built our own migration system many years ago.
We have 8 basic DB setup .sql
files, 3 initial creation .sql
files, and currently 924 individual migration files to modify the schemas etc.
what is the difference between basic and initial files?
The basic files create the four databases and populate our geolocation DB (one of the four). Those are only run on a "cold start" (in CI and occasionally in dev). The initial creation files 1) drop all the tables, 2) create the original set of tables we started the project with (our MVP schema), and set up the dblevel
table (to level 0
).
So we have cold-start
and database-setup
as two tasks in our build.clj
file.
dblevel
is the migration level?
We chose a simple increasing number. And we also have the concept of dev-only migrations (which are applied in dev/CI but not QA or production) which are used for loading test data -- but are otherwise just part of the regular sequence of migrations... 00001_metadata.sql, 00002dev_initial_test_data.sql, 00004_cheater_create.sql, 00005_bannedIP_add_admin.sql etc up to 00923_bugfix_WS_14085_covalence_source_too_long.sql, and 00924_feature_WS_14075_admin_filter_skywriting_by_platform.sql -- during the (decade-plus) life of the project we switched to Jira and now use branch names for SQL migrations -- via a next-migration
task in our build.clj
file π
Hopefully we'll never hit 99,999 migrations π
(but, yes, we started with ticket 1 and we're up to about 14,140 now)
I blogged about the first ten tickets we created, when we got started on this project back in 2009: https://corfield.org/blog/2014/06/03/getting-started/
I have a code below for future which executing its bosy again and again on calling the function, But the main definition of future is it catch the value, How to write it in function?
(def x 0)
(defn increment-number []
(let [future-var (future
(loop [y x]
(Thread/sleep 1000)
(println "---y---" y)
(if (> y 3)
y
(recur (inc y)))))]
@future-var
[x @future-var]))
(increment-number)
(defn increment-number []
(let [future-var
(future
(loop [y 0]
(Thread/sleep 1000)
(println "---y---" y)
(if (> y 3)
y
(recur (inc y)))))]
@future-var))
(increment-number)
?@UC1DTFY1G updated code,
So I assume you mean on each call of (increment-number)
you see the print statement right?
This is because you are creating a new future in each call inside the function. If you wanted to get the cached value, you can do something like this (simplified):
(defn increment-number []
(future
(loop [y 0]
(Thread/sleep 1000)
(println "---y---" y)
(if (> y 3)
y
(recur (inc y))))))
(let [f (increment-number)]
[@f @f @f])
If you run (increment-number)
again, it will print again because you are creating a new future.
@UC1DTFY1G Promise also catch the value right? How it will be helpful in real world scenario?
I haven't used promise
much so if I'm wrong someone can correct me...
A future
is a computation that starts immediately on a separate thread after the future is created. If you try to deref
the future before it's completed, it will block. so:
(def f (future (Thread/sleep 5000) 42))
@f ;Will return 42 after 5 secs
A promise
is a promise that a value will be deliver
ed to the promise at some time. Difference from future
is it does not specify how that will be done:
(def p (promise))
@p
This will block indefinitely as no one delivers on the promise. However, we can deliver in the promise from somewhere else:
(def p (promise))
(future
(Thread/sleep 10000)
(deliver p 42))
@p ;Will block for 10 secs then return 42
So, I use future when you want to do something in a separate thread.
I haven't used promises yet but I can imagine waiting for some event to happen and deliver on any promises available when that happens.No, not outside these toy examples. I think deliver
is only used in tandem with promise
Is there a way to dynamically name a variable? I have the following code
(thread-pool-bulkhead/defbulkhead symbol-name)
defbulkhead
is a macro which creates a var in the current namespace with the name "symbol-name" (check docs here - https://github.com/ylgrgyq/resilience-for-clojure/blob/0.2.7/src/resilience/thread_pool_bulkhead.clj#L137)
I need that symbol-name
to be dynamic in nature.
I have this for now,
(eval `(thread-pool-bulkhead/defbulkhead ~(symbol symbol-name)))
but I'm wondering if there's a better way to do it.It's just my use-case. I am giving user the ability to create bulkheads dynamically and fetch the correct one when needed
eval
is one answer. This is another https://clojuredocs.org/clojure.core/intern
I am currently learning about spec and why qualified keys are a good idea. How does one deal with keysets which you have no direct control over (e.g. a body of a ring request)? Is there an idiomatic way to wrap an existing map in a namespace so it can be validated by a spec?
another option could be to use (s/keys :req-un [β¦]
for handling the unqualified keys directly (https://clojure.org/guides/spec#_entity_maps section of the Spec guide has examples)
I got bitten pretty bad by this (using unqualified keys) in my days of learning spec. I left some notes here https://github.com/clojure/clojure-site/issues/517 (which still haven't been reflected in the guide) - Since then I have adopted malli (https://github.com/metosin/malli) which solves this and many other design flaws of spec (the API is data+fns instead of macros being a huge one). I recommend taking a look at at it.
:req-un
suffers from the flaw that your specs still need to be namespaced keywords, even though in the map they are not. This can lead to painful collisions of those fully qualified keywords later on, especially in a large codebase, due to spec using a global registry
malli looks interesting, thanks for the tip π
@U051V5LLP thanks, I will give it a look π