Add support for editing of resultsets in the Query Tool, if the data can be identified as updatable. Fixes #1760

When a query is run in the Query Tool, check if the source of the columns
can be identified as being from a single table, and that we have all
columns that make up the primary key. If so, consider the resultset to
be editable and allow the user to edit data and add/remove rows in the
grid. Changes to data are saved using SAVEPOINTs as part of any
transaction that's in progress, and rolled back if there are integrity
violations, without otherwise affecting the ongoing transaction.

Implemented by Yosry Muhammad as a Google Summer of Code project.
This commit is contained in:
Yosry Muhammad
2019-07-17 11:45:20 +01:00
committed by Dave Page
parent beb06a4c76
commit 710d520631
38 changed files with 1868 additions and 605 deletions

View File

@@ -23,6 +23,7 @@ describe('#callRenderAfterPoll', () => {
update_msg_history: jasmine.createSpy('SQLEditor.update_msg_history'),
disable_tool_buttons: jasmine.createSpy('SQLEditor.disable_tool_buttons'),
disable_transaction_buttons: jasmine.createSpy('SQLEditor.disable_transaction_buttons'),
reset_data_store: jasmine.createSpy('SQLEditor.reset_data_store'),
query_start_time: new Date(),
};
alertify = jasmine.createSpyObj('alertify', ['success']);
@@ -37,7 +38,7 @@ describe('#callRenderAfterPoll', () => {
sqlEditorSpy.is_query_tool = false;
});
describe('query was successful but had no result to display', () => {
describe('query was successful and have results', () => {
beforeEach(() => {
queryResult = {
rows_affected: 10,
@@ -65,7 +66,7 @@ describe('#callRenderAfterPoll', () => {
});
});
describe('query was successful and have results', () => {
describe('query was successful but had no result to display', () => {
beforeEach(() => {
queryResult = {
rows_affected: 10,
@@ -81,10 +82,16 @@ describe('#callRenderAfterPoll', () => {
expect(sqlEditorSpy.update_msg_history).toHaveBeenCalledWith(
true,
'Some result\n\nQuery returned successfully in 0 msec.',
false
true
);
});
it('resets the changed data store', () => {
callRenderAfterPoll(sqlEditorSpy, alertify, queryResult);
expect(sqlEditorSpy.reset_data_store).toHaveBeenCalled();
});
it('inform sqleditor that the query stopped running', () => {
callRenderAfterPoll(sqlEditorSpy, alertify, queryResult);
@@ -116,7 +123,7 @@ describe('#callRenderAfterPoll', () => {
sqlEditorSpy.is_query_tool = true;
});
describe('query was successful but had no result to display', () => {
describe('query was successful and have results', () => {
beforeEach(() => {
queryResult = {
rows_affected: 10,
@@ -150,7 +157,7 @@ describe('#callRenderAfterPoll', () => {
});
});
describe('query was successful and have results', () => {
describe('query was successful but had no result to display', () => {
beforeEach(() => {
queryResult = {
rows_affected: 10,
@@ -166,10 +173,16 @@ describe('#callRenderAfterPoll', () => {
expect(sqlEditorSpy.update_msg_history).toHaveBeenCalledWith(
true,
'Some result\n\nQuery returned successfully in 0 msec.',
false
true
);
});
it('resets the changed data store', () => {
callRenderAfterPoll(sqlEditorSpy, alertify, queryResult);
expect(sqlEditorSpy.reset_data_store).toHaveBeenCalled();
});
it('inform sqleditor that the query stopped running', () => {
callRenderAfterPoll(sqlEditorSpy, alertify, queryResult);

View File

@@ -14,6 +14,7 @@ import gettext from 'sources/gettext';
describe('the keyboard shortcuts', () => {
const F1_KEY = 112,
F5_KEY = 116,
F6_KEY = 117,
F7_KEY = 118,
F8_KEY = 119,
PERIOD_KEY = 190,
@@ -109,6 +110,14 @@ describe('the keyboard shortcuts', () => {
key_code: 'r',
},
},
save_data: {
alt : false,
shift: false,
control: false,
key: {
key_code: F6_KEY,
},
},
};
queryToolActionsSpy = jasmine.createSpyObj(queryToolActions, [
@@ -121,6 +130,7 @@ describe('the keyboard shortcuts', () => {
'executeQuery',
'executeCommit',
'executeRollback',
'saveDataChanges',
]);
});
@@ -176,6 +186,42 @@ describe('the keyboard shortcuts', () => {
});
});
describe('F6', () => {
describe('when there is not a query already running', () => {
beforeEach(() => {
event.which = F6_KEY;
event.altKey = false;
event.shiftKey = false;
event.ctrlKey = false;
keyboardShortcuts.processEventQueryTool(
sqlEditorControllerSpy, queryToolActionsSpy, event
);
});
it('should save the changed data', () => {
expect(queryToolActionsSpy.saveDataChanges).toHaveBeenCalledWith(sqlEditorControllerSpy);
});
expectEventPropagationToStop();
});
describe('when the query is already running', () => {
it('does nothing', () => {
event.keyCode = F6_KEY;
event.altKey = false;
event.shiftKey = false;
event.ctrlKey = false;
sqlEditorControllerSpy.isQueryRunning.and.returnValue(true);
keyboardShortcuts.processEventQueryTool(
sqlEditorControllerSpy, queryToolActionsSpy, event
);
expect(queryToolActionsSpy.saveDataChanges).not.toHaveBeenCalled();
});
});
});
describe('F7', () => {
describe('when there is not a query already running', () => {
beforeEach(() => {