diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 00000000..8c849748 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,5 @@ +{ + "include": [ + "./src/renderer/**/*" + ] + } \ No newline at end of file diff --git a/src/main/libs/clients/MySQLClient.js b/src/main/libs/clients/MySQLClient.js index 0569f9bb..38648c55 100644 --- a/src/main/libs/clients/MySQLClient.js +++ b/src/main/libs/clients/MySQLClient.js @@ -237,17 +237,27 @@ export class MySQLClient extends AntaresCore { .where({ TABLE_SCHEMA: `= '${schema}'`, TABLE_NAME: `= '${table}'`, REFERENCED_TABLE_NAME: 'IS NOT NULL' }) .run(); + const { rows: extras } = await this + .select('*') + .schema('information_schema') + .from('REFERENTIAL_CONSTRAINTS') + .where({ CONSTRAINT_SCHEMA: `= '${schema}'`, TABLE_NAME: `= '${table}'`, REFERENCED_TABLE_NAME: 'IS NOT NULL' }) + .run(); + return rows.map(field => { + const extra = extras.find(x => x.CONSTRAINT_NAME === field.CONSTRAINT_NAME); return { schema: field.TABLE_SCHEMA, table: field.TABLE_NAME, - column: field.COLUMN_NAME, + field: 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 + refField: field.REFERENCED_COLUMN_NAME, + onUpdate: extra.UPDATE_RULE, + onDelete: extra.DELETE_RULE }; }); } @@ -346,6 +356,7 @@ export class MySQLClient extends AntaresCore { deletions, changes, indexChanges, + foreignChanges, options } = params; @@ -390,6 +401,11 @@ export class MySQLClient extends AntaresCore { } }); + // ADD FOREIGN KEYS + foreignChanges.additions.forEach(addition => { + alterColumns.push(`ADD CONSTRAINT \`${addition.constraintName}\` FOREIGN KEY (\`${addition.field}\`) REFERENCES \`${addition.refTable}\` (\`${addition.refField}\`) ON UPDATE ${addition.onUpdate} ON DELETE ${addition.onDelete}`); + }); + // CHANGE FIELDS changes.forEach(change => { const length = change.numLength || change.charLength || change.datePrecision; @@ -427,6 +443,12 @@ export class MySQLClient extends AntaresCore { } }); + // CHANGE FOREIGN KEYS + foreignChanges.changes.forEach(change => { + alterColumns.push(`DROP FOREIGN KEY \`${change.oldName}\``); + alterColumns.push(`ADD CONSTRAINT \`${change.constraintName}\` FOREIGN KEY (\`${change.field}\`) REFERENCES \`${change.refTable}\` (\`${change.refField}\`) ON UPDATE ${change.onUpdate} ON DELETE ${change.onDelete}`); + }); + // DROP FIELDS deletions.forEach(deletion => { alterColumns.push(`DROP COLUMN \`${deletion.name}\``); @@ -440,6 +462,11 @@ export class MySQLClient extends AntaresCore { alterColumns.push(`DROP INDEX \`${deletion.name}\``); }); + // DROP FOREIGN KEYS + foreignChanges.deletions.forEach(deletion => { + alterColumns.push(`DROP FOREIGN KEY \`${deletion.constraintName}\``); + }); + sql += alterColumns.join(', '); // RENAME diff --git a/src/renderer/components/ForeignKeySelect.vue b/src/renderer/components/ForeignKeySelect.vue index f13e3528..de7b8992 100644 --- a/src/renderer/components/ForeignKeySelect.vue +++ b/src/renderer/components/ForeignKeySelect.vue @@ -1,10 +1,14 @@ @@ -96,13 +109,15 @@ import Tables from '@/ipc-api/Tables'; import WorkspacePropsTable from '@/components/WorkspacePropsTable'; import WorkspacePropsOptionsModal from '@/components/WorkspacePropsOptionsModal'; import WorkspacePropsIndexesModal from '@/components/WorkspacePropsIndexesModal'; +import WorkspacePropsForeignModal from '@/components/WorkspacePropsForeignModal'; export default { name: 'WorkspacePropsTab', components: { WorkspacePropsTable, WorkspacePropsOptionsModal, - WorkspacePropsIndexesModal + WorkspacePropsIndexesModal, + WorkspacePropsForeignModal }, props: { connection: Object, @@ -115,6 +130,7 @@ export default { isSaving: false, isOptionsModal: false, isIndexesModal: false, + isForeignModal: false, isOptionsChanging: false, originalFields: [], localFields: [], @@ -148,6 +164,13 @@ export default { schema () { return this.workspace.breadcrumbs.schema; }, + schemaTables () { + const schemaTables = this.workspace.structure + .filter(schema => schema.name === this.schema) + .map(schema => schema.tables); + + return schemaTables.length ? schemaTables[0].filter(table => table.type === 'table') : []; + }, isChanged () { return JSON.stringify(this.originalFields) !== JSON.stringify(this.localFields) || JSON.stringify(this.originalKeyUsage) !== JSON.stringify(this.localKeyUsage) || @@ -242,8 +265,13 @@ export default { const { status, response } = await Tables.getKeyUsage(params); if (status === 'success') { - this.originalKeyUsage = response; - this.localKeyUsage = JSON.parse(JSON.stringify(response)); + this.originalKeyUsage = response.map(foreign => { + return { + _id: uidGen(), + ...foreign + }; + }); + this.localKeyUsage = JSON.parse(JSON.stringify(this.originalKeyUsage)); } else this.addNotification({ status: 'error', message: response }); @@ -321,6 +349,35 @@ export default { // Index Deletions indexChanges.deletions = this.originalIndexes.filter(index => !localIndexIDs.includes(index._id)); + // FOREIGN KEYS + const foreignChanges = { + additions: [], + changes: [], + deletions: [] + }; + const originalForeignIDs = this.originalKeyUsage.reduce((acc, curr) => [...acc, curr._id], []); + const localForeignIDs = this.localKeyUsage.reduce((acc, curr) => [...acc, curr._id], []); + + // Foreigns Additions + foreignChanges.additions = this.localKeyUsage.filter(foreign => !originalForeignIDs.includes(foreign._id)); + + // Foreigns Changes + this.originalKeyUsage.forEach(originalForeign => { + const lI = this.localKeyUsage.findIndex(localForeign => localForeign._id === originalForeign._id); + if (JSON.stringify(originalForeign) !== JSON.stringify(this.localKeyUsage[lI])) { + if (this.localKeyUsage[lI]) { + foreignChanges.changes.push({ + ...this.localKeyUsage[lI], + oldName: originalForeign.constraintName + }); + } + } + }); + + // Foreigns Deletions + foreignChanges.deletions = this.originalKeyUsage.filter(foreign => !localForeignIDs.includes(foreign._id)); + + // ALTER const params = { uid: this.connection.uid, schema: this.schema, @@ -329,10 +386,11 @@ export default { changes, deletions, indexChanges, + foreignChanges, options }; - try { // Key usage (foreign keys) + try { const { status, response } = await Tables.alterTable(params); if (status === 'success') { @@ -423,6 +481,15 @@ export default { }, indexesUpdate (indexes) { this.localIndexes = indexes; + }, + showForeignModal () { + this.isForeignModal = true; + }, + hideForeignModal () { + this.isForeignModal = false; + }, + foreignsUpdate (foreigns) { + this.localKeyUsage = foreigns; } } }; diff --git a/src/renderer/components/WorkspacePropsTable.vue b/src/renderer/components/WorkspacePropsTable.vue index d6089525..8709a10a 100644 --- a/src/renderer/components/WorkspacePropsTable.vue +++ b/src/renderer/components/WorkspacePropsTable.vue @@ -85,7 +85,7 @@
-
+
{{ $t('word.collation') }}
@@ -104,6 +104,7 @@ :key="row._id" :row="row" :indexes="getIndexes(row.name)" + :foreigns="getForeigns(row.name)" :data-types="dataTypes" @contextmenu="contextMenu" /> @@ -128,6 +129,7 @@ export default { props: { fields: Array, indexes: Array, + foreigns: Array, indexTypes: Array, tabUid: [String, Number], connUid: String, @@ -214,6 +216,13 @@ export default { acc.push(...curr.fields.map(f => ({ name: f, type: curr.type }))); return acc; }, []).filter(f => f.name === field); + }, + getForeigns (field) { + return this.foreigns.reduce((acc, curr) => { + if (curr.field === field) + acc.push(`${curr.refTable}.${curr.refField}`); + return acc; + }, []); } } }; diff --git a/src/renderer/components/WorkspacePropsTableRow.vue b/src/renderer/components/WorkspacePropsTableRow.vue index 22df21d4..4ddb155e 100644 --- a/src/renderer/components/WorkspacePropsTableRow.vue +++ b/src/renderer/components/WorkspacePropsTableRow.vue @@ -15,6 +15,12 @@ class="d-inline-block mdi mdi-key column-key c-help" :class="`key-${index.type}`" /> +
@@ -287,7 +293,8 @@ export default { props: { row: Object, dataTypes: Array, - indexes: Array + indexes: Array, + foreigns: Array }, data () { return { diff --git a/src/renderer/components/WorkspaceQueryTableRow.vue b/src/renderer/components/WorkspaceQueryTableRow.vue index 7ca68875..96d30d65 100644 --- a/src/renderer/components/WorkspaceQueryTableRow.vue +++ b/src/renderer/components/WorkspaceQueryTableRow.vue @@ -20,6 +20,7 @@ class="editable-field" :value.sync="editingContent" :key-usage="getKeyUsage(cKey)" + size="small" @blur="editOFF" />