Skip to content
Snippets Groups Projects
Commit 3c1bc195 authored by Allen Gilliland's avatar Allen Gilliland
Browse files

* add liquibase for migration management.

* setup a basic example of a unit test that runs migrations (up & down) while testing some model code.
* create inital liquibase migration file (only 2 tables reflected so far).
parent bfdaa381
No related branches found
No related tags found
No related merge requests found
......@@ -18,6 +18,9 @@
[environ "0.5.0"] ; easy environment management
[expectations "2.0.12"] ; unit tests
[korma "0.4.0"] ; SQL lib
[org.clojure/java.jdbc "0.3.6"] ; basic jdbc access from clojure
[org.liquibase/liquibase-core "3.3.2"] ; migration management (Java lib)
[org.yaml/snakeyaml "1.14"] ; YAML parser (required by liquibase)
[log4j/log4j "1.2.17"
:exclusions [javax.mail/mail
javax.jms/jms
......@@ -34,6 +37,7 @@
[lein-marginalia "LATEST"] ; generate documentation with 'lein marg'
[lein-ring "0.8.10"] ; start the HTTP server with 'lein ring server'
]
:java-source-paths ["src/java"]
:main ^:skip-aot metabase.core
:target-path "target/%s"
:ring {:handler metabase.core/app}
......
{
"databaseChangeLog": [
{"include": {"file": "migrations/liquibase_initial.json"}}
]
}
\ No newline at end of file
{
"databaseChangeLog": [
{
"changeSet": {
"id": "1",
"author": "agilliland",
"changes": [
{
"createTable": {
"tableName": "CORE_ORGANIZATION",
"columns": [
{
"column": {
"name": "ID",
"type": "int",
"autoIncrement": true,
"constraints": {
"primaryKey": true,
"nullable": false
}
}
},
{
"column": {
"name": "SLUG",
"type": "varchar(254)",
"constraints": {
"unique": true,
"nullable": false
}
}
},
{
"column": {
"name": "NAME",
"type": "varchar(254)",
"constraints": {"nullable": false}
}
},
{
"column": {
"name": "DESCRIPTION",
"type": "varchar(254)"
}
},
{
"column": {
"name": "LOGO_URL",
"type": "varchar(254)"
}
},
{
"column": {
"name": "INHERITS",
"type": "boolean",
"defaultValue": false,
"constraints": {"nullable": false}
}
}
]
}
},
{
"createTable": {
"tableName": "CORE_USER",
"columns": [
{
"column": {
"name": "ID",
"type": "int",
"autoIncrement": true,
"constraints": {
"primaryKey": true,
"nullable": false
}
}
},
{
"column": {
"name": "EMAIL",
"type": "varchar(254)",
"constraints": {
"unique": true,
"nullable": false
}
}
},
{
"column": {
"name": "FIRST_NAME",
"type": "varchar(254)",
"constraints": {"nullable": false}
}
},
{
"column": {
"name": "LAST_NAME",
"type": "varchar(254)"
}
},
{
"column": {
"name": "PASSWORD",
"type": "varchar(254)",
"constraints": {"nullable": false}
}
},
{
"column": {
"name": "DATE_JOINED",
"type": "DATETIME",
"constraints": {"nullable": false}
}
},
{
"column": {
"name": "LAST_LOGIN",
"type": "DATETIME"
}
},
{
"column": {
"name": "IS_STAFF",
"type": "boolean",
"defaultValue": false,
"constraints": {"nullable": false}
}
},
{
"column": {
"name": "IS_SUPERUSER",
"type": "boolean",
"defaultValue": false,
"constraints": {"nullable": false}
}
},
{
"column": {
"name": "IS_ACTIVE",
"type": "boolean",
"defaultValue": true,
"constraints": {"nullable": false}
}
}
]
}
}
]
}
}
]
}
\ No newline at end of file
package com.metabase.corvus.migrations;
import java.sql.SQLException;
import liquibase.Liquibase;
import liquibase.database.DatabaseFactory;
import liquibase.database.Database;
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.DatabaseException;
import liquibase.resource.ClassLoaderResourceAccessor;
public class LiquibaseMigrations {
private static final String LIQUIBASE_CHANGELOG = "migrations/liquibase.json";
public static final void setupDatabase(java.sql.Connection dbConnection) throws Exception {
try {
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(dbConnection));
Liquibase liquibase = new Liquibase(LIQUIBASE_CHANGELOG, new ClassLoaderResourceAccessor(), database);
liquibase.update("");
} catch (Exception e) {
throw new DatabaseException(e);
} finally {
if (dbConnection != null) {
try {
dbConnection.rollback();
dbConnection.close();
} catch (SQLException e){
//nothing to do
}
}
}
}
public static final void teardownDatabase(java.sql.Connection dbConnection) throws Exception {
try {
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(dbConnection));
Liquibase liquibase = new Liquibase(LIQUIBASE_CHANGELOG, new ClassLoaderResourceAccessor(), database);
liquibase.rollback(10000, "");
} catch (Exception e) {
throw new DatabaseException(e);
} finally {
if (dbConnection != null) {
try {
dbConnection.rollback();
dbConnection.close();
} catch (SQLException e){
//nothing to do
}
}
}
}
}
(ns metabase.db
(:require [clojure.tools.logging :as log]
[clojure.string :as str]
[environ.core :refer [env]]
[korma.core :refer :all]
[korma.db :refer :all]
......@@ -9,9 +10,11 @@
(defn get-db-file
"Check config/environment to determine the path to the h2 db file we want to use"
[]
(or (env :database-file) (get app-defaults :database-file)))
(str "file:" (or (env :database-file) (get app-defaults :database-file))))
(defdb db (do
(log/info (str "Using H2 database file: " (get-db-file)))
(h2 {:db (get-db-file)})))
(h2 {:db (get-db-file)
:naming {:keys str/lower-case
:fields str/upper-case}})))
(ns metabase.models.org
(:use korma.core
[metabase.models.org-perm :only (OrgPerm)]))
(defentity Org
(table :core_organization)
; (entity-fields
; :id
; :name
; :description
; :logo_url
; :inherits
; :slug)
(has-many OrgPerm {:fk :organization_id}))
(ns metabase.models.org-test
(:require [clojure.tools.logging :as log]
[clojure.java.jdbc :as jdbc]
[metabase.db :refer :all]
[metabase.config :refer [app-defaults]]
[metabase.models.org :refer [Org]]
[korma.core :refer :all]
[midje.sweet :refer :all]))
(defn liquibase-up []
(let [conn (jdbc/get-connection {:subprotocol "h2"
:subname (get-db-file)})]
(com.metabase.corvus.migrations.LiquibaseMigrations/setupDatabase conn)))
(defn liquibase-down []
(let [conn (jdbc/get-connection {:subprotocol "h2"
:subname (get-db-file)})]
(com.metabase.corvus.migrations.LiquibaseMigrations/teardownDatabase conn)))
(defn count-orgs []
(get-in (first (select Org (aggregate (count :*) :cnt))) [:cnt]))
(facts "about Core model"
(with-state-changes [(before :facts (liquibase-up))
(after :facts (liquibase-down))]
(fact "starts with 0 entries"
(count-orgs) => 0)
(fact "can insert new entries"
(let [result (insert Org (values {:name "test"
:slug "test"
:inherits false}))]
(nil? result) => false
(> 0 (or (get-in result [:generated_key]) (get-in result [:scope_identity()]) -1)))
(count-orgs) => 1)
))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment