@friggframework/core 2.0.0--canary.463.62579dd.0 → 2.0.0--canary.461.84ff4f5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -0
- package/database/prisma.js +2 -2
- package/database/use-cases/run-database-migration-use-case.js +137 -0
- package/database/use-cases/run-database-migration-use-case.test.js +310 -0
- package/database/utils/prisma-runner.js +377 -0
- package/database/utils/prisma-runner.test.js +486 -0
- package/handlers/backend-utils.js +29 -41
- package/handlers/workers/db-migration.js +208 -0
- package/handlers/workers/db-migration.test.js +437 -0
- package/integrations/repositories/process-repository-postgres.js +2 -2
- package/package.json +18 -9
- package/prisma-mongodb/schema.prisma +22 -20
- package/prisma-postgresql/schema.prisma +16 -14
package/README.md
CHANGED
|
@@ -62,6 +62,34 @@ npm install @friggframework/core
|
|
|
62
62
|
yarn add @friggframework/core
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
+
### Prisma Support (Optional)
|
|
66
|
+
|
|
67
|
+
`@friggframework/core` supports both MongoDB and PostgreSQL via Prisma ORM. **Prisma is an optional peer dependency** - you only need to install it if you're using database features that require migrations or schema generation.
|
|
68
|
+
|
|
69
|
+
**When you need Prisma:**
|
|
70
|
+
- Running database migrations (`prisma migrate`, `prisma db push`)
|
|
71
|
+
- Generating Prisma clients for your application
|
|
72
|
+
- Using the migration Lambda function (`dbMigrate`)
|
|
73
|
+
|
|
74
|
+
**Installation:**
|
|
75
|
+
```bash
|
|
76
|
+
# Install Prisma CLI and Client as dev dependencies
|
|
77
|
+
npm install --save-dev prisma @prisma/client
|
|
78
|
+
|
|
79
|
+
# Or with yarn
|
|
80
|
+
yarn add -D prisma @prisma/client
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Generate Prisma Clients:**
|
|
84
|
+
```bash
|
|
85
|
+
# From @friggframework/core directory
|
|
86
|
+
npm run prisma:generate:mongo # MongoDB only
|
|
87
|
+
npm run prisma:generate:postgres # PostgreSQL only
|
|
88
|
+
npm run prisma:generate # Both databases
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Note:** The published npm package includes pre-generated Prisma clients, so you don't need to install Prisma just to use `@friggframework/core` in production. Prisma is only required if you're actively developing migrations or running the migration Lambda function.
|
|
92
|
+
|
|
65
93
|
### Prerequisites
|
|
66
94
|
|
|
67
95
|
- Node.js 16+
|
package/database/prisma.js
CHANGED
|
@@ -77,9 +77,9 @@ const prismaClientSingleton = () => {
|
|
|
77
77
|
let PrismaClient;
|
|
78
78
|
|
|
79
79
|
if (config.DB_TYPE === 'mongodb') {
|
|
80
|
-
PrismaClient = require('
|
|
80
|
+
PrismaClient = require('../generated/prisma-mongodb').PrismaClient;
|
|
81
81
|
} else if (config.DB_TYPE === 'postgresql') {
|
|
82
|
-
PrismaClient = require('
|
|
82
|
+
PrismaClient = require('../generated/prisma-postgresql').PrismaClient;
|
|
83
83
|
} else {
|
|
84
84
|
throw new Error(
|
|
85
85
|
`Unsupported database type: ${config.DB_TYPE}. Supported values: 'mongodb', 'postgresql'`
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run Database Migration Use Case
|
|
3
|
+
*
|
|
4
|
+
* Business logic for running Prisma database migrations.
|
|
5
|
+
* Orchestrates Prisma client generation and migration execution.
|
|
6
|
+
*
|
|
7
|
+
* This use case follows the Frigg hexagonal architecture pattern where:
|
|
8
|
+
* - Handlers (adapters) call use cases
|
|
9
|
+
* - Use cases contain business logic and orchestration
|
|
10
|
+
* - Use cases call repositories/utilities for data access
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
class RunDatabaseMigrationUseCase {
|
|
14
|
+
/**
|
|
15
|
+
* @param {Object} dependencies
|
|
16
|
+
* @param {Object} dependencies.prismaRunner - Prisma runner utilities
|
|
17
|
+
*/
|
|
18
|
+
constructor({ prismaRunner }) {
|
|
19
|
+
if (!prismaRunner) {
|
|
20
|
+
throw new Error('prismaRunner dependency is required');
|
|
21
|
+
}
|
|
22
|
+
this.prismaRunner = prismaRunner;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Execute database migration
|
|
27
|
+
*
|
|
28
|
+
* @param {Object} params
|
|
29
|
+
* @param {string} params.dbType - Database type ('postgresql' or 'mongodb')
|
|
30
|
+
* @param {string} params.stage - Deployment stage (determines migration command)
|
|
31
|
+
* @param {boolean} [params.verbose=false] - Enable verbose output
|
|
32
|
+
* @returns {Promise<Object>} Migration result { success, dbType, stage, command, message }
|
|
33
|
+
* @throws {MigrationError} If migration fails
|
|
34
|
+
* @throws {ValidationError} If parameters are invalid
|
|
35
|
+
*/
|
|
36
|
+
async execute({ dbType, stage, verbose = false }) {
|
|
37
|
+
// Validation
|
|
38
|
+
this._validateParams({ dbType, stage });
|
|
39
|
+
|
|
40
|
+
// Step 1: Generate Prisma client
|
|
41
|
+
const generateResult = await this.prismaRunner.runPrismaGenerate(dbType, verbose);
|
|
42
|
+
|
|
43
|
+
if (!generateResult.success) {
|
|
44
|
+
throw new MigrationError(
|
|
45
|
+
`Failed to generate Prisma client: ${generateResult.error || 'Unknown error'}`,
|
|
46
|
+
{ dbType, stage, step: 'generate', output: generateResult.output }
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Step 2: Run migrations based on database type
|
|
51
|
+
let migrationResult;
|
|
52
|
+
let migrationCommand;
|
|
53
|
+
|
|
54
|
+
if (dbType === 'postgresql') {
|
|
55
|
+
migrationCommand = this.prismaRunner.getMigrationCommand(stage);
|
|
56
|
+
migrationResult = await this.prismaRunner.runPrismaMigrate(migrationCommand, verbose);
|
|
57
|
+
|
|
58
|
+
if (!migrationResult.success) {
|
|
59
|
+
throw new MigrationError(
|
|
60
|
+
`PostgreSQL migration failed: ${migrationResult.error || 'Unknown error'}`,
|
|
61
|
+
{ dbType, stage, command: migrationCommand, step: 'migrate', output: migrationResult.output }
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
} else if (dbType === 'mongodb') {
|
|
65
|
+
migrationCommand = 'db push';
|
|
66
|
+
// Use non-interactive mode for automated/Lambda environments
|
|
67
|
+
migrationResult = await this.prismaRunner.runPrismaDbPush(verbose, true);
|
|
68
|
+
|
|
69
|
+
if (!migrationResult.success) {
|
|
70
|
+
throw new MigrationError(
|
|
71
|
+
`MongoDB push failed: ${migrationResult.error || 'Unknown error'}`,
|
|
72
|
+
{ dbType, stage, command: migrationCommand, step: 'push', output: migrationResult.output }
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
throw new ValidationError(`Unsupported database type: ${dbType}. Must be 'postgresql' or 'mongodb'.`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Return success result
|
|
80
|
+
return {
|
|
81
|
+
success: true,
|
|
82
|
+
dbType,
|
|
83
|
+
stage,
|
|
84
|
+
command: migrationCommand,
|
|
85
|
+
message: 'Database migration completed successfully',
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Validate execution parameters
|
|
91
|
+
* @private
|
|
92
|
+
*/
|
|
93
|
+
_validateParams({ dbType, stage }) {
|
|
94
|
+
if (!dbType) {
|
|
95
|
+
throw new ValidationError('dbType is required');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (typeof dbType !== 'string') {
|
|
99
|
+
throw new ValidationError('dbType must be a string');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (!stage) {
|
|
103
|
+
throw new ValidationError('stage is required');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (typeof stage !== 'string') {
|
|
107
|
+
throw new ValidationError('stage must be a string');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Custom error for migration failures
|
|
114
|
+
*/
|
|
115
|
+
class MigrationError extends Error {
|
|
116
|
+
constructor(message, context = {}) {
|
|
117
|
+
super(message);
|
|
118
|
+
this.name = 'MigrationError';
|
|
119
|
+
this.context = context;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Custom error for validation failures
|
|
125
|
+
*/
|
|
126
|
+
class ValidationError extends Error {
|
|
127
|
+
constructor(message) {
|
|
128
|
+
super(message);
|
|
129
|
+
this.name = 'ValidationError';
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
module.exports = {
|
|
134
|
+
RunDatabaseMigrationUseCase,
|
|
135
|
+
MigrationError,
|
|
136
|
+
ValidationError,
|
|
137
|
+
};
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Run Database Migration Use Case
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const {
|
|
6
|
+
RunDatabaseMigrationUseCase,
|
|
7
|
+
MigrationError,
|
|
8
|
+
ValidationError,
|
|
9
|
+
} = require('./run-database-migration-use-case');
|
|
10
|
+
|
|
11
|
+
describe('RunDatabaseMigrationUseCase', () => {
|
|
12
|
+
let useCase;
|
|
13
|
+
let mockPrismaRunner;
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
// Mock prisma runner with all required methods
|
|
17
|
+
mockPrismaRunner = {
|
|
18
|
+
runPrismaGenerate: jest.fn(),
|
|
19
|
+
runPrismaMigrate: jest.fn(),
|
|
20
|
+
runPrismaDbPush: jest.fn(),
|
|
21
|
+
getMigrationCommand: jest.fn(),
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
useCase = new RunDatabaseMigrationUseCase({ prismaRunner: mockPrismaRunner });
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe('Constructor', () => {
|
|
28
|
+
it('should throw error if prismaRunner is not provided', () => {
|
|
29
|
+
expect(() => new RunDatabaseMigrationUseCase({})).toThrow('prismaRunner dependency is required');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should create instance with valid dependencies', () => {
|
|
33
|
+
expect(useCase).toBeInstanceOf(RunDatabaseMigrationUseCase);
|
|
34
|
+
expect(useCase.prismaRunner).toBe(mockPrismaRunner);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe('Parameter Validation', () => {
|
|
39
|
+
it('should throw ValidationError if dbType is missing', async () => {
|
|
40
|
+
await expect(useCase.execute({ stage: 'production' })).rejects.toThrow(ValidationError);
|
|
41
|
+
await expect(useCase.execute({ stage: 'production' })).rejects.toThrow('dbType is required');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should throw ValidationError if dbType is not a string', async () => {
|
|
45
|
+
await expect(useCase.execute({ dbType: 123, stage: 'production' })).rejects.toThrow(ValidationError);
|
|
46
|
+
await expect(useCase.execute({ dbType: 123, stage: 'production' })).rejects.toThrow(
|
|
47
|
+
'dbType must be a string'
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should throw ValidationError if stage is missing', async () => {
|
|
52
|
+
await expect(useCase.execute({ dbType: 'postgresql' })).rejects.toThrow(ValidationError);
|
|
53
|
+
await expect(useCase.execute({ dbType: 'postgresql' })).rejects.toThrow('stage is required');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should throw ValidationError if stage is not a string', async () => {
|
|
57
|
+
await expect(useCase.execute({ dbType: 'postgresql', stage: 123 })).rejects.toThrow(ValidationError);
|
|
58
|
+
await expect(useCase.execute({ dbType: 'postgresql', stage: 123 })).rejects.toThrow(
|
|
59
|
+
'stage must be a string'
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe('PostgreSQL Migrations', () => {
|
|
65
|
+
beforeEach(() => {
|
|
66
|
+
mockPrismaRunner.runPrismaGenerate.mockResolvedValue({ success: true });
|
|
67
|
+
mockPrismaRunner.runPrismaMigrate.mockResolvedValue({ success: true });
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should successfully run PostgreSQL production migration', async () => {
|
|
71
|
+
mockPrismaRunner.getMigrationCommand.mockReturnValue('deploy');
|
|
72
|
+
|
|
73
|
+
const result = await useCase.execute({
|
|
74
|
+
dbType: 'postgresql',
|
|
75
|
+
stage: 'production',
|
|
76
|
+
verbose: true,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
expect(result).toEqual({
|
|
80
|
+
success: true,
|
|
81
|
+
dbType: 'postgresql',
|
|
82
|
+
stage: 'production',
|
|
83
|
+
command: 'deploy',
|
|
84
|
+
message: 'Database migration completed successfully',
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
expect(mockPrismaRunner.runPrismaGenerate).toHaveBeenCalledWith('postgresql', true);
|
|
88
|
+
expect(mockPrismaRunner.getMigrationCommand).toHaveBeenCalledWith('production');
|
|
89
|
+
expect(mockPrismaRunner.runPrismaMigrate).toHaveBeenCalledWith('deploy', true);
|
|
90
|
+
expect(mockPrismaRunner.runPrismaDbPush).not.toHaveBeenCalled();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should successfully run PostgreSQL development migration', async () => {
|
|
94
|
+
mockPrismaRunner.getMigrationCommand.mockReturnValue('dev');
|
|
95
|
+
|
|
96
|
+
const result = await useCase.execute({
|
|
97
|
+
dbType: 'postgresql',
|
|
98
|
+
stage: 'dev',
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
expect(result.success).toBe(true);
|
|
102
|
+
expect(result.command).toBe('dev');
|
|
103
|
+
expect(mockPrismaRunner.getMigrationCommand).toHaveBeenCalledWith('dev');
|
|
104
|
+
expect(mockPrismaRunner.runPrismaMigrate).toHaveBeenCalledWith('dev', false);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should throw MigrationError if Prisma generate fails', async () => {
|
|
108
|
+
mockPrismaRunner.runPrismaGenerate.mockResolvedValue({
|
|
109
|
+
success: false,
|
|
110
|
+
error: 'Schema file not found',
|
|
111
|
+
output: 'Error output',
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
await expect(
|
|
115
|
+
useCase.execute({ dbType: 'postgresql', stage: 'production' })
|
|
116
|
+
).rejects.toThrow(MigrationError);
|
|
117
|
+
|
|
118
|
+
await expect(
|
|
119
|
+
useCase.execute({ dbType: 'postgresql', stage: 'production' })
|
|
120
|
+
).rejects.toThrow('Failed to generate Prisma client: Schema file not found');
|
|
121
|
+
|
|
122
|
+
expect(mockPrismaRunner.runPrismaMigrate).not.toHaveBeenCalled();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should throw MigrationError if PostgreSQL migration fails', async () => {
|
|
126
|
+
mockPrismaRunner.getMigrationCommand.mockReturnValue('deploy');
|
|
127
|
+
mockPrismaRunner.runPrismaMigrate.mockResolvedValue({
|
|
128
|
+
success: false,
|
|
129
|
+
error: 'Migration conflict detected',
|
|
130
|
+
output: 'Conflict output',
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
await expect(
|
|
134
|
+
useCase.execute({ dbType: 'postgresql', stage: 'production' })
|
|
135
|
+
).rejects.toThrow(MigrationError);
|
|
136
|
+
|
|
137
|
+
await expect(
|
|
138
|
+
useCase.execute({ dbType: 'postgresql', stage: 'production' })
|
|
139
|
+
).rejects.toThrow('PostgreSQL migration failed: Migration conflict detected');
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('should include context in MigrationError', async () => {
|
|
143
|
+
mockPrismaRunner.getMigrationCommand.mockReturnValue('deploy');
|
|
144
|
+
mockPrismaRunner.runPrismaMigrate.mockResolvedValue({
|
|
145
|
+
success: false,
|
|
146
|
+
error: 'Migration failed',
|
|
147
|
+
output: 'Error output',
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
await useCase.execute({ dbType: 'postgresql', stage: 'production' });
|
|
152
|
+
fail('Should have thrown MigrationError');
|
|
153
|
+
} catch (error) {
|
|
154
|
+
expect(error).toBeInstanceOf(MigrationError);
|
|
155
|
+
expect(error.context).toEqual({
|
|
156
|
+
dbType: 'postgresql',
|
|
157
|
+
stage: 'production',
|
|
158
|
+
command: 'deploy',
|
|
159
|
+
step: 'migrate',
|
|
160
|
+
output: 'Error output',
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
describe('MongoDB Migrations', () => {
|
|
167
|
+
beforeEach(() => {
|
|
168
|
+
mockPrismaRunner.runPrismaGenerate.mockResolvedValue({ success: true });
|
|
169
|
+
mockPrismaRunner.runPrismaDbPush.mockResolvedValue({ success: true });
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('should successfully run MongoDB migration', async () => {
|
|
173
|
+
const result = await useCase.execute({
|
|
174
|
+
dbType: 'mongodb',
|
|
175
|
+
stage: 'production',
|
|
176
|
+
verbose: true,
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
expect(result).toEqual({
|
|
180
|
+
success: true,
|
|
181
|
+
dbType: 'mongodb',
|
|
182
|
+
stage: 'production',
|
|
183
|
+
command: 'db push',
|
|
184
|
+
message: 'Database migration completed successfully',
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
expect(mockPrismaRunner.runPrismaGenerate).toHaveBeenCalledWith('mongodb', true);
|
|
188
|
+
expect(mockPrismaRunner.runPrismaDbPush).toHaveBeenCalledWith(true, true); // verbose=true, nonInteractive=true
|
|
189
|
+
expect(mockPrismaRunner.runPrismaMigrate).not.toHaveBeenCalled();
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('should use non-interactive mode for MongoDB', async () => {
|
|
193
|
+
await useCase.execute({
|
|
194
|
+
dbType: 'mongodb',
|
|
195
|
+
stage: 'production',
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Second parameter should be true for non-interactive
|
|
199
|
+
expect(mockPrismaRunner.runPrismaDbPush).toHaveBeenCalledWith(false, true);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('should throw MigrationError if MongoDB push fails', async () => {
|
|
203
|
+
mockPrismaRunner.runPrismaDbPush.mockResolvedValue({
|
|
204
|
+
success: false,
|
|
205
|
+
error: 'Connection timeout',
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
await expect(useCase.execute({ dbType: 'mongodb', stage: 'production' })).rejects.toThrow(
|
|
209
|
+
MigrationError
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
await expect(useCase.execute({ dbType: 'mongodb', stage: 'production' })).rejects.toThrow(
|
|
213
|
+
'MongoDB push failed: Connection timeout'
|
|
214
|
+
);
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
describe('Unsupported Database Types', () => {
|
|
219
|
+
beforeEach(() => {
|
|
220
|
+
mockPrismaRunner.runPrismaGenerate.mockResolvedValue({ success: true });
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('should throw ValidationError for unsupported database type', async () => {
|
|
224
|
+
await expect(useCase.execute({ dbType: 'mysql', stage: 'production' })).rejects.toThrow(
|
|
225
|
+
ValidationError
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
await expect(useCase.execute({ dbType: 'mysql', stage: 'production' })).rejects.toThrow(
|
|
229
|
+
"Unsupported database type: mysql. Must be 'postgresql' or 'mongodb'."
|
|
230
|
+
);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('should run Prisma generate before checking database type', async () => {
|
|
234
|
+
try {
|
|
235
|
+
await useCase.execute({ dbType: 'mysql', stage: 'production' });
|
|
236
|
+
} catch (error) {
|
|
237
|
+
// Expected error
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
expect(mockPrismaRunner.runPrismaGenerate).toHaveBeenCalledWith('mysql', false);
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
describe('Error Handling', () => {
|
|
245
|
+
it('should handle undefined error from Prisma generate', async () => {
|
|
246
|
+
mockPrismaRunner.runPrismaGenerate.mockResolvedValue({
|
|
247
|
+
success: false,
|
|
248
|
+
error: undefined,
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
await expect(useCase.execute({ dbType: 'postgresql', stage: 'production' })).rejects.toThrow(
|
|
252
|
+
'Failed to generate Prisma client: Unknown error'
|
|
253
|
+
);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it('should handle undefined error from PostgreSQL migration', async () => {
|
|
257
|
+
mockPrismaRunner.runPrismaGenerate.mockResolvedValue({ success: true });
|
|
258
|
+
mockPrismaRunner.getMigrationCommand.mockReturnValue('deploy');
|
|
259
|
+
mockPrismaRunner.runPrismaMigrate.mockResolvedValue({
|
|
260
|
+
success: false,
|
|
261
|
+
error: undefined,
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
await expect(useCase.execute({ dbType: 'postgresql', stage: 'production' })).rejects.toThrow(
|
|
265
|
+
'PostgreSQL migration failed: Unknown error'
|
|
266
|
+
);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it('should handle undefined error from MongoDB push', async () => {
|
|
270
|
+
mockPrismaRunner.runPrismaGenerate.mockResolvedValue({ success: true });
|
|
271
|
+
mockPrismaRunner.runPrismaDbPush.mockResolvedValue({
|
|
272
|
+
success: false,
|
|
273
|
+
error: undefined,
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
await expect(useCase.execute({ dbType: 'mongodb', stage: 'production' })).rejects.toThrow(
|
|
277
|
+
'MongoDB push failed: Unknown error'
|
|
278
|
+
);
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
describe('Verbose Mode', () => {
|
|
283
|
+
beforeEach(() => {
|
|
284
|
+
mockPrismaRunner.runPrismaGenerate.mockResolvedValue({ success: true });
|
|
285
|
+
mockPrismaRunner.runPrismaMigrate.mockResolvedValue({ success: true });
|
|
286
|
+
mockPrismaRunner.getMigrationCommand.mockReturnValue('deploy');
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it('should pass verbose flag to all Prisma operations', async () => {
|
|
290
|
+
await useCase.execute({
|
|
291
|
+
dbType: 'postgresql',
|
|
292
|
+
stage: 'production',
|
|
293
|
+
verbose: true,
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
expect(mockPrismaRunner.runPrismaGenerate).toHaveBeenCalledWith('postgresql', true);
|
|
297
|
+
expect(mockPrismaRunner.runPrismaMigrate).toHaveBeenCalledWith('deploy', true);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it('should default verbose to false', async () => {
|
|
301
|
+
await useCase.execute({
|
|
302
|
+
dbType: 'postgresql',
|
|
303
|
+
stage: 'production',
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
expect(mockPrismaRunner.runPrismaGenerate).toHaveBeenCalledWith('postgresql', false);
|
|
307
|
+
expect(mockPrismaRunner.runPrismaMigrate).toHaveBeenCalledWith('deploy', false);
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
});
|