UNPKG

ordinality

Version:
72 lines (70 loc) 11.1 kB
import { existsSync } from 'fs'; import path from 'path'; import { z } from 'zod'; import { mkdir, readFile, writeFile } from 'fs/promises'; // TODO: lock file and wait unlock to ensure consistent state when multiple instances in run export class MigrationFileStorage { filename; options; constructor(filename, options = {}) { this.filename = filename; this.options = options; } getCodec() { return (this.options.codec ?? { encode(data) { return Buffer.from(JSON.stringify(data, undefined, 2)); }, decode(buffer) { return JSON.parse(buffer.toString('utf-8')); }, }); } getMigrationScheme() { return z.object({ name: z.string(), meta: this.options.metaScheme ?? z.void().nullish().optional(), }); } getStorageScheme() { return z.object({ migrations: this.getMigrationScheme().array(), }); } async fetchState() { if (!existsSync(this.filename)) return { migrations: [] }; const fileBuffer = await readFile(this.filename); const jsonState = this.getCodec().decode(fileBuffer); return this.getStorageScheme().parse(jsonState); } async list() { const state = await this.fetchState(); return state.migrations.map((migration) => migration.name); } async log(uid, context) { const newState = await this.fetchState(); // Ensure unique name for (const migration of newState.migrations) { if (migration.name === uid) throw new Error(`Migration with name ${uid} is already applied`); } // Add and validate newState.migrations.push({ name: uid, meta: context.meta }); await mkdir(path.dirname(this.filename), { recursive: true }); const verifiedState = this.getStorageScheme().parse(newState); await writeFile(this.filename, this.getCodec().encode(verifiedState)); } async unlog(uid) { const state = await this.fetchState(); // Update migrations list const filteredMigrations = state.migrations.filter((migration) => migration.name === uid); if (state.migrations.length === filteredMigrations.length) throw new Error(`Migration with name ${uid} is not found`); state.migrations = filteredMigrations; await mkdir(path.dirname(this.filename), { recursive: true }); const verifiedState = this.getStorageScheme().parse(state); await writeFile(this.filename, this.getCodec().encode(verifiedState)); } } //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0b3JhZ2UvTWlncmF0aW9uRmlsZVN0b3JhZ2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLElBQUksQ0FBQztBQUNoQyxPQUFPLElBQUksTUFBTSxNQUFNLENBQUM7QUFDeEIsT0FBTyxFQUFFLENBQUMsRUFBRSxNQUFNLEtBQUssQ0FBQztBQUd4QixPQUFPLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFlekQsNEZBQTRGO0FBQzVGLE1BQU0sT0FBTyxvQkFBb0I7SUFJZDtJQUNBO0lBRmxCLFlBQ2tCLFFBQWdCLEVBQ2hCLFVBWWIsRUFBRTtRQWJXLGFBQVEsR0FBUixRQUFRLENBQVE7UUFDaEIsWUFBTyxHQUFQLE9BQU8sQ0FZbEI7SUFDSixDQUFDO0lBRU0sUUFBUTtRQUNqQixPQUFPLENBQ04sSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLElBQUk7WUFDckIsTUFBTSxDQUFDLElBQUk7Z0JBQ1YsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFLFNBQVMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ3hELENBQUM7WUFDRCxNQUFNLENBQUMsTUFBTTtnQkFDWixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO1lBQzdDLENBQUM7U0FDRCxDQUNELENBQUM7SUFDSCxDQUFDO0lBRVMsa0JBQWtCO1FBQzNCLE9BQU8sQ0FBQyxDQUFDLE1BQU0sQ0FBQztZQUNmLElBQUksRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFO1lBQ2hCLElBQUksRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsSUFBSSxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUMsUUFBUSxFQUFFO1NBQzlELENBQUMsQ0FBQztJQUNKLENB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Q0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztJQUN2RSxDQUFDO0NBQ0QiLCJmaWxlIjoic3RvcmFnZS9NaWdyYXRpb25GaWxlU3RvcmFnZS5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGV4aXN0c1N5bmMgfSBmcm9tICdmcyc7XG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7IHogfSBmcm9tICd6b2QnO1xuXG5pbXBvcnQgeyBNaWdyYXRpb25Db250ZXh0IH0gZnJvbSAnLi4vTWlncmF0aW9uJztcbmltcG9ydCB7IG1rZGlyLCByZWFkRmlsZSwgd3JpdGVGaWxlIH0gZnJvbSAnZnMvcHJvbWlzZXMnO1xuaW1wb3J0IHR5cGUgeyBNaWdyYXRpb25TdG9yYWdlIH0gZnJvbSAnLi9NaWdyYXRpb25TdG9yYWdlJztcblxuZXhwb3J0IHR5cGUgQ29kZWM8VD4gPSB7XG5cdGVuY29kZTogKGRhdGE6IFQpID0+IEJ1ZmZlcjtcblx0ZGVjb2RlOiAoYnVmZmVyOiBCdWZmZXIpID0+IFQ7XG59O1xuXG5leHBvcnQgdHlwZSBTdGF0ZTxNID0gdm9pZD4gPSB7XG5cdG1pZ3JhdGlvbnM6IHtcblx0XHRuYW1lOiBzdHJpbmc7XG5cdFx0bWV0YTogTTtcblx0fVtdO1xufTtcblxuLy8gVE9ETzogbG9jayBmaWxlIGFuZCB3YWl0IHVubG9jayB0byBlbnN1cmUgY29uc2lzdGVudCBzdGF0ZSB3aGVuIG11bHRpcGxlIGluc3RhbmNlcyBpbiBydW5cbmV4cG9ydCBjbGFzcyBNaWdyYXRpb25GaWxlU3RvcmFnZTxDIGV4dGVuZHMgTWlncmF0aW9uQ29udGV4dDxhbnksIGFueT4+XG5cdGltcGxlbWVudHMgTWlncmF0aW9uU3RvcmFnZTxDPlxue1xuXHRjb25zdHJ1Y3Rvcihcblx0XHRwcml2YXRlIHJlYWRvbmx5IGZpbGVuYW1lOiBzdHJpbmcsXG5cdFx0cHJpdmF0ZSByZWFkb25seSBvcHRpb25zOiB7XG5cdFx0XHQvKipcblx0XHRcdCAqIFNjaGVtZSB2YWxpZGF0b3IgZm9yIGEgbWlncmF0aW9uIG1ldGFcblx0XHRcdCAqL1xuXHRcdFx0bWV0YVNjaGVtZT86IENbJ21ldGEnXSBleHRlbmRzIHouVHlwZU9mPGluZmVyIFg+ID8gWCA6IG5ldmVyO1xuXG5cdFx0XHQvKipcblx0XHRcdCAqIEN1c3RvbSBsb2dpYyB0byBlbmNvZGUvZGVjb2RlIGRhdGFcblx0XHRcdCAqXG5cdFx0XHQgKiBCeSBkZWZhdWx0IGRhdGEgd2lsbCBiZSBlbmNvZGVkIGFzIEpTT04gc3RyaW5nXG5cdFx0XHQgKi9cblx0XHRcdGNvZGVjPzogQ29kZWM8U3RhdGU8Q1snbWV0YSddPj47XG5cdFx0fSA9IHt9LFxuXHQpIHt9XG5cblx0cHJvdGVjdGVkIGdldENvZGVjKCk6IENvZGVjPFN0YXRlPENbJ21ldGEnXT4+IHtcblx0XHRyZXR1cm4gKFxuXHRcdFx0dGhpcy5vcHRpb25zLmNvZGVjID8/IHtcblx0XHRcdFx0ZW5jb2RlKGRhdGEpIHtcblx0XHRcdFx0XHRyZXR1cm4gQnVmZmVyLmZyb20oSlNPTi5zdHJpbmdpZnkoZGF0YSwgdW5kZWZpbmVkLCAyKSk7XG5cdFx0XHRcdH0sXG5cdFx0XHRcdGRlY29kZShidWZmZXIpIHtcblx0XHRcdFx0XHRyZXR1cm4gSlNPTi5wYXJzZShidWZmZXIudG9TdHJpbmcoJ3V0Zi04JykpO1xuXHRcdFx0XHR9LFxuXHRcdFx0fVxuXHRcdCk7XG5cdH1cblxuXHRwcm90ZWN0ZWQgZ2V0TWlncmF0aW9uU2NoZW1lKCkge1xuXHRcdHJldHVybiB6Lm9iamVjdCh7XG5cdFx0XHRuYW1lOiB6LnN0cmluZygpLFxuXHRcdFx0bWV0YTogdGhpcy5vcHRpb25zLm1ldGFTY2hlbWUgPz8gei52b2lkKCkubnVsbGlzaCgpLm9wdGlvbmFsKCksXG5cdFx0fSk7XG5cdH1cblxuXHRwcm90ZWN0ZWQgZ2V0U3RvcmFnZVNjaGVtZSgpIHtcblx0XHRyZXR1cm4gei5vYmplY3Qoe1xuXHRcdFx0bWlncmF0aW9uczogdGhpcy5nZXRNaWdyYXRpb25TY2hlbWUoKS5hcnJheSgpLFxuXHRcdH0pO1xuXHR9XG5cblx0cHJvdGVjdGVkIGFzeW5jIGZldGNoU3RhdGUoKSB7XG5cdFx0aWYgKCFleGlzdHNTeW5jKHRoaXMuZmlsZW5hbWUpKSByZXR1cm4geyBtaWdyYXRpb25zOiBbXSB9O1xuXG5cdFx0Y29uc3QgZmlsZUJ1ZmZlciA9IGF3YWl0IHJlYWRGaWxlKHRoaXMuZmlsZW5hbWUpO1xuXHRcdGNvbnN0IGpzb25TdGF0ZSA9IHRoaXMuZ2V0Q29kZWMoKS5kZWNvZGUoZmlsZUJ1ZmZlcik7XG5cblx0XHRyZXR1cm4gdGhpcy5nZXRTdG9yYWdlU2NoZW1lKCkucGFyc2UoanNvblN0YXRlKSBhcyBTdGF0ZTxDWydtZXRhJ10+O1xuXHR9XG5cblx0YXN5bmMgbGlzdCgpOiBQcm9taXNlPHN0cmluZ1tdPiB7XG5cdFx0Y29uc3Qgc3RhdGUgPSBhd2FpdCB0aGlzLmZldGNoU3RhdGUoKTtcblxuXHRcdHJldHVybiBzdGF0ZS5taWdyYXRpb25zLm1hcCgobWlncmF0aW9uKSA9PiBtaWdyYXRpb24ubmFtZSk7XG5cdH1cblxuXHRhc3luYyBsb2codWlkOiBzdHJpbmcsIGNvbnRleHQ6IEMpOiBQcm9taXNlPHZvaWQ+IHtcblx0XHRjb25zdCBuZXdTdGF0ZSA9IGF3YWl0IHRoaXMuZmV0Y2hTdGF0ZSgpO1xuXG5cdFx0Ly8gRW5zdXJlIHVuaXF1ZSBuYW1lXG5cdFx0Zm9yIChjb25zdCBtaWdyYXRpb24gb2YgbmV3U3RhdGUubWlncmF0aW9ucykge1xuXHRcdFx0aWYgKG1pZ3JhdGlvbi5uYW1lID09PSB1aWQpXG5cdFx0XHRcdHRocm93IG5ldyBFcnJvcihgTWlncmF0aW9uIHdpdGggbmFtZSAke3VpZH0gaXMgYWxyZWFkeSBhcHBsaWVkYCk7XG5cdFx0fVxuXG5cdFx0Ly8gQWRkIGFuZCB2YWxpZGF0ZVxuXHRcdG5ld1N0YXRlLm1pZ3JhdGlvbnMucHVzaCh7IG5hbWU6IHVpZCwgbWV0YTogY29udGV4dC5tZXRhIH0pO1xuXG5cdFx0YXdhaXQgbWtkaXIocGF0aC5kaXJuYW1lKHRoaXMuZmlsZW5hbWUpLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcblxuXHRcdGNvbnN0IHZlcmlmaWVkU3RhdGUgPSB0aGlzLmdldFN0b3JhZ2VTY2hlbWUoKS5wYXJzZShuZXdTdGF0ZSkgYXMgU3RhdGU8Q1snbWV0YSddPjtcblx0XHRhd2FpdCB3cml0ZUZpbGUodGhpcy5maWxlbmFtZSwgdGhpcy5nZXRDb2RlYygpLmVuY29kZSh2ZXJpZmllZFN0YXRlKSk7XG5cdH1cblxuXHRhc3luYyB1bmxvZyh1aWQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuXHRcdGNvbnN0IHN0YXRlID0gYXdhaXQgdGhpcy5mZXRjaFN0YXRlKCk7XG5cblx0XHQvLyBVcGRhdGUgbWlncmF0aW9ucyBsaXN0XG5cdFx0Y29uc3QgZmlsdGVyZWRNaWdyYXRpb25zID0gc3RhdGUubWlncmF0aW9ucy5maWx0ZXIoXG5cdFx0XHQobWlncmF0aW9uKSA9PiBtaWdyYXRpb24ubmFtZSA9PT0gdWlkLFxuXHRcdCk7XG5cdFx0aWYgKHN0YXRlLm1pZ3JhdGlvbnMubGVuZ3RoID09PSBmaWx0ZXJlZE1pZ3JhdGlvbnMubGVuZ3RoKVxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKGBNaWdyYXRpb24gd2l0aCBuYW1lICR7dWlkfSBpcyBub3QgZm91bmRgKTtcblxuXHRcdHN0YXRlLm1pZ3JhdGlvbnMgPSBmaWx0ZXJlZE1pZ3JhdGlvbnM7XG5cblx0XHRhd2FpdCBta2RpcihwYXRoLmRpcm5hbWUodGhpcy5maWxlbmFtZSksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuXG5cdFx0Y29uc3QgdmVyaWZpZWRTdGF0ZSA9IHRoaXMuZ2V0U3RvcmFnZVNjaGVtZSgpLnBhcnNlKHN0YXRlKSBhcyBTdGF0ZTxDWydtZXRhJ10+O1xuXHRcdGF3YWl0IHdyaXRlRmlsZSh0aGlzLmZpbGVuYW1lLCB0aGlzLmdldENvZGVjKCkuZW5jb2RlKHZlcmlmaWVkU3RhdGUpKTtcblx0fVxufVxuIl19