6 ms·
This is a good starting point if you want to get a web app going quickly: https://biffweb.com https://biffweb.com It uses XTDB by default but you can switch to
by rads 2y ago
This is a good starting point if you want to get a web app going quickly:
https://biffweb.com https://biffweb.com
It uses XTDB by default but you can switch to Postgres:
https://biffweb.com/p/how-to-use-postgres-with-biff/ https://biffweb.com/p/how-to-use-postgres-with-biff/
People don't really use ORMs in Clojure, they just write SQL directly and abstract the details from consumers using functions. That said, HoneySQL is a common alternative to writing SQL that makes it a lot less painful (and composable!):
https://github.com/seancorfield/honeysql https://github.com/seancorfield/honeysql
- neilyio 2y agoHoneySQL is so, so good. It does for SQL what Hiccup did for HTML. Once you start writing with those, it's hard to remember there's any other way.
- zerg000000 2y agoTotally agree! or datalog is even better if you can accept not using the mainstream databases.
- winrid 2y agoBiff looks neat, thanks! I mainly just don't want to write raw sql/mappers to structures for simple queries. Looks like most sql libraries with clojure can just return maps so that's neat.
- rads 2y agoHere's a quick example of how DB access generally looks in production: (ns rads.sql-example (:require [next.jdbc :as jdbc] [honey.sql :as sql] [clojure.string :as str])) ;; DB Table: posts ;; +----+-------+ ;; | id | title | ;; +----+-------+ ;; | 1 | hello | ;; +----+-------+ (def ds (jdbc/get-datasource (System/getenv "DATABASE_URL"))) (defn row->post [row] ;; This is your optional mapping layer (a plain function that takes a map). ;; You can hide DB details here. (update row :title str/capitalize)) (defn get-posts [ds] ;; Write a SQL query using Clojure data structures. (let [query {:select [:*] :from [:posts]}] ;; Run the query. (->> (jdbc/execute! ds (sql/format query)) ;; Convert each raw DB map to a "post" map (map row->post)))) (println (get-posts ds)) ;; => [{:id 1, :title "Hello"}]
- winrid 2y agoYou would abstract away the jdbc/execute part though, right? otherwise that's terribly unproductive compared to django etc.
- rads 2y agoIn practice I do wrap `jdbc/execute!` with my own `execute!` function to set some default options. However, there is no ORM layer. What makes you think the code above is terribly unproductive? Edit: Not trying to dismiss your concerns, by the way. In Clojure you can often get away with doing less than you might think so I'm genuinely curious about the critique.
- winrid 2y agoIn Django I would just do Posts.objects.filter(title=x) I don't need to define driver boilerplate for every query (or ever have to write it... at all).
- rads 2y agoThe key thing is experienced Clojure programmers often see a lack of ORM as a feature rather than an oversight. There were some more ORM-like libraries years ago (see Korma) but my impression is that people ultimately didn't want this and moved on to lower-level JDBC wrappers combined with HoneySQL. I found a more detailed discussion on Reddit about Clojure and ORMs back in 2020 if you want to get more info: https://reddit.com/r/Clojure/comments/g7qyoy/why_does_orm_have_omg_complexity/ https://reddit.com/r/Clojure/comments/g7qyoy/why_does_orm_ha... Note that I'm not making a value judgement about Python/Django or any other library/framework combination. It's obviously a valid path, but Clojure is a different path. I can assure you there are straightforward solutions to create readable APIs like the Django example with minimal boilerplate, but the approach is fundamentally different from Python/Django. If you do decide to build something in Clojure and think, "I already know how to do this in Django, why is it missing?", don't hesitate to join the Clojurians Slack and hop into the #beginners channel. There are plenty of people who can help you there.
- deleted 2y ago[deleted]
- didibus 2y agoThere's no object in Clojure, so there's no need for an Object Relational Mapper. You just work directly of the query result sets, which the SQL library itself can conveniently turn into rows of maps if you prefer (over rows of lists).
- winrid 2y agoNo object is kinda mind blowing since it has java interop. I guess everything just becomes maps?
- didibus 2y agoWell, there are objects through interop, and under the hood everything is compiled into one. But when you develop an app, you won't be defining classes and instantiating objects of them, you'll be instead writing functions that return maps or other data-structures.