diff --git a/src/common/libs/uidGen.js b/src/common/libs/uidGen.js
index f109f023..f8def6b1 100644
--- a/src/common/libs/uidGen.js
+++ b/src/common/libs/uidGen.js
@@ -1,4 +1,8 @@
-'use strict';
-export function uidGen () {
- return Math.random().toString(36).substr(2, 9).toUpperCase();
+/**
+ * @export
+ * @param {String} [prefix]
+ * @returns {String} Unique ID
+ */
+export function uidGen (prefix) {
+ return (prefix ? `${prefix}:` : '') + Math.random().toString(36).substr(2, 9).toUpperCase();
};
diff --git a/src/main/ipc-handlers/tables.js b/src/main/ipc-handlers/tables.js
index d66de0b4..6e9a7361 100644
--- a/src/main/ipc-handlers/tables.js
+++ b/src/main/ipc-handlers/tables.js
@@ -25,6 +25,16 @@ export default (connections) => {
}
});
+ ipcMain.handle('get-key-usage', async (event, { uid, schema, table }) => {
+ try {
+ const result = await InformationSchema.getKeyUsage(connections[uid], schema, table);
+ return { status: 'success', response: result };
+ }
+ catch (err) {
+ return { status: 'error', response: err.toString() };
+ }
+ });
+
ipcMain.handle('updateTableCell', async (event, params) => {
try {
const result = await Tables.updateTableCell(connections[params.uid], params);
diff --git a/src/main/models/InformationSchema.js b/src/main/models/InformationSchema.js
index 130e95bd..2729611f 100644
--- a/src/main/models/InformationSchema.js
+++ b/src/main/models/InformationSchema.js
@@ -38,4 +38,29 @@ export default class {
};
});
}
+
+ static async getKeyUsage (connection, schema, table) {
+ // SELECT * FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA='fep-gprs' AND TABLE_NAME='struttura_macchine' AND REFERENCED_TABLE_NAME IS NOT NULL;
+
+ const { rows } = await connection
+ .select('*')
+ .schema('information_schema')
+ .from('KEY_COLUMN_USAGE')
+ .where({ TABLE_SCHEMA: `= '${schema}'`, TABLE_NAME: `= '${table}'`, REFERENCED_TABLE_NAME: 'IS NOT NULL' })
+ .run();
+
+ return rows.map(field => {
+ return {
+ schema: field.TABLE_SCHEMA,
+ table: field.TABLE_NAME,
+ column: field.COLUMN_NAME,
+ position: field.ORDINAL_POSITION,
+ constraintPosition: field.POSITION_IN_UNIQUE_CONSTRAINT,
+ constraintName: field.CONSTRAINT_NAME,
+ refSchema: field.REFERENCED_TABLE_SCHEMA,
+ refTable: field.REFERENCED_TABLE_NAME,
+ refColumn: field.REFERENCED_COLUMN_NAME
+ };
+ });
+ }
}
diff --git a/src/renderer/components/ModalNewConnection.vue b/src/renderer/components/ModalNewConnection.vue
index 6ff3e998..91ac9169 100644
--- a/src/renderer/components/ModalNewConnection.vue
+++ b/src/renderer/components/ModalNewConnection.vue
@@ -170,7 +170,7 @@ export default {
user: 'root',
password: '',
ask: false,
- uid: uidGen()
+ uid: uidGen('C')
},
toast: {
status: '',
diff --git a/src/renderer/components/Workspace.vue b/src/renderer/components/Workspace.vue
index dea186f4..1db9d182 100644
--- a/src/renderer/components/Workspace.vue
+++ b/src/renderer/components/Workspace.vue
@@ -42,6 +42,7 @@
v-for="tab of queryTabs"
v-show="selectedTab === tab.uid"
:key="tab.uid"
+ :tab-uid="tab.uid"
:connection="connection"
/>
diff --git a/src/renderer/components/WorkspaceQueryTab.vue b/src/renderer/components/WorkspaceQueryTab.vue
index a9bce245..72abc614 100644
--- a/src/renderer/components/WorkspaceQueryTab.vue
+++ b/src/renderer/components/WorkspaceQueryTab.vue
@@ -27,9 +27,10 @@
@@ -53,7 +54,8 @@ export default {
},
mixins: [tableTabs],
props: {
- connection: Object
+ connection: Object,
+ tabUid: String
},
data () {
return {
@@ -61,7 +63,7 @@ export default {
lastQuery: '',
isQuering: false,
results: {},
- fields: []
+ selectedFields: []
};
},
computed: {
@@ -72,37 +74,39 @@ export default {
return this.getWorkspace(this.connection.uid);
},
table () {
- if (this.results.fields.length)
+ if ('fields' in this.results && this.results.fields.length)
return this.results.fields[0].orgTable;
return '';
},
schema () {
- if (this.results.fields.length)
+ if ('fields' in this.results && this.results.fields.length)
return this.results.fields[0].db;
- return '';
+ return this.workspace.breadcrumbs.schema;
}
},
methods: {
...mapActions({
- addNotification: 'notifications/addNotification'
+ addNotification: 'notifications/addNotification',
+ setTabFields: 'workspaces/setTabFields',
+ setTabKeyUsage: 'workspaces/setTabKeyUsage'
}),
async runQuery (query) {
if (!query) return;
this.isQuering = true;
this.results = {};
- this.fields = [];
- let selectedFields = [];
+ this.setTabFields({ cUid: this.connection.uid, tUid: this.tabUid, fields: [] });
- try {
+ try { // Query Data
const params = {
uid: this.connection.uid,
+ schema: this.schema,
query
};
const { status, response } = await Connection.rawQuery(params);
if (status === 'success') {
this.results = response;
- selectedFields = response.fields.map(field => field.orgName);
+ this.selectedFields = response.fields.map(field => field.orgName);
}
else
this.addNotification({ status: 'error', message: response });
@@ -111,7 +115,7 @@ export default {
this.addNotification({ status: 'error', message: err.stack });
}
- try {
+ try { // Table data
const params = {
uid: this.connection.uid,
schema: this.schema,
@@ -119,8 +123,27 @@ export default {
};
const { status, response } = await Tables.getTableColumns(params);
+ if (status === 'success') {
+ const fields = response.filter(field => this.selectedFields.includes(field.name));
+ this.setTabFields({ cUid: this.connection.uid, tUid: this.tabUid, fields });
+ }
+ else
+ this.addNotification({ status: 'error', message: response });
+ }
+ catch (err) {
+ this.addNotification({ status: 'error', message: err.stack });
+ }
+
+ try { // Key usage (foreign keys)
+ const params = {
+ uid: this.connection.uid,
+ schema: this.schema,
+ table: this.table
+ };
+
+ const { status, response } = await Tables.getKeyUsage(params);
if (status === 'success')
- this.fields = response.filter(field => selectedFields.includes(field.name));
+ this.setTabKeyUsage({ cUid: this.connection.uid, tUid: this.tabUid, keyUsage: response });
else
this.addNotification({ status: 'error', message: response });
}
diff --git a/src/renderer/components/WorkspaceQueryTable.vue b/src/renderer/components/WorkspaceQueryTable.vue
index 63f03bdc..df5fb791 100644
--- a/src/renderer/components/WorkspaceQueryTable.vue
+++ b/src/renderer/components/WorkspaceQueryTable.vue
@@ -53,6 +53,7 @@
:key="row._id"
:row="row"
:fields="fields"
+ :key-usage="keyUsage"
class="tr"
:class="{'selected': selectedRows.includes(row._id)}"
@selectRow="selectRow($event, row._id)"
@@ -70,7 +71,7 @@ import { uidGen } from 'common/libs/uidGen';
import BaseVirtualScroll from '@/components/BaseVirtualScroll';
import WorkspaceQueryTableRow from '@/components/WorkspaceQueryTableRow';
import TableContext from '@/components/WorkspaceQueryTableContext';
-import { mapActions } from 'vuex';
+import { mapActions, mapGetters } from 'vuex';
export default {
name: 'WorkspaceQueryTable',
@@ -81,7 +82,7 @@ export default {
},
props: {
results: Object,
- fields: Array
+ tabUid: [String, Number]
},
data () {
return {
@@ -96,6 +97,9 @@ export default {
};
},
computed: {
+ ...mapGetters({
+ getWorkspaceTab: 'workspaces/getWorkspaceTab'
+ }),
primaryField () {
return this.fields.filter(field => ['pri', 'uni'].includes(field.key))[0] || false;
},
@@ -114,6 +118,12 @@ export default {
else
return this.localResults;
},
+ fields () {
+ return this.getWorkspaceTab(this.tabUid) ? this.getWorkspaceTab(this.tabUid).fields : [];
+ },
+ keyUsage () {
+ return this.getWorkspaceTab(this.tabUid) ? this.getWorkspaceTab(this.tabUid).keyUsage : [];
+ },
scrollElement () {
return this.$refs.tableWrapper;
}
diff --git a/src/renderer/components/WorkspaceQueryTableRow.vue b/src/renderer/components/WorkspaceQueryTableRow.vue
index e44766ac..fece3791 100644
--- a/src/renderer/components/WorkspaceQueryTableRow.vue
+++ b/src/renderer/components/WorkspaceQueryTableRow.vue
@@ -178,7 +178,8 @@ export default {
},
props: {
row: Object,
- fields: Array
+ fields: Array,
+ keyUsage: Array
},
data () {
return {
@@ -318,7 +319,7 @@ export default {
editOFF () {
this.isInlineEditor[this.editingField] = false;
let content;
- if (!['blob', 'mediumblob', 'longblob'].includes(this.editingType)) {
+ if (!BLOB.includes(this.editingType)) {
if (this.editingContent === this.$options.filters.typeFormat(this.originalContent, this.editingType)) return;// If not changed
content = this.editingContent;
}
diff --git a/src/renderer/components/WorkspaceTableTab.vue b/src/renderer/components/WorkspaceTableTab.vue
index da1e593e..d408a6fd 100644
--- a/src/renderer/components/WorkspaceTableTab.vue
+++ b/src/renderer/components/WorkspaceTableTab.vue
@@ -33,9 +33,10 @@
@@ -56,6 +57,7 @@ import WorkspaceQueryTable from '@/components/WorkspaceQueryTable';
import ModalNewTableRow from '@/components/ModalNewTableRow';
import { mapGetters, mapActions } from 'vuex';
import tableTabs from '@/mixins/tableTabs';
+// import { TEXT, LONG_TEXT } from 'common/fieldTypes';
export default {
name: 'WorkspaceTableTab',
@@ -70,9 +72,11 @@ export default {
},
data () {
return {
+ tabUid: 1,
isQuering: false,
results: {},
fields: [],
+ keyUsage: [],
lastTable: null,
isAddModal: false
};
@@ -86,6 +90,13 @@ export default {
},
isSelected () {
return this.workspace.selected_tab === 1;
+ },
+ firstTextField () { // TODO: move inside new row modal and row components
+ if (this.fields.length) {
+ const textField = this.fields.find(field => [...TEXT, ...LONG_TEXT].includes(field.type));
+ return textField ? textField.name : '';
+ }
+ return '';
}
},
watch: {
@@ -107,12 +118,15 @@ export default {
},
methods: {
...mapActions({
- addNotification: 'notifications/addNotification'
+ addNotification: 'notifications/addNotification',
+ setTabFields: 'workspaces/setTabFields',
+ setTabKeyUsage: 'workspaces/setTabKeyUsage'
}),
async getTableData () {
if (!this.table) return;
this.isQuering = true;
this.results = {};
+ this.setTabFields({ cUid: this.connection.uid, tUid: this.tabUid, fields: [] });
const params = {
uid: this.connection.uid,
@@ -120,10 +134,12 @@ export default {
table: this.workspace.breadcrumbs.table
};
- try {
+ try { // Columns data
const { status, response } = await Tables.getTableColumns(params);
- if (status === 'success')
- this.fields = response;
+ if (status === 'success') {
+ this.fields = response;// Needed to add new rows
+ this.setTabFields({ cUid: this.connection.uid, tUid: this.tabUid, fields: response });
+ }
else
this.addNotification({ status: 'error', message: response });
}
@@ -131,7 +147,7 @@ export default {
this.addNotification({ status: 'error', message: err.stack });
}
- try {
+ try { // Table data
const { status, response } = await Tables.getTableData(params);
if (status === 'success')
@@ -143,6 +159,19 @@ export default {
this.addNotification({ status: 'error', message: err.stack });
}
+ try { // Key usage (foreign keys)
+ const { status, response } = await Tables.getKeyUsage(params);
+ if (status === 'success') {
+ this.keyUsage = response;// Needed to add new rows
+ this.setTabKeyUsage({ cUid: this.connection.uid, tUid: this.tabUid, keyUsage: response });
+ }
+ else
+ this.addNotification({ status: 'error', message: response });
+ }
+ catch (err) {
+ this.addNotification({ status: 'error', message: err.stack });
+ }
+
this.isQuering = false;
},
reloadTable () {
diff --git a/src/renderer/ipc-api/Tables.js b/src/renderer/ipc-api/Tables.js
index c4975188..1b95d38e 100644
--- a/src/renderer/ipc-api/Tables.js
+++ b/src/renderer/ipc-api/Tables.js
@@ -10,6 +10,10 @@ export default class {
return ipcRenderer.invoke('getTableData', params);
}
+ static getKeyUsage (params) {
+ return ipcRenderer.invoke('get-key-usage', params);
+ }
+
static updateTableCell (params) {
return ipcRenderer.invoke('updateTableCell', params);
}
diff --git a/src/renderer/store/modules/notifications.store.js b/src/renderer/store/modules/notifications.store.js
index 6cfd1308..861a3bd7 100644
--- a/src/renderer/store/modules/notifications.store.js
+++ b/src/renderer/store/modules/notifications.store.js
@@ -20,7 +20,7 @@ export default {
},
actions: {
addNotification ({ commit }, payload) {
- payload.uid = uidGen();
+ payload.uid = uidGen('N');
commit('ADD_NOTIFICATION', payload);
},
removeNotification ({ commit }, uid) {
diff --git a/src/renderer/store/modules/workspaces.store.js b/src/renderer/store/modules/workspaces.store.js
index 32a32855..4ba77fd3 100644
--- a/src/renderer/store/modules/workspaces.store.js
+++ b/src/renderer/store/modules/workspaces.store.js
@@ -28,8 +28,14 @@ export default {
return null;
},
getWorkspace: state => uid => {
- const workspace = state.workspaces.filter(workspace => workspace.uid === uid);
- return workspace.length ? workspace[0] : {};
+ return state.workspaces.find(workspace => workspace.uid === uid);
+ },
+ getWorkspaceTab: (state, getters) => tUid => {
+ if (!getters.getSelected) return;
+ const workspace = state.workspaces.find(workspace => workspace.uid === getters.getSelected);
+ if ('tabs' in workspace)
+ return workspace.tabs.find(tab => tab.uid === tUid);
+ return {};
},
getConnected: state => {
return state.workspaces
@@ -58,9 +64,11 @@ export default {
},
NEW_TAB (state, uid) {
const newTab = {
- uid: uidGen(),
+ uid: uidGen('T'),
selected: false,
- type: 'query'
+ type: 'query',
+ fields: [],
+ keyUsage: []
};
state.workspaces = state.workspaces.map(workspace => {
if (workspace.uid === uid) {
@@ -75,6 +83,40 @@ export default {
},
SELECT_TAB (state, { uid, tab }) {
state.workspaces = state.workspaces.map(workspace => workspace.uid === uid ? { ...workspace, selected_tab: tab } : workspace);
+ },
+ SET_TAB_FIELDS (state, { cUid, tUid, fields }) {
+ state.workspaces = state.workspaces.map(workspace => {
+ if (workspace.uid === cUid) {
+ return {
+ ...workspace,
+ tabs: workspace.tabs.map(tab => {
+ if (tab.uid === tUid)
+ return { ...tab, fields };
+ else
+ return tab;
+ })
+ };
+ }
+ else
+ return workspace;
+ });
+ },
+ SET_TAB_KEY_USAGE (state, { cUid, tUid, keyUsage }) {
+ state.workspaces = state.workspaces.map(workspace => {
+ if (workspace.uid === cUid) {
+ return {
+ ...workspace,
+ tabs: workspace.tabs.map(tab => {
+ if (tab.uid === tUid)
+ return { ...tab, keyUsage };
+ else
+ return tab;
+ })
+ };
+ }
+ else
+ return workspace;
+ });
}
},
actions: {
@@ -115,7 +157,12 @@ export default {
uid,
connected: false,
selected_tab: 0,
- tabs: [{ uid: 1, type: 'table' }],
+ tabs: [{
+ uid: 1,
+ type: 'table',
+ fields: [],
+ keyUsage: []
+ }],
structure: {},
breadcrumbs: {}
};
@@ -133,6 +180,12 @@ export default {
},
selectTab ({ commit }, payload) {
commit('SELECT_TAB', payload);
+ },
+ setTabFields ({ commit }, payload) {
+ commit('SET_TAB_FIELDS', payload);
+ },
+ setTabKeyUsage ({ commit }, payload) {
+ commit('SET_TAB_KEY_USAGE', payload);
}
}
};