Skip to content

Commit

Permalink
Introduce work unit actions.
Browse files Browse the repository at this point in the history
  • Loading branch information
fr33r committed Jul 19, 2020
1 parent 97b6cac commit 026998a
Show file tree
Hide file tree
Showing 5 changed files with 220 additions and 3 deletions.
61 changes: 61 additions & 0 deletions v3/action.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/* Copyright 2019 Freerware
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package work

// Action represents an operation performed during a paticular lifecycle event of a work unit.
type UnitAction func(UnitContext)

// ActionType represents the type of work unit action.
type ActionType int

// The various types of actions that are executed throughout the lifecycle of a work unit.
const (
// ActionTypeAfterRegister indicates an action type that occurs after an entity is registered.
ActionTypeAfterRegister = iota
// ActionTypeAfterAdd indicates an action type that occurs after an entity is added.
ActionTypeAfterAdd
// ActionTypeAfterAlter indicates an action type that occurs after an entity is altered.
ActionTypeAfterAlter
// ActionTypeAfterRemove indicates an action type that occurs after an entity is removed.
ActionTypeAfterRemove
// ActionTypeAfterInserts indicates an action type that occurs after new entities are inserted in the data store.
ActionTypeAfterInserts
// ActionTypeAfterUpdates indicates an action type that occurs after existing entities are updated in the data store.
ActionTypeAfterUpdates
// ActionTypeAfterDeletes indicates an action type that occurs after existing entities are deleted in the data store.
ActionTypeAfterDeletes
// ActionTypeAfterRollback indicates an action type that occurs after rollback.
ActionTypeAfterRollback
// ActionTypeAfterSave indicates an action type that occurs after save.
ActionTypeAfterSave
// ActionTypeBeforeRegister indicates an action type that occurs before an entity is registered.
ActionTypeBeforeRegister
// ActionTypeBeforeAdd indicates an action type that occurs before an entity is added.
ActionTypeBeforeAdd
// ActionTypeBeforeAlter indicates an action type that occurs before an entity is altered.
ActionTypeBeforeAlter
// ActionTypeBeforeRemove indicates an action type that occurs before an entity is removed.
ActionTypeBeforeRemove
// ActionTypeBeforeInserts indicates an action type that occurs before new entities are inserted in the data store.
ActionTypeBeforeInserts
// ActionTypeBeforeUpdates indicates an action type that occurs before existing entities are updated in the data store.
ActionTypeBeforeUpdates
// ActionTypeBeforeDeletes indicates an action type that occurs before existing entities are deleted in the data store.
ActionTypeBeforeDeletes
// ActionTypeBeforeRollback indicates an action type that occurs before rollback.
ActionTypeBeforeRollback
// ActionTypeBeforeSave indicates an action type that occurs before save.
ActionTypeBeforeSave
)
9 changes: 9 additions & 0 deletions v3/sql_unit.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ func (u *sqlUnit) Remove(entities ...interface{}) error {
}

func (u *sqlUnit) rollback(tx *sql.Tx) (err error) {
u.executeActions(ActionTypeBeforeRollback)

//setup timer.
stop := u.scope.Timer(rollback).Start().Stop
Expand All @@ -124,43 +125,50 @@ func (u *sqlUnit) rollback(tx *sql.Tx) (err error) {

func (u *sqlUnit) applyInserts(tx *sql.Tx) (err error) {
u.logger.Debug("attempting to insert entities", zap.Int("count", u.additionCount))
u.executeActions(ActionTypeBeforeInserts)
for typeName, additions := range u.additions {
if err = u.mappers[typeName].Insert(tx, additions...); err != nil {
err = multierr.Combine(err, u.rollback(tx))
u.logger.Error(err.Error(), zap.String("typeName", typeName.String()))
return
}
}
u.executeActions(ActionTypeAfterInserts)
return
}

func (u *sqlUnit) applyUpdates(tx *sql.Tx) (err error) {
u.logger.Debug("attempting to update entities", zap.Int("count", u.alterationCount))
u.executeActions(ActionTypeBeforeUpdates)
for typeName, alterations := range u.alterations {
if err = u.mappers[typeName].Update(tx, alterations...); err != nil {
err = multierr.Combine(err, u.rollback(tx))
u.logger.Error(err.Error(), zap.String("typeName", typeName.String()))
return
}
}
u.executeActions(ActionTypeAfterUpdates)
return
}

func (u *sqlUnit) applyDeletes(tx *sql.Tx) (err error) {
u.logger.Debug("attempting to remove entities", zap.Int("count", u.removalCount))
u.executeActions(ActionTypeBeforeDeletes)
for typeName, removals := range u.removals {
if err = u.mappers[typeName].Delete(tx, removals...); err != nil {
err = multierr.Combine(err, u.rollback(tx))
u.logger.Error(err.Error(), zap.String("typeName", typeName.String()))
return
}
}
u.executeActions(ActionTypeAfterDeletes)
return
}

// Save commits the new additions, modifications, and removals
// within the work unit to an SQL store.
func (u *sqlUnit) Save() (err error) {
u.executeActions(ActionTypeBeforeSave)

//setup timer.
stop := u.scope.Timer(save).Start().Stop
Expand Down Expand Up @@ -214,6 +222,7 @@ func (u *sqlUnit) Save() (err error) {
u.logger.Error(err.Error())
return
}
u.executeActions(ActionTypeBeforeSave)

totalCount :=
u.additionCount + u.alterationCount + u.removalCount + u.registerCount
Expand Down
17 changes: 16 additions & 1 deletion v3/unit.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ type unit struct {
registerCount int
logger *zap.Logger
scope tally.Scope
actions map[ActionType][]UnitAction
}

func newUnit(options UnitOptions) unit {
Expand All @@ -83,11 +84,13 @@ func newUnit(options UnitOptions) unit {
registered: make(map[TypeName][]interface{}),
logger: options.Logger,
scope: options.Scope.SubScope("unit"),
actions: options.Actions,
}
return u
}

func (u *unit) register(checker func(t TypeName) bool, entities ...interface{}) error {
u.executeActions(ActionTypeBeforeRegister)
for _, entity := range entities {
tName := TypeNameOf(entity)
if ok := checker(tName); !ok {
Expand All @@ -101,11 +104,12 @@ func (u *unit) register(checker func(t TypeName) bool, entities ...interface{})
u.registered[tName] = append(u.registered[tName], entity)
u.registerCount = u.registerCount + 1
}
u.executeActions(ActionTypeAfterRegister)
return nil
}

func (u *unit) add(checker func(t TypeName) bool, entities ...interface{}) error {

u.executeActions(ActionTypeBeforeAdd)
for _, entity := range entities {
tName := TypeNameOf(entity)
if ok := checker(tName); !ok {
Expand All @@ -120,10 +124,12 @@ func (u *unit) add(checker func(t TypeName) bool, entities ...interface{}) error
u.additions[tName] = append(u.additions[tName], entity)
u.additionCount = u.additionCount + 1
}
u.executeActions(ActionTypeAfterAdd)
return nil
}

func (u *unit) alter(checker func(t TypeName) bool, entities ...interface{}) error {
u.executeActions(ActionTypeBeforeAlter)
for _, entity := range entities {
tName := TypeNameOf(entity)
if ok := checker(tName); !ok {
Expand All @@ -138,10 +144,12 @@ func (u *unit) alter(checker func(t TypeName) bool, entities ...interface{}) err
u.alterations[tName] = append(u.alterations[tName], entity)
u.alterationCount = u.alterationCount + 1
}
u.executeActions(ActionTypeAfterAlter)
return nil
}

func (u *unit) remove(checker func(t TypeName) bool, entities ...interface{}) error {
u.executeActions(ActionTypeBeforeRemove)
for _, entity := range entities {
tName := TypeNameOf(entity)
if ok := checker(tName); !ok {
Expand All @@ -156,5 +164,12 @@ func (u *unit) remove(checker func(t TypeName) bool, entities ...interface{}) er
u.removals[tName] = append(u.removals[tName], entity)
u.removalCount = u.removalCount + 1
}
u.executeActions(ActionTypeAfterRemove)
return nil
}

func (u *unit) executeActions(actionType ActionType) {
for _, action := range u.actions[actionType] {
action(UnitContext{logger: u.logger})
}
}
23 changes: 23 additions & 0 deletions v3/unit_context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* Copyright 2019 Freerware
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package work

import "go.uber.org/zap"

// UnitContext represents context about a work unit passed through to work unit actions.
type UnitContext struct {
logger *zap.Logger
}
113 changes: 111 additions & 2 deletions v3/unit_options.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
/* Copyright 2019 Freerware
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package work

import (
Expand All @@ -8,8 +22,9 @@ import (
// UnitOptions represents the configuration options
// for the work unit.
type UnitOptions struct {
Logger *zap.Logger
Scope tally.Scope
Logger *zap.Logger
Scope tally.Scope
Actions map[ActionType][]UnitAction
}

// Option applies an option to the provided configuration.
Expand All @@ -29,4 +44,98 @@ var (
o.Scope = s
}
}

// setActions appends the provided actions as the provided action type.
setActions = func(t ActionType, a ...UnitAction) Option {
return func(o *UnitOptions) {
if o.Actions == nil {
o.Actions = make(map[ActionType][]UnitAction)
}
o.Actions[t] = append(o.Actions[t], a...)
}
}

// UnitAfterRegisterActions specifies the option to provide actions to execute
// after entities are registered with the work unit.
UnitAfterRegisterActions = func(a ...UnitAction) Option {
return setActions(ActionTypeAfterRegister, a...)
}

// UnitAfterAddActions specifies the option to provide actions to execute
// after entities are added with the work unit.
UnitAfterAddActions = func(a ...UnitAction) Option {
return setActions(ActionTypeAfterAdd, a...)
}

// UnitAfterAlterActions specifies the option to provide actions to execute
// after entities are altered with the work unit.
UnitAfterAlterActions = func(a ...UnitAction) Option {
return setActions(ActionTypeAfterAlter, a...)
}

// UnitAfterRemoveActions specifies the option to provide actions to execute
// after entities are removed with the work unit.
UnitAfterRemoveActions = func(a ...UnitAction) Option {
return setActions(ActionTypeAfterRemove, a...)
}

// UnitAfterInsertsActions specifies the option to provide actions to execute
// after new entities are inserted in the data store.
UnitAfterInsertsActions = func(a ...UnitAction) Option {
return setActions(ActionTypeAfterInserts, a...)
}

// UnitAfterUpdatesActions specifies the option to provide actions to execute
// after altered entities are updated in the data store.
UnitAfterUpdatesActions = func(a ...UnitAction) Option {
return setActions(ActionTypeAfterUpdates, a...)
}

// UnitAfterDeletesActions specifies the option to provide actions to execute
// after removed entities are deleted in the data store.
UnitAfterDeletesActions = func(a ...UnitAction) Option {
return setActions(ActionTypeAfterDeletes, a...)
}

// UnitAfterRollbackActions specifies the option to provide actions to execute
// after a rollback is performed.
UnitAfterRollbackActions = func(a ...UnitAction) Option {
return setActions(ActionTypeAfterRollback, a...)
}

// UnitAfterSaveActions specifies the option to provide actions to execute
// after a save is performed.
UnitAfterSaveActions = func(a ...UnitAction) Option {
return setActions(ActionTypeAfterSave, a...)
}

// UnitBeforeInsertsActions specifies the option to provide actions to execute
// before new entities are inserted in the data store.
UnitBeforeInsertsActions = func(a ...UnitAction) Option {
return setActions(ActionTypeBeforeInserts, a...)
}

// UnitBeforeUpdatesActions specifies the option to provide actions to execute
// before altered entities are updated in the data store.
UnitBeforeUpdatesActions = func(a ...UnitAction) Option {
return setActions(ActionTypeBeforeUpdates, a...)
}

// UnitBeforeDeletesActions specifies the option to provide actions to execute
// before removed entities are deleted in the data store.
UnitBeforeDeletesActions = func(a ...UnitAction) Option {
return setActions(ActionTypeBeforeDeletes, a...)
}

// UnitBeforeRollbackActions specifies the option to provide actions to execute
// before a rollback is performed.
UnitBeforeRollbackActions = func(a ...UnitAction) Option {
return setActions(ActionTypeBeforeRollback, a...)
}

// UnitBeforeSaveActions specifies the option to provide actions to execute
// before a save is performed.
UnitBeforeSaveActions = func(a ...UnitAction) Option {
return setActions(ActionTypeBeforeSave, a...)
}
)

0 comments on commit 026998a

Please sign in to comment.