/**
* migrations/state.js - migration state for hsd.
* Copyright (c) 2021, Nodari Chkuaselidze (MIT License)
*/
'use strict';
const assert = require('bsert');
const bio = require('bufio');
const {encoding} = bio;
/** @typedef {import('../types').BufioWriter} BufioWriter */
const EMPTY = Buffer.alloc(0);
/**
* State of database migrations.
* Because migration IDs are only increasing, we only need
* to store the last one.
* @alias module.migrations.MigrationState
* @property {Boolean} inProgress - is/was migration in progress
* NOTE: If inProgress is true, we know lastMigration + 1 was the one in
* progress.
* @property {Number} lastMigration - last migration
* NOTE: Migration numbers start from 1.
* 0 - means there is no migration.
*/
class MigrationState extends bio.Struct {
/**
* Create MigrationState
* @constructor
*/
constructor() {
super();
this.version = 1;
this.inProgress = false;
this.nextMigration = 0;
/** @type {Number[]} */
this.skipped = [];
this.inProgressData = EMPTY;
}
get lastMigration() {
return this.nextMigration - 1;
}
/**
* Inject properties from another state.
* @param {MigrationState} obj
* @returns MigrationState;
*/
inject(obj) {
assert(obj instanceof MigrationState);
this.inProgress = obj.inProgress;
this.nextMigration = obj.nextMigration;
this.skipped = obj.skipped.slice();
this.inProgressData = obj.inProgressData.slice();
return this;
}
/**
* Get size of the encoded migration state object.
* @returns {Number}
*/
getSize() {
let size = 2; // flags
size += 2; // version
size += encoding.sizeVarint(this.nextMigration);
size += encoding.sizeVarint(this.skipped.length);
for (const id of this.skipped)
size += encoding.sizeVarint(id);
if (this.version > 0)
size += encoding.sizeVarBytes(this.inProgressData);
return size;
}
/**
* Serialize migration state.
* @param {BufioWriter} bw
* @returns {BufioWriter}
*/
write(bw) {
let flags = 0;
if (this.inProgress)
flags |= 1 << 0;
bw.writeU16(flags);
bw.writeU16(this.version);
bw.writeVarint(this.nextMigration);
bw.writeVarint(this.skipped.length);
for (const id of this.skipped)
bw.writeVarint(id);
if (this.version > 0)
bw.writeVarBytes(this.inProgressData);
return bw;
}
/**
* Deserialize migration state.
* @param {bio.BufferReader} br
* @returns {this}
*/
read(br) {
const flags = br.readU16();
this.inProgress = (flags & 1) !== 0;
this.version = br.readU16();
this.nextMigration = br.readVarint();
this.skipped = [];
const skippedItems = br.readVarint();
for (let i = 0; i < skippedItems; i++)
this.skipped.push(br.readVarint());
if (this.version > 0)
this.inProgressData = br.readVarBytes();
return this;
}
}
module.exports = MigrationState;