Skip to content

Automatic Schema Versioning

Oxford Harrison edited this page Nov 9, 2024 · 17 revisions

⚡️ Create, alter, and drop schemas without needing to worry about versioning.

Linked QL comes with the concept of versioning to your database, and along with it, a powerful rollback and rollforward system! Meet Automatic Schema Savepoints and Rollbacks!

Here, you alter your schema and get back a reference to a "savepoint" automatically created for you:

// Alter schema
const savepoint = await client.query(
    `CREATE TABLE public.users (
        id int,
        name varchar
    )`,
    { desc: 'Create users table' }
);

And you are able obtain same savepoint on-demand:

const savepoint = await client.database('public').savepoint();

Inspect savepoint:

// Some details
console.log(savepoint.versionTag()); // 1
console.log(savepoint.commitDesc()); // Create users table
console.log(savepoint.commitDate()); // 2024-07-17T22:40:56.786Z
// Everything...
console.log(savepoint.jsonfy());
Console
{
  // Internal parameters...
  master_savepoint: null,
  id: '952cc6ae-5b5b-4534-8b03-dc38ee8658ac',
  database_tag: 'db.1730978107426',
  // Schema snapshot...
  name: 'public',
  '$name': null,
  tables: [
    {
      name: 'users',
      columns: [Array],
      constraints: [],
      indexes: [],
      status: 'new'
    }
  ],
  status: null,
  // Version details...
  version_tag: 1,
  version_tags: [ 1 ],
  version_state: 'commit',
  commit_date: '2024-07-17T22:40:56.786Z',
  commit_desc: 'Create users table',
  commit_ref: null,
  commit_pid: '72776',
  rollback_date: null,
  rollback_desc: null,
  rollback_ref: null,
  rollback_pid: null,
  // Cascades...
  cascades: []
}

Roll back savepoint:

// SQL preview
console.log(savepoint.restorePreview());
// "DROP TABLE public.users CASCADE"
// Execute now (drops "users" table)
await savepoint.rollback({
    desc: 'Users table unnecessary'
});

Roll forward savepoint:

// SQL preview
console.log(savepoint.restorePreview());
// "CREATE TABLE public.users (...)"
// Execute now (recreates "users" table)
await savepoint.recommit({
    desc: 'Users table necessary again'
});

Roll all the way back (or forward) to a point in time:

// Rollback to a point
let savepoint;
while((savepoint = await client.database('public').savepoint()) && savepoint.versionTag() > 3) {
    await savepoint.rollback({
        desc: 'These changes are no more necessary'
    });
}
// Rollforward to a point
let savepoint;
while((savepoint = await client.database('public').savepoint({ lookAhead: true })) && savepoint.versionTag() <= 5) {
    await savepoint.recommit({
        desc: 'These changes are necessary again'
    });
}

You essentially get time travel in any direction - and as seamlessly as you move on a movie track!

✨ Meanwhile, your schema histories now live as data (instead of as files), making them queryable, analyzable, and even visualizable, just as regular data! Plus, the DB now essentially becomes the absolute source of truth for both itself and its client applications!

See Linked QL Migrations to see how versioning comes in during migrations.

Clone this wiki locally