feat: Add support for mysql / mariadb (#21525)

This commit is contained in:
Stephen Wright 2025-11-04 13:15:24 +00:00 committed by GitHub
parent 6945e21423
commit 9bcad5ae2d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 65 additions and 42 deletions

View File

@ -681,18 +681,6 @@ describe('ImportService', () => {
);
});
it('should throw error when migration IDs do not match', async () => {
const migrationsContent = '{"id":"001","timestamp":"1000","name":"TestMigration"}';
const dbMigrations = [{ id: '002', timestamp: '1000', name: 'TestMigration' }];
jest.mocked(readFile).mockResolvedValue(migrationsContent);
jest.mocked(mockDataSource.query).mockResolvedValue(dbMigrations);
await expect(importService.validateMigrations('/test/input')).rejects.toThrow(
'Migration ID mismatch. Import data: TestMigration (id: 001) does not match target database TestMigration (id: 002). Cannot import data from different migration states.',
);
});
it('should pass validation when migrations match exactly', async () => {
const migrationsContent = '{"id":"1","timestamp":"1000","name":"TestMigration"}';
const dbMigrations = [{ id: '1', timestamp: '1000', name: 'TestMigration' }];
@ -703,18 +691,6 @@ describe('ImportService', () => {
await expect(importService.validateMigrations('/test/input')).resolves.not.toThrow();
});
it('should throw error when migration IDs have different formats', async () => {
const migrationsContent = '{"id":"001","timestamp":"1000","name":"TestMigration"}';
const dbMigrations = [{ id: '1', timestamp: '1000', name: 'TestMigration' }];
jest.mocked(readFile).mockResolvedValue(migrationsContent);
jest.mocked(mockDataSource.query).mockResolvedValue(dbMigrations);
await expect(importService.validateMigrations('/test/input')).rejects.toThrow(
'Migration ID mismatch. Import data: TestMigration (id: 001) does not match target database TestMigration (id: 1). Cannot import data from different migration states.',
);
});
it('should handle multiple migrations and find the latest one', async () => {
const migrationsContent = '{"id":"2","timestamp":"2000","name":"LatestMigration"}';
const dbMigrations = [

View File

@ -566,8 +566,6 @@ export class ImportService {
const dbTimestamp = parseInt(String(latestDbMigration.timestamp || '0'));
const importName = latestImportMigration.name;
const dbName = latestDbMigration.name;
const importId = latestImportMigration.id;
const dbId = latestDbMigration.id;
// Check timestamp match
if (importTimestamp !== dbTimestamp) {
@ -583,13 +581,6 @@ export class ImportService {
);
}
// Check ID match (if both have IDs)
if (importId && dbId && importId !== dbId) {
throw new Error(
`Migration ID mismatch. Import data: ${String(importName)} (id: ${String(importId)}) does not match target database ${String(dbName)} (id: ${String(dbId)}). Cannot import data from different migration states.`,
);
}
this.logger.info(
'✅ Migration validation passed - import data matches target database migration state',
);

View File

@ -1,14 +1,47 @@
import { validateDbTypeForExportEntities } from '../validate-database-type';
import {
supportedTypesForExport,
supportedTypesForImport,
validateDbTypeForExportEntities,
validateDbTypeForImportEntities,
} from '../validate-database-type';
describe('validateDbTypeForExportEntities', () => {
it('should throw an error if the database type is not supported', () => {
expect(() => validateDbTypeForExportEntities('invalid')).toThrow(
'Unsupported database type: invalid. Supported types: sqlite, postgres',
'Unsupported database type: invalid. Supported types: ' + supportedTypesForExport.join(', '),
);
});
it('should not throw an error if the database type is supported', () => {
expect(() => validateDbTypeForExportEntities('sqlite')).not.toThrow();
expect(() => validateDbTypeForExportEntities('postgres')).not.toThrow();
expect(() => validateDbTypeForExportEntities('mysql')).not.toThrow();
expect(() => validateDbTypeForExportEntities('mariadb')).not.toThrow();
expect(() => validateDbTypeForExportEntities('mysqldb')).not.toThrow();
expect(() => validateDbTypeForExportEntities('sqlite-pooled')).not.toThrow();
expect(() => validateDbTypeForExportEntities('sqlite-memory')).not.toThrow();
expect(() => validateDbTypeForExportEntities('postgresql')).not.toThrow();
});
});
describe('validateDbTypeForImportEntities', () => {
it('should throw an error if the database type is not supported', () => {
expect(() => validateDbTypeForImportEntities('invalid')).toThrow(
'Unsupported database type: invalid. Supported types: ' + supportedTypesForImport.join(', '),
);
});
it('should throw an error for MySQL/MariaDB (not supported for imports)', () => {
expect(() => validateDbTypeForImportEntities('mysql')).toThrow();
expect(() => validateDbTypeForImportEntities('mariadb')).toThrow();
expect(() => validateDbTypeForImportEntities('mysqldb')).toThrow();
});
it('should not throw an error if the database type is supported', () => {
expect(() => validateDbTypeForImportEntities('sqlite')).not.toThrow();
expect(() => validateDbTypeForImportEntities('postgres')).not.toThrow();
expect(() => validateDbTypeForImportEntities('sqlite-pooled')).not.toThrow();
expect(() => validateDbTypeForImportEntities('sqlite-memory')).not.toThrow();
expect(() => validateDbTypeForImportEntities('postgresql')).not.toThrow();
});
});

View File

@ -1,11 +1,34 @@
export const supportedTypesForExport = [
'sqlite',
'sqlite-pooled',
'sqlite-memory',
'postgres',
'postgresql',
'mysql',
'mariadb',
'mysqldb',
];
export const supportedTypesForImport = [
'sqlite',
'sqlite-pooled',
'sqlite-memory',
'postgres',
'postgresql',
];
export function validateDbTypeForExportEntities(dbType: string) {
if (
!['sqlite', 'sqlite-pooled', 'sqlite-memory', 'postgres', 'postgresql'].includes(
dbType.toLowerCase(),
)
) {
throw new Error(`Unsupported database type: ${dbType}. Supported types: sqlite, postgres`);
if (!supportedTypesForExport.includes(dbType.toLowerCase())) {
throw new Error(
`Unsupported database type: ${dbType}. Supported types: ${supportedTypesForExport.join(', ')}`,
);
}
}
export const validateDbTypeForImportEntities = validateDbTypeForExportEntities;
export function validateDbTypeForImportEntities(dbType: string) {
if (!supportedTypesForImport.includes(dbType.toLowerCase())) {
throw new Error(
`Unsupported database type: ${dbType}. Supported types: ${supportedTypesForImport.join(', ')}`,
);
}
}