mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-13 19:33:55 +03:00
console/mssql: support CRUD operations for foreign keys
adds foreign key functionality to mssql tables under Modify Tab. Steps to test: 1. Connect an MSSQL data source. 2. Create a table 3. go to modify page 4. make sure the `Add foreign key `button is visible 5. click on `Add foreign key`, and try to add FK 6. after adding the FK, we will see the `edit` and `remove` button, try to edit and remove the FK Co-authored-by: Vijay Prasanna <11921040+vijayprasanna13@users.noreply.github.com> GitOrigin-RevId: 63be7c4ef909503ac05096a64c686b72f7c47307
This commit is contained in:
parent
205a31de0c
commit
f3643f26ad
@ -4,6 +4,7 @@
|
||||
|
||||
### Bug fixes and improvements
|
||||
(Add entries below in the order of server, console, cli, docs, others)
|
||||
- console: add foreign key CRUD functionality to ms sql server tables
|
||||
|
||||
|
||||
## v2.0.0-beta.1
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { dataSource } from '../../../../dataSources';
|
||||
|
||||
const defaultState = {
|
||||
tableName: null,
|
||||
tableComment: null,
|
||||
@ -13,8 +15,8 @@ const defaultState = {
|
||||
refColumn: '',
|
||||
},
|
||||
],
|
||||
onUpdate: 'restrict',
|
||||
onDelete: 'restrict',
|
||||
onUpdate: dataSource?.violationActions?.[0],
|
||||
onDelete: dataSource?.violationActions?.[0],
|
||||
},
|
||||
],
|
||||
uniqueKeys: [[]],
|
||||
|
@ -74,6 +74,7 @@ const ForeignKeySelector = ({
|
||||
// dispatch action for setting reference table
|
||||
const dispatchSetRefTable = event => {
|
||||
const newFks = JSON.parse(JSON.stringify(foreignKeys));
|
||||
const violiationActions = dataSource?.violationActions;
|
||||
if (newFks[index].refTableName !== event.target.value) {
|
||||
newFks[index].colMappings = [{ column: '', refColumn: '' }];
|
||||
}
|
||||
@ -88,8 +89,8 @@ const ForeignKeySelector = ({
|
||||
refColumn: '',
|
||||
},
|
||||
],
|
||||
onUpdate: 'restrict',
|
||||
onDelete: 'restrict',
|
||||
onUpdate: violiationActions?.[0],
|
||||
onDelete: violiationActions?.[0],
|
||||
});
|
||||
}
|
||||
dispatch(setForeignKeys(newFks));
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { dataSource } from '../../../dataSources';
|
||||
|
||||
const defaultCurFilter = {
|
||||
where: { $and: [{ '': { $eq: '' } }] },
|
||||
limit: 10,
|
||||
@ -89,8 +91,8 @@ const defaultModifyState = {
|
||||
refSchemaName: '',
|
||||
refTableName: '',
|
||||
colMappings: [{ '': '' }],
|
||||
onDelete: 'restrict',
|
||||
onUpdate: 'restrict',
|
||||
onDelete: dataSource?.violationActions?.[0],
|
||||
onUpdate: dataSource?.violationActions?.[0],
|
||||
},
|
||||
],
|
||||
checkConstraintsModify: [],
|
||||
|
@ -14,6 +14,7 @@ import ForeignKeySelector from '../Common/Components/ForeignKeySelector';
|
||||
import { updateSchemaInfo } from '../DataActions';
|
||||
|
||||
import { getConfirmation } from '../../../Common/utils/jsUtils';
|
||||
import { dataSource } from '../../../../dataSources';
|
||||
|
||||
const ForeignKeyEditor = ({
|
||||
tableSchema,
|
||||
@ -43,8 +44,8 @@ const ForeignKeyEditor = ({
|
||||
existingForeignKeys.push({
|
||||
refSchemaName: '',
|
||||
refTableName: '',
|
||||
onUpdate: 'restrict',
|
||||
onDelete: 'restrict',
|
||||
onUpdate: dataSource?.violationActions?.[0],
|
||||
onDelete: dataSource?.violationActions?.[0],
|
||||
colMappings: [{ column: '', refColumn: '' }],
|
||||
});
|
||||
useEffect(() => {
|
||||
|
@ -655,7 +655,7 @@ const saveForeignKeys = (index, tableSchema, columns) => {
|
||||
const requestMsg = 'Saving foreign key...';
|
||||
const successMsg = 'Foreign key saved';
|
||||
const errorMsg = 'Failed setting foreign key';
|
||||
|
||||
const violiationActions = dataSource?.violationActions;
|
||||
const customOnSuccess = () => {
|
||||
if (!constraintName) {
|
||||
const newFks = [...getState().tables.modify.fkModify];
|
||||
@ -666,8 +666,8 @@ const saveForeignKeys = (index, tableSchema, columns) => {
|
||||
{
|
||||
refTableName: '',
|
||||
colMappings: [{ column: '', refColumn: '' }],
|
||||
onUpdate: 'restrict',
|
||||
onDelete: 'restrict',
|
||||
onUpdate: violiationActions?.[0],
|
||||
onDelete: violiationActions?.[0],
|
||||
},
|
||||
])
|
||||
);
|
||||
|
@ -72,6 +72,21 @@ type MSSqlCheckConstraint = {
|
||||
check_definition: string;
|
||||
};
|
||||
|
||||
const modifyViolationType = (fkType: string) => {
|
||||
switch (fkType) {
|
||||
case 'NO_ACTION':
|
||||
return 'no action';
|
||||
case 'CASCADE':
|
||||
return 'cascade';
|
||||
case 'SET_NULL':
|
||||
return 'set null';
|
||||
case 'SET_DEFAULT':
|
||||
return 'set default';
|
||||
default:
|
||||
return fkType;
|
||||
}
|
||||
};
|
||||
|
||||
export const mergeDataMssql = (
|
||||
data: Array<{ result: string[] }>,
|
||||
metadataTables: TableEntry[]
|
||||
@ -183,6 +198,8 @@ export const mergeDataMssql = (
|
||||
...fk,
|
||||
column_mapping: mapping,
|
||||
ref_table_table_schema: fk.ref_table_schema,
|
||||
on_delete: modifyViolationType(fk.on_delete),
|
||||
on_update: modifyViolationType(fk.on_update),
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -0,0 +1,49 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`mssql datasource tests getAlterFKSql should generate SQL query for altering foreign keys with multiple columns 1`] = `
|
||||
"
|
||||
BEGIN transaction;
|
||||
ALTER TABLE \\"dbo\\".\\"user\\"
|
||||
DROP CONSTRAINT IF EXISTS \\"oldConstraint\\";
|
||||
ALTER TABLE \\"dbo\\".\\"user\\"
|
||||
ADD CONSTRAINT \\"newConstraint\\"
|
||||
FOREIGN KEY (id, id2)
|
||||
REFERENCES \\"dbo\\".\\"user1\\" (id, id2)
|
||||
ON UPDATE cascade ON DELETE cascade;
|
||||
COMMIT transaction;
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`mssql datasource tests getAlterFKSql should generate SQL query for altering foreign keys with one column 1`] = `
|
||||
"
|
||||
BEGIN transaction;
|
||||
ALTER TABLE \\"dbo\\".\\"user\\"
|
||||
DROP CONSTRAINT IF EXISTS \\"oldConstraint\\";
|
||||
ALTER TABLE \\"dbo\\".\\"user\\"
|
||||
ADD CONSTRAINT \\"newConstraint\\"
|
||||
FOREIGN KEY (id)
|
||||
REFERENCES \\"dbo\\".\\"user1\\" (id)
|
||||
ON UPDATE no action ON DELETE cascade;
|
||||
COMMIT transaction;
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`mssql datasource tests getCreateFKeySql should generate query for create foreign keys with multiple columns 1`] = `
|
||||
"
|
||||
ALTER TABLE \\"dbo\\".\\"user\\"
|
||||
ADD CONSTRAINT \\"newConstraint\\"
|
||||
FOREIGN KEY (id, id2)
|
||||
REFERENCES \\"dbo\\".\\"user1\\" (id, id2)
|
||||
ON UPDATE cascade ON DELETE cascade"
|
||||
`;
|
||||
|
||||
exports[`mssql datasource tests getCreateFKeySql should generate query for create foreign keys with one columns 1`] = `
|
||||
"
|
||||
ALTER TABLE \\"dbo\\".\\"user\\"
|
||||
ADD CONSTRAINT \\"newConstraint\\"
|
||||
FOREIGN KEY (id)
|
||||
REFERENCES \\"dbo\\".\\"user1\\" (id)
|
||||
ON UPDATE cascade ON DELETE cascade"
|
||||
`;
|
||||
|
||||
exports[`mssql datasource tests getDropConstraintSql should generate query for droping foreign keys 1`] = `"ALTER TABLE \\"schemaName\\".\\"tableName1\\" DROP CONSTRAINT \\"constraintName\\""`;
|
@ -5,6 +5,11 @@ describe('mssql datasource tests', () => {
|
||||
it('should have delete enabled', () => {
|
||||
expect(mssql?.supportedFeatures?.tables?.modify?.delete).toBe(true);
|
||||
});
|
||||
it('should have edit FK enabled', () => {
|
||||
expect(mssql?.supportedFeatures?.tables?.modify?.foreignKeys?.edit).toBe(
|
||||
true
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('getDropSql', () => {
|
||||
const { getDropSql } = mssql;
|
||||
@ -21,4 +26,115 @@ describe('mssql datasource tests', () => {
|
||||
expect(query2).toContain(`DROP table "public"."users";`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAlterFKSql', () => {
|
||||
const { getAlterForeignKeySql } = mssql;
|
||||
it('should generate SQL query for altering foreign keys with one column', () => {
|
||||
const query = getAlterForeignKeySql(
|
||||
{
|
||||
tableName: 'user',
|
||||
schemaName: 'dbo',
|
||||
columns: ['id'],
|
||||
},
|
||||
{
|
||||
tableName: 'user1',
|
||||
schemaName: 'dbo',
|
||||
columns: ['id'],
|
||||
},
|
||||
'oldConstraint',
|
||||
'newConstraint',
|
||||
'no action',
|
||||
'cascade'
|
||||
);
|
||||
expect(query).toContain(`DROP CONSTRAINT IF EXISTS "oldConstraint"`);
|
||||
expect(query).toContain(`ADD CONSTRAINT "newConstraint"`);
|
||||
expect(query).toContain(` ON DELETE cascade`);
|
||||
expect(query).toContain(` ON UPDATE no action`);
|
||||
expect(query).toMatchSnapshot();
|
||||
});
|
||||
it('should generate SQL query for altering foreign keys with multiple columns', () => {
|
||||
const query = getAlterForeignKeySql(
|
||||
{
|
||||
tableName: 'user',
|
||||
schemaName: 'dbo',
|
||||
columns: ['id', 'id2'],
|
||||
},
|
||||
{
|
||||
tableName: 'user1',
|
||||
schemaName: 'dbo',
|
||||
columns: ['id', 'id2'],
|
||||
},
|
||||
'oldConstraint',
|
||||
'newConstraint',
|
||||
'cascade',
|
||||
'cascade'
|
||||
);
|
||||
expect(query).toContain(`DROP CONSTRAINT IF EXISTS "oldConstraint"`);
|
||||
expect(query).toContain(`ADD CONSTRAINT "newConstraint"`);
|
||||
expect(query).toContain('FOREIGN KEY (id, id2)');
|
||||
expect(query).toContain('REFERENCES "dbo"."user1" (id, id2)');
|
||||
expect(query).toContain('ON UPDATE cascade ON DELETE cascade');
|
||||
expect(query).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCreateFKeySql', () => {
|
||||
const { getCreateFKeySql } = mssql;
|
||||
it('should generate query for create foreign keys with multiple columns', () => {
|
||||
const query = getCreateFKeySql(
|
||||
{
|
||||
tableName: 'user',
|
||||
schemaName: 'dbo',
|
||||
columns: ['id', 'id2'],
|
||||
},
|
||||
{
|
||||
tableName: 'user1',
|
||||
schemaName: 'dbo',
|
||||
columns: ['id', 'id2'],
|
||||
},
|
||||
'newConstraint',
|
||||
'cascade',
|
||||
'cascade'
|
||||
);
|
||||
expect(query).toContain('ALTER TABLE "dbo"."user"');
|
||||
expect(query).toContain('ADD CONSTRAINT "newConstraint"');
|
||||
expect(query).toContain('FOREIGN KEY (id, id2)');
|
||||
expect(query).toContain('REFERENCES "dbo"."user1" (id, id2)');
|
||||
expect(query).toContain('ON UPDATE cascade ON DELETE cascade');
|
||||
expect(query).toMatchSnapshot();
|
||||
});
|
||||
it('should generate query for create foreign keys with one columns', () => {
|
||||
const query = getCreateFKeySql(
|
||||
{
|
||||
tableName: 'user',
|
||||
schemaName: 'dbo',
|
||||
columns: ['id'],
|
||||
},
|
||||
{
|
||||
tableName: 'user1',
|
||||
schemaName: 'dbo',
|
||||
columns: ['id'],
|
||||
},
|
||||
'newConstraint',
|
||||
'cascade',
|
||||
'cascade'
|
||||
);
|
||||
expect(query).toContain('ALTER TABLE "dbo"."user"');
|
||||
expect(query).toContain('ADD CONSTRAINT "newConstraint"');
|
||||
expect(query).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDropConstraintSql', () => {
|
||||
const { getDropConstraintSql } = mssql;
|
||||
it('should generate query for droping foreign keys', () => {
|
||||
const query = getDropConstraintSql(
|
||||
'tableName1',
|
||||
'schemaName',
|
||||
'constraintName'
|
||||
);
|
||||
expect(query).toContain(`DROP CONSTRAINT "constraintName"`);
|
||||
expect(query).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -130,7 +130,7 @@ export const supportedFeatures: SupportedFeaturesType = {
|
||||
},
|
||||
foreignKeys: {
|
||||
view: true,
|
||||
edit: false,
|
||||
edit: true,
|
||||
},
|
||||
uniqueKeys: {
|
||||
view: true,
|
||||
@ -480,14 +480,62 @@ FROM sys.objects as obj
|
||||
isTimeoutError: () => {
|
||||
return false;
|
||||
},
|
||||
getAlterForeignKeySql: () => {
|
||||
return '';
|
||||
getAlterForeignKeySql: (
|
||||
from: {
|
||||
tableName: string;
|
||||
schemaName: string;
|
||||
columns: string[];
|
||||
},
|
||||
to: {
|
||||
tableName: string;
|
||||
schemaName: string;
|
||||
columns: string[];
|
||||
},
|
||||
dropConstraint: string,
|
||||
newConstraint: string,
|
||||
onUpdate: string,
|
||||
onDelete: string
|
||||
) => {
|
||||
return `
|
||||
BEGIN transaction;
|
||||
ALTER TABLE "${from.schemaName}"."${from.tableName}"
|
||||
DROP CONSTRAINT IF EXISTS "${dropConstraint}";
|
||||
ALTER TABLE "${from.schemaName}"."${from.tableName}"
|
||||
ADD CONSTRAINT "${newConstraint}"
|
||||
FOREIGN KEY (${from.columns.join(', ')})
|
||||
REFERENCES "${to.schemaName}"."${to.tableName}" (${to.columns.join(', ')})
|
||||
ON UPDATE ${onUpdate} ON DELETE ${onDelete};
|
||||
COMMIT transaction;
|
||||
`;
|
||||
},
|
||||
getCreateFKeySql: () => {
|
||||
return '';
|
||||
getCreateFKeySql: (
|
||||
from: {
|
||||
tableName: string;
|
||||
schemaName: string;
|
||||
columns: string[];
|
||||
},
|
||||
to: {
|
||||
tableName: string;
|
||||
schemaName: string;
|
||||
columns: string[];
|
||||
},
|
||||
newConstraint: string,
|
||||
onUpdate: string,
|
||||
onDelete: string
|
||||
) => {
|
||||
return `
|
||||
ALTER TABLE "${from.schemaName}"."${from.tableName}"
|
||||
ADD CONSTRAINT "${newConstraint}"
|
||||
FOREIGN KEY (${from.columns.join(', ')})
|
||||
REFERENCES "${to.schemaName}"."${to.tableName}" (${to.columns.join(', ')})
|
||||
ON UPDATE ${onUpdate} ON DELETE ${onDelete}`;
|
||||
},
|
||||
getDropConstraintSql: () => {
|
||||
return '';
|
||||
getDropConstraintSql: (
|
||||
tableName: string,
|
||||
schemaName: string,
|
||||
constraintName: string
|
||||
) => {
|
||||
return `ALTER TABLE "${schemaName}"."${tableName}" DROP CONSTRAINT "${constraintName}"`;
|
||||
},
|
||||
getRenameTableSql: () => {
|
||||
return '';
|
||||
@ -679,8 +727,8 @@ INNER JOIN sys.schemas sch2
|
||||
ON tab2.schema_id = sch2.schema_id for json path;
|
||||
`;
|
||||
},
|
||||
getReferenceOption: () => {
|
||||
return '';
|
||||
getReferenceOption: (opt: string) => {
|
||||
return opt;
|
||||
},
|
||||
deleteFunctionSql: () => {
|
||||
return '';
|
||||
|
Loading…
Reference in New Issue
Block a user