            ------
            mirage-scala
            ------
            Naoki Takezoe
            ------
            2011-07-25

mirage-scala

%{toc|section=1|fromDepth=1|toDepth=3}

* {What's mirage-scala?}

 <<mirage-scala>> is Scala wrapper for Mirage.
 It provides the best interface to access to the database using Mirage for Scala.

 [Note] mirage-scala is still under preview release. So main interface might be changed in the future release.

 []

 To use mirage-scala with sbt based project, please add following deoendency into your project definition.

--------
val amaterasRepos = "Project Amateras" at "http://amateras.sourceforge.jp/mvn/"

val mirageScala = "jp.sf.amateras.mirage" % "mirage-scala_2.8.1" % "0.0.1" % "compile"
--------

 This is a simple example to query using mirage-scala:

--------
// A class that mapped to ResultList
class Book {
  var bookId: java.lang.Integer = null
  var bookName: String = null
  var author: String = null
  var price: java.lang.Integer = null
}
--------

--------
import jp.sf.amateras.mirage.scala._

// get Session and SqlManager
val session: Session = SessionFactory.getSession()
val sqlManager: SqlManager = session.getSqlManager()

// begin transaction
session.begin()

try {
  val books: List[Book] = sqlManager.getResultList(
    classOf[Book], Sql("""
      SELECT BOOK_ID, BOOK_NAME, AUTHOR, PRICE
      FROM BOOK
      /*IF author!=null*/
        WHERE AUTHOR = /*author*/
      /*END*/
    """), Map("author"->"Naoki Takezoe"))

  books.foreach { book =>
    println("bookId: " + book.bookId)
    println("bookName: " + book.bookName)
    println("author: " + book.author)
    println("price: " + book.price)
    println("--")
  }

  // commit transaction
  session.commit()
} catch {
  // rollback transaction
  ex: Exception => session.rollback()
}
--------

 mirage-scala provides <<SqlManager>> that has a similar interface of Mirage.

 [Note] In mirage-scala, SqlManager#getSingleResult() returns Option[T].

 []

 As different point of Mirage and mirage-scala, you can write {{{2waysql.html}2waySQL}} inline using <<Sql()>> in mirage-scala.
 Of course, you can use external SQL file in mirage-scala using <<SqlFile()>>:

--------
val result: List[Book] = sqlManager.getResultList(
  classOf[Book],
  SqlFile("META-INF/selectBooks.sql"),
  Map("author"->"Naoki Takezoe"))
--------

 In mirage-scala, you can use DTO or Map[String, _] as result class / parameter class.
 DTO must have var fields which correspond to select columns.

 See also {{{welcome.html}Mirage documentation}} to learn about usage of Mirage.

* {SQL less Update}

 mirage-scala also supports SQL less select / update using the entity class.
 The entity class has var fields which correspond to columns and annotations.

--------
class Book {
  @PrimaryKey(generationType=GenerationType.IDENTITY)
  var bookId: java.lang.Integer = null
  var bookName: String = null
  var author: String = null
  var price: java.lang.Integer = null
}
--------

 You can select / insert / update / delete table rows using the entity.

--------
val book: Book = new Book()
book.bookName = "Mirage in Action"
book.author = "Naoki Takezoe"
book.price = 20

sqlManager.insertEntity(book);
--------

 As other way, you can generate Java source code of entities using {{{apidocs/jp/sf/amateras/mirage/tool/EntityGenTask.html}Ant Task}}.
 Generated Java based entities are able to be used with mirage-scala.

* {Iteration Search}

 To handle large data, Mirage provide iteration search.

 <<SqlManager#iterate()>> takes an IterateCallback object in Mirage.
 However in mirage-scala, it takes a callback function instead of an IterateCallback object.

--------
var sum = 0
val result = sqlManager.iterate(classOf[Book],
  Sql("SELECT BOOK_ID, BOOK_NAME, AUTHOR, PRICE FROM BOOK"),
  (book: Book) => {
    sum = sum + book.price
    sum
  })
--------

 In this example, var variable 'sum' is required to keep a total value outside of the callback function.
 You can remove it as following:

--------
val result = sqlManager.iterate(classOf[Book],
  Sql("SELECT BOOK_ID, BOOK_NAME, AUTHOR, PRICE FROM BOOK"),
  (book: Book, sum: Int) => {
    sum + book.price
  }, 0)
--------

 The callback function is given a resut of the previous callback invocation.
 And initial value is given at first. In this example, initial value is 0.

* {Automatic Transaction Controlling}

 <<Session#withTransaction()>> provides automatic transaction controlling.

 When you give a function which uses SqlManager to Session#withTransaction(),
 it begins a transaction and invokes a given function.
 If exception is occurred in your function, it rollback a transaction,
 otherwise it commits a transaction and returns a return value of a given function.

--------
val key: Long = ...

Session.withTransaction { session =>
  val sqlManager = session.sqlManager
  val book: Option[Book] = sqlManager.findEntity(classOf[book], key)
  ...
}
--------

* {TODO}

 * Batch updating

 * Stored procedure / function support

 * Ant task for Scala based entity generation

 []

