Skip to content
James Reeves edited this page Jun 24, 2015 · 17 revisions

Databases

Ragtime needs an implementation of the ragtime.core/Migratable protocol to tell it how to migrate a particular database.

As an example, we'll create a Migratable in-memory database:

(require '[ragtime.core :as ragtime])

(defrecord MemoryDatabase [data migrations]
  ragtime/Migratable
  (add-migration-id [_ id]
    (swap! migrations conj id))
  (remove-migration-id [_ id]
    (swap! migrations (partial filterv (complement #{id}))))
  (applied-migration-ids [_]
    (seq @migrations)))

(defn memory-database []
  (->MemoryDatabase (atom {}) (atom [])))

We can define an new instance of this database, and see that it is empty, and has no migrations:

user=> (def db (memory-database))
#'user/db
user=> (-> db :data deref)
{}
user=> (ragtime/applied-migrations db)
nil

Migrations

Migrations are maps that contain three keys:

  • :id - a unique ID for the migration
  • :up - a function that applies the migration to a database
  • :down - a function that rolls back the migration in a database

Here's an example of one that modifies the MemoryDatabase defined earlier.

(def add-foo
  {:id   "add-foo"
   :up   (fn [db] (swap! (:data db) assoc :foo 1))
   :down (fn [db] (swap! (:data db) dissoc :foo))})

We can apply a migration to a database using the migrate function:

user=> (ragtime/migrate db add-foo)
["add-foo"]
user=> (ragtime/applied-migration-ids db)
("add-foo")
user=> (-> db :data deref)
{:foo 1}

And remove a migration using rollback:

user=> (ragtime/migrate db add-foo)
[]
user=> (ragtime/applied-migration-ids db)
nil
user=> (-> db :data deref)
{}

Indexes

Often we'll want to work with migrations that have already been applied to the database. For example, we may wish to roll back the latest migration. The Migratable protocol provides a way of finding the IDs of the migrations applied to the database, but we need some way of associating these IDs with the migrations themselves. In other words, we need a migration index.

An index simply maps IDs to migrations. We can create an index for a collection of migrations by using the into-index function:

user=> (def idx (ragtime/into-index [add-foo]))
#'user/idx
user=> idx
{"add-foo" {:id "add-foo", :up ..., :down ...}}

Once we have an index, we can use the migrate-all function to update the database with an ordered collection of migrations:

user=> (ragtime/migrate-all db idx [add-foo])
nil
user=> (ragtime/applied-migration-ids db)
("add-foo")

Or to roll back the last migrations applied to the database:

user=> (ragtime/rollback-last db idx)
nil
user=> (ragtime/applied-migration-ids db)
nil
Clone this wiki locally