Instead of writing an ad-hoc SQL parser and doing string manipulation, you can write relatively simple Clojure functions to manipulate these lists and generate valid SQL.
Instead of writing an ad-hoc SQL parser and doing string manipulation, you can write relatively simple Clojure functions to manipulate these lists and generate valid SQL.
2. They are not simple functions. Compare this : (-> (select (table {} {:employees :p})(where (= :name "John")))(join (table {} {:employees :b})(where (= :p.manager :b.id)))to-sql)
to this :
SELECT p.,b. FROM employees p JOIN employees b ON (p.manager = b.id) WHERE (name = 'John')
Which one is more verbose ?
EDIT: SQL examples with "employees" and "departmets" are very misleading and usually oversimplify the reality.
(def users (cql/table db :users))
(def photos (cql/table db :photos))
(def users-and-photos
(cql/join users photos
(cql/where (= :users.id :photos.user_id))))
(def photo-titles
(-> users-and-photos
(cql/project #{:photos.title})))
Note that my queries just keep getting smaller and smaller ;) By writing the mundane portions of your SQL queries again and again by hand you will have more duplication.With SQL it is straight-forward: you prototype your query using some GUI client and then you just embed it in your program. How it can be done with Clojure-QL ?
SELECT p.*,b.* FROM employees p JOIN employees b ON (p.manager = b.id) WHERE (p.name = 'John')
is only 8 characters less than: (join (select (table {:employees :p}) (=* :name "John")) (table {:employees :b}) (=* :p.manager :b.id))
but that isn't the point. the point is composabilty. you can take 8 simple functions (select, project, join, rename, aggregate, take, drop, sort) and build any query you want. these queries can be passed around your code, reused, modified, and refined, in a way that plain SQL strings cannot.