Phase II

Lottery Domain Module

‘Create Lottery’ Command

  • Add a domain module in Lottery.ksmile
Lottery.ksmile
   domain-module LotteryDomain at com.metastay.lotterydomain
  • $smile
  • Refresh Eclipse to see LotteryDomain.kdomain
  • Add Lottery.create Command
LotteryDomain.kdomain
   domain Lottery {
       function lotteryNameExists(lotteryName:String):Boolean
   }

   aggregate Lottery {
       domain-ref lottery:Lottery
       command create {
           input(lotteryName:String, amount:Int)
           pre {
               require NewLotteryName => !(lottery.lotteryNameExists(input.lotteryName)) failing "Lottery name already exists!"
           }
       }
   }
  • $compile
  • Open LotteryAggregateCode to save it to implement.

Warning

LotteryWriter and other mongo related files not available to implement because LotteryDomain is not dependent on LotteryMongo.

  • Add the LotteryMongo dependency in LotteryDomain in Lottery.ksmile file
Lottery.ksmile
group Lottery {
    mongo-module LotteryMongo at com.metastay.lotterymongo
    domain-module LotteryDomain(LotteryMongo) at com.metastay.lotterydomain
    play-module LotteryPlay(LotteryMongo) at lotteryplay
}
  • $smile
  • Open LotteryAggregateCode to implement create command as below.
       LotteryAggregateCode.scala
       override def create = CreateCommand {
           import CreateCommand._;
           input: Input =>
           LotteryWriter().save(LotteryRow(lotteryName = input.lotteryName, amount = input.amount, open = false))
       }

* Open LotteryDomainCode to implement lotteryNameExists method as below

.. code-block:: scala
       LotteryDomainCode
       override def lotteryNameExists (lotteryName:String):Boolean = LotteryQuery().lotteryName.is(lotteryName).exists
  • $compile
  • Write test in LotteryDomainTestSuite as below.
LotteryDomainTestSuite
test("create", Tag("create")) {
    val lotteryAggregate = grab[LotteryAggregate]
    lotteryAggregate.create("WBLoto", 20000).println;
}
  • $project LotteryDomain
  • $test-only com.metastay.lotterydomain.LotteryDomainTestSuite – -n create
  • Check in DB if the WBLoto Lottery has been created

‘Add Participant’ And ‘Run’Command

Adding two more commands.

LotteryDomain.kdomain
domain Lottery {
    function lotteryNameExists(lotteryName:String):Boolean
    function participantExist(lotteryName:String, participantName:String):Boolean
    function participantCount(lotteryName:String):Int
}

aggregate Lottery {
    domain-ref lottery:Lottery
    command create {
        input(lotteryName:String, amount:Int)
        pre {
            require NewLotteryName => !(lottery.lotteryNameExists(input.lotteryName)) failing "Lottery name already exists!"
        }
    }

    command addParticipant {
        input(lotteryName:String, participantName:String)
        pre {
            require lotteryMustExists "Lottery must exist" => lottery.lotteryNameExists(input.lotteryName)
            require particpantNotYetAdded "Participant Not yet added" => !lottery.participantExist(input.lotteryName, input.participantName)

        }
    }

    command run {
        input(lotteryName:String)
        pre {
            require ExistingLotteryName => lottery.lotteryNameExists(input.lotteryName) failing "Lottery name does not exists"
            require atLeastTwoParticipants => ExistingLotteryName -> `domainRef.lottery.participantCount(input.lotteryName) > 1` failing "The lottery does not have any participant!"
        }
        output(winner:String)
    }

}
  • $compile
  • Implementing addParticipant() and run() in LotteryAggregateCode
LotteryAggregateCode.scala
class LotteryAggregateCode(domainRef: DomainRef) extends LotteryAggregateCommands {
  override def create = CreateCommand {
    import CreateCommand._;
    input: Input =>
      LotteryWriter().save(LotteryRow(lotteryName = input.lotteryName, amount = input.amount))
  }

  override def addParticipant = AddParticipantCommand {
    import AddParticipantCommand._;
    input: Input =>
      val q = LotteryQuery().lotteryName.is(input.lotteryName)
      val u = LotteryUpdate().participantList.addToSet(input.participantName)
      LotteryWriter().updateOne(q, u)

  }

  override def run = RunCommand {
    import RunCommand._;
    input: Input =>
      val q = LotteryQuery().lotteryName.is(input.lotteryName)
      val participantList = q.findOne.get.participantList //To find the participantList
      val winnerIndex = scala.util.Random.nextInt(participantList.size) //To find a winner Index
      val winner = participantList(winnerIndex)
      val u = LotteryUpdate().winner.set(Some(winner)).open.set(false)
      LotteryWriter().updateOne(q, u)
      Output(winner)
  }
}
  • Implementing participantExist() and participantCount() in LotteryDomainCode
LotteryDomainCode.scala
override def lotteryNameExists (lotteryName:String):Boolean = LotteryQuery().lotteryName.equalsIgnoreCase(lotteryName).exists
override def participantExist(lotteryName: String, participantName: String): Boolean =  LotteryQuery().lotteryName.is(lotteryName).participantList.contains(participantName).exists
override def participantCount(lotteryName: String): Int = LotteryQuery().lotteryName.is(lotteryName).findOne.get.participantList.size
def lotteryOpen  (lotteryName:String):Boolean  = (LotteryQuery().lotteryName.is(lotteryName).findOne.get.open)
  • Add test for addParticipant and run in RunCommandTestSuite
  • $project LoteryDomain
  • $test-only com.metastay.lotterydomain.aggregate.lottery.RunCommandTestSuite – -n run

Integrate Play and Domain

  • Adding all the validations and checks which are available in domain to the rest api.
  • Add LotteryDomain as a dependency to LotteryPlay Module rather than LotteryMongo in Lottery.ksmile
Lottery.ksmile
group Lottery {
    mongo-module LotteryMongo at com.metastay.lotterymongo
    domain-module LotteryDomain(LotteryMongo) at com.metastay.lotterydomain
    play-module LotteryPlay(LotteryDomain) at lotteryplay
}
  • $smile
  • Add the command-action in place of action to link it to command in LotteryPlay.kplay
LotteryPlay.kplay
web-writer Lottery {
    command-action createLottery(POST) LotteryDomain::Lottery.create
    command-action addParticipant(POST) LotteryDomain::Lottery.addParticipant
    command-action run(POST) LotteryDomain::Lottery.run
}

Lottery Vue Module

  • To create visual access of apis created in play module
  • Open Lottery.ksmile
  • Edit Lottery.ksmile and insert the below content to create a LotteryVue module Lottery.ksmile
group lottery {
    vue-module/0.2 LotteryVue(LotteryPlay) at com.metastay.lotteryvue
}
  • $smile
  • In Eclipse refresh to see the LotteryVue.kvue
  • Edit LotteryVue.kvue to create html files LotteryVue.kvue
route "lottery"
 html-fragment Header
 html-fragment Footer
 html-fragment Home
 html-fragment LotteryList
 html-fragment CreateLottery
 html-fragment LotteryDetails
  • $compile
  • open html-fragment Header.html under “/LotteryVue/src/com/metastay/lotteryvue/fragment/header.html” headerhtml
  • Edit footer.html footerhtml
  • Edit home.html homehtml
  • Edit lottery-list.html lotterylisthtml
  • Edit create_lottery.html,lottery_details.html
  • Edit lotteryvue-main.html mainhtml
  • Edit lotteryvue-router.js
var routes = [
   { path : '/', redirect: '/home'},
   { path : '/home', name : 'home', component: LotteryVue.Components.Home},
   { path : '/lottery-list', name : 'lotteryList', component: LotteryVue.Components.LotteryList},
   { path : '/create-lottery', name : 'createLottery', component: LotteryVue.Components.CreateLottery},
   { path : '/lottery-details/:lotteryName', name : 'lotteryDetails', component: LotteryVue.Components.LotteryDetails}
   ]
  • Edit lotteryvue-shell.html, add the title as Lottery
  • $run and access http://localhost:9000/lottery, go through all the links and they should be access right pages
  • Connect with Play (Web Writer and Web Reader) edit LotteryVue.kvue
data LotteryForm (lotteryName:String, amount:Int)
data LotteryDetails (lotteryName:String"{\"link\" : \"lottery-details/:lotteryName\"}", amount:Int, participantList:String* "{\"visible\" :false}", winner:String?,  status:String)

bus Lottery {
    lotteryListAvailable(lotteryList:LotteryDetails*)
    LotteryDetailsAvailable(lotteryDetails:LotteryDetails)
}

actions Lottery{
    loadLotteryList
    createLottery
    loadLotteryDetails
    addParticipant
    runLottery
}
backend-writer Lottery LotteryPlay::Lottery
backend-reader Lottery LotteryPlay:: Lottery
  • $compile
  • Edit LotteryActionsCode.scala lotteryActions
  • To get a better display of lottery list we need to add buter component to the project
  • add-component buter-release-0.1,in ksmile file and follow the guided steps(if any)
  • Edit Lottery.ksmile
import-component buter-release-0.1(ButerVue)
vue-module/0.2 LotteryVue(LotteryPlay, ButerVue) at com.metastay.lotteryvue

Enhancement (change is easy)