Skip to content

Commit

Permalink
feat: add dropCollection migration method (#168)
Browse files Browse the repository at this point in the history
  • Loading branch information
targos authored Jan 15, 2025
1 parent 25e74f0 commit 2928b95
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 21 deletions.
12 changes: 10 additions & 2 deletions adonis-typings/migration.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
declare module '@ioc:Zakodium/Mongodb/Migration' {
import type {
Db,
ClientSession,
IndexSpecification,
CreateIndexesOptions,
Db,
DropIndexesOptions,
IndexSpecification,
} from 'mongodb';

export default abstract class Migration {
public createCollections(collectionNames: string[]): void;

/**
* Drop a collection.
* This operation will be done last in the migration.
* It cannot be run in a transaction, so we recommend doing it in a separate migration file.
* @param collectionName
*/
public dropCollection(collectionName: string): void;
public createCollection(collectionName: string): void;
public createIndex(
collectionName: string,
Expand Down
4 changes: 2 additions & 2 deletions reset-dev.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ try {
stdio: 'inherit',
},
);
} catch (error) {
process.stderr.write(error.stderr);
} catch {
// Ignore error, it is already piped to the console.
process.exit(1);
}
33 changes: 31 additions & 2 deletions src/Migration.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { Logger } from '@poppinss/cliui/build/src/Logger';
import type {
CreateIndexesOptions,
ClientSession,
CreateIndexesOptions,
Db,
IndexSpecification,
DropIndexesOptions,
IndexSpecification,
} from 'mongodb';

import type {
Expand All @@ -13,12 +13,18 @@ import type {
} from '@ioc:Zakodium/Mongodb/Database';

enum MigrationType {
DropCollection = 'DropCollection',
CreateCollection = 'CreateCollection',
DropIndex = 'DropIndex',
CreateIndex = 'CreateIndex',
Custom = 'Custom',
}

interface DropCollectionOperation {
type: MigrationType.DropCollection;
collectionName: string;
}

interface CreateCollectionOperation {
type: MigrationType.CreateCollection;
collectionName: string;
Expand All @@ -44,6 +50,7 @@ interface CustomOperation {
}

type MigrationOperation =
| DropCollectionOperation
| CreateCollectionOperation
| DropIndexOperation
| CreateIndexOperation
Expand All @@ -68,6 +75,13 @@ export default function createMigration(Database: DatabaseContract): any {
}
}

public dropCollection(collectionName: string): void {
this.$operations.push({
type: MigrationType.DropCollection,
collectionName,
});
}

public createCollection(collectionName: string): void {
this.$operations.push({
type: MigrationType.CreateCollection,
Expand Down Expand Up @@ -114,6 +128,7 @@ export default function createMigration(Database: DatabaseContract): any {
await this._dropIndexes(session);
await this._createIndexes(session);
await this._executeDeferred(session);
await this._dropCollections();
}

private async _listCollections() {
Expand All @@ -128,6 +143,14 @@ export default function createMigration(Database: DatabaseContract): any {
return this.$collectionList;
}

private async _dropCollections(): Promise<void> {
const db = await this.$connection.database();
for (const op of this.$operations.filter(isDropCollection)) {
this.$logger.info(`Dropping collection ${op.collectionName}`);
await db.dropCollection(op.collectionName);
}
}

private async _createCollections(session: ClientSession): Promise<void> {
const db = await this.$connection.database();
for (const op of this.$operations.filter(isCreateCollection)) {
Expand Down Expand Up @@ -179,6 +202,12 @@ export default function createMigration(Database: DatabaseContract): any {
return Migration;
}

function isDropCollection(
op: MigrationOperation,
): op is DropCollectionOperation {
return op.type === MigrationType.DropCollection;
}

function isCreateCollection(
op: MigrationOperation,
): op is CreateCollectionOperation {
Expand Down
3 changes: 2 additions & 1 deletion src/Model/__tests__/Model.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ObjectId } from 'mongodb';

import { setupDatabase } from '../../../test-utils/TestUtils';
import { computed, field } from '../../Odm/decorators';
import { BaseModel, BaseAutoIncrementModel } from '../Model';
import { BaseAutoIncrementModel, BaseModel } from '../Model';

const db = setupDatabase();

Expand Down Expand Up @@ -444,6 +444,7 @@ test('toJSON method', async () => {

test('spreading a model should throw', async () => {
const post = await Post.query().firstOrFail();
// eslint-disable-next-line @typescript-eslint/no-misused-spread
expect(() => ({ ...post })).toThrow(/Getting model keys is disallowed/);
});

Expand Down
58 changes: 44 additions & 14 deletions src/__tests__/Migration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,57 @@ const logger = new Logger();
const db = getMongodb();
const BaseMigration = createMigration(db);

class TestMigration extends BaseMigration {
class TestMigration1 extends BaseMigration {
public constructor(connection: string | undefined, logger: Logger) {
super(connection, logger);
}
public up(): void {
this.createCollection('migration');
this.createCollection('migration1');
this.createCollections(['migration2', 'migration3']);
}
}

afterAll(async () => {
const database = await db.connection('mongo').database();
await database.dropDatabase();
await db.manager.closeAll();
});
class TestMigration2 extends BaseMigration {
public constructor(connection: string | undefined, logger: Logger) {
super(connection, logger);
}
public up(): void {
this.dropCollection('migration2');
}
}

test('runs a migration correctly edit database', async () => {
await db.connection('mongo').transaction(async (session) => {
const migration = new TestMigration('mongo', logger);
await migration.execUp(session);
describe('running migrations correctly changes database', () => {
afterAll(async () => {
const database = await db.connection('mongo').database();
await database.dropDatabase();
await db.manager.closeAll();
});

it('should create collections', async () => {
await db.connection('mongo').transaction(async (session) => {
const migration1 = new TestMigration1('mongo', logger);
await migration1.execUp(session);
});
const database = await db.connection('mongo').database();
const collections = await database.listCollections().map(getName).toArray();
expect(collections.sort()).toStrictEqual([
'migration1',
'migration2',
'migration3',
]);
});

it('should drop collection', async () => {
await db.connection('mongo').transaction(async (session) => {
const migration2 = new TestMigration2('mongo', logger);
await migration2.execUp(session);
});
const database = await db.connection('mongo').database();
const collections = await database.listCollections().map(getName).toArray();
expect(collections.sort()).toStrictEqual(['migration1', 'migration3']);
});
const database = await db.connection('mongo').database();
const collections = await database.listCollections().toArray();
expect(collections).toHaveLength(1);
});

function getName(collection: { name: string }) {
return collection.name;
}

0 comments on commit 2928b95

Please sign in to comment.