CodeLionX / actordb

Actor Database System Framework using Akka
MIT License
0 stars 2 forks source link

Midterm presentation #92

Closed CodeLionX closed 6 years ago

CodeLionX commented 6 years ago

Collection of code snippets highlighted with github-scala, so everybody can relate to.

CodeLionX commented 6 years ago

Customer domain actor example:

object Customer {
  object CustomerInfo extends RelationDef {
    val custName: ColumnDef[String] = ColumnDef("cust_name")
    val custGroupId: ColumnDef[Int] = ColumnDef("c_g_id")

    override val columns: Set[UntypedColumnDef] =
      Set(custName, custGroupId)
    override val name: String = "customer_info"
  }

  object StoreVisits extends RelationDef {
    val storeId: ColumnDef[Int] = ColumnDef("store_id")
    val timestamp: ColumnDef[ZonedDateTime] =
      ColumnDef("time", ZonedDateTime.EPOCH)
    val amount: ColumnDef[Double] = ColumnDef("amount")
    val fixedDiscount: ColumnDef[Double] = ColumnDef("fixed_disc")
    val varDiscount: ColumnDef[Double] = ColumnDef("var_disc")

    override val columns: Set[UntypedColumnDef] =
      Set(storeId, timestamp, amount, fixedDiscount, varDiscount)
    override val name: String = "store_visits"
  }
}

class Customer(id: Int) extends Dactor(id) {

  override protected val relations: Map[RelationDef, MutableRelation] =
    Dactor.createAsRowRelations(Seq(CustomerInfo, StoreVisits, Password))

  override def receive: Receive = {
    case GetCustomerInfo.Request() => getCustomerInfo()
    case AddStoreVisit.Request([params]) => addStoreVisit([params])
  }

}
CodeLionX commented 6 years ago

Example for relation usage:

override def receive: Receive = {
  case AddStoreVisit.Request(params: AsvParams) =>
    addStoreVisit(params) match {
      case Success(_) => sender() ! AddStoreVisit.Success(Relation.empty)
      case Failure(e) => sender() ! AddStoreVisit.Failure(e)
   }
  [...]
}

def addStoreVisit(p: AsvParams): Try[Relation] =
  if(!isValid(p))
    throw NotValidStoreVisitException(p)

  val svRecord = StoreVisits.newRecord(
    StoreVisits.storeId ~> p.storeId
    & StoreVisits.timestamp ~> p.time
    & StoreVisits.amount ~> p.amount
    & StoreVisits.fixedDiscount ~> p.fixedDiscount
    & StoreVisits.varDiscount ~> p.varDiscount
  ).build()
  relations(StoreVisits).insert(svRecord)
}
CodeLionX commented 6 years ago

how to access a relation:

relation(StoreVisits)
  .project(Set(StoreVisits.storeId))
  .where([...])
  .insert([...])
  .delete([...])
  .update([...])
CodeLionX commented 6 years ago

definition of message protocol of customer:

object GetCustomerInfo {
  case class Request() extends RequestResponseProtocol.Request
  case class Success(result: Relation) extends RequestResponseProtocol.Success
  case class Failure(e: Throwable) extends RequestResponseProtocol.Failure
}
object AddStoreVisit {
  case class Request(params: AsvParams) extends RequestResponseProtocol.Request
  case class Success(result: Relation) extends RequestResponseProtocol.Success
  case class Failure(e: Throwable) extends RequestResponseProtocol.Failure
}
// not in architecture:
object GetCustomerGroupId {
  case class Request() extends RequestResponseProtocol.Request
  case class Success(result: Relation) extends RequestResponseProtocol.Success
  case class Failure(e: Throwable) extends RequestResponseProtocol.Failure
}
CodeLionX commented 6 years ago

send messages to store sections

val purchaseRequests = sectionIds.map( sectionId => {
  val cartItems: Relation = allCartItems
    .where(CartPurchases.sectionId -> { _ == sectionId })

  sectionId -> StoreSection.GetVariableDiscountUpdateInventory.Request(
    customerId, time, cartItems
  )
})

val variableDiscounts: FutureRelation =
  Dactor.askDactor(system, classOf[StoreSection], purchaseRequests)
// process discounts: calculate sum

notify customer

val variableDiscountSumResult: Relation = Await.result(variableDiscountSum)
val sumRecord = variableDiscountSumResult.head
val msg = Customer.AddStoreVisit.Request(
  storeId,
  time,
  sumRecord.get(amountCol),
  sumRecord.get(fixedDiscCol),
  sumRecord.get(varDiscCol)
)
Dactor.dactorSelection(system, classOf[Customer], customerId) ! msg
CodeLionX commented 6 years ago

Final Presentation below

CodeLionX commented 6 years ago

Film domain actor example:

object FilmInfo extends RelationDef("film_info") {
  val title: ColumnDef[String] = ColumnDef("title")
  val description: ColumnDef[String] = ColumnDef("description")
  val release: ColumnDef[ZonedDateTime] =
    ColumnDef("release", ZonedDateTime.EPOCH)
}

object Cast extends RelationDef("cast") {
  val actorId: ColumnDef[Int] = ColumnDef("actor_id")
  val name: ColumnDef[String] = ColumnDef("name")
  val role: ColumnDef[String] = ColumnDef("role")
}

class Film(id: Int) extends Dactor(id) {
  override protected val relations: Map[RelationDef, MutableRelation] =
    Dactor.createAsRowRelations(Seq(FilmInfo, Cast))

  override def receive: Receive = {
    case PrepareDisplayInfo.Request() => prepareDisplayInfo()
  }
}
CodeLionX commented 6 years ago

how to access a relation:

relation(FilmInfo)
  .project(Set(FilmInfo.title, FilmInfo.description))
  .where([...])
  .insert([...])
  .delete([...])
  .update([...])

more functionality:

val results: Seq[Record] =
  relation(Cast)
    .where(Cast.role ~> {
      _ equals "Casey Bracket"
    })
    .project(Set(Cast.name))
    .records

results.foreach(println)
// ["Olivia Munn"]
CodeLionX commented 6 years ago

Functor usage:

val filmId = 1
val actorId= 13
val role = "Quinn McKenna"

val addCastToFilm = SequentialFunction()
  .start( (_: AddCastToFilm.Start) => 
    GetActorInfo.Request()
  }, Dactor.dactorSelection(classOf[Actor], actorId)

  .next(response => {
    response.records.headOption match {
      case Some(actorInfo: Record) =>
        val name= actorInfo(ActorInfo.name)
        AddCast.Request(actorId, name, role)
      case None =>
        fail(ActorInfoNotFoundException())
    }
  }, Dactor.dactorSelection(classOf[Film], filmId)

  //.next(response => new request, receiver)

  .end(identity)  // sends last response or failure message to caller

val functorRef = Dactor.startFunctor(
    // functor, akka-context, reference to Actor receiving response
    addCastToFilm, context, self
  )(
    // start-message
    AddCastToFilm.Start
  )