All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.scalarelational.h2.H2Datastore.scala Maven / Gradle / Ivy

There is a newer version: 1.3.15
Show newest version
package org.scalarelational.h2

import javax.sql.DataSource

import org.h2.jdbcx.JdbcConnectionPool
import org.scalarelational.Session
import org.scalarelational.h2.trigger.{TriggerEvent, TriggerType}
import org.scalarelational.model._
import org.scalarelational.table.Table
import org.scalarelational.util.StringUtil
import pl.metastack.metarx.{Channel, Opt, Var}

abstract class H2Datastore private() extends SQLDatastore {
  protected def this(mode: H2ConnectionMode = H2Memory(StringUtil.randomString()),
                     username: String = "sa",
                     password: String = "sa") {
    this()
    dbUsername := username
    dbPassword := password
    modeProperty := mode
  }

  protected def this(dataSource: DataSource) = {
    this()
    dataSourceProperty := dataSource
  }

  Class.forName("org.h2.Driver")

  val modeProperty = Opt[H2ConnectionMode]()
  val dbUsername = Var("sa")
  val dbPassword = Var("sa")
  val trigger = Channel[TriggerEvent]()

  private var functions = Set.empty[H2Function]

  // Update the data source if the mode changes
  modeProperty.values.attach(updateDataSource)

  override protected def catalog: Option[String] = None

  private def updateDataSource(mode: H2ConnectionMode): Unit = {
    dispose()  // Make sure to shut down the previous DataSource if possible
    dataSourceProperty := JdbcConnectionPool.create(
      mode.url, dbUsername.get, dbPassword.get)
  }

  def function[F](obj: AnyRef, methodName: String, functionName: Option[String] = None): H2Function = synchronized {
    val f = H2Function(this, obj, methodName, functionName)
    functions += f
    f
  }

  override def create(tables: Table*)(implicit session: Session): Int = {
    val created = super.create(tables: _*)

    // TODO convert this to use CallableInstructions
    val b = new StringBuilder
    tables.foreach {
      case table => createTableTriggers(table, b)
    }

    createFunctions(b)

    if (b.nonEmpty) {
      session.execute(b.toString())
    }

    created
  }

  private def createTableTriggers(table: Table, b: StringBuilder) = if (table.has(Triggers.name)) {
    val triggers = table.get[Triggers](Triggers.name).get
    if (triggers.has(TriggerType.Insert)) {
      b.append(s"""CREATE TRIGGER IF NOT EXISTS ${table.tableName}_INSERT_TRIGGER AFTER INSERT ON ${table.tableName} FOR EACH ROW CALL "org.scalarelational.h2.trigger.TriggerInstance";\r\n\r\n""")
    }
    if (triggers.has(TriggerType.Update)) {
      b.append(s"""CREATE TRIGGER IF NOT EXISTS ${table.tableName}_UPDATE_TRIGGER AFTER UPDATE ON ${table.tableName} FOR EACH ROW CALL "org.scalarelational.h2.trigger.TriggerInstance";\r\n\r\n""")
    }
    if (triggers.has(TriggerType.Delete)) {
      b.append(s"""CREATE TRIGGER IF NOT EXISTS ${table.tableName}_DELETE_TRIGGER AFTER DELETE ON ${table.tableName} FOR EACH ROW CALL "org.scalarelational.h2.trigger.TriggerInstance";\r\n\r\n""")
    }
    if (triggers.has(TriggerType.Select)) {
      b.append(s"""CREATE TRIGGER IF NOT EXISTS ${table.tableName}_SELECT_TRIGGER BEFORE SELECT ON ${table.tableName} CALL "org.scalarelational.h2.trigger.TriggerInstance";\r\n\r\n""")
    }
  }

  private def createFunctions(b: StringBuilder): Unit = functions.foreach {
    case f => b.append(s"""CREATE ALIAS IF NOT EXISTS ${f.name} FOR "${f.obj.getClass.getName.replaceAll("[$]", "")}.${f.methodName}";\r\n\r\n""")
  }

  override protected def disposeDataSource(dataSource: DataSource): Unit = {
    super.disposeDataSource(dataSource)

    dataSource match {
      case ds: JdbcConnectionPool => ds.dispose()
      case _ => // Ignore
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy