From 9e144eb702f29bc9b30f4b6b49997f77c6439a00 Mon Sep 17 00:00:00 2001 From: Ivan Hell Date: Thu, 27 Aug 2020 15:55:26 +0200 Subject: [PATCH] feat: export function for reading/writing model/collection versions directly --- src/abstract-migrator.spec.ts | 19 ++++++- src/index.ts | 16 ++++-- src/mongodb-collection-migrator.ts | 18 ------- ...mongodb-collection-version-storage.spec.ts | 33 ++++++++++++ src/mongodb-collection-version-storage.ts | 5 -- src/mongodb-collection-versioning-utils.ts | 50 ++++++++++++++++++ src/mongoose-model-migrator.ts | 18 ------- src/mongoose-model-versioning-utils.ts | 51 +++++++++++++++++++ 8 files changed, 164 insertions(+), 46 deletions(-) create mode 100644 src/mongodb-collection-version-storage.spec.ts create mode 100644 src/mongodb-collection-versioning-utils.ts create mode 100644 src/mongoose-model-versioning-utils.ts diff --git a/src/abstract-migrator.spec.ts b/src/abstract-migrator.spec.ts index 8c12fe0..8168192 100644 --- a/src/abstract-migrator.spec.ts +++ b/src/abstract-migrator.spec.ts @@ -34,7 +34,7 @@ class TestVersionStorage implements VersionStorage { } describe('AbstractMigrator', () => { - test('Migrator should not update is existing version matches target version', async () => { + test('Migrator should not update if existing version matches target version', async () => { const initialVersion = { current: 1, updated: new Date() }; const versionStorage = new TestVersionStorage(initialVersion); const migrator = new TestMigrator(versionStorage); @@ -50,4 +50,21 @@ describe('AbstractMigrator', () => { expect(writeVersionSpy).toHaveBeenCalledTimes(0); expect(readVersionSpy).toHaveBeenCalledTimes(1); }); + + test('Migrator should update if current version is lower than target version', async () => { + const initialVersion = { current: 1, updated: new Date() }; + const versionStorage = new TestVersionStorage(initialVersion); + const migrator = new TestMigrator(versionStorage); + const upgradeSpy = jest.spyOn(migrator, 'upgrade'); + const downgradeSpy = jest.spyOn(migrator, 'downgrade'); + const writeVersionSpy = jest.spyOn(versionStorage, 'writeVersion'); + const readVersionSpy = jest.spyOn(versionStorage, 'readVersion'); + + const result = await migrator.migrate(2); + expect(result).toMatchObject({ last: 1, current: 2, updated: expect.any(Date) }); + expect(upgradeSpy).toHaveBeenCalledTimes(1); + expect(downgradeSpy).toHaveBeenCalledTimes(0); + expect(writeVersionSpy).toHaveBeenCalledTimes(1); + expect(readVersionSpy).toHaveBeenCalledTimes(1); + }); }); diff --git a/src/index.ts b/src/index.ts index 297434e..3ea7412 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,15 @@ export { AbstractMigrator, VersionInformation, VersionStorage } from './abstract-migrator'; +export { CollectionMigrationHandler } from './mongodb-collection-migrator'; +export { ModelMigrationHandler } from './mongoose-model-migrator'; export { - CollectionMigrationHandler, CollectionMigratorOptions, - migrateCollection -} from './mongodb-collection-migrator'; -export { ModelMigrationHandler, ModelMigratorOptions, migrateModel } from './mongoose-model-migrator'; + migrateCollection, + readCollectionVersion, + writeCollectionVersion +} from './mongodb-collection-versioning-utils'; +export { + ModelMigratorOptions, + migrateModel, + readModelVersion, + writeModelVersion +} from './mongoose-model-versioning-utils'; diff --git a/src/mongodb-collection-migrator.ts b/src/mongodb-collection-migrator.ts index 6df8d32..59c3718 100644 --- a/src/mongodb-collection-migrator.ts +++ b/src/mongodb-collection-migrator.ts @@ -2,7 +2,6 @@ import { Collection, Db } from 'mongodb'; import { AbstractMigrator } from './abstract-migrator'; import { MongodbCollectionVersionStorage } from './mongodb-collection-version-storage'; -import { getGlobalMongooseConnectionDb } from './utils'; // TODO: remove // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -31,20 +30,3 @@ export class CollectionMigrator extends AbstractMigrato throw new Error(`Downgrading a collection from version ${fromVersion} to ${toVersion} not supported yet!`); } } - -export interface CollectionMigratorOptions { - db?: Db; - versionCollectionName?: string; -} - -export async function migrateCollection( - collectionName: string, - version: number, - migrationHandler: CollectionMigrationHandler, - options?: CollectionMigratorOptions -): Promise { - const versionCollectionName = options?.versionCollectionName || `${collectionName}.version`; - const db = options?.db ?? (await getGlobalMongooseConnectionDb()); - const migrator = new CollectionMigrator(db, collectionName, versionCollectionName, migrationHandler); - await migrator.migrate(version); -} diff --git a/src/mongodb-collection-version-storage.spec.ts b/src/mongodb-collection-version-storage.spec.ts new file mode 100644 index 0000000..bf33418 --- /dev/null +++ b/src/mongodb-collection-version-storage.spec.ts @@ -0,0 +1,33 @@ +import { MongodbCollectionVersionStorage } from './mongodb-collection-version-storage'; +import { VersionInformation } from './abstract-migrator'; + +class VersionCollectionMock { + private versionInformation: VersionInformation | null; + + constructor(versionInformation?: VersionInformation) { + this.versionInformation = versionInformation ?? null; + } + + public async findOne(_filter: unknown): Promise { + return this.versionInformation; + } + public async insertOne(versionInformation: VersionInformation): Promise { + this.versionInformation = versionInformation; + } + public async findOneAndUpdate(filter: unknown, updateOptions: { $set: VersionInformation }): Promise { + this.versionInformation = { ...this.versionInformation, ...updateOptions.$set }; + } +} + +describe('MongodbCollectionVersionStorage', () => { + test('read version should return the current version information', async () => { + const currentVersion = { current: 1, updated: new Date() }; + const collectionMock = new VersionCollectionMock(currentVersion); + const versionStorage = new MongodbCollectionVersionStorage(collectionMock as any); + const findOneSpy = jest.spyOn(collectionMock, 'findOne'); + + const resultVersion = await versionStorage.readVersion(); + expect(resultVersion).toEqual(currentVersion); + expect(findOneSpy).toHaveBeenCalledWith({}); + }); +}); diff --git a/src/mongodb-collection-version-storage.ts b/src/mongodb-collection-version-storage.ts index 5ed05a0..757329d 100644 --- a/src/mongodb-collection-version-storage.ts +++ b/src/mongodb-collection-version-storage.ts @@ -27,8 +27,3 @@ export class MongodbCollectionVersionStorage implements VersionStorage { return this.versionCollection.findOne({}); } } - -/*protected getVersionCollection(): Collection { - const collectionName = this.options?.versionCollectionName || `${this.collectionName}.version`; - return connection.db.collection(collectionName); -}*/ diff --git a/src/mongodb-collection-versioning-utils.ts b/src/mongodb-collection-versioning-utils.ts new file mode 100644 index 0000000..c1130f4 --- /dev/null +++ b/src/mongodb-collection-versioning-utils.ts @@ -0,0 +1,50 @@ +import { Db } from 'mongodb'; + +import { VersionInformation } from './abstract-migrator'; +import { CollectionMigrationHandler, CollectionMigrator } from './mongodb-collection-migrator'; +import { MongodbCollectionVersionStorage } from './mongodb-collection-version-storage'; +import { getGlobalMongooseConnectionDb } from './utils'; + +export interface CollectionMigratorOptions { + db?: Db; + versionCollectionName?: string; +} + +async function sanitizeCollectionMigratorOptions( + collectionName: string, + options?: CollectionMigratorOptions +): Promise> { + const versionCollectionName = options?.versionCollectionName || `${collectionName}.version`; + const db = options?.db ?? (await getGlobalMongooseConnectionDb()); + return { db, versionCollectionName }; +} + +export async function migrateCollection( + collectionName: string, + version: number, + migrationHandler: CollectionMigrationHandler, + options?: CollectionMigratorOptions +): Promise { + const { db, versionCollectionName } = await sanitizeCollectionMigratorOptions(collectionName, options); + const migrator = new CollectionMigrator(db, collectionName, versionCollectionName, migrationHandler); + await migrator.migrate(version); +} + +export async function writeCollectionVersion( + collectionName: string, + version: number, + options?: CollectionMigratorOptions +): Promise { + const { db, versionCollectionName } = await sanitizeCollectionMigratorOptions(collectionName, options); + const versionStorage = new MongodbCollectionVersionStorage(db.collection(versionCollectionName)); + return versionStorage.writeVersion(version); +} + +export async function readCollectionVersion( + collectionName: string, + options?: CollectionMigratorOptions +): Promise { + const { db, versionCollectionName } = await sanitizeCollectionMigratorOptions(collectionName, options); + const versionStorage = new MongodbCollectionVersionStorage(db.collection(versionCollectionName)); + return versionStorage.readVersion(); +} diff --git a/src/mongoose-model-migrator.ts b/src/mongoose-model-migrator.ts index 7c99bae..b713e1e 100644 --- a/src/mongoose-model-migrator.ts +++ b/src/mongoose-model-migrator.ts @@ -3,7 +3,6 @@ import { Db } from 'mongodb'; import { AbstractMigrator } from './abstract-migrator'; import { MongodbCollectionVersionStorage } from './mongodb-collection-version-storage'; -import { getGlobalMongooseConnectionDb } from './utils'; export interface ModelMigrationHandler { up(db: Db, model: Model, fromVersion: number, toVersion: number): Promise; @@ -28,20 +27,3 @@ export class ModelMigrator extends AbstractMigr throw new Error(`Downgrading a model version from ${fromVersion} to ${toVersion} not supported yet!`); } } - -export interface ModelMigratorOptions { - db?: Db; - versionCollectionName?: string; -} - -export async function migrateModel( - model: Model, - version: number, - migrationHandler: ModelMigrationHandler, - options?: ModelMigratorOptions -): Promise { - const versionCollectionName = options?.versionCollectionName || `${model.collection.collectionName}.version`; - const db = options?.db ?? (await getGlobalMongooseConnectionDb()); - const migrator = new ModelMigrator(db, model, versionCollectionName, migrationHandler); - await migrator.migrate(version); -} diff --git a/src/mongoose-model-versioning-utils.ts b/src/mongoose-model-versioning-utils.ts new file mode 100644 index 0000000..aa5264f --- /dev/null +++ b/src/mongoose-model-versioning-utils.ts @@ -0,0 +1,51 @@ +import { Document, Model } from 'mongoose'; +import { Db } from 'mongodb'; + +import { ModelMigrationHandler, ModelMigrator } from './mongoose-model-migrator'; +import { getGlobalMongooseConnectionDb } from './utils'; +import { VersionInformation } from './abstract-migrator'; +import { MongodbCollectionVersionStorage } from './mongodb-collection-version-storage'; + +export interface ModelMigratorOptions { + db?: Db; + versionCollectionName?: string; +} + +async function sanitizeModelMigratorOptions( + model: Model, + options?: ModelMigratorOptions +): Promise> { + const versionCollectionName = options?.versionCollectionName || `${model.collection.collectionName}.version`; + const db = options?.db ?? (await getGlobalMongooseConnectionDb()); + return { db, versionCollectionName }; +} + +export async function migrateModel( + model: Model, + version: number, + migrationHandler: ModelMigrationHandler, + options?: ModelMigratorOptions +): Promise { + const { db, versionCollectionName } = await sanitizeModelMigratorOptions(model, options); + const migrator = new ModelMigrator(db, model, versionCollectionName, migrationHandler); + await migrator.migrate(version); +} + +export async function writeModelVersion( + model: Model, + version: number, + options?: ModelMigratorOptions +): Promise { + const { db, versionCollectionName } = await sanitizeModelMigratorOptions(model, options); + const versionStorage = new MongodbCollectionVersionStorage(db.collection(versionCollectionName)); + return versionStorage.writeVersion(version); +} + +export async function readModelVersion( + model: Model, + options?: ModelMigratorOptions +): Promise { + const { db, versionCollectionName } = await sanitizeModelMigratorOptions(model, options); + const versionStorage = new MongodbCollectionVersionStorage(db.collection(versionCollectionName)); + return versionStorage.readVersion(); +}