Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes without backward compatibility (H2 adapter, Migrator api changes, etc) #6

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
583 changes: 0 additions & 583 deletions README

This file was deleted.

19 changes: 15 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,28 +105,28 @@ object Test

// Now apply all migrations that are in the
// com.imageworks.vnp.dao.migrations package.
migrator.migrate(InstallAllMigrations, "com.imageworks.vnp.dao.migrations", false)
migrator.migrate(InstallAllMigrations, Seq("com.imageworks.vnp.dao.migrations"), false)
}
```

To rollback a database to its pristine state:

```scala
migrator.migrate(RemoveAllMigrations, "com.imageworks.vnp.dao.migrations", false)
migrator.migrate(RemoveAllMigrations, Seq("com.imageworks.vnp.dao.migrations"), false)
```

To rollback two migrations:

```scala
migrator.migrate(RollbackMigration(2), "com.imageworks.vnp.dao.migrations", false)
migrator.migrate(RollbackMigration(2), Seq("com.imageworks.vnp.dao.migrations"), false)
```

And to migrate to a specific migration, rollbacking back migrations
that are newer than the requested migration version and installing
migrations older than the requested version.

```scala
migrator.migrate(MigrateToVersion(20090731), "com.imageworks.vnp.dao.migrations", false)
migrator.migrate(MigrateToVersion(20090731), Seq("com.imageworks.vnp.dao.migrations"), false)
```

### Supported Databases
Expand All @@ -135,8 +135,13 @@ Scala Migrations currently supports

* Derby
* MySQL
* MariaDB
* Oracle
* PostgreSQL
* H2

The behavior of the MariaDB adapter is currently completely identical to MySQL adapter.
So all things described for MySQL also true for MariaDB.

Patches for other databases are welcome; however, you will need to
submit a [Contributor License Agreement](http://opensource.imageworks.com/cla/).
Expand Down Expand Up @@ -334,6 +339,10 @@ More information on the mappings is below.
* Default: `DECIMAL`
* Oracle: `NUMBER`

* Float
* Default: `REAL`
* MySQL: `FLOAT`

* Integer
* Default: `INTEGER`
* Oracle: `NUMBER(10, 0)`
Expand Down Expand Up @@ -387,6 +396,8 @@ Each database treats BLOB and VARBINARY differently.
| | Varbinary | `RAW` | 2,000 | Required | ?? | | |
| PostgreSQL | Blob | `BYTEA` | 1,073,741,823 | No | Yes | [7](http://www.postgresql.org/docs/9.1/static/storage-toast.html)| |
| | Varbinary | `BYTEA` | 1,073,741,823 | No | Yes || || ||
| H2 | Blob | `BLOB` | 2,147,483,647 | No | No | [8](http://www.h2database.com/html/datatypes.html#blob_type) | |
| | Varbinary | `VARBINARY` | 2,147,483,647 | Required | Yes | [9](http://www.h2database.com/html/datatypes.html#binary_type) | |

### Oracle and SMALLINT, INTEGER and BIGINT

Expand Down
8 changes: 5 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import com.typesafe.sbt.SbtScalariform.ScalariformKeys
import scalariform.formatter.preferences._

name := "scala-migrations"
Expand All @@ -16,9 +17,9 @@ organizationHomepage := Some(url("http://www.imageworks.com/"))

licenses += "New BSD License" -> url("http://opensource.org/licenses/BSD-3-Clause")

version := "1.1.2-SNAPSHOT"
version := "2.0.0-SNAPSHOT"

scalaVersion := "2.10.3"
scalaVersion := "2.11.7"

// For a single major Scala release, e.g. 2.x.y, include at most one
// Scala release candidate in crossScalaVersions, e.g. "2.x.y-RC3".
Expand Down Expand Up @@ -62,7 +63,8 @@ libraryDependencies ++= Seq(
"org.jmock" % "jmock-junit4" % "[2.5.1,3.0)" % "test",
"org.slf4j" % "slf4j-api" % "[1.5.8,2.0)",
"org.slf4j" % "slf4j-log4j12" % "[1.5.8,2.0)" % "test",
"postgresql" % "postgresql" % "9.1-901.jdbc4" % "test")
"postgresql" % "postgresql" % "9.1-901.jdbc4" % "test",
"com.h2database" % "h2" % "1.3.176" % "test")

// Run unit tests serially otherwise races can occur between two
// threads checking if the 'schema_migrations' table exists and
Expand Down
2 changes: 1 addition & 1 deletion project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version=0.13.0
sbt.version=0.13.11
6 changes: 4 additions & 2 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.5.1")

addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "0.8.1")
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0")

addSbtPlugin("com.typesafe.sbt" % "sbt-scalariform" % "1.2.0")
addSbtPlugin("org.scalariform" % "sbt-scalariform" % "1.6.0")

resolvers += "Sonatype OSS Releases" at "https://oss.sonatype.org/service/local/staging/deploy/maven2"
42 changes: 41 additions & 1 deletion src/main/scala/com/imageworks/migration/ColumnDefinition.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ trait ColumnSupportsAutoIncrement {
this: ColumnDefinition =>
}

/**
* Marker trait for a ColumnDefinition sublcass that the column type
* supports having unsigned value.
*/
trait ColumnSupportsUnsigned {
this: ColumnDefinition =>
}

/**
* Marker trait for a ColumnDefinition subclass that the column type
* supports a default value.
Expand Down Expand Up @@ -141,6 +149,11 @@ abstract class ColumnDefinition {
*/
protected var isAutoIncrement: Boolean = false

/**
* If Unsigned is specified for the column.
*/
protected var isUnsigned: Boolean = false

/**
* If a default is specified for the column.
*/
Expand All @@ -161,6 +174,10 @@ abstract class ColumnDefinition {
throw new UnsupportedOperationException(message)
}

if (this.isInstanceOf[ColumnSupportsUnsigned]) {
checkForUnsigned()
}

if (this.isInstanceOf[ColumnSupportsLimit]) {
checkForLimit()
}
Expand Down Expand Up @@ -195,6 +212,23 @@ abstract class ColumnDefinition {
}
}

/**
* Search for and remove all Unsigned case objects from the
* option list, setting isUnsigned if Unsigned was found
* and warning if two or more Unsigned case objects are given.
*/
private def checkForUnsigned() {
for (option @ Unsigned <- options) {
options = options filter { _ ne option }

if (isUnsigned) {
logger.warn("Redundant Unsigned specified for the '{}' column.",
getColumnName)
}
isUnsigned = true
}
}

/**
* Search for and remove all default values specified in the option
* list, saving the last one and warning if two or more default
Expand Down Expand Up @@ -243,7 +277,7 @@ abstract class ColumnDefinition {
/**
* If the column can or cannot be null.
*/
private lazy val notNullOpt: Option[Boolean] = {
protected lazy val notNullOpt: Option[Boolean] = {
var n1: Option[Boolean] = None

for (option <- options) {
Expand Down Expand Up @@ -560,3 +594,9 @@ class DefaultVarcharColumnDefinition
with ColumnSupportsDefault {
override protected def sql = optionallyAddLimitToDataType("VARCHAR")
}

class DefaultFloatColumnDefinition
extends ColumnDefinition
with ColumnSupportsDefault {
override protected def sql = "REAL"
}
6 changes: 6 additions & 0 deletions src/main/scala/com/imageworks/migration/DatabaseAdapter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,18 @@ object DatabaseAdapter {
case Mysql =>
new MysqlDatabaseAdapter(schemaNameOpt)

case Mariadb =>
new MariadbDatabaseAdapter(schemaNameOpt)

case Oracle =>
new OracleDatabaseAdapter(schemaNameOpt)

case Postgresql =>
new PostgresqlDatabaseAdapter(schemaNameOpt)

case H2 =>
new H2DatabaseAdapter(schemaNameOpt)

case null =>
throw new IllegalArgumentException("Must pass a non-null vendor to " +
"this function.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ class DerbyDatabaseAdapter(override val schemaNameOpt: Option[String])
new DerbyVarbinaryColumnDefinition
case VarcharType =>
new DefaultVarcharColumnDefinition
case FloatType =>
new DefaultFloatColumnDefinition
}
}

Expand Down
134 changes: 134 additions & 0 deletions src/main/scala/com/imageworks/migration/H2DatabaseAdapter.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
* Copyright (c) 2015 Sony Pictures Imageworks Inc.
*
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution. Neither the name of Sony Pictures Imageworks nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.imageworks.migration

trait H2AutoIncrementingColumnDefinitionMixin
extends ColumnDefinition
with ColumnSupportsAutoIncrement {
override protected abstract def sql: String = {
if (isAutoIncrement) super.sql + " AUTO_INCREMENT"
else super.sql
}
}

class H2BigintColumnDefinition
extends DefaultBigintColumnDefinition
with H2AutoIncrementingColumnDefinitionMixin

class H2IntegerColumnDefinition
extends DefaultIntegerColumnDefinition
with H2AutoIncrementingColumnDefinitionMixin

class H2SmallintColumnDefinition
extends DefaultSmallintColumnDefinition
with H2AutoIncrementingColumnDefinitionMixin

// H2 does not support size specifiers for the TIMESTAMP data type.
class H2TimestampColumnDefinition
extends ColumnDefinition
with ColumnSupportsDefault {
override val sql = "TIMESTAMP"
}

class H2DatabaseAdapter(override val schemaNameOpt: Option[String])
extends DatabaseAdapter(schemaNameOpt) {
override val vendor = H2

override val quoteCharacter = '`'

override val unquotedNameConverter = UppercaseUnquotedNameConverter

override val userFactory = PlainUserFactory

override val alterTableDropForeignKeyConstraintPhrase = "CONSTRAINT"

override val addingForeignKeyConstraintCreatesIndex = true

override val supportsCheckConstraints = false

override def columnDefinitionFactory(columnType: SqlType,
characterSetOpt: Option[CharacterSet]): ColumnDefinition = {
columnType match {
case BigintType =>
new H2BigintColumnDefinition
case BlobType =>
new DefaultBlobColumnDefinition
case BooleanType =>
new DefaultBooleanColumnDefinition
case CharType =>
new DefaultCharColumnDefinition
case DecimalType =>
new DefaultDecimalColumnDefinition
case IntegerType =>
new H2IntegerColumnDefinition
case SmallintType =>
new H2SmallintColumnDefinition
case TimestampType =>
new H2TimestampColumnDefinition
case VarbinaryType =>
new DefaultVarbinaryColumnDefinition
case VarcharType =>
new DefaultVarcharColumnDefinition
case FloatType =>
new DefaultFloatColumnDefinition
}
}

override def lockTableSql(schemaNameOpt: Option[String],
tableName: String): String = {
"SELECT * FROM " + quoteTableName(schemaNameOpt, tableName) + " FOR UPDATE"
}

override protected def alterColumnSql(schemaNameOpt: Option[String],
columnDefinition: ColumnDefinition): String = {
new java.lang.StringBuilder(512)
.append("ALTER TABLE ")
.append(quoteTableName(schemaNameOpt, columnDefinition.getTableName))
.append(" MODIFY COLUMN ")
.append(quoteColumnName(columnDefinition.getColumnName))
.append(columnDefinition.toSql)
.toString
}

override def removeIndexSql(schemaNameOpt: Option[String],
tableName: String,
indexName: String): String = {
new java.lang.StringBuilder(128)
.append("ALTER TABLE ")
.append(quoteTableName(schemaNameOpt, tableName))
.append(" DROP INDEX ")
.append(quoteIndexName(None, indexName))
.toString
}
}
19 changes: 19 additions & 0 deletions src/main/scala/com/imageworks/migration/JavaDatabaseAdapter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,23 @@ object JavaDatabaseAdapter {
def getPostgresqlDatabaseAdapter(schemaName: String): PostgresqlDatabaseAdapter = {
new PostgresqlDatabaseAdapter(Some(schemaName))
}

/**
* Create a H2 Database Adapter.
*
* @return newly constructed H2DatabaseAdapter
*/
def getH2DatabaseAdapter: H2DatabaseAdapter = {
new H2DatabaseAdapter(None)
}

/**
* Create a H2 Database Adapter.
*
* @param schemaName the default schema name in the adapter
* @return newly constructed H2DatabaseAdapter
*/
def getH2DatabaseAdapter(schemaName: String): H2DatabaseAdapter = {
new H2DatabaseAdapter(Some(schemaName))
}
}
Loading