mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-06-15 02:49:49 +08:00
🐛 fix(sql-editor): 补全对象定义片段修改模板
- 视图定义以 VIEW 片段开头时转换为 CREATE OR REPLACE VIEW,避免重复拼接 VIEW - 触发器定义以 TRIGGER 或触发时机片段开头时自动补 CREATE OR REPLACE TRIGGER - 增加视图和触发器对象修改模板回归测试
This commit is contained in:
@@ -87,6 +87,7 @@ describe('DefinitionViewer object edit entry', () => {
|
||||
storeState.addTab.mockReset();
|
||||
storeState.setActiveContext.mockReset();
|
||||
storeState.theme = 'light';
|
||||
storeState.connections[0].config.type = 'postgres';
|
||||
backendApp.DBQuery.mockResolvedValue({
|
||||
success: true,
|
||||
data: [{ view_definition: 'SELECT id, name FROM users' }],
|
||||
@@ -117,6 +118,30 @@ describe('DefinitionViewer object edit entry', () => {
|
||||
expect(storeState.addTab.mock.calls[0][0].query).toContain('SELECT id, name FROM users;');
|
||||
});
|
||||
|
||||
it('adds CREATE OR REPLACE without duplicating view fragments returned without ddl prefix', async () => {
|
||||
backendApp.DBQuery.mockResolvedValue({
|
||||
success: true,
|
||||
data: [{ view_definition: 'VIEW reporting.active_users AS\nSELECT id, name FROM users' }],
|
||||
});
|
||||
|
||||
let renderer: any;
|
||||
await act(async () => {
|
||||
renderer = create(<DefinitionViewer tab={createTab()} />);
|
||||
await flushPromises();
|
||||
});
|
||||
|
||||
const button = renderer.root.findAll((node: any) => node.type === 'button' && findButtonText(node).includes('对象修改'))[0];
|
||||
|
||||
await act(async () => {
|
||||
button.props.onClick();
|
||||
});
|
||||
|
||||
const query = storeState.addTab.mock.calls[0][0].query;
|
||||
expect(query).toContain('CREATE OR REPLACE VIEW reporting.active_users AS');
|
||||
expect(query).toContain('SELECT id, name FROM users;');
|
||||
expect(query).not.toContain('AS\nVIEW reporting.active_users AS');
|
||||
});
|
||||
|
||||
it('opens an editable query tab for routine definitions', async () => {
|
||||
backendApp.DBQuery.mockResolvedValue({
|
||||
success: true,
|
||||
|
||||
@@ -48,6 +48,9 @@ const buildEditableDefinitionSql = (tab: TabData, definition: string, objectLabe
|
||||
}
|
||||
|
||||
if (tab.type === 'view-def' && !/^\s*create\b/i.test(normalizedDefinition)) {
|
||||
if (/^\s*view\b/i.test(normalizedDefinition)) {
|
||||
return `${header}${ensureSqlStatementTerminator(normalizedDefinition.replace(/^\s*view\b/i, 'CREATE OR REPLACE VIEW'))}`;
|
||||
}
|
||||
return `${header}CREATE OR REPLACE VIEW ${objectName} AS\n${ensureSqlStatementTerminator(normalizedDefinition)}`;
|
||||
}
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ describe('TriggerViewer object edit entry', () => {
|
||||
beforeEach(() => {
|
||||
storeState.addTab.mockReset();
|
||||
storeState.setActiveContext.mockReset();
|
||||
storeState.connections[0].config.type = 'postgres';
|
||||
backendApp.DBQuery.mockResolvedValue({
|
||||
success: true,
|
||||
data: [{ trigger_definition: 'CREATE TRIGGER users_bi BEFORE INSERT ON audit.users EXECUTE FUNCTION audit.audit_users();' }],
|
||||
@@ -113,4 +114,60 @@ describe('TriggerViewer object edit entry', () => {
|
||||
query: expect.stringContaining('CREATE TRIGGER users_bi BEFORE INSERT'),
|
||||
}));
|
||||
});
|
||||
|
||||
it('adds CREATE OR REPLACE for trigger source snippets returned without ddl prefix', async () => {
|
||||
storeState.connections[0].config.type = 'oracle';
|
||||
backendApp.DBQuery.mockResolvedValue({
|
||||
success: true,
|
||||
data: [{
|
||||
TRIGGER_BODY: 'TRIGGER users_bi\nBEFORE INSERT ON audit.users\nFOR EACH ROW\nBEGIN\n :NEW.created_at := SYSDATE;\nEND;',
|
||||
}],
|
||||
});
|
||||
|
||||
let renderer: any;
|
||||
await act(async () => {
|
||||
renderer = create(<TriggerViewer tab={tab} />);
|
||||
await flushPromises();
|
||||
});
|
||||
|
||||
const button = renderer.root.findAll((node: any) => node.type === 'button' && findButtonText(node).includes('对象修改'))[0];
|
||||
|
||||
await act(async () => {
|
||||
button.props.onClick();
|
||||
});
|
||||
|
||||
const query = storeState.addTab.mock.calls[0][0].query;
|
||||
expect(query).toContain('CREATE OR REPLACE TRIGGER users_bi');
|
||||
expect(query).toContain('BEFORE INSERT ON audit.users');
|
||||
expect(query).toContain(':NEW.created_at := SYSDATE;');
|
||||
expect(query).not.toContain('请补全 CREATE TRIGGER 语句');
|
||||
});
|
||||
|
||||
it('adds trigger name for trigger body snippets returned without ddl header', async () => {
|
||||
storeState.connections[0].config.type = 'oracle';
|
||||
backendApp.DBQuery.mockResolvedValue({
|
||||
success: true,
|
||||
data: [{
|
||||
TRIGGER_BODY: 'BEFORE UPDATE ON audit.users\nFOR EACH ROW\nBEGIN\n :NEW.updated_at := SYSDATE;\nEND;',
|
||||
}],
|
||||
});
|
||||
|
||||
let renderer: any;
|
||||
await act(async () => {
|
||||
renderer = create(<TriggerViewer tab={tab} />);
|
||||
await flushPromises();
|
||||
});
|
||||
|
||||
const button = renderer.root.findAll((node: any) => node.type === 'button' && findButtonText(node).includes('对象修改'))[0];
|
||||
|
||||
await act(async () => {
|
||||
button.props.onClick();
|
||||
});
|
||||
|
||||
const query = storeState.addTab.mock.calls[0][0].query;
|
||||
expect(query).toContain('CREATE OR REPLACE TRIGGER audit.users_bi');
|
||||
expect(query).toContain('BEFORE UPDATE ON audit.users');
|
||||
expect(query).toContain(':NEW.updated_at := SYSDATE;');
|
||||
expect(query).not.toContain('请补全 CREATE TRIGGER 语句');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -29,6 +29,12 @@ const buildEditableTriggerSql = (triggerName: string, triggerDefinition: string)
|
||||
if (/^\s*create\s+(?:or\s+replace\s+)?trigger\b/i.test(normalizedDefinition)) {
|
||||
return `${header}${ensureSqlStatementTerminator(normalizedDefinition)}`;
|
||||
}
|
||||
if (/^\s*trigger\b/i.test(normalizedDefinition)) {
|
||||
return `${header}${ensureSqlStatementTerminator(normalizedDefinition.replace(/^\s*trigger\b/i, 'CREATE OR REPLACE TRIGGER'))}`;
|
||||
}
|
||||
if (/^\s*(?:before|after|instead\s+of)\b/i.test(normalizedDefinition)) {
|
||||
return `${header}${ensureSqlStatementTerminator(`CREATE OR REPLACE TRIGGER ${normalizedName}\n${normalizedDefinition}`)}`;
|
||||
}
|
||||
return `${header}-- 当前数据源仅返回触发器定义片段,请补全 CREATE TRIGGER 语句后执行\n${ensureSqlStatementTerminator(normalizedDefinition)}`;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user