Skip to content

Containers

Angel Sanadinov edited this page Apr 10, 2017 · 11 revisions

Overview

The data management of a core3 application is based around two main concepts: database abstraction layers and containers. In addition to that, there are views which can be used to further process and group data coming from the databases.

Containers

Containers represent data going in and out of the data layer and, usually, each one maps to a distinct entity in one or more DBs (for example, table row in MariaDB or a document in CouchDB). Each container has at least an id and a containerType, used for identifying an object across all DBs.

LocalUser and Container Traits

Immutable

Useful for storing data that does not change, such as logs or data snapshots.

Mutable

Used for everything else and has the following additional pieces of information:

  • created - Data and time of the object's creation
  • updated - Date and time of the object's last update
  • updatedBy - ID of the user that performed the last update
  • revision - Unique ID used for ensuring data integrity
  • revisionNumber - Sequential ID used for ensuring data integrity and tracking the number of changes to an object

Companion Objects

A container class' companion object is used for converting the container to and from the format a DB expects.

BasicContainerCompanion

Defines the basic methods required from all companion objects:

trait BasicContainerCompanion {
  def getDatabaseName(dataType: DataType): String
  def matchCustomQuery(queryName: String, queryParams: Map[String, String], container: Container): Boolean
}
JSONContainerCompanion

Defines the methods required to convert a container object to/from JSON:

trait JSONContainerCompanion extends BasicContainerCompanion {
  def toJsonData(container: Container, format: JsonDataFormat): JsValue
  def fromJsonData(data: JsValue): Container
}
SlickContainerCompanion and SlickContainerCompanionImpl

Defines the methods required to convert containers to/from SQL DBs:

trait SlickContainerCompanion extends BasicContainerCompanion {
  def runCreateSchema(db: DatabaseDef)(implicit ec: ExecutionContext): Future[Boolean]
  def runDropSchema(db: DatabaseDef)(implicit ec: ExecutionContext): Future[Boolean]
  def runGenericQuery(query: SQLActionBuilder, db: DatabaseDef)(implicit ec: ExecutionContext): Future[Vector[Container]]
  def runGet(objectID: ObjectID, db: DatabaseDef)(implicit ec: ExecutionContext): Future[Container]
  def runCreate(container: Container, db: DatabaseDef)(implicit ec: ExecutionContext): Future[Boolean]
  def runUpdate(container: MutableContainer, db: DatabaseDef)(implicit ec: ExecutionContext): Future[Boolean]
  def runDelete(objectID: ObjectID, db: DatabaseDef)(implicit ec: ExecutionContext): Future[Boolean]
  def runCustomQuery(queryName: String, queryParams: Map[String, String], db: DatabaseDef)(implicit ec: ExecutionContext): Future[Vector[Container]]
}

trait SlickContainerCompanionImpl[ContainerTupleDef] extends SlickContainerCompanion {
  protected def convertToTuple(container: Container): ContainerTupleDef
  protected def convertFromTuple(tuple: ContainerTupleDef): Container
}

Note: SlickContainerCompanionImpl is the trait to be extended by container companions. SlickContainerCompanion is used by the DALs.

SearchContainerCompanion

Defines the methods required to convert a container to a searchable entity:

trait SearchContainerCompanion extends JSONContainerCompanion {
  def getSearchFields: Map[String, String]
}

Note: Normally, a container cannot be reconstructed from search data.

Core containers

  • Group - Allows grouping of other containers
  • LocalUser - Basic user container; used for local authentication
  • TransactionLog - Used for storing data about the operations the workflow engine is performing

Defining your own

  1. Decide on whether the container is going to be mutable or not

  2. Extend the appropriate trait (MutableContainer or ImmutableContainer) and define all container fields

case class Group(
  shortName: String,
  var name: String,
  var items: Vector[ObjectID],
  itemsType: ContainerType,
  created: Timestamp,
  var updated: Timestamp,
  var updatedBy: String,
  id: ObjectID,
  var revision: RevisionID,
  var revisionNumber: RevisionSequenceNumber
)
  extends MutableContainer {
  override val objectType: ContainerType = "Group"

  //... additional methods and/or constructors ...

}
  1. Decide on the container's target DBs and extend the appropriate companion traits:
object Group
  extends JSONContainerCompanion        //adds support for JSON-based DBs
    with SlickContainerCompanionImpl[(  //adds support for SQL DBs
    //Slick table row / tuple definition
    String, String, String, String, String, java.sql.Timestamp, java.sql.Timestamp, String, String, Int
    )] {
  private type ContainerTupleDef = (
    //Slick table row / tuple definition
    String, String, String, String, String, java.sql.Timestamp, java.sql.Timestamp, String, String, Int
    )

  //... trait method implementation ...

}
  1. Done

For complete container implementations, see the core containers package.

Clone this wiki locally