{"id":32187536,"url":"https://github.com/taylorlapeyre/oj","last_synced_at":"2025-10-22T00:09:54.525Z","repository":{"id":22678592,"uuid":"26022136","full_name":"taylorlapeyre/oj","owner":"taylorlapeyre","description":":tropical_drink: A Clojure library for talking to your database.","archived":false,"fork":false,"pushed_at":"2015-01-23T19:44:17.000Z","size":531,"stargazers_count":175,"open_issues_count":4,"forks_count":6,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-10-22T00:05:58.072Z","etag":null,"topics":["clojure","clojure-library","orm","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/taylorlapeyre.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}},"created_at":"2014-10-31T15:42:20.000Z","updated_at":"2025-09-02T07:55:48.000Z","dependencies_parsed_at":"2022-08-21T00:00:54.097Z","dependency_job_id":null,"html_url":"https://github.com/taylorlapeyre/oj","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/taylorlapeyre/oj","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taylorlapeyre%2Foj","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taylorlapeyre%2Foj/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taylorlapeyre%2Foj/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taylorlapeyre%2Foj/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/taylorlapeyre","download_url":"https://codeload.github.com/taylorlapeyre/oj/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taylorlapeyre%2Foj/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280354860,"owners_count":26316556,"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-21T02:00:06.614Z","response_time":58,"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","clojure-library","orm","sql"],"created_at":"2025-10-22T00:05:08.397Z","updated_at":"2025-10-22T00:09:54.518Z","avatar_url":"https://github.com/taylorlapeyre.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"![oj](http://i.imgur.com/xEi1K4l.jpg)\n\n# oj\n\n[![Build Status](https://travis-ci.org/taylorlapeyre/oj.svg?branch=master)](https://travis-ci.org/taylorlapeyre/oj)\n\nA refreshing Clojure library for talking to your database, heavily influenced by [Ring][ring].\n\n#### Features\n- Gives you a [standard interface](https://github.com/taylorlapeyre/oj/blob/master/doc/SPEC) for running and generating SQL\n- Focuses on the most common and useful features of SQL\n- Enforces type checking and validation for queries\n- Sensible defaults\n- Concise and powerful API\n- Encourages reusable components\n\n#### Anti-features\n- Doesn't try to implement the entiretly of SQL\n- Doesn't require you to write SQL\n- Doesn't create its own domain-specific language\n- Doesn't surprise you\n\n\nThe [SPEC][spec] file provides a complete description of the OJ interface.\n\n## Installation\n\nAdd this to your Leiningen :dependencies:\n\n```\n[oj \"0.3.0\"]\n```\n\nYou'll also need a database driver (thanks to [yesql][yesql] for providing\nthis handy table):\n\n|Database|`:dependencies` Entry|\n|---|---|\n|PostgreSQL|`[org.postgresql/postgresql \"9.3-1102-jdbc41\"]`|\n|MySQL|`[mysql/mysql-connector-java \"5.1.32\"]`|\n|Oracle|`[com.oracle/ojdbc14 \"10.2.0.4.0\"]`|\n|SQLite|`[org.xerial/sqlite-jdbc \"3.7.2\"]`|\n|Derby|`[org.apache.derby/derby \"10.11.1.1\"]`|\n\n## Usage\n\nQueries are represented as a Clojure map. The full specification of a **query map** can be found [here](/doc/SPEC).\n``` clojure\n(def users-named-taylor\n  {:table :users\n   :select [:id :email]\n   :where {:first_name \"taylor\"}})\n```\n\nQueries can be executed by passing a query map and a database config into `oj/exec`:\n``` clojure\n(def db {:subprotocol \"mysql\"\n         :subname \"//127.0.0.1:3306/wishwheel3\"\n         :user \"root\"\n         :password \"\"})\n\n(oj/exec users-named-taylor db)\n; =\u003e ({:id 1 :email \"taylorlapeyre@gmail\"} ...)\n```\n\n**Modifiers** are functions that transform a query map into another query map. This allows us to chain them together. Some basic modifiers are provided by default at `oj.modifiers`.\n``` clojure\n(require [oj.core :as oj]\n         [oj.modifiers :as db])\n\n(defn find-by-username [username]\n  (-\u003e (db/query :users)\n      (db/select [:id :username :email :created_at])\n      (db/where {:username username})\n      (oj/exec db-config)\n      (first)))\n\n(find-by-username \"taylorlapeyre\")\n; =\u003e {:id 1 :username \"taylorlapeyre\"}\n```\n\nOJ's roots in regular Clojure data structures make it extremely powerful for building abstractions.\n``` clojure\n(defn user [\u0026 forms]\n  (let [query (reduce merge {:table :users} forms)]\n    (oj/exec query db)))\n\n(user {:where {:id 1}})\n=\u003e SELECT * FROM users WHERE users.id=1\n\n(user {:where {:id 1}}\n      {:select [:id :username]})\n=\u003e SELECT id, username FROM users WHERE users.id=1\n```\n\nNot quite ActiveRecord, but it's getting there. And in 3 lines of code no less!\n\nOf course, you can also perform all of the standard CRUD operations that you'd expect:\n``` clojure\n(defn create [user-data]\n  (when (valid? user-data)\n    (-\u003e (db/query :users)\n        (db/insert user-data)\n        (oj/exec db-config))))\n\n(defn update [id user-data]\n  (when (valid? user-data)\n    (-\u003e (db/query :users)\n        (db/where {:id id})\n        (db/update user-data)\n        (oj/exec db-config))))\n\n(defn delete [id]\n  (-\u003e (db/query :users)\n      (db/where {:id id})\n      (db/delete)\n      (oj/exec db-config)))\n```\n\nHow about using SQL's aggregate functions? OJ allows you to use those as well, using a Clojure-like syntax.\n\nFor example, to get the average price of all items:\n\n```clojure\n(-\u003e (db/query :items)\n    (select '(avg :price))\n    (oj/exec db-config))\n; =\u003e 46.76\n```\n\nFor more advanced uses, OJ will provide the data in a useful format.\n\n```clojure\n(-\u003e (db/query :items)\n    (group :published)\n    (select [:published '(avg :price)])\n    (oj/exec db-config))\n; ({:published 1 :avg {:price 64.35}}, {:published 0 :avg {:price 10.35}})\n```\n\nOJ gives you a lot of flexibility. For instance, you could write some custom modifier functions and then execute them when you like. This allows you to combine them.\n  ``` clojure\n(defn find-by-username\n  [query username]\n  (-\u003e query\n      (db/where {:username username})))\n\n(-\u003e (query :users)\n    (find-by-username \"taylor\")\n    (oj/exec db-config)\n    (first))\n```\n\n## Printing SQL Queries\n\nIf you'd like SQL queries logged to your console when executed, you can enable it by setting the environment variable `PRINT_DB_LOGS` to true.\n\n## Contributing\n\n1. Fork this repository\n2. Create a new branch\n3. Do your thing\n4. Submit a pull request with a description of the change.\n\n## TODO\n\n- Joins\n\n\n## License\n\nCopyright © 2014 Taylor Lapeyre\n\nDistributed under the Eclipse Public License either version 1.0 or (at\nyour option) any later version.\n\n[yesql]: https://github.com/krisajenkins/yesql\n[ring]: https://github.com/ring-clojure/ring\n[spec]: /doc/SPEC\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftaylorlapeyre%2Foj","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftaylorlapeyre%2Foj","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftaylorlapeyre%2Foj/lists"}