Skip to content

Commit 83a882d

Browse files
committed
fix: add missing migrate diff command
1 parent d680c5b commit 83a882d

File tree

3 files changed

+102
-0
lines changed

3 files changed

+102
-0
lines changed

packages/cli/src/actions/migrate.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,21 @@ type ResolveOptions = CommonOptions & {
2929
rolledBack?: string;
3030
};
3131

32+
type DiffOptions = CommonOptions & {
33+
fromEmpty?: boolean;
34+
toEmpty?: boolean;
35+
fromSchemaDatamodel?: boolean;
36+
toSchemaDatamodel?: boolean;
37+
fromMigrationsDirectory?: string;
38+
toMigrationsDirectory?: string;
39+
fromUrl?: string;
40+
toUrl?: string;
41+
shadowDatabaseUrl?: string;
42+
script?: boolean;
43+
exitCode?: boolean;
44+
extraArgs?: string[];
45+
};
46+
3247
/**
3348
* CLI action for migration-related commands
3449
*/
@@ -62,6 +77,10 @@ export async function run(command: string, options: CommonOptions) {
6277
case 'resolve':
6378
await runResolve(prismaSchemaFile, options as ResolveOptions);
6479
break;
80+
81+
case 'diff':
82+
runDiff(prismaSchemaFile, options as DiffOptions);
83+
break;
6584
}
6685
} finally {
6786
if (fs.existsSync(prismaSchemaFile)) {
@@ -140,6 +159,55 @@ function runResolve(prismaSchemaFile: string, options: ResolveOptions) {
140159
}
141160
}
142161

162+
function runDiff(prismaSchemaFile: string, options: DiffOptions) {
163+
try {
164+
const parts = ['migrate diff'];
165+
166+
if (options.fromEmpty) {
167+
parts.push('--from-empty');
168+
}
169+
if (options.toEmpty) {
170+
parts.push('--to-empty');
171+
}
172+
if (options.fromSchemaDatamodel) {
173+
parts.push(`--from-schema-datamodel "${prismaSchemaFile}"`);
174+
}
175+
if (options.toSchemaDatamodel) {
176+
parts.push(`--to-schema-datamodel "${prismaSchemaFile}"`);
177+
}
178+
if (options.fromMigrationsDirectory) {
179+
parts.push(`--from-migrations-directory "${options.fromMigrationsDirectory}"`);
180+
}
181+
if (options.toMigrationsDirectory) {
182+
parts.push(`--to-migrations-directory "${options.toMigrationsDirectory}"`);
183+
}
184+
if (options.fromUrl) {
185+
parts.push(`--from-url "${options.fromUrl}"`);
186+
}
187+
if (options.toUrl) {
188+
parts.push(`--to-url "${options.toUrl}"`);
189+
}
190+
if (options.shadowDatabaseUrl) {
191+
parts.push(`--shadow-database-url "${options.shadowDatabaseUrl}"`);
192+
}
193+
if (options.script) {
194+
parts.push('--script');
195+
}
196+
if (options.exitCode) {
197+
parts.push('--exit-code');
198+
}
199+
200+
// pass through any extra args
201+
if (options.extraArgs?.length) {
202+
parts.push(...options.extraArgs);
203+
}
204+
205+
execPrisma(parts.join(' '));
206+
} catch (err) {
207+
handleSubProcessError(err);
208+
}
209+
}
210+
143211
function handleSubProcessError(err: unknown) {
144212
if (err instanceof Error && 'status' in err && typeof err.status === 'number') {
145213
process.exit(err.status);

packages/cli/src/index.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,35 @@ function createProgram() {
154154
.description('Resolve issues with database migrations in deployment databases')
155155
.action((options) => migrateAction('resolve', options));
156156

157+
migrateCommand
158+
.command('diff')
159+
.addOption(schemaOption)
160+
.addOption(noVersionCheckOption)
161+
.addOption(new Option('--from-empty', 'assume the "from" state is an empty schema'))
162+
.addOption(new Option('--to-empty', 'assume the "to" state is an empty schema'))
163+
.addOption(
164+
new Option(
165+
'--from-schema-datamodel',
166+
'use the ZModel schema as the "from" source (auto-generates Prisma schema)',
167+
),
168+
)
169+
.addOption(
170+
new Option(
171+
'--to-schema-datamodel',
172+
'use the ZModel schema as the "to" source (auto-generates Prisma schema)',
173+
),
174+
)
175+
.addOption(new Option('--from-migrations-directory <path>', 'path to the "from" migrations directory'))
176+
.addOption(new Option('--to-migrations-directory <path>', 'path to the "to" migrations directory'))
177+
.addOption(new Option('--from-url <url>', 'database URL as the "from" source'))
178+
.addOption(new Option('--to-url <url>', 'database URL as the "to" source'))
179+
.addOption(new Option('--shadow-database-url <url>', 'shadow database URL for migrations'))
180+
.addOption(new Option('--script', 'output a SQL script instead of human-readable diff'))
181+
.addOption(new Option('--exit-code', 'exit with non-zero code if diff is not empty'))
182+
.allowExcessArguments(true)
183+
.description('Compare database schemas from two sources and output the differences')
184+
.action((options, command) => migrateAction('diff', { ...options, extraArgs: command.args }));
185+
157186
const dbCommand = program.command('db').description('Manage your database schema during development');
158187

159188
dbCommand

packages/cli/test/migrate.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,9 @@ describe('CLI migrate commands test', () => {
6969
const { workDir } = await createProject(model, { provider: 'sqlite' });
7070
expect(() => runCli('migrate resolve', workDir)).toThrow();
7171
});
72+
73+
it('supports migrate diff with --from-empty and --to-schema-datamodel', async () => {
74+
const { workDir } = await createProject(model, { provider: 'sqlite' });
75+
runCli('migrate diff --from-empty --to-schema-datamodel --script', workDir);
76+
});
7277
});

0 commit comments

Comments
 (0)