Gungnir
A fully featured, data-driven database library for Clojure.
It is said that Gungnir could strike any target, regardless of the wielder's skill.
- Developer, speaking to the database admin.
Dutch Clojure Meetup - Gungnir
(gungnir.database/make-datasource!
{:adapter "postgresql"
:username "postgres"
:password "postgres"
:database-name "postgres"
:server-name "localhost"
:port-number 5432})
(def account-model
[:map
[:account/id {:primary-key true} uuid?]
[:account/email {:before-save [:string/lower-case]
:before-read [:string/lower-case]}
[:re {:error/message "Invalid email"} #".+@.+\..+"]]
[:account/password {:before-save [:bcrypt]} [:string {:min 6}]]
[:account/password-confirmation {:virtual true} [:string {:min 6}]]
[:account/created-at {:auto true} inst?]
[:account/updated-at {:auto true} inst?]])
(gungnir.model/register!
{:account account-model})
(defn password-match? [m]
(= (:account/password m)
(:account/password-confirmation m)))
(defmethod gungnir.model/validator :account/password-match? [_]
{:validator/key :account/password-confirmation
:validator/fn password-match?
:validator/message "Passwords don't match"})
(defmethod gungnir.model/before-save :bcrypt [_k v]
(buddy.hashers/derive v))
(defn attempt-register-account [request]
(-> (:form-params request)
(gungnir.changeset/cast :account)
(gungnir.changeset/create [:account/password-match?])
(gungnir.query/save!)))
(gungnir.query/find-by! :account/email "[email protected]") ;; => {:account/email "[email protected]",,,}
(-> (gungnir.query/limit 5)
(gungnir.query/select :account/id :account/email)
(gungnir.query/all! :account)) ;; => [{:account/email "..." :account/id "..."},,,]
Installation
Gungnir is still in its design phase and can result in breaking changes while on the SNAPSHOT version. Any breaking changes will be reflected in the updated documentation.
Add the following dependencies to your project.clj
Versions
:dependencies [[kwrooijen/gungnir "0.0.2-xxxxxxxx.yyyyyy-z"]
;; Optionally for frontend validation
[kwrooijen/gungnir.ui "0.0.2-xxxxxxxx.yyyyyy-z"]
,,,]
Rationale
Plug & Play setup with quality of life
The Clojure community tends to lean towards the "pick the libraries that you need" method rather than using a "framework" when building an application. This can make it challenging for new users. Once you're familiar with the Clojure ecosystem you'll know which libraries you prefer and create your own setup. And that's exactly what I've done.
If you want complete control over your database stack, then this is probably not for you. If you're a beginner and are overwhelmed with all the necessary libraries and configuration, or if you're looking for a Clojure database library that aims to provide a quality of life experience similar to Ruby's ActiveRecord or Elixir's Ecto, then stick around.
Data Driven
I cannot stress this enough, I really dislike macros. Clojure and a large part of it's community have taught me the beauty of writing data driven code. With great libraries such as HoneySQL, Hiccup, Integrant, Reitit, Malli, I think this is the Golden age of Data Driven Clojure. I never want to see macros in my API again.
Features
Plug & Playâ„¢
Include Gungnir in your project, and off you go! Gungnir includes everything for your database needs.
Models
Gungnir uses models to provide data validation and seamless translation between Clojure and SQL. Read more
Changesets
Inspired by Elixir Ecto's Changesets. Validate your data before inserting or updating it in your database. View the actual changes being made, and aggregate any error messages. Read more
Querying & Extension to HoneySQL
Gungnir isn't here to reinvent the wheel. Even though we have an interface for querying the database, we can still make use of HoneySQL syntax. This allows us to expand our queries, or write more complex ones for the edge cases. Read more
Migrations
Define your migrations using Clojure data structures and extend them as needed. You can also fallback to raw SQL if necessary. Read more
Relational mapping
Relations are easily accessed with Gungnir. Records with relations will have
access to relational atoms
which can be dereffed to query any related
rows. Read
more,
and more
Frontend validation
Gungnir also provides an extra package, gungnir.ui. Which provides some validation in the frontend. Read more
Resources
Guide
Read the guide for a full overview of all the features and how to use them.
Code Playground
The Gungnir code playground is a repository with an "interactive tutorial". Clone the repository and execute the code in the core namespace step by step.
Developing
Testing
In order to run the tests you'll need docker-compose. Make sure this is an up to date version. Inside of the root directory you can setup the testing databases with the following command.
docker-compose up -d
Then run the tests with lein
lein test
Author / License
Released under the MIT License by Kevin William van Rooijen.