Q server

Migrations

At some point you may need to implement breaking changes in your tool specific schema. Breaking means that older Q items may not validate anymore against the new schema. Hence, you’ll need to migrate your old Q items in your database. Q server contains an endpoint for that purpose. To be able to use this endpoint you have to

Q server migration endpoint

Database view

The migration endpoint in Q server expects a specific view called byTool which you have to add to your Q item database(s):

{
  "_id": "_design/items",
  "views": {
    "byTool": {
      "map": "function (doc) {\n  if (doc.tool) {\n    emit(doc.tool, 1);\n  }\n}",
      "reduce": "_count"
    }
  }
}

Q server uses this view without the reduce option. See also Installation to get an overview of all views you should define on your Q item database(s).

Migration mechanism in tools

Endpoint

You have to define the following endpoint if you want to be able to migrate items via Q server:

Migration scripts

We create one migration module for each major, i.e. breaking, version of the tool and name it after the version we want to release, e.g. to-v2.0.0.js. Each module exports one migrate function. Of course it can contain several methods with different migration conditions.

In the following example you see one migration module with just one method. Since we made the party name required in the schema of Q election votes tool in version v2.0.0, an item will only be migrated if it has a party without having a name. The return value is a result object containing the item (modified or not) and a isChanged flag which is used by the handler method of the migration endpoint to reply with the appropriate response.

// contains all scripts which shall be executed to migrate to tool version 2.0.0
// each module has to return a result object holding the modified item and a
// flag property indicating if item was changed or not
module.exports.migrate = function (item) {
  let result = {
    isChanged: false,
  };
  if (item.parties) {
    let truthyparties = item.parties.filter((party) => {
      return party.name !== undefined && party.name !== "";
    });
    if (truthyparties.length < item.parties.length) {
      item.parties = truthyparties;
      result.isChanged = true;
    }
  }
  result.item = item;
  return result;
};

Tests

We recommend to include a migration mechanism in your tests, too, that will check whether items are migrated correctly and whether the validation against the new schema results in no errors after migration. For that purpose