Migrations let developers easily write database upgrade (and downgrade) scripts, in the same context where they work (module that they are developing). This feature is introduced late in Angie history to address several issues that existing upgrade process had:

1. There was no way for a developer to update his development database mid-development. Instead, they had to either wait for release to get close to completion, suffer from random crashes due conflicts when running new code on the old database, or manually execute the steps necessary to upgrade their database schema,
2. If upgrade failed at one of the middle steps, there was no way to resume from the failed script. Instead, entire process had to be rolled back, and user had to start over,
3. There was no support for per-module upgrade scripts. Instead, there was one massive script that checked if modules were installed before performing steps. This proved to be error prone and caused problems and hot-fix releases in several occasions,
4. Third party modules had to invent their own way to perform upgrades,
5. There was no way to write downgrade scripts.

Migrations address these problems by providing:

1. Decentralised upgrade system. Developers can write upgrade steps as they go, and other developers can later run these scripts to upgrade their system without waiting for an official release with upgrade script to be shipped,
2. Successful upgrade steps are recorded and there is no need to repeat them in cases when one of the later steps fails,
3. Scripts work with data copies, so reverting from backup is rarely needed.

### Groups and Scripts

There are three levels of script organisation:

1. **Per Module <{path}>/migrations<{/path}> folder** contains all module related migration groups,
2. **Migration Group**. Due to the nature of environments where Angie applications run and frequent lack of CLI tools to perform upgrades, we introduced migration groups as a way to group multiple scripts that execute distinct steps of a bigger database transformation. Reason why we separate them is so we can trigger them via web browser without hitting PHP resource limits. Each group has a timestamp (in <{code}>YYYY-MM-DD<{/code}> format) and a name,
3. **Migration Script**. A single script is a PHP class that extends <{code}>AngieModelMigration<{/code}> and implements <{code}>up()<{/code}> method. Even if a particular migration script works alone and is not a part of a bigger operation, it needs to be put in a properly timestamped group.

### Writing Your First Migration Script

First, start by adding <{path}>/migrations<{/path}> folder in your module. Than, create a group. Groups are properly named folder under <{path}>/migrations<{/path}>. Name format is <{code}>YYYY-MM-DD-migration-name<{/code}>, ex: <{path}>2013-11-11-migrate-attachments<{/path}>. 

Once we have the group ready, we can define a migration class. There are several rules that this class needs to meet in order for system to recognise, load and execute it:

1. It's name needs to start with <{code}>Migrate<{/code}>,
2. File that defines it needs to be in a migration group, and has to have <{path}>.class.php<{/path}> extension,
3. It needs to extend <{code}>AngieModelMigration<{/code}> and implements <{code}>up()<{/code}> method.

To create our first script, lets create <{path}>MigrateAttachments.class.php<{/path}> under our migration group folder. Folder structure looks like this:

<{code}>/my_module
- /migrations
-- /2013-11-11-migrate-attachments
--- /MigrateAttachments.class.php<{/code}>

and our class looks like this:

<{code highlight=php}><?php

class MigrateAttachments extends AngieModelMigration {

  function up() {

    // Lets tell migration that we want to use attachments table for alteration
    $attachments = $this->useTableForAlter('attachments');

    // Transform the table (changes are auto-commuted)
    $attachments->getColumn('type')->setDefault('File');
    $attachments->addColumn(DBEnumColumn::create('kind', array('image', 'video', 'audio', 'document', 'archive', 'other')), 'mime_type');
    $attachments->addColumn(DBActionOnByColumn::create('updated', true, true), 'created_by_email');
    $attachments->addIndex(DBIndex::create('file_context'));
    $attachments->addIndex(DBIndex::create('kind'));

    // Let the migration know that we are done with data transformation
    $this->doneUsingTables('attachments');

  }

}<{/code}>

In the following couple of sections, we'll discuss what exactly we did with this simple script.

### Use Tables to Work With Data Copies

First line of our upgrade script tells the system that we want to transform <{code}>attachments<{/code}> table. In early days, we would work with the table directly and transformed the data on the go. If script crashed mid execution, there was great likelihood what we corrupted the data and user had to revert it from the backup.

New system allows you to **working with a table copy** instead of the main table to avoid that problem. To get a copy, simply tell the system that you want to work with one or more tables:

1. <{code}>useTable()<{/code}> - use a single table. This function returns name of the table copy as a string,
2. <{code}>useTableForAlter()<{/code}> - use a single table. Instead of return name of the copy table, system will load and return DBTable instance that you can use to transform the columns and indexes,
3. <{code}>useTables()<{/code}> - provide a list of tables that you want to use, and system will return a list of names of the tables copies.

Example for <{code}>useTables()<{/code}>:

<{code highlight=php inline=false}>list($attachments, $comments, $reminders) = $this->useTables('attachments', 'comments', 'reminders');<{/code}>

When you have done working with the data, you can simply call <{code}>doneUsingTables()<{/code}> method to "commit" changes.

<{code highlight=php inline=false}>list($attachments, $comments, $reminders) = $this->doneUsingTables('attachments', 'comments', 'reminders');<{/code}>

Note that this operation does not execute a typical <{code}>COMMIT<{/code}> database command, but actually:

1. Renames original copies using a temporal name,
2. Renames transformed copies to original name (this basically replaces the old tables),
3. Drops old, untransformed copies of original tables.

### Transforming Tables

Table transformations are done using Angie's built in <{code}>DBEngineer<{/code}> utility. You can get <{code}>DBTable<{/code}> instances by calling one of the following two methods:

1. <{code}>loadTable()<{/code}> - Return <{code}>DBTable<{/code}> instance, 
2. <{code}>useTableForAlter()<{/code}> - Create a copy of the original table, and return <{code}>DBTable<{/code}> instance.

### Running SQL in Migrations

Migrations offer full list of commands, but you should use them directly via migration instance instead of calling static <{code}>DB<{/code}> class methods:

<{code highlight=php}>// Run SQL like this
$this->execute('SELECT * FROM ' . $this->getTableName('modules'));

// NOT like this
DB::execute('SELECT * FROM ' . TABLE_PREFIX . 'modules'); // NOT GOOD!<{/code}>

### Setting Dependencies between Upgrade Scripts

In large groups developer usually wants upgrade scripts to be executed in a given order. This is a requirement when one script depends on successful execution of a particular script from the group.

To define this dependency, call <{code}>executeAfter()<{/code}> method in script's constructor:

<{code highlight=php}>class MigrateAttachments extends AngieModelMigration {

  /**
   * Construct and make sure that it is executed after we have file storage prepared
   */
  function __construct() {
    $this->executeAfter('MigratePrepareFileStorage');
  } // __construct

}<{/code}>

### Command Line Tools

Development environment offers several commands that help your every day work with migrations:

* <{code}>angie migrations<{/code}> - List all defined migrations and show their status
* <{code}>angie migrate_up<{/code}> - Upgrade all migrations up
* <{code}>angie migrate_down<{/code}> - Upgrade all way down, or to a particular timestamp

For details and parameters, simply type <{code}>--help<{/code}> after the command:

<{code inline=false}>angie migrate --help<{/code}>