State machine in DB model

A state machine is an abstract machine that can be in one of a finite number of states. The machine is in only one state at a time; the state it is in at any given time is called the current state.

While using the database, individual records should be in allowed states. The database or application stores rules for the states. There are many ways to design the database schema to achieve this. The most followed methods are using int or string field, where each value represents a state. Above is the direct method approach. An indirect and unaware method is the use of multiple boolean values to calculate the state. Like is_archived and is_published. The combination of two fields shows four different states.

At work, the similar situation arose. First, it started with single boolean value and after some time, the second column showed up. Then, of course, the third one. That’s when I realized; use state machine. I spent time looking up a relevant library and meet transition. The library supports transitions, state change validation.

Consider a simple model Order with five states. 'placed', 'dispatched', 'delivered', 'canceled', 'returned'. Well, real world model will have way more states. The important point of these states, object transition should follow rules. An order can be in returned state when the previous state was delivered. And this requires custom validation code with multiple if conditions. Here is state machine diagram.

When the number of states increases, the code starts to fall apart with conditions and repetition.

Transition library supports the declaration of states, allowed triggers and takes care of validation. It provides a set of helper methods to do transitions. Here is a simple example.

Machine class takes a list of transitions. Transitions is a collection of iterable with trigger, start state and destination state as arguments respectively.

To trigger an event, invoke machine.model.<trigger>(). Method returns True or False. True when the trigger succeeds and False when the trigger isn’t allowed in the current state. The machine calculates the logic from the list of configured transitions.

Delivery isn’t possible with the canceled order!

ignore_invalid_triggers=True makes the method to return True or False. The library raise MachineError Exception when ignore_invalid_triggers is set to False.

Declarative style of creating state machine makes the library easy to use and prevents a lot of boilerplate code.