• Stars
    star
    173
  • Rank 220,124 (Top 5 %)
  • Language
    Clojure
  • License
    Eclipse Public Li...
  • Created about 10 years ago
  • Updated almost 10 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

🍹 A Clojure library for talking to your database.

oj

oj

Build Status

A refreshing Clojure library for talking to your database, heavily influenced by Ring.

Features

  • Gives you a standard interface for running and generating SQL
  • Focuses on the most common and useful features of SQL
  • Enforces type checking and validation for queries
  • Sensible defaults
  • Concise and powerful API
  • Encourages reusable components

Anti-features

  • Doesn't try to implement the entiretly of SQL
  • Doesn't require you to write SQL
  • Doesn't create its own domain-specific language
  • Doesn't surprise you

The SPEC file provides a complete description of the OJ interface.

Installation

Add this to your Leiningen :dependencies:

[oj "0.3.0"]

You'll also need a database driver (thanks to yesql for providing this handy table):

Database :dependencies Entry
PostgreSQL [org.postgresql/postgresql "9.3-1102-jdbc41"]
MySQL [mysql/mysql-connector-java "5.1.32"]
Oracle [com.oracle/ojdbc14 "10.2.0.4.0"]
SQLite [org.xerial/sqlite-jdbc "3.7.2"]
Derby [org.apache.derby/derby "10.11.1.1"]

Usage

Queries are represented as a Clojure map. The full specification of a query map can be found here.

(def users-named-taylor
  {:table :users
   :select [:id :email]
   :where {:first_name "taylor"}})

Queries can be executed by passing a query map and a database config into oj/exec:

(def db {:subprotocol "mysql"
         :subname "//127.0.0.1:3306/wishwheel3"
         :user "root"
         :password ""})

(oj/exec users-named-taylor db)
; => ({:id 1 :email "taylorlapeyre@gmail"} ...)

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.

(require [oj.core :as oj]
         [oj.modifiers :as db])

(defn find-by-username [username]
  (-> (db/query :users)
      (db/select [:id :username :email :created_at])
      (db/where {:username username})
      (oj/exec db-config)
      (first)))

(find-by-username "taylorlapeyre")
; => {:id 1 :username "taylorlapeyre"}

OJ's roots in regular Clojure data structures make it extremely powerful for building abstractions.

(defn user [& forms]
  (let [query (reduce merge {:table :users} forms)]
    (oj/exec query db)))

(user {:where {:id 1}})
=> SELECT * FROM users WHERE users.id=1

(user {:where {:id 1}}
      {:select [:id :username]})
=> SELECT id, username FROM users WHERE users.id=1

Not quite ActiveRecord, but it's getting there. And in 3 lines of code no less!

Of course, you can also perform all of the standard CRUD operations that you'd expect:

(defn create [user-data]
  (when (valid? user-data)
    (-> (db/query :users)
        (db/insert user-data)
        (oj/exec db-config))))

(defn update [id user-data]
  (when (valid? user-data)
    (-> (db/query :users)
        (db/where {:id id})
        (db/update user-data)
        (oj/exec db-config))))

(defn delete [id]
  (-> (db/query :users)
      (db/where {:id id})
      (db/delete)
      (oj/exec db-config)))

How about using SQL's aggregate functions? OJ allows you to use those as well, using a Clojure-like syntax.

For example, to get the average price of all items:

(-> (db/query :items)
    (select '(avg :price))
    (oj/exec db-config))
; => 46.76

For more advanced uses, OJ will provide the data in a useful format.

(-> (db/query :items)
    (group :published)
    (select [:published '(avg :price)])
    (oj/exec db-config))
; ({:published 1 :avg {:price 64.35}}, {:published 0 :avg {:price 10.35}})

OJ 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.

(defn find-by-username
[query username]
(-> query
    (db/where {:username username})))

(-> (query :users)
  (find-by-username "taylor")
  (oj/exec db-config)
  (first))

Printing SQL Queries

If 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.

Contributing

  1. Fork this repository
  2. Create a new branch
  3. Do your thing
  4. Submit a pull request with a description of the change.

TODO

  • Joins

License

Copyright Β© 2014 Taylor Lapeyre

Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.

More Repositories

1

hn-clojure

Hacker News in Clojure.
Clojure
30
star
2

basicwardrobe.info

A website to help you establish a wardrobe.
HTML
27
star
3

flux-example

A small but exemplary Flux/React application made with ES6 and jspm.
JavaScript
10
star
4

nav

A tiny Clojure routing library for Ring.
Clojure
10
star
5

.files

My tools and command line environment.
Vim Script
8
star
6

language-x86

An Atom package providing syntax support for x86 Assembly.
CoffeeScript
7
star
7

lita-pullrequests

A Lita handler to help you keep track of your pull requests.
Ruby
5
star
8

reactive-record

A small coffeescript library that provides a simple and intuitive interface for asynchronous data.
CoffeeScript
4
star
9

lita-youtube-me

A Lita handler that replies with a youtube URL when given a query.
Ruby
3
star
10

clojure-web-app

A website written entirely in Clojure & Clojurescript for reference.
Clojure
2
star
11

gsd

A tool to block distracting sites when you want to concentrate.
Ruby
2
star
12

csc

Answers to assignments for Computer Science classes at LSU.
Java
2
star
13

lita-howdoi

A Lita handler for searching Stack Overflow and returning the first answer to your question.
Ruby
2
star
14

yelp-review-sentiment-analyser

Predict the rating of a business based on the language of its reviews.
Java
2
star
15

wishwheel

A gift sharing website.
JavaScript
1
star
16

lita-message-router

This handler allows you to specify as many 'mention names' as you want for your Lita robot.
Ruby
1
star
17

l-system-art

A way to create art using L-systems and turtle rendering with JS Canvas
TypeScript
1
star
18

lita-morin

A Lita handler for showing quotes from Dave Morin.
Ruby
1
star
19

taylorlapeyre.github.io

My personal website.
HTML
1
star
20

lita-whoami

A Lita handler that tells you who people are.
Ruby
1
star
21

codeagora.co

A code snippet sharing website.
Ruby
1
star