@magic-mustard/sqlsync
Version:
SQLSync simplifies database schema evolution by allowing a declarative approach to table management
150 lines (149 loc) • 7.03 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const split_statement_processor_1 = require("./split.statement.processor");
const namespace_1 = require("./namespace");
describe('SplitStatementProcessor', () => {
let processor;
let mockFile;
let mockAppender;
let mockHandler;
let mockContentBetweenFlags;
beforeEach(() => {
mockFile = {
path: '/path/to/file.sql',
contents: 'SQL content here'
};
mockAppender = {
append: jest.fn(),
getLatestMigrationName: jest.fn().mockReturnValue('migration_1')
};
mockHandler = {
getMigrationState: jest.fn().mockReturnValue({}),
updateMigrationState: jest.fn(),
getNamespaceState: jest.fn().mockReturnValue({}),
updateNamespaceState: jest.fn()
};
mockContentBetweenFlags = {
extractContentBetweenFlags: jest.fn().mockReturnValue([])
};
processor = new split_statement_processor_1.SplitStatementProcessor(mockFile, mockAppender, mockHandler, mockContentBetweenFlags);
});
describe('getSplitStatementBlocks', () => {
it('should extract content between split statement flags', () => {
const mockBlocks = ['block1', 'block2'];
mockContentBetweenFlags.extractContentBetweenFlags.mockReturnValue(mockBlocks);
const result = processor.getSplitStatementBlocks();
expect(result).toEqual(mockBlocks);
expect(mockContentBetweenFlags.extractContentBetweenFlags).toHaveBeenCalledWith(mockFile.contents, mockFile.path, namespace_1.SplitStatements.Flags.start, namespace_1.SplitStatements.Flags.end, false);
});
});
describe('hasSplitStatements', () => {
it('should return true if there are split statement blocks', () => {
mockContentBetweenFlags.extractContentBetweenFlags.mockReturnValue(['block1']);
const result = processor.hasSplitStatements();
expect(result).toBe(true);
});
it('should return false if there are no split statement blocks', () => {
mockContentBetweenFlags.extractContentBetweenFlags.mockReturnValue([]);
const result = processor.hasSplitStatements();
expect(result).toBe(false);
});
it('should return false if an error occurs', () => {
mockContentBetweenFlags.extractContentBetweenFlags.mockImplementation(() => {
throw new Error('Test error');
});
const result = processor.hasSplitStatements();
expect(result).toBe(false);
});
});
describe('process', () => {
it('should process split statement blocks', () => {
const mockBlocks = ['block1', 'block2'];
mockContentBetweenFlags.extractContentBetweenFlags.mockReturnValue(mockBlocks);
jest.spyOn(processor, 'processSplitStatements');
processor.process();
expect(processor.processSplitStatements).toHaveBeenCalledWith(mockBlocks);
});
});
describe('processSplitStatements', () => {
it('should process each block as a single statement', () => {
const mockBlocks = [
'CREATE TRIGGER trigger1 ...',
'CREATE TRIGGER trigger2 ...'
];
const mockState = {
'migration_1': {
[namespace_1.SplitStatements.StateIndex]: []
}
};
mockHandler.getMigrationState.mockReturnValue(mockState);
jest.spyOn(processor, 'cleanStatementBlock').mockImplementation(block => block);
jest.spyOn(processor, 'generateChecksum').mockImplementation(block => block === mockBlocks[0] ? 'checksum1' : 'checksum2');
console.log('Before processing blocks');
processor.processSplitStatements(mockBlocks);
console.log('After processing blocks');
expect(mockAppender.append).toHaveBeenCalledTimes(2);
expect(mockAppender.append).toHaveBeenCalledWith({
token: mockBlocks[0],
filePath: mockFile.path,
checksum: 'checksum1'
});
expect(mockAppender.append).toHaveBeenCalledWith({
token: mockBlocks[1],
filePath: mockFile.path,
checksum: 'checksum2'
});
expect(mockHandler.updateMigrationState).toHaveBeenCalledTimes(2);
});
it('should skip empty statements after cleaning', () => {
const mockBlocks = [' ', 'CREATE TRIGGER trigger1 ...'];
const mockState = {
'migration_1': {
[namespace_1.SplitStatements.StateIndex]: []
}
};
mockHandler.getMigrationState.mockReturnValue(mockState);
jest.spyOn(processor, 'cleanStatementBlock').mockImplementation((block) => block.trim());
jest.spyOn(processor, 'generateChecksum').mockReturnValue('checksum');
processor.processSplitStatements(mockBlocks);
expect(mockAppender.append).toHaveBeenCalledTimes(1);
expect(mockHandler.updateMigrationState).toHaveBeenCalledTimes(1);
});
it('should not add statements that already exist in state', () => {
const mockBlocks = ['CREATE TRIGGER trigger1 ...'];
const mockState = {
'migration_1': {
[namespace_1.SplitStatements.StateIndex]: ['checksum']
}
};
mockHandler.getMigrationState.mockReturnValue(mockState);
jest.spyOn(processor, 'cleanStatementBlock').mockImplementation(block => block);
jest.spyOn(processor, 'generateChecksum').mockReturnValue('checksum');
processor.processSplitStatements(mockBlocks);
expect(mockAppender.append).not.toHaveBeenCalled();
expect(mockHandler.updateMigrationState).not.toHaveBeenCalled();
});
});
describe('cleanStatementBlock', () => {
it('should remove comments and normalize whitespace', () => {
const block = `
-- This is a comment
CREATE TRIGGER trigger1
/* Another comment */
AFTER INSERT ON table1
`;
const expected = 'CREATE TRIGGER trigger1 AFTER INSERT ON table1';
const result = processor.cleanStatementBlock(block);
expect(result).toBe(expected);
});
});
describe('generateChecksum', () => {
it('should generate a SHA256 checksum for the statement', () => {
const statement = 'CREATE TRIGGER trigger1 ...';
const expectedChecksum = expect.any(String);
const result = processor.generateChecksum(statement);
expect(result).toEqual(expectedChecksum);
expect(result).toHaveLength(64); // SHA256 hash length
});
});
});