Skip to content

Add reset / squash migrations feature. Fixes #46 #47

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ A VS Code extension to manage Entity Framework migrations.
- List migrations by [`DbContext`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.dbcontext)
- Add / Remove / Run / Undo migrations
- Show migration applied status
- Reset (Squash) Migrations
- Export `DbContext` as SQL script
- View `DbContext` information
- [Scaffold](https://learn.microsoft.com/en-us/ef/core/cli/dotnet#dotnet-ef-dbcontext-scaffold) `DbContext` & entity types
Expand Down
17 changes: 17 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@
"dark": "icons/trash_dark.svg"
}
},
{
"command": "entityframework.resetMigrations",
"title": "Reset Migrations to Here",
"icon": {
"light": "icons/reply_light.svg",
"dark": "icons/reply_dark.svg"
}
},
{
"command": "entityframework.dbContextInfo",
"title": "Information",
Expand Down Expand Up @@ -157,6 +165,10 @@
"command": "entityframework.removeMigrations",
"when": "false"
},
{
"command": "entityframework.resetMigrations",
"when": "false"
},
{
"command": "entityframework.dbContextInfo",
"when": "false"
Expand Down Expand Up @@ -204,6 +216,11 @@
"when": "viewItem =~ /^migration-.*\\|?can-remove\\|?.*$/",
"group": "context@2"
},
{
"command": "entityframework.resetMigrations",
"when": "viewItem =~ /^migration-.*\\|?can-reset\\|?.*$/",
"group": "context@3"
},
{
"command": "entityframework.runMigration",
"when": "viewItem =~ /^migration-.*\\|?can-apply\\|?.*$/",
Expand Down
13 changes: 8 additions & 5 deletions src/actions/AddMigrationAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export class AddMigrationAction extends TerminalAction {
private readonly workspaceRoot: string,
private readonly dbContext: string,
private readonly project: string,
private readonly migrationName?: string,
) {
super(
terminalProvider,
Expand All @@ -30,11 +31,13 @@ export class AddMigrationAction extends TerminalAction {
}

public async run() {
const migrationName = await vscode.window.showInputBox({
title: 'Enter Migration Name',
prompt: 'EG: MigrationName',
ignoreFocusOut: true,
});
const migrationName =
this.migrationName ||
(await vscode.window.showInputBox({
title: 'Enter Migration Name',
prompt: 'EG: MigrationName',
ignoreFocusOut: true,
}));
if (!migrationName) {
return '';
}
Expand Down
22 changes: 19 additions & 3 deletions src/actions/RemoveMigrationsAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import * as vscode from 'vscode';
import { CommandProvider } from '../commands/CommandProvider';
import { RefreshTreeCommand } from '../commands/RefreshTreeCommand';
import type { TerminalProvider } from '../terminal/TerminalProvider';
import {
dbContextsCache,
DbContextTreeItem,
} from '../treeView/DbContextTreeItem';
import type { MigrationTreeItem } from '../treeView/MigrationTreeItem';
import type { IAction } from './IAction';
import { RemoveMigrationAction } from './RemoveMigrationAction';
Expand All @@ -12,11 +16,23 @@ export class RemoveMigrationsAction implements IAction {
private readonly workspaceRoot: string,
private readonly dbContext: string,
private readonly project: string,
private readonly migrationsToRemove: MigrationTreeItem[],
private readonly item: MigrationTreeItem,
) {}

public async run() {
for (let i = 0; i < this.migrationsToRemove.length; i++) {
const migrations = dbContextsCache.get(
DbContextTreeItem.getCacheId(
this.workspaceRoot,
this.project,
this.dbContext,
),
);
const index = (migrations || []).indexOf(this.item);
if (index === -1) {
return;
}
const migrationsToRemove = migrations?.slice(index) || [];
for (let i = 0; i < migrationsToRemove.length; i++) {
await new RemoveMigrationAction(
this.terminalProvider,
this.workspaceRoot,
Expand All @@ -25,7 +41,7 @@ export class RemoveMigrationsAction implements IAction {
false,
).run();
}
if (this.migrationsToRemove.length > 0) {
if (migrationsToRemove.length > 0) {
await vscode.commands.executeCommand(
CommandProvider.getCommandName(RefreshTreeCommand.commandName),
false,
Expand Down
76 changes: 76 additions & 0 deletions src/actions/ResetMigrationsAction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import * as vscode from 'vscode';
import { UndoMigrationCommand } from '../commands/UndoMigrationCommand';
import type { TerminalProvider } from '../terminal/TerminalProvider';
import {
dbContextsCache,
DbContextTreeItem,
} from '../treeView/DbContextTreeItem';
import type { MigrationTreeItem } from '../treeView/MigrationTreeItem';
import { AddMigrationAction } from './AddMigrationAction';
import type { IAction } from './IAction';
import { RemoveMigrationAction } from './RemoveMigrationAction';

export class ResetMigrationsAction implements IAction {
constructor(
private readonly terminalProvider: TerminalProvider,
private readonly workspaceRoot: string,
private readonly dbContext: string,
private readonly project: string,
private readonly item: MigrationTreeItem,
) {}

public async run() {
const migrations = dbContextsCache.get(
DbContextTreeItem.getCacheId(
this.workspaceRoot,
this.project,
this.dbContext,
),
);
const index = (migrations || []).indexOf(this.item);
if (index === -1) {
return;
}
const migrationsToReset = migrations?.slice(index) || [];
if (!migrationsToReset.length) {
return;
}
const options = ['Yes', 'Cancel'] as const;
const answer = await vscode.window.showInformationMessage(
'Any manual migration modifications will be lost! Are you sure you want to do this?',
...options,
);
if (answer === 'Cancel') {
return;
}
const migrationName = await vscode.window.showInputBox({
title: 'Enter Migration Name',
prompt: 'EG: MigrationName',
ignoreFocusOut: true,
});
if (!migrationName) {
return '';
}
await new UndoMigrationCommand(
this.terminalProvider,
this.item,
false,
).run();
for (let i = 0; i < migrationsToReset.length; i++) {
await new RemoveMigrationAction(
this.terminalProvider,
this.workspaceRoot,
this.dbContext,
this.project,
false,
).run();
}
await new AddMigrationAction(
this.terminalProvider,
this.workspaceRoot,
this.dbContext,
this.project,
migrationName,
).run();
}
}
11 changes: 7 additions & 4 deletions src/actions/RunMigrationAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export class RunMigrationAction extends TerminalAction {
private readonly dbContext: string,
private readonly project: string,
migrationId: string,
private readonly refresh?: boolean,
) {
super(
terminalProvider,
Expand Down Expand Up @@ -51,10 +52,12 @@ export class RunMigrationAction extends TerminalAction {
);
dbContextsCache.clear(cacheId);

await vscode.commands.executeCommand(
CommandProvider.getCommandName(RefreshTreeCommand.commandName),
false,
);
if (this.refresh) {
await vscode.commands.executeCommand(
CommandProvider.getCommandName(RefreshTreeCommand.commandName),
false,
);
}

return output;
},
Expand Down
7 changes: 7 additions & 0 deletions src/commands/CommandProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { RefreshDbContextTreeCommand } from './RefreshDbContextTreeCommand';
import { RefreshProjectTreeCommand } from './RefreshProjectTreeCommand';
import { RefreshTreeCommand } from './RefreshTreeCommand';
import { RemoveMigrationsCommand } from './RemoveMigrationsCommand';
import { ResetMigrationsCommand } from './ResetMigrationsCommand';
import { RunMigrationCommand } from './RunMigrationCommand';
import { ScaffoldCommand } from './ScaffoldCommand';
import { UndoMigrationCommand } from './UndoMigrationCommand';
Expand All @@ -42,6 +43,12 @@ export class CommandProvider extends Disposable {
return new RemoveMigrationsCommand(terminalProvider, item);
},
);
this.registerCommand(
ResetMigrationsCommand.commandName,
(item?: MigrationTreeItem) => {
return new ResetMigrationsCommand(terminalProvider, item);
},
);
this.registerCommand(
RunMigrationCommand.commandName,
(item?: MigrationTreeItem) =>
Expand Down
18 changes: 1 addition & 17 deletions src/commands/RemoveMigrationsCommand.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { RemoveMigrationsAction } from '../actions/RemoveMigrationsAction';
import type { TerminalProvider } from '../terminal/TerminalProvider';
import {
dbContextsCache,
DbContextTreeItem,
} from '../treeView/DbContextTreeItem';
import { type MigrationTreeItem } from '../treeView/MigrationTreeItem';
import { Command } from './Command';

Expand All @@ -21,24 +17,12 @@ export class RemoveMigrationsCommand extends Command {
if (!this.item) {
return;
}
const migrations = dbContextsCache.get(
DbContextTreeItem.getCacheId(
this.item.workspaceRoot,
this.item.projectFile.name,
this.item.dbContext,
),
);
const index = (migrations || []).indexOf(this.item);
if (index === -1) {
return;
}
const migrationsToRemove = migrations?.slice(index) || [];
return new RemoveMigrationsAction(
this.terminalProvider,
this.item.workspaceRoot,
this.item.dbContext,
this.item.projectFile.name,
migrationsToRemove,
this.item,
).run();
}
}
29 changes: 29 additions & 0 deletions src/commands/ResetMigrationsCommand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { ResetMigrationsAction } from '../actions/ResetMigrationsAction';
import type { TerminalProvider } from '../terminal/TerminalProvider';

import { type MigrationTreeItem } from '../treeView/MigrationTreeItem';
import { Command } from './Command';

export class ResetMigrationsCommand extends Command {
public static commandName = 'resetMigrations';

constructor(
private readonly terminalProvider: TerminalProvider,
private readonly item?: MigrationTreeItem,
) {
super();
}

public async run() {
if (!this.item) {
return;
}
return new ResetMigrationsAction(
this.terminalProvider,
this.item.workspaceRoot,
this.item.dbContext,
this.item.projectFile.name,
this.item,
).run();
}
}
1 change: 1 addition & 0 deletions src/commands/RunMigrationCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export class RunMigrationCommand extends Command {
this.item.dbContext,
this.item.projectFile.name,
this.item.migration.id,
true,
).run();
}
}
4 changes: 3 additions & 1 deletion src/commands/UndoMigrationCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export class UndoMigrationCommand extends Command {
constructor(
private readonly terminalProvider: TerminalProvider,
private readonly item?: MigrationTreeItem,
private readonly refresh?: boolean,
) {
super();
}
Expand All @@ -31,12 +32,13 @@ export class UndoMigrationCommand extends Command {
const index = migrations.indexOf(this.item);
const migrationId =
index === 0 ? '0' : migrations[index - 1].migration.id;
return new RunMigrationAction(
return await new RunMigrationAction(
this.terminalProvider,
this.item.workspaceRoot,
this.item.dbContext,
this.item.projectFile.name,
migrationId,
this.refresh,
).run();
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/treeView/DbContextTreeItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export class DbContextTreeItem extends TreeItem {
} catch (e) {
const msg = `Unable to get migrations: ${(e as Error).message}`.trim();
this.logger.error(msg);
await vscode.window.showErrorMessage(msg, 'OK');
void vscode.window.showErrorMessage(msg, 'OK');
return [];
}
}
Expand Down
8 changes: 7 additions & 1 deletion src/treeView/MigrationTreeItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,17 @@ export class MigrationTreeItem extends TreeItem {

function getMigrationContextValue(migration: Migration): string {
const states: Array<
'can-apply' | 'can-undo' | 'can-remove' | 'applied' | 'not-applied'
| 'can-apply'
| 'can-undo'
| 'can-remove'
| 'applied'
| 'not-applied'
| 'can-reset'
> = [];
if (migration.applied) {
states.push('applied');
states.push('can-undo');
states.push('can-reset');
} else {
states.push('can-remove');
states.push('can-apply');
Expand Down
2 changes: 1 addition & 1 deletion src/treeView/ProjectTreeItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export class ProjectTreeItem extends TreeItem {
} catch (e) {
const msg = `Unable to get dbContexts: ${(e as Error).message}`.trim();
this.logger.error(msg);
await vscode.window.showErrorMessage(msg, 'OK');
void vscode.window.showErrorMessage(msg, 'OK');
return [];
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/util/InputWizard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export class InputWizard {
inputValues.push(inputVal);
}
} catch (e) {
await vscode.window.showErrorMessage('Invalid input');
void vscode.window.showErrorMessage('Invalid input');
return [];
}
return inputValues;
Expand Down