Migrations — JazzRecord JavaScript ORM Documentation

Once all of your applications's have been declared, simply make a call to JazzRecord.migrate().

JazzRecord.migrate() can be called one of two ways: automigration or manual migration.

Automigration causes tables to be created with schema matching the column names and types defined in the model. When performing automigration, the inclusion of an id column in the columns option of the model is optional. Automigration is great for an application in development, because the developer can avoid having to write tedious migrations and concentrate on application code itself. At a later time, the developer can add migrations which port data from the auto-migrated state, which allows applications to actually ship auto-migrated and simply perform updates using real migrations.

Manual migration is an entirely different beast. Manual migration uses an ordered set of schema operations (detailed below) to invoke changes to the schema as well as to modify data in the database.

In either case, fixture data may also be provided. Fixtures are used for two purposes: Test data when in development, and preexisting, necessary data when in production. Examples of production fixtures would be a pre-selected list of URLs for a feed reader or a list of message strings you don't want hard-coded in the application code.


Automigrations

Automigration occurs on any call to JazzRecord.migrate() when JazzRecord.migrations is unassigned.

JazzRecord.migrate() can be called with no parameters, in which case it will simply create all non-extant tables.

To drop table data and start from scratch, passing in an options object with refresh: true is required. This is required if automigrating and your model's column definitions have changed.

Any fixture data will be loaded upon recreating the tables when calling JazzRecord.migrate({refresh: true}).


Fixtures

Fixture data is described with an object literal assigned to JazzRecord.fixtures. This object can consist of two sub-objects called tables and mappingTables respectively. Each of these sub-objects contains a set of arrays named exactly as their respective table names, consisting of a number of object literals representing rows in the respective table.

Row data will be inserted in the order it is coded, and so may contain an ID value or not. If an ID is included, be sure to setup associated record data accordingly. If not included, the ID will be the autoincrement value automatically assigned by SQLite.

An example would illustrate this better:

JazzRecord.fixtures = {
  tables: {
    people: [
      {name: "Nick", age: 28, gender: "m", home_id: 1, has_vehicle: true},
      {name: "Terri", age: 32, gender: "f", home_id: 1, has_vehicle: true},
      {name: "David", age: 23, gender: "m"},
      {name: "Karen", age: 30, gender: "f"},
      {name: "Jesse", age: 24, gender: "m", has_vehicle: true}
    ],
    homes: [
      {address: "4605 Deming Ave"},
      {address: "15009 Ulderic Dr"},
      {address: "65 Branch Way"}
    ],
    vehicles: [
      {make: "Suzuki", model: "Forenza", year: 2004, person_id: 1},
      {make: "Nissan", model: "Altima", year: 2005, person_id: 2}
    ],
    high_school_classes: [
      {name: "English"},
      {name: "Phys. Ed."}
    ],
    students: [
      {name: "Joe Bob", home_id: 1},
      {name: "Peggy Sue"}
    ],
    animals: [
    {name: "Tigra", species: "tiger", say: "rawr!"},
    {name: "Shere Khan", species: "tiger", say: "rawr!"},
    {name: "Tweety", species: "bird", say: "bawk!!"},
    {name: "Punkin", species: "cat", say: "meow!!"},
    {name: "Akai", species: "dog", say: "woof!"}
    ]
  },

  mappingTables: {
    high_school_classes_students: [
      {high_school_class_id: 1, student_id: 1},
      {high_school_class_id: 1, student_id: 2},
      {high_school_class_id: 2, student_id: 1}
    ]
  }
};

Fixtures can also be loaded manually by a call to JazzRecord.loadFixtures() after having been assigned to JazzRecord.fixtures. Note, however, that this will perform insertions again, so calling it multiple times will lead to duplicate data in the database.


Manual Migrations

Manual migrations are described as an object literal (assigned to JazzRecord.migrations) with a series of numerically-named objects, each with an up() method and a down() method, each of which contains one or more calls to various schema operations. These operations include JazzRecord.createTable(), JazzRecord.addColumn() and more, as described in the following section.

A migration is defined as a numbered function containing calls to schema operations. Each migration should contain an up() method and a down() method. These methods are used to shift the schema up or down from version to version.

Calling JazzRecord.migrate() with no parameters will migrate up to the latest (highest-numbered) migration, and if the schema is already current, no migrations will be performed.

Calling JazzRecord.migrate(X), where X is a number -Infinity to Infinity, causes JazzRecord to run up or down migrations to the specified number (or min/max valid number) migration. This allows you to quickly and easily roll back after realizing changes to the schema are not what was intended, or if they have introduced errors into the application.

Here's a working example of manual migrations:

JazzRecord.migrations = {
  1: {
    up: function() {
      JazzRecord.createTable("people", {
        id: "number",
        name: "text",
        age: "number",
        gender: "text",
        home_id: "number",
        income: "float",
        has_vehicle: "bool"
      });

      JazzRecord.createTable("homes", {
        id: "number",
        style: "text",
        footage: "number",
        address: "text",
        vacant: "bool"
      });

      JazzRecord.createTable("vehicles", {
        id: "number",
        make: "text",
        model: "text",
        year: "number",
        person_id: "number"
      });

      JazzRecord.createTable("high_school_classes", {
        id: "number",
        name: "text",
        room: "number"
      });

      JazzRecord.createTable("students", {
        id: "number",
        name: "text",
        grade: "text",
        home_id: "number"
      });

      JazzRecord.createTable("animals", {
        id: "number",
        name: "text",
        species: "text",
        say: "text"
      });

      JazzRecord.createTable("high_school_classes_students", {
        student_id: "number",
        high_school_class_id: "number"
      });
    },
    down: function() {
      JazzRecord.dropTable("high_school_classes_students");
      JazzRecord.dropTable("animals");
      JazzRecord.dropTable("students");
      JazzRecord.dropTable("high_school_classes");
      JazzRecord.dropTable("vehicles");
      JazzRecord.dropTable("homes");
      JazzRecord.dropTable("people");
    }
  },
  2: {
    up: function() {
      JazzRecord.removeColumn("people", "income");
    },
    down: function() {
      JazzRecord.addColumn("people", "income", "float");
    }
  }
};

Calling JazzRecord.migrate() the first time will advance the schema to version 2. Calling JazzRecord.migrate(0) will roll it back to the beginning, dropping all tables and losing all data. Calling JazzRecord.migrate(1) will bring the schema to version 1, wherein the income column still exists (though income data will not), and calling JazzRecord.migrate(2) will advance it to having removed the income column once more.

At any time, the current schema version can be determined by a call to JazzRecord.currentSchemaVersion(), which will return the version number.


Schema Operations

The following schema operations are defined for use in JazzRecord:

  • JazzRecord.createTable(name, columns): Creates a table of name name with columns defined in an object literal columns. These are of the same format as described in the Model documentation
  • JazzRecord.dropTable(name): Drops table of name name from the database, along with all the data contained therein.
  • JazzRecord.renameTable(oldName, newName): Renames a table of oldName to newName. Useful for rearranging/repurposing concepts in your application.
  • JazzRecord.addColumn(tableName, columnName, dataType): Adds a column of columnName to table tableName of type dataType.
  • JazzRecord.removeColumn(tableName, columnName): Removes column columnName from table tableName.
  • JazzRecord.renameColumn(tableName, columnName, newColumnName): Renames column columnName in table tableName to newColumnName.
  • JazzRecord.changeColumn(tableName, columnName, type): Changes the type of column columnName in table tableName to type type. This affects both the schema and the model's in-memory definition, and therefor may affect escapement of data during save operations.