All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
sss.openstar.wallet.ClientWallet.scala Maven / Gradle / Ivy
package sss.openstar.wallet
import sss.db._
import sss.openstar.BusEvent
import sss.openstar.ledger.LedgerId
import sss.openstar.util.Amount
import sss.openstar.schemamigration.SqlSchemaNames.ColumnNames._
import sss.db.ops.DbOps.{DbRunOps, OptFutureTxOps}
import sss.openstar.schemamigration.SqlSchemaNames.TableNames.clientWalletTableName
import scala.util.Try
object ClientWallet {
case class ClientBalance(ledgerId: LedgerId, walletOwner: String, client: String, balance: Amount)
case class NewClientBalance(ledgerId: LedgerId,
walletOwner: String,
client: String,
balance: Amount,
delta: Amount
) extends BusEvent
}
/**
* This class includes the persistence mechanism
* NB- Not reentrant!! An unlocked wallet should only be used
* by a single client
* @param walletOwner
* @param db
*/
class ClientWallet(walletOwner: String)(implicit db: Db) {
private[wallet] lazy val clientAccountsTable = db.table(clientWalletTableName)
private[wallet] def total: Long = {
db
.select(s"SELECT SUM($amountCol) as total FROM ${clientAccountsTable.name}")
.find(where(ownerCol -> walletOwner))
.map(_.flatMap(_.bigDecimalOpt("total")).fold(0L)(_.longValue()))
.dbRunSyncGet
}
private[wallet] def balance(client: String): Option[Long] = balanceFTx(client).dbRunSyncGet
private[wallet] def balanceFTx(client: String): FutureTx[Option[Long]] =
clientAccountsTable
.find(
where(
ownerCol -> walletOwner,
clientCol -> client
)
)
.map(_.map(_.long(amountCol)))
private[wallet] def listClients(startIndex: Long, pageSize: Int): Seq[Row] = {
val rows = clientAccountsTable
.filter(where(ownerCol -> walletOwner).limit(startIndex, pageSize))
rows
}.dbRunSyncGet
private[wallet] def transfer(amount: Long, fromClient: String, toClient: String): Try[Long] = (for {
_ <- debit(amount, fromClient)
bal <- credit(amount, toClient)
} yield bal).dbRunSync
private[wallet] def lodge(amount: Long, toClient: String): Try[Long] = {
credit(amount, toClient).dbRunSync
}
private[wallet] def withdraw(amount: Long, fromClient: String): Try[Long] = {
debit(amount, fromClient).dbRunSync
}
private[wallet] def withdrawAll(fromClient: String): Try[Long] = (for {
balOpt <- balanceFTx(fromClient)
newBal <- balOpt.map(debit(_, fromClient)).toFutureTxOpt
} yield newBal)
.dbRunSync map {
case None => throw new IllegalArgumentException(s"No such client $fromClient")
case (Some(value)) => value
}
private[wallet] def credit(amount: Long, client: String): FutureTx[Long] = for {
foundOpt <- clientAccountsTable.find(where(ownerCol -> walletOwner, clientCol -> client))
_ = require(amount > 0, "Cannot credit 0 to account")
resultBalance <- foundOpt match {
case None =>
clientAccountsTable.insert(
Map(
ownerCol -> walletOwner,
amountCol -> amount,
clientCol -> client
)
).map(_ => amount)
case Some(row) =>
val existingBalance = row.long(amountCol)
val newBalance = existingBalance + amount
clientAccountsTable.update(
Map(
amountCol -> newBalance
),
where(ownerCol -> walletOwner, clientCol -> client),
updateVersionCol = false
).map(_ => newBalance)
}
} yield resultBalance
private def debit(amount: Long, client: String): FutureTx[Long] = for {
rowOpt <- clientAccountsTable.find(where(ownerCol -> walletOwner, clientCol -> client))
_ = require(rowOpt.isDefined, s"Cannot debit from non existent client $client")
row = rowOpt.get
existingBalance = row.long(amountCol)
_ = require(existingBalance >= amount, s"Existing balance ($existingBalance) must exceed amount ($amount)")
newBalance = existingBalance - amount
_ <- if (newBalance == 0) {
clientAccountsTable.delete(
where(idCol -> row.id)
)
} else {
clientAccountsTable.updateRow(
Map(
amountCol -> newBalance,
idCol -> row.id
)
)
}
} yield newBalance
}