Skip to content

Commit

Permalink
Merge pull request #9 from takama/feature/stub_driver
Browse files Browse the repository at this point in the history
Added stub controller
  • Loading branch information
takama authored Apr 15, 2018
2 parents a57d0d6 + e3c339f commit 686f023
Show file tree
Hide file tree
Showing 9 changed files with 423 additions and 349 deletions.
16 changes: 16 additions & 0 deletions db/controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package db

import (
"github.com/takama/backer/model"
)

// Controller defines DB interface for Player and Tournament Entry
type Controller interface {
Transaction() (Transact, error)
NewPlayer(ID string, tx Transact) error
FindPlayer(ID string, tx Transact) (*model.Player, error)
SavePlayer(player *model.Player, tx Transact) error
NewTournament(ID uint64, tx Transact) error
FindTournament(ID uint64, tx Transact) (*model.Tournament, error)
SaveTournament(tournament *model.Tournament, tx Transact) error
}
9 changes: 9 additions & 0 deletions db/store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package db

// Store contains DB store control methods
type Store interface {
Ready() bool
Reset() error
MigrateUp() error
MigrateDown() error
}
242 changes: 242 additions & 0 deletions db/stub.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
package db

import (
"errors"
"sync"

"github.com/takama/backer/model"
)

var (
// ErrAlreadyExist appears for existing records when try to create new one
ErrAlreadyExist = errors.New("Record already exists")
// ErrNotFound appears if record does not exist
ErrNotFound = errors.New("Record not found")
)

// Stub in-memory controller
type Stub struct {
mutex sync.RWMutex
tx Transact
transacts []transactData
ErrReset []error
ErrMigUp []error
ErrMigDn []error
ErrTx []error
ErrTxCmt []error
ErrTxRbk []error
ErrNew []error
ErrFind []error
ErrSave []error
ErrDelete []error
players map[string]model.Player
tournaments map[uint64]model.Tournament
}

type transactData struct {
mutex sync.RWMutex
players map[string]model.Player
tournaments map[uint64]model.Tournament
}

// Ready returns connection state
func (stub *Stub) Ready() bool {
return true
}

// Reset makes the DB initialization
func (stub *Stub) Reset() error {
var err error
stub.players = make(map[string]model.Player)
stub.tournaments = make(map[uint64]model.Tournament)
stub.tx = stub
if len(stub.ErrReset) == 0 {
return nil
}
err, stub.ErrReset = stub.ErrReset[len(stub.ErrReset)-1], stub.ErrReset[:len(stub.ErrReset)-1]
return err
}

// MigrateUp migrates DB schema
func (stub *Stub) MigrateUp() error {
return stub.Reset()
}

// MigrateDown remove DB schema and data
func (stub *Stub) MigrateDown() error {
return stub.Reset()
}

// Transaction returns DB transaction control
func (stub *Stub) Transaction() (Transact, error) {
var err error
stub.transacts = append(stub.transacts, transactData{})
stub.mutex.RLock()
defer stub.mutex.RUnlock()
stub.transacts[len(stub.transacts)-1].players = make(map[string]model.Player)
stub.transacts[len(stub.transacts)-1].tournaments = make(map[uint64]model.Tournament)
for idx, val := range stub.players {
stub.transacts[len(stub.transacts)-1].players[idx] = val
}
for idx, val := range stub.tournaments {
stub.transacts[len(stub.transacts)-1].tournaments[idx] = val
}
if len(stub.ErrTx) == 0 {
return stub.tx, nil
}
err, stub.ErrTx = stub.ErrTx[len(stub.ErrTx)-1], stub.ErrTx[:len(stub.ErrTx)-1]
return stub.tx, err
}

// Commit confirms all changes during a transaction
func (stub *Stub) Commit() error {
var err error
stub.transacts = stub.transacts[:len(stub.transacts)-1]
if len(stub.ErrTxCmt) == 0 {
return nil
}
err, stub.ErrTxCmt = stub.ErrTxCmt[len(stub.ErrTxCmt)-1], stub.ErrTxCmt[:len(stub.ErrTxCmt)-1]
return err
}

// Rollback undo all changes during a transaction
func (stub *Stub) Rollback() error {
var err error
stub.mutex.RLock()
defer stub.mutex.RUnlock()
stub.Reset()
for idx, val := range stub.transacts[len(stub.transacts)-1].players {
stub.players[idx] = val
}
for idx, val := range stub.transacts[len(stub.transacts)-1].tournaments {
stub.tournaments[idx] = val
}
stub.transacts = stub.transacts[:len(stub.transacts)-1]
if len(stub.ErrTxRbk) == 0 {
return nil
}
err, stub.ErrTxRbk = stub.ErrTxRbk[len(stub.ErrTxRbk)-1], stub.ErrTxRbk[:len(stub.ErrTxRbk)-1]
return err
}

// NewPlayer creates a new player with specified ID
func (stub *Stub) NewPlayer(ID string, tx Transact) error {
var err error
stub.mutex.RLock()
defer stub.mutex.RUnlock()
_, ok := stub.players[ID]
if ok {
return ErrAlreadyExist
}
stub.players[ID] = model.Player{ID: ID}
if len(stub.ErrNew) == 0 {
return nil
}
err, stub.ErrNew = stub.ErrNew[len(stub.ErrNew)-1], stub.ErrNew[:len(stub.ErrNew)-1]
return err
}

// FindPlayer finds existing player by specified ID
func (stub *Stub) FindPlayer(ID string, tx Transact) (*model.Player, error) {
var err error
stub.mutex.RLock()
defer stub.mutex.RUnlock()
player, ok := stub.players[ID]
if !ok {
return nil, ErrNotFound
}
if len(stub.ErrFind) == 0 {
return &player, nil
}
err, stub.ErrFind = stub.ErrFind[len(stub.ErrFind)-1], stub.ErrFind[:len(stub.ErrFind)-1]
return &player, err
}

// SavePlayer saves a Player model
func (stub *Stub) SavePlayer(player *model.Player, tx Transact) error {
var err error
stub.mutex.Lock()
defer stub.mutex.Unlock()

stub.players[player.ID] = *player
if len(stub.ErrSave) == 0 {
return nil
}
err, stub.ErrSave = stub.ErrSave[len(stub.ErrSave)-1], stub.ErrSave[:len(stub.ErrSave)-1]
return err
}

// DeletePlayer delete player by specified ID
func (stub *Stub) DeletePlayer(ID string, tx Transact) error {
var err error
stub.mutex.Lock()
defer stub.mutex.Unlock()

delete(stub.players, ID)
if len(stub.ErrDelete) == 0 {
return nil
}
err, stub.ErrDelete = stub.ErrDelete[len(stub.ErrDelete)-1], stub.ErrDelete[:len(stub.ErrDelete)-1]
return err
}

// NewTournament creates a new tournament with specified ID
func (stub *Stub) NewTournament(ID uint64, tx Transact) error {
var err error
stub.mutex.RLock()
defer stub.mutex.RUnlock()
_, ok := stub.tournaments[ID]
if ok {
return ErrAlreadyExist
}
stub.tournaments[ID] = model.Tournament{ID: ID}
if len(stub.ErrNew) == 0 {
return nil
}
err, stub.ErrNew = stub.ErrNew[len(stub.ErrNew)-1], stub.ErrNew[:len(stub.ErrNew)-1]
return err
}

// FindTournament finds existing tournament by specified ID
func (stub *Stub) FindTournament(ID uint64, tx Transact) (*model.Tournament, error) {
var err error
stub.mutex.RLock()
defer stub.mutex.RUnlock()
tournament, ok := stub.tournaments[ID]
if !ok {
return nil, ErrNotFound
}
if len(stub.ErrFind) == 0 {
return &tournament, nil
}
err, stub.ErrFind = stub.ErrFind[len(stub.ErrFind)-1], stub.ErrFind[:len(stub.ErrFind)-1]
return &tournament, err
}

// SaveTournament saves a Tournament model
func (stub *Stub) SaveTournament(tournament *model.Tournament, tx Transact) error {
var err error
stub.mutex.Lock()
defer stub.mutex.Unlock()

stub.tournaments[tournament.ID] = *tournament
if len(stub.ErrSave) == 0 {
return nil
}
err, stub.ErrSave = stub.ErrSave[len(stub.ErrSave)-1], stub.ErrSave[:len(stub.ErrSave)-1]
return err
}

// DeleteTournament delete tournament by specified ID
func (stub *Stub) DeleteTournament(ID uint64, tx Transact) error {
var err error
stub.mutex.Lock()
defer stub.mutex.Unlock()

delete(stub.tournaments, ID)
if len(stub.ErrDelete) == 0 {
return nil
}
err, stub.ErrDelete = stub.ErrDelete[len(stub.ErrDelete)-1], stub.ErrDelete[:len(stub.ErrDelete)-1]
return err
}
14 changes: 0 additions & 14 deletions player/controller.go

This file was deleted.

12 changes: 9 additions & 3 deletions player/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"sync"

"github.com/takama/backer"
"github.com/takama/backer/db"
"github.com/takama/backer/helper"
"github.com/takama/backer/model"
)
Expand All @@ -16,15 +17,16 @@ var (

// Entry implements Player interface
type Entry struct {
Controller
db.Controller
mutex sync.RWMutex
model.Player
}

// New returns new Entry which implement Player interface
func New(id string, ctrl Controller) (*Entry, error) {
func New(id string, ctrl db.Controller) (*Entry, error) {
tx, err := ctrl.Transaction()
if err != nil {
tx.Rollback()
return nil, err
}

Expand All @@ -50,9 +52,10 @@ func New(id string, ctrl Controller) (*Entry, error) {
}

// Find returns Entry with existing Player
func Find(id string, ctrl Controller) (*Entry, error) {
func Find(id string, ctrl db.Controller) (*Entry, error) {
tx, err := ctrl.Transaction()
if err != nil {
tx.Rollback()
return nil, err
}

Expand All @@ -77,6 +80,7 @@ func Find(id string, ctrl Controller) (*Entry, error) {
func (entry *Entry) Fund(amount backer.Points) error {
tx, err := entry.Controller.Transaction()
if err != nil {
tx.Rollback()
return err
}

Expand Down Expand Up @@ -110,6 +114,7 @@ func (entry *Entry) Fund(amount backer.Points) error {
func (entry *Entry) Take(amount backer.Points) error {
tx, err := entry.Controller.Transaction()
if err != nil {
tx.Rollback()
return err
}

Expand All @@ -120,6 +125,7 @@ func (entry *Entry) Take(amount backer.Points) error {
}

if player.Balance < amount {
tx.Rollback()
return ErrInsufficientPoints
}

Expand Down
Loading

0 comments on commit 686f023

Please sign in to comment.