{"id":20390504,"url":"https://github.com/swlkr/oksql","last_synced_at":"2025-10-14T13:12:29.711Z","repository":{"id":25653984,"uuid":"105495858","full_name":"swlkr/oksql","owner":"swlkr","description":"An easy clojure postgres library","archived":false,"fork":false,"pushed_at":"2024-03-08T20:58:21.000Z","size":57,"stargazers_count":77,"open_issues_count":2,"forks_count":3,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-09-19T00:22:37.166Z","etag":null,"topics":["clojure","jdbc","postgres","postgresql","sql"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/swlkr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-10-02T03:49:51.000Z","updated_at":"2024-05-31T07:49:21.000Z","dependencies_parsed_at":"2024-11-15T03:25:46.794Z","dependency_job_id":"1c3cc54d-1f32-4167-98e5-b07321a2603f","html_url":"https://github.com/swlkr/oksql","commit_stats":{"total_commits":38,"total_committers":3,"mean_commits":"12.666666666666666","dds":"0.13157894736842102","last_synced_commit":"0db3be72125aa2735da56d0dc46e0102c6bbfb80"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/swlkr/oksql","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swlkr%2Foksql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swlkr%2Foksql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swlkr%2Foksql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swlkr%2Foksql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/swlkr","download_url":"https://codeload.github.com/swlkr/oksql/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swlkr%2Foksql/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279018704,"owners_count":26086605,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-14T02:00:06.444Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojure","jdbc","postgres","postgresql","sql"],"created_at":"2024-11-15T03:25:28.700Z","updated_at":"2025-10-14T13:12:29.695Z","avatar_url":"https://github.com/swlkr.png","language":"Clojure","readme":"# oksql\n\noksql is a library for using postgres.\n\n## Usage\n\nAdd `[oksql \"1.3.2\"]` to your `:dependencies` in your `project.clj`\n\n*or*\n\nAdd `oksql {:mvn/version \"1.3.2\"}` to your `deps.edn` file\n\nThen, create a `.sql` file in your `resources/sql` folder like this one for example:\n\n```sql\n-- items.sql\n\n-- name: fetch\n-- fn: first\nselect *\nfrom items\nwhere id = :id\n\n-- name: all\nselect *\nfrom items\norder by created_at desc\n\n-- name: insert\n-- fn: first\ninsert into items (id, name, created_at)\nvalues (:id, :name, :created_at)\nreturning *\n\n-- name: update\n-- fn: first\nupdate items\nset name = :name\nwhere id = :id\nreturning *\n\n-- name: delete\n-- fn: first\ndelete\nfrom items\nwhere id = :id\nreturning *\n```\n\nThen create a file to wire up your queries and you're done!\n\n```clojure\n(ns your-project.models.items\n  (:require [oksql.core :as oksql])\n  (:refer-clojure :exclude [update]))\n\n(def db {:connection-uri \"jdbc:postgresql://localhost:5432/your_project_db\"})\n\n(def query (partial oksql/query db))\n\n(defn all []\n  (query :items/all))\n\n(defn fetch [id]\n  (query :items/fetch {:id id}))\n\n(defn create [{:keys [name created-at]}]\n  (query :items/insert {:name name\n                        :created-at created-at})) ; implicit! kebab -\u003e snake case\n\n(defn update [id m]\n  (query :items/update (merge {:id id} m)))\n\n(defn delete [id]\n  (query :items/delete {:id id}))\n```\n\nA real advantage to this code (which can be generated statically) over the alternatives is that\nyou can add your own validation logic before and after these functions and you get go to definition\nsince there aren't any macros generating functions for you.\n\nA good example of this:\n\n```clojure\n(ns your-project.models.users\n  (:require [oksql.core :as oksql]))\n\n(defn validate [user]\n  (if (contains? user :email)\n    user\n    (throw (Exception. \"Email required\"))))\n\n(defn insert [m]\n  (let [user (validate m)]\n    (oksql/query :items/insert m)))\n```\n\nSo I know what you're thinking, man that sucks to keep the super simple write sql parts (insert/update/delete)\nin sync every time I make a change to a table. Well.\n\n```clojure\n; namespace keyword corresponds to db schema name\n; public by default, just like postgres\n(oksql/update db :items {:name \"update name\"} :items/where {:id 123})\n\n(oksql/insert db :items {:name \"new item\"})\n\n(oksql/delete db :items :items/where {:id 123})\n```\n\nSo to review, oksql is kind of an ORM now, but not really! Only for writes if you want them.\n\nYou still have the full power of sql at your disposal, but for writing, it's kind of unnecessary.\nHere are the four functions again:\n\n```clojure\n(ns your-project.models.items\n  (:require [oksql.core :as oksql])\n  (:refer-clojure :exclude [update]))\n\n(def db {:connection-uri \"jdbc:postgresql://localhost:5432/your_project_db\"})\n\n(def query (partial oksql/query db))\n\n(defn all []\n  (query :items/all))\n\n(defn fetch [id]\n  (query :items/fetch {:id id}))\n\n(defn create [m]\n  (oksql/insert db :items m))\n\n(defn update [id m]\n  (oksql/update db :items m :items/where {:id id}))\n\n(defn delete [id]\n  (oksql/delete db :items :items/where {:id id}))\n```\n\n## Why\n\nThe default for interacting with postgres from clojure without a library looks like this\n\n```clojure\n(def db {:connection-uri \"jdbc:postgresql://localhost:5432/items_db\"})\n(jdbc/query db [\"select items.id, items.name, items.created_at from items where id = ?\" 123])\n```\n\nIt's not too bad with a short query, but you can imagine several joins and many to many relationships getting\nout of hand. Plus there probably isn't any syntax highlighting in your editor for sql strings in a `.clj` file.\n\nSo you might graduate to something like this\n\n```clojure\n(select item\n  (fields :id :name :created_at)\n  (where {:id 123}))\n```\n\nIt's a lot nicer syntactically, but you're now writing a sql dsl, not sql. So you have to know not only sql\nbut a clojure sql dsl which will eventually [not have the thing you're looking for](https://github.com/korma/Korma/issues/379).\n\nSo, fed up with these things and probably more, [yesql](https://github.com/krisajenkins/yesql) was born. Yesql basically solved my problems and I've been using it for the past two years on all of my projects. There are a few problems with yesql outlined in a fork here, [jeesql](https://github.com/tatut/jeesql).\n\njeesql solved most of my problems with yesql:\n\n- No instaparse dependency\n- No way to specify that you just want a single row\n\nUnfortunately it added some stuff that I didn't really need:\n- Positional arguments\n- Various query attributes\n\nI also didn't like that I couldn't \"go to definition\" with `defqueries` since it generated the functions with a macro. I'd rather just take a page from rails' book and generate the code statically and have it sitting in files, at least then it's easy to see and change it later. So those are the main differences from yesql, hugsql, and jeesql:\n\n- No defqueries macro\n- Simple results fn support (`-- fn: first`) support and that's it\n- No symbolic representation of `returning *`, just declare it explicitly\n- Implicit! Conversion of snake case to kebab case to and from the database!\n\n## Inspiration\n\n- [yesql](https://github.com/krisajenkins/yesql)\n- [hugsql](https://github.com/layerware/hugsql)\n- [jeesql](https://github.com/tatut/jeesql)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswlkr%2Foksql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fswlkr%2Foksql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswlkr%2Foksql/lists"}