mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 17:02:49 +03:00
Add support for Graphql Customizations in Browse Rows
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/9845 Co-authored-by: Matthew Goodwin <49927862+m4ttheweric@users.noreply.github.com> GitOrigin-RevId: c9daa739437df20daa3db7ba912dd898274e7303
This commit is contained in:
parent
47a2eaf686
commit
38b3c5258d
@ -15,7 +15,7 @@ import {
|
||||
findTableFromRel,
|
||||
isFeatureSupported,
|
||||
} from '../../../../dataSources';
|
||||
import { getTableConfiguration } from './utils';
|
||||
import { getTableConfiguration, getTableCustomization } from './utils';
|
||||
import { reloadDataSource } from '../../../../metadata/actions';
|
||||
import { updateLimit } from './ViewAction.utils';
|
||||
|
||||
@ -73,11 +73,17 @@ const getConfiguration = (tables, sources) => {
|
||||
)?.configuration;
|
||||
};
|
||||
|
||||
const getCustomization = (tables, sources) => {
|
||||
const { currentDataSource } = tables;
|
||||
return sources?.find(s => s.name === currentDataSource)?.customization;
|
||||
};
|
||||
|
||||
const vMakeRowsRequest = () => {
|
||||
return (dispatch, getState) => {
|
||||
const { tables, metadata } = getState();
|
||||
const sources = metadata.metadataObject?.sources;
|
||||
const tableConfiguration = getTableConfiguration(tables, sources);
|
||||
const dataSourceCustomization = getCustomization(tables, sources);
|
||||
const headers = dataHeaders(getState);
|
||||
dispatch({ type: V_REQUEST_PROGRESS, data: true });
|
||||
|
||||
@ -86,7 +92,11 @@ const vMakeRowsRequest = () => {
|
||||
const options = {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(
|
||||
getTableRowRequestBody({ tables, tableConfiguration })
|
||||
getTableRowRequestBody({
|
||||
tables,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
})
|
||||
),
|
||||
headers,
|
||||
credentials: globalCookiePolicy,
|
||||
@ -117,10 +127,13 @@ const vMakeRowsRequest = () => {
|
||||
return;
|
||||
}
|
||||
const { currentSchema, currentTable: originalTable } = tables;
|
||||
|
||||
const dataSourceCustomization = getCustomization(tables, sources);
|
||||
const { rows, estimatedCount } = processTableRowData(data, {
|
||||
currentSchema,
|
||||
originalTable,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
});
|
||||
|
||||
const currentTable = getState().tables.currentTable;
|
||||
@ -153,12 +166,18 @@ const vMakeExportRequest = () => {
|
||||
const headers = dataHeaders(getState);
|
||||
const sources = metadata.metadataObject?.sources;
|
||||
const tableConfiguration = getConfiguration(tables, sources);
|
||||
const dataSourceCustomization = getCustomization(tables, sources);
|
||||
const { endpoint, getTableRowRequestBody, processTableRowData } =
|
||||
dataSource.generateTableRowRequest();
|
||||
const options = {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(
|
||||
getTableRowRequestBody({ tables, tableConfiguration, isExport: true })
|
||||
getTableRowRequestBody({
|
||||
tables,
|
||||
tableConfiguration,
|
||||
isExport: true,
|
||||
dataSourceCustomization,
|
||||
})
|
||||
),
|
||||
headers,
|
||||
credentials: globalCookiePolicy,
|
||||
@ -195,10 +214,15 @@ const vMakeCountRequest = () => {
|
||||
const { tables, metadata } = getState();
|
||||
const sources = metadata.metadataObject?.sources;
|
||||
const tableConfiguration = getConfiguration(tables, sources);
|
||||
const dataSourceCustomization = getCustomization(tables, sources);
|
||||
|
||||
const { endpoint, getRowsCountRequestBody, processCount } =
|
||||
dataSource.generateRowsCountRequest();
|
||||
const requestBody = getRowsCountRequestBody({ tables, tableConfiguration });
|
||||
const requestBody = getRowsCountRequestBody({
|
||||
tables,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
});
|
||||
|
||||
const options = {
|
||||
method: 'POST',
|
||||
@ -211,11 +235,13 @@ const vMakeCountRequest = () => {
|
||||
data => {
|
||||
if (!isEmpty(data)) {
|
||||
const { currentTable: originalTable, currentSchema } = tables;
|
||||
const dataSourceCustomization = getCustomization(tables, sources);
|
||||
const count = processCount({
|
||||
data,
|
||||
currentSchema,
|
||||
originalTable,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
});
|
||||
const currentTable = getState().tables.currentTable;
|
||||
// in case table has changed before count load
|
||||
@ -281,6 +307,7 @@ const deleteItem = (pkClause, tableName, tableSchema) => {
|
||||
|
||||
const sources = metadata.metadataObject?.sources;
|
||||
const tableConfiguration = getTableConfiguration(tables, sources);
|
||||
const tableCustomization = getTableCustomization(tables, sources);
|
||||
|
||||
const { endpoint, getDeleteRowRequestBody, processDeleteRowData } =
|
||||
dataSource.generateDeleteRowRequest();
|
||||
@ -291,6 +318,7 @@ const deleteItem = (pkClause, tableName, tableSchema) => {
|
||||
source,
|
||||
columnInfo: columnTypeInfo,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization: tableCustomization,
|
||||
});
|
||||
|
||||
const options = {
|
||||
@ -302,11 +330,9 @@ const deleteItem = (pkClause, tableName, tableSchema) => {
|
||||
dispatch(requestAction(endpoint, options)).then(
|
||||
data => {
|
||||
try {
|
||||
const affectedRows = processDeleteRowData(
|
||||
data,
|
||||
tableName,
|
||||
tableSchema
|
||||
);
|
||||
const affectedRows = processDeleteRowData(data, {
|
||||
dataSourceCustomization: tableCustomization,
|
||||
});
|
||||
dispatch(vMakeTableRequests());
|
||||
dispatch(
|
||||
showSuccessNotification(
|
||||
@ -350,6 +376,7 @@ const deleteItems = (pkClauses, tableName, tableSchema) => {
|
||||
|
||||
const sources = metadata.metadataObject?.sources;
|
||||
const tableConfiguration = getTableConfiguration(tables, sources);
|
||||
const tableCustomization = getTableCustomization(tables, sources);
|
||||
|
||||
const reqBody = getBulkDeleteRowRequestBody({
|
||||
pkClauses,
|
||||
@ -358,6 +385,7 @@ const deleteItems = (pkClauses, tableName, tableSchema) => {
|
||||
source,
|
||||
columnInfo: columnTypeInfo,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization: tableCustomization,
|
||||
});
|
||||
|
||||
const options = {
|
||||
@ -370,11 +398,9 @@ const deleteItems = (pkClauses, tableName, tableSchema) => {
|
||||
dispatch(requestAction(endpoint, options)).then(
|
||||
data => {
|
||||
try {
|
||||
const affected = processBulkDeleteRowData(
|
||||
data,
|
||||
tableName,
|
||||
tableSchema
|
||||
);
|
||||
const affected = processBulkDeleteRowData(data, {
|
||||
dataSourceCustomization: tableCustomization,
|
||||
});
|
||||
dispatch(vMakeTableRequests());
|
||||
dispatch(
|
||||
showSuccessNotification(
|
||||
|
@ -18,7 +18,14 @@ export const isTableWithPK = (
|
||||
);
|
||||
};
|
||||
|
||||
export const getTableConfiguration = (
|
||||
const getSource = (
|
||||
currentDataSource: string,
|
||||
sources: MetadataDataSource[]
|
||||
) => {
|
||||
return sources?.find(s => s.name === currentDataSource);
|
||||
};
|
||||
|
||||
const getTable = (
|
||||
tables: ReduxState['tables'],
|
||||
sources: MetadataDataSource[]
|
||||
) => {
|
||||
@ -27,11 +34,26 @@ export const getTableConfiguration = (
|
||||
currentTable: originalTable,
|
||||
currentDataSource,
|
||||
} = tables;
|
||||
return sources
|
||||
?.find(s => s.name === currentDataSource)
|
||||
?.tables.find(
|
||||
t => originalTable === t.table.name && currentSchema === t.table.schema
|
||||
)?.configuration;
|
||||
|
||||
return getSource(currentDataSource, sources)?.tables.find(
|
||||
t => originalTable === t.table.name && currentSchema === t.table.schema
|
||||
);
|
||||
};
|
||||
|
||||
export const getTableConfiguration = (
|
||||
tables: ReduxState['tables'],
|
||||
sources: MetadataDataSource[]
|
||||
) => {
|
||||
return getTable(tables, sources)?.configuration;
|
||||
};
|
||||
|
||||
export const getTableCustomization = (
|
||||
tables: ReduxState['tables'],
|
||||
sources: MetadataDataSource[]
|
||||
) => {
|
||||
const { currentDataSource } = tables;
|
||||
|
||||
return getSource(currentDataSource, sources)?.customization ?? {};
|
||||
};
|
||||
|
||||
export const compareRows = (
|
||||
|
@ -15,7 +15,10 @@ import {
|
||||
import { getEnumOptionsQuery } from '../../../Common/utils/v1QueryUtils';
|
||||
import { isArray, isStringArray } from '../../../Common/utils/jsUtils';
|
||||
import { generateTableDef } from '../../../../dataSources';
|
||||
import { getTableConfiguration } from '../TableBrowseRows/utils';
|
||||
import {
|
||||
getTableConfiguration,
|
||||
getTableCustomization,
|
||||
} from '../TableBrowseRows/utils';
|
||||
|
||||
const E_SET_EDITITEM = 'EditItem/E_SET_EDITITEM';
|
||||
const E_ONGOING_REQ = 'EditItem/E_ONGOING_REQ';
|
||||
@ -35,6 +38,7 @@ const editItem = (tableName, colValues) => {
|
||||
const { tables, metadata } = getState();
|
||||
const sources = metadata.metadataObject?.sources;
|
||||
const tableConfiguration = getTableConfiguration(tables, sources);
|
||||
const tableCustomization = getTableCustomization(tables, sources);
|
||||
/* Type all the values correctly */
|
||||
const { currentSchema, allSchemas, currentDataSource } = tables;
|
||||
|
||||
@ -133,6 +137,7 @@ const editItem = (tableName, colValues) => {
|
||||
source: currentDataSource,
|
||||
tableDef,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization: tableCustomization,
|
||||
set: _setObject,
|
||||
defaultArray: _defaultArray,
|
||||
where: tables.update.pkClause,
|
||||
@ -153,7 +158,12 @@ const editItem = (tableName, colValues) => {
|
||||
showSuccessNotification(
|
||||
'Edited!',
|
||||
'Affected rows: ' +
|
||||
processEditData({ data, tableDef, tableConfiguration })
|
||||
processEditData({
|
||||
data,
|
||||
tableDef,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization: tableCustomization,
|
||||
})
|
||||
)
|
||||
);
|
||||
},
|
||||
|
@ -21,7 +21,10 @@ import {
|
||||
import { makeMigrationCall } from '../DataActions';
|
||||
import toast from 'react-hot-toast/headless';
|
||||
import { getNotificationDetails } from '../../Common/Notification';
|
||||
import { getTableConfiguration } from '../TableBrowseRows/utils';
|
||||
import {
|
||||
getTableConfiguration,
|
||||
getTableCustomization,
|
||||
} from '../TableBrowseRows/utils';
|
||||
|
||||
const I_RESET = 'InsertItem/I_RESET';
|
||||
const I_ONGOING_REQ = 'InsertItem/I_ONGOING_REQ';
|
||||
@ -92,6 +95,7 @@ const insertItem = (tableName, colValues, isMigration = false) => {
|
||||
const tableDef = { name: tableName, schema: currentSchema };
|
||||
const sources = metadata.metadataObject?.sources;
|
||||
const tableConfiguration = getTableConfiguration(tables, sources);
|
||||
const tableCustomization = getTableCustomization(tables, sources);
|
||||
const currentTableInfo = findTable(allSchemas, tableDef);
|
||||
if (!currentTableInfo) return;
|
||||
const columns = currentTableInfo.columns;
|
||||
@ -157,6 +161,7 @@ const insertItem = (tableName, colValues, isMigration = false) => {
|
||||
source: currentDataSource,
|
||||
tableDef,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization: tableCustomization,
|
||||
insertObject,
|
||||
returning,
|
||||
});
|
||||
@ -206,6 +211,7 @@ const insertItem = (tableName, colValues, isMigration = false) => {
|
||||
const { affectedRows, returnedFields } = processInsertData(
|
||||
data,
|
||||
tableConfiguration,
|
||||
tableCustomization,
|
||||
{
|
||||
currentSchema,
|
||||
currentTable: tableName,
|
||||
|
@ -0,0 +1,110 @@
|
||||
import { getQueryWithNamespace, getFullQueryNameBase } from './graphqlUtil';
|
||||
import { formatSdl } from 'format-graphql';
|
||||
|
||||
describe('getQueryWithNamespace', () => {
|
||||
it('returns a query with namespace', () => {
|
||||
const result = getQueryWithNamespace({
|
||||
namespace: 'namespace',
|
||||
queryName: 'query Rows',
|
||||
innerQuery: 'Album { id }',
|
||||
});
|
||||
const expected = formatSdl(`query Rows
|
||||
{
|
||||
namespace {
|
||||
Album { id }
|
||||
}
|
||||
}`);
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('returns a query without namespace', () => {
|
||||
const result = getQueryWithNamespace({
|
||||
namespace: '',
|
||||
queryName: 'query Rows',
|
||||
innerQuery: 'Album { id }',
|
||||
});
|
||||
|
||||
const expected = formatSdl(`query Rows
|
||||
{
|
||||
Album { id }
|
||||
}`);
|
||||
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFullQueryNameBase', () => {
|
||||
it.each`
|
||||
custom_name | custom_root_fields | namespace | prefix | suffix | operation | expected
|
||||
${''} | ${{}} | ${''} | ${''} | ${''} | ${'select'} | ${'Album'}
|
||||
${'alb'} | ${{}} | ${''} | ${''} | ${''} | ${'select'} | ${'alb'}
|
||||
${''} | ${{}} | ${'ns'} | ${''} | ${''} | ${'select'} | ${'Album'}
|
||||
${''} | ${{}} | ${''} | ${'pre_'} | ${''} | ${'select'} | ${'pre_Album'}
|
||||
${''} | ${{}} | ${''} | ${''} | ${'_suf'} | ${'select'} | ${'Album_suf'}
|
||||
${''} | ${{}} | ${'ns'} | ${'pre_'} | ${'_suf'} | ${'select'} | ${'pre_Album_suf'}
|
||||
${''} | ${{ select: 'my_select' }} | ${'ns'} | ${'pre_'} | ${'_suf'} | ${'select'} | ${'pre_my_select_suf'}
|
||||
${'alb'} | ${{ select: 'my_select' }} | ${'ns'} | ${'pre_'} | ${'_suf'} | ${'select'} | ${'pre_my_select_suf'}
|
||||
${''} | ${{}} | ${''} | ${''} | ${''} | ${'update'} | ${'update_Album'}
|
||||
${'alb'} | ${{}} | ${''} | ${''} | ${''} | ${'update'} | ${'update_alb'}
|
||||
${''} | ${{}} | ${'ns'} | ${''} | ${''} | ${'update'} | ${'update_Album'}
|
||||
${''} | ${{}} | ${''} | ${'pre_'} | ${''} | ${'update'} | ${'pre_update_Album'}
|
||||
${''} | ${{}} | ${''} | ${''} | ${'_suf'} | ${'update'} | ${'update_Album_suf'}
|
||||
${''} | ${{}} | ${'ns'} | ${'pre_'} | ${'_suf'} | ${'update'} | ${'pre_update_Album_suf'}
|
||||
${''} | ${{ update: 'my_update' }} | ${'ns'} | ${'pre_'} | ${'_suf'} | ${'update'} | ${'pre_my_update_suf'}
|
||||
${'alb'} | ${{ update: 'my_update' }} | ${'ns'} | ${'pre_'} | ${'_suf'} | ${'select'} | ${'pre_alb_suf'}
|
||||
${''} | ${{}} | ${''} | ${''} | ${''} | ${'select_aggregate'} | ${'Album_aggregate'}
|
||||
${'alb'} | ${{}} | ${''} | ${''} | ${''} | ${'select_aggregate'} | ${'alb_aggregate'}
|
||||
${''} | ${{}} | ${'ns'} | ${''} | ${''} | ${'select_aggregate'} | ${'Album_aggregate'}
|
||||
${''} | ${{}} | ${''} | ${'pre_'} | ${''} | ${'select_aggregate'} | ${'pre_Album_aggregate'}
|
||||
${''} | ${{}} | ${''} | ${''} | ${'_suf'} | ${'select_aggregate'} | ${'Album_aggregate_suf'}
|
||||
${''} | ${{}} | ${'ns'} | ${'pre_'} | ${'_suf'} | ${'select_aggregate'} | ${'pre_Album_aggregate_suf'}
|
||||
${''} | ${{ select_aggregate: 'my_select_aggregate' }} | ${'ns'} | ${'pre_'} | ${'_suf'} | ${'select_aggregate'} | ${'pre_my_select_aggregate_suf'}
|
||||
${'alb'} | ${{ select_aggregate: 'my_select_aggregate' }} | ${'ns'} | ${'pre_'} | ${'_suf'} | ${'select_aggregate'} | ${'pre_my_select_aggregate_suf'}
|
||||
${''} | ${{}} | ${''} | ${''} | ${''} | ${'insert'} | ${'insert_Album'}
|
||||
${'alb'} | ${{}} | ${''} | ${''} | ${''} | ${'insert'} | ${'insert_alb'}
|
||||
${''} | ${{}} | ${'ns'} | ${''} | ${''} | ${'insert'} | ${'insert_Album'}
|
||||
${''} | ${{}} | ${''} | ${'pre_'} | ${''} | ${'insert'} | ${'pre_insert_Album'}
|
||||
${''} | ${{}} | ${''} | ${''} | ${'_suf'} | ${'insert'} | ${'insert_Album_suf'}
|
||||
${''} | ${{}} | ${'ns'} | ${'pre_'} | ${'_suf'} | ${'insert'} | ${'pre_insert_Album_suf'}
|
||||
${''} | ${{ insert: 'my_insert' }} | ${''} | ${''} | ${''} | ${'insert'} | ${'my_insert'}
|
||||
${'alb'} | ${{ insert: 'my_insert' }} | ${'ns'} | ${'pre_'} | ${'_suf'} | ${'insert'} | ${'pre_my_insert_suf'}
|
||||
${''} | ${{}} | ${''} | ${''} | ${''} | ${'delete'} | ${'delete_Album'}
|
||||
${'alb'} | ${{}} | ${''} | ${''} | ${''} | ${'delete'} | ${'delete_alb'}
|
||||
${''} | ${{}} | ${'ns'} | ${''} | ${''} | ${'delete'} | ${'delete_Album'}
|
||||
${''} | ${{}} | ${''} | ${'pre_'} | ${''} | ${'delete'} | ${'pre_delete_Album'}
|
||||
${''} | ${{}} | ${''} | ${''} | ${'_suf'} | ${'delete'} | ${'delete_Album_suf'}
|
||||
${''} | ${{}} | ${'ns'} | ${'pre_'} | ${'_suf'} | ${'delete'} | ${'pre_delete_Album_suf'}
|
||||
${''} | ${{ delete: 'my_delete' }} | ${''} | ${''} | ${''} | ${'delete'} | ${'my_delete'}
|
||||
${'alb'} | ${{ delete: 'my_delete' }} | ${''} | ${''} | ${''} | ${'delete'} | ${'my_delete'}
|
||||
`(
|
||||
'given custom name: "$custom_name", custom_root_fields: $custom_root_fields, namespace: "$namespace", prefix: "$prefix", suffix: "$suffix", operation: "$operation", returns "$expected"',
|
||||
({
|
||||
custom_name,
|
||||
custom_root_fields,
|
||||
namespace,
|
||||
prefix,
|
||||
suffix,
|
||||
operation,
|
||||
expected,
|
||||
}) => {
|
||||
const result = getFullQueryNameBase('public')({
|
||||
tableName: 'Album',
|
||||
schema: 'public',
|
||||
tableConfiguration: {
|
||||
custom_name,
|
||||
custom_root_fields,
|
||||
},
|
||||
dataSourceCustomization: {
|
||||
root_fields: {
|
||||
namespace,
|
||||
prefix,
|
||||
suffix,
|
||||
},
|
||||
},
|
||||
operation,
|
||||
});
|
||||
|
||||
expect(result).toEqual(expected);
|
||||
}
|
||||
);
|
||||
});
|
@ -1,3 +1,4 @@
|
||||
import { formatSdl } from 'format-graphql';
|
||||
import { CustomRootFields, TableConfig } from './../../metadata/types';
|
||||
import {
|
||||
OrderBy,
|
||||
@ -5,6 +6,8 @@ import {
|
||||
} from '../../components/Common/utils/v1QueryUtils';
|
||||
import { ReduxState } from '../../types';
|
||||
import { BaseTableColumn, Relationship, Table } from '../types';
|
||||
import { SourceCustomization } from '../../features/hasura-metadata-types';
|
||||
import { getQueryName } from './utils';
|
||||
|
||||
type Tables = ReduxState['tables'];
|
||||
|
||||
@ -26,6 +29,7 @@ interface GetFullQueryName {
|
||||
tableName: string;
|
||||
schema: string;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
defaultSchema?: string;
|
||||
operation: keyof Omit<
|
||||
CustomRootFields,
|
||||
@ -50,18 +54,31 @@ export const getColQuery = (
|
||||
cols: (string | { name: string; columns: string[] })[],
|
||||
limit: number,
|
||||
relationships: Relationship[],
|
||||
tableConfiguration: TableConfig
|
||||
tableConfiguration: TableConfig,
|
||||
dataSourceCustomization: SourceCustomization
|
||||
): string[] => {
|
||||
return cols.map(c => {
|
||||
return cols.map(column => {
|
||||
const columnConfig = tableConfiguration?.column_config ?? {};
|
||||
if (typeof c === 'string') return columnConfig[c]?.custom_name ?? c;
|
||||
const rel = relationships.find((r: any) => r.rel_name === c.name);
|
||||
return `${columnConfig[c.name]?.custom_name ?? c.name} ${
|
||||
if (typeof column === 'string')
|
||||
return columnConfig[column]?.custom_name ?? column;
|
||||
|
||||
const queryName = getQueryName({
|
||||
column,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
});
|
||||
|
||||
const rel = relationships.find((r: any) => r.rel_name === column.name);
|
||||
return `${queryName} ${
|
||||
rel?.rel_type === 'array' ? `(limit: ${limit})` : ''
|
||||
} {
|
||||
${getColQuery(c.columns, limit, relationships, tableConfiguration).join(
|
||||
'\n'
|
||||
)} }`;
|
||||
${getColQuery(
|
||||
column.columns,
|
||||
limit,
|
||||
relationships,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization
|
||||
).join('\n')} }`;
|
||||
});
|
||||
};
|
||||
|
||||
@ -175,20 +192,53 @@ export const getFullQueryNameBase =
|
||||
tableName,
|
||||
schema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation,
|
||||
}: GetFullQueryName): string => {
|
||||
const prefix = dataSourceCustomization?.root_fields?.prefix ?? '';
|
||||
const suffix = dataSourceCustomization?.root_fields?.suffix ?? '';
|
||||
|
||||
const customRootFields = tableConfiguration?.custom_root_fields ?? {};
|
||||
const customRootField = customRootFields[operation];
|
||||
if (typeof customRootField === 'string') return customRootField;
|
||||
else if (customRootField?.name) return customRootField.name;
|
||||
const withUpdate = operation === 'update' ? 'update_' : '';
|
||||
|
||||
const withUpdate =
|
||||
operation === 'update' && !customRootFields?.update ? 'update_' : '';
|
||||
const withSchema =
|
||||
schema === defaultSchema || tableConfiguration?.custom_name
|
||||
? ''
|
||||
: `${schema}_`;
|
||||
const withAgg = operation === 'select_aggregate' ? `_aggregate` : '';
|
||||
const withDelete = operation === 'delete' ? 'delete_' : '';
|
||||
const withInsert = operation === 'insert' ? 'insert_' : '';
|
||||
const trackedTableName = tableConfiguration?.custom_name || tableName;
|
||||
return `${withDelete}${withUpdate}${withInsert}${withSchema}${trackedTableName}${withAgg}`;
|
||||
const withAgg =
|
||||
operation === 'select_aggregate' && !customRootFields?.select_aggregate
|
||||
? `_aggregate`
|
||||
: '';
|
||||
const withDelete =
|
||||
operation === 'delete' && !customRootFields?.delete ? 'delete_' : '';
|
||||
const withInsert =
|
||||
operation === 'insert' && !customRootFields?.insert ? 'insert_' : '';
|
||||
|
||||
const trackedTableName =
|
||||
customRootField || tableConfiguration?.custom_name || tableName;
|
||||
|
||||
return `${prefix}${withDelete}${withUpdate}${withInsert}${withSchema}${trackedTableName}${withAgg}${suffix}`;
|
||||
};
|
||||
|
||||
type GetQueryWithNamespaceArgs = {
|
||||
queryName: string;
|
||||
namespace: string;
|
||||
innerQuery: string;
|
||||
};
|
||||
|
||||
export const getQueryWithNamespace = ({
|
||||
queryName,
|
||||
namespace,
|
||||
innerQuery,
|
||||
}: GetQueryWithNamespaceArgs) => {
|
||||
return formatSdl(`${queryName}
|
||||
{
|
||||
${namespace ? `${namespace} {` : ''}
|
||||
|
||||
${innerQuery}
|
||||
|
||||
${namespace ? `}` : ''}
|
||||
}`);
|
||||
};
|
||||
|
@ -0,0 +1,89 @@
|
||||
import { getQueryName } from './utils';
|
||||
|
||||
describe('getQueryName', () => {
|
||||
describe('when no customizations', () => {
|
||||
it('returns the query name', () => {
|
||||
const result = getQueryName({
|
||||
column: {
|
||||
name: 'name',
|
||||
columns: ['name'],
|
||||
},
|
||||
tableConfiguration: {
|
||||
custom_name: '',
|
||||
},
|
||||
dataSourceCustomization: {},
|
||||
});
|
||||
expect(result).toEqual('name');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when table configuration is present', () => {
|
||||
it('returns the query name', () => {
|
||||
const result = getQueryName({
|
||||
column: {
|
||||
name: 'name',
|
||||
columns: ['name'],
|
||||
},
|
||||
tableConfiguration: {
|
||||
custom_name: 'my_name',
|
||||
column_config: {
|
||||
name: {
|
||||
custom_name: 'my_custom_name',
|
||||
},
|
||||
},
|
||||
},
|
||||
dataSourceCustomization: {},
|
||||
});
|
||||
expect(result).toEqual('my_custom_name');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when data source customization are present', () => {
|
||||
it('returns the query name', () => {
|
||||
const result = getQueryName({
|
||||
column: {
|
||||
name: 'name',
|
||||
columns: ['name'],
|
||||
},
|
||||
tableConfiguration: {
|
||||
custom_name: '',
|
||||
},
|
||||
dataSourceCustomization: {
|
||||
root_fields: {
|
||||
prefix: 'pre_',
|
||||
suffix: '_suf',
|
||||
namespace: 'ns',
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(result).toEqual('pre_name_suf');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when table configuration and data source customization are present', () => {
|
||||
it('returns the query name', () => {
|
||||
const result = getQueryName({
|
||||
column: {
|
||||
name: 'name',
|
||||
columns: ['name'],
|
||||
},
|
||||
tableConfiguration: {
|
||||
custom_name: 'my_name',
|
||||
column_config: {
|
||||
name: {
|
||||
custom_name: 'my_custom_name',
|
||||
},
|
||||
},
|
||||
},
|
||||
dataSourceCustomization: {
|
||||
root_fields: {
|
||||
prefix: 'pre_',
|
||||
suffix: '_suf',
|
||||
namespace: 'ns',
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(result).toEqual('pre_my_custom_name_suf');
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,37 @@
|
||||
import { SourceCustomization } from '../../features/hasura-metadata-types';
|
||||
import { TableConfig } from '../../metadata/types';
|
||||
|
||||
export type Column = { name: string; columns: string[] };
|
||||
|
||||
export type QueryNameArgs = {
|
||||
column: Column;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
};
|
||||
|
||||
export const getQueryName = ({
|
||||
column,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
}: QueryNameArgs) => {
|
||||
const columnConfig = tableConfiguration?.column_config ?? {};
|
||||
|
||||
const prefix = dataSourceCustomization.root_fields?.prefix ?? '';
|
||||
const suffix = dataSourceCustomization.root_fields?.suffix ?? '';
|
||||
|
||||
const columnName = column.name;
|
||||
|
||||
if (columnConfig[columnName]?.custom_name) {
|
||||
return `${prefix}${columnConfig[columnName].custom_name}${suffix}`;
|
||||
}
|
||||
|
||||
if (columnConfig[columnName]?.custom_name) {
|
||||
return `${prefix}${columnConfig[columnName].custom_name}${suffix}`;
|
||||
}
|
||||
|
||||
if (tableConfiguration?.custom_root_fields?.select) {
|
||||
return `${prefix}${tableConfiguration.custom_root_fields.select}${suffix}`;
|
||||
}
|
||||
|
||||
return `${prefix}${columnName}${suffix}`;
|
||||
};
|
@ -8,6 +8,8 @@ import { TableConfig } from '../../../metadata/types';
|
||||
import { ReduxState } from '../../../types';
|
||||
import { Relationship } from '../../types';
|
||||
import { isEmpty } from '../../../components/Common/utils/jsUtils';
|
||||
import { SourceCustomization } from '../../../features/hasura-metadata-types';
|
||||
import { getQueryName } from '../../common/utils';
|
||||
|
||||
type Tables = ReduxState['tables'];
|
||||
|
||||
@ -64,18 +66,31 @@ const getColQuery = (
|
||||
cols: (string | { name: string; columns: string[] })[],
|
||||
limit: number,
|
||||
relationships: Relationship[],
|
||||
tableConfiguration: TableConfig
|
||||
tableConfiguration: TableConfig,
|
||||
dataSourceCustomization: SourceCustomization
|
||||
): string[] => {
|
||||
return cols.map(c => {
|
||||
return cols.map(column => {
|
||||
const columnConfig = tableConfiguration?.column_config ?? {};
|
||||
if (typeof c === 'string') return columnConfig[c]?.custom_name ?? c;
|
||||
const rel = relationships.find((r: any) => r.rel_name === c.name);
|
||||
return `${columnConfig[c.name]?.custom_name ?? c.name} ${
|
||||
if (typeof column === 'string')
|
||||
return columnConfig[column]?.custom_name ?? column;
|
||||
|
||||
const queryName = getQueryName({
|
||||
column,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
});
|
||||
|
||||
const rel = relationships.find((r: any) => r.rel_name === column.name);
|
||||
return `${queryName} ${
|
||||
rel?.rel_type === 'array' ? `(limit: ${limit})` : ''
|
||||
} {
|
||||
${getColQuery(c.columns, limit, relationships, tableConfiguration).join(
|
||||
'\n'
|
||||
)} }`;
|
||||
${getColQuery(
|
||||
column.columns,
|
||||
limit,
|
||||
relationships,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization
|
||||
).join('\n')} }`;
|
||||
});
|
||||
};
|
||||
|
||||
@ -83,10 +98,12 @@ export const getTableRowRequestBody = ({
|
||||
tables,
|
||||
isExport,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
}: {
|
||||
tables: Tables;
|
||||
isExport?: boolean;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}) => {
|
||||
const {
|
||||
currentTable: originalTable,
|
||||
@ -99,12 +116,14 @@ export const getTableRowRequestBody = ({
|
||||
tableName,
|
||||
schema: currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'select',
|
||||
});
|
||||
const aggregateName = getFullQueryName({
|
||||
tableName,
|
||||
schema: currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'select_aggregate',
|
||||
});
|
||||
const queryBody = ({ clauses, relationshipInfo }: QueryBody) => {
|
||||
@ -114,7 +133,8 @@ export const getTableRowRequestBody = ({
|
||||
view.query.columns,
|
||||
view.curFilter.limit,
|
||||
relationshipInfo,
|
||||
tableConfiguration
|
||||
tableConfiguration,
|
||||
dataSourceCustomization
|
||||
).join('\n')}
|
||||
}
|
||||
${aggregateName} {
|
||||
@ -147,9 +167,15 @@ const processTableRowData = (
|
||||
originalTable: string;
|
||||
currentSchema: string;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}
|
||||
) => {
|
||||
const { originalTable, currentSchema, tableConfiguration } = config!;
|
||||
const {
|
||||
originalTable,
|
||||
currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
} = config!;
|
||||
|
||||
const reversedCustomColumns = Object.entries(
|
||||
tableConfiguration?.column_config ?? {}
|
||||
@ -163,6 +189,7 @@ const processTableRowData = (
|
||||
tableName,
|
||||
schema: currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'select',
|
||||
});
|
||||
const results = data?.data[queryName];
|
||||
@ -192,9 +219,11 @@ export const generateTableRowRequest = () => ({
|
||||
export const getRowsCountRequestBody = ({
|
||||
tables,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
}: {
|
||||
tables: Tables;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}) => {
|
||||
const {
|
||||
currentTable: originalTable,
|
||||
@ -207,6 +236,7 @@ export const getRowsCountRequestBody = ({
|
||||
tableName: originalTable,
|
||||
schema: currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'select_aggregate',
|
||||
});
|
||||
return `query TableCount {
|
||||
@ -239,11 +269,13 @@ const processCount = (c: {
|
||||
currentSchema: string;
|
||||
originalTable: string;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}): number => {
|
||||
const key = getFullQueryName({
|
||||
tableName: c.originalTable,
|
||||
schema: c.currentSchema,
|
||||
tableConfiguration: c.tableConfiguration,
|
||||
dataSourceCustomization: c.dataSourceCustomization,
|
||||
operation: 'select_aggregate',
|
||||
});
|
||||
return c.data?.data?.[key]?.aggregate?.count;
|
||||
|
@ -19,9 +19,11 @@ import {
|
||||
getColQuery,
|
||||
getFullQueryNameBase,
|
||||
getGraphQLQueryBase,
|
||||
getQueryWithNamespace,
|
||||
} from '../../common';
|
||||
import { WhereClause } from '../../../components/Common/utils/v1QueryUtils';
|
||||
import { replaceAllStringOccurrences } from '../../common/index';
|
||||
import { SourceCustomization } from '../../../features/hasura-metadata-types';
|
||||
|
||||
type Tables = ReduxState['tables'];
|
||||
|
||||
@ -107,9 +109,11 @@ const getFullQueryName = getFullQueryNameBase('public');
|
||||
export const getRowsCountRequestBody = ({
|
||||
tables,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
}: {
|
||||
tables: Tables;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}) => {
|
||||
const {
|
||||
currentTable: originalTable,
|
||||
@ -122,15 +126,22 @@ export const getRowsCountRequestBody = ({
|
||||
tableName: originalTable,
|
||||
schema: currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'select_aggregate',
|
||||
});
|
||||
return `query TableCount {
|
||||
${queryName} ${clauses && `(${clauses})`} {
|
||||
aggregate {
|
||||
count
|
||||
|
||||
const namespace = dataSourceCustomization?.root_fields?.namespace ?? '';
|
||||
return getQueryWithNamespace({
|
||||
queryName: 'query TableCount',
|
||||
namespace: namespace,
|
||||
innerQuery: `
|
||||
${queryName} ${clauses && `(${clauses})`} {
|
||||
aggregate {
|
||||
count
|
||||
}
|
||||
}
|
||||
}
|
||||
}`;
|
||||
`,
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
@ -154,11 +165,13 @@ const processCount = (c: {
|
||||
currentSchema: string;
|
||||
originalTable: string;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}): number => {
|
||||
const key = getFullQueryName({
|
||||
tableName: c.originalTable,
|
||||
schema: c.currentSchema,
|
||||
tableConfiguration: c.tableConfiguration,
|
||||
dataSourceCustomization: c.dataSourceCustomization,
|
||||
operation: 'select_aggregate',
|
||||
});
|
||||
return c.data?.data[key]?.aggregate?.count;
|
||||
@ -174,10 +187,12 @@ export const getTableRowRequestBody = ({
|
||||
tables,
|
||||
isExport,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
}: {
|
||||
tables: Tables;
|
||||
isExport?: boolean;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}) => {
|
||||
const {
|
||||
currentTable: originalTable,
|
||||
@ -189,30 +204,41 @@ export const getTableRowRequestBody = ({
|
||||
tableName: originalTable,
|
||||
schema: currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'select',
|
||||
});
|
||||
const aggregateName = getFullQueryName({
|
||||
tableName: originalTable,
|
||||
schema: currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'select_aggregate',
|
||||
});
|
||||
|
||||
const namespace = dataSourceCustomization?.root_fields?.namespace ?? '';
|
||||
const queryBody = ({ clauses, relationshipInfo }: QueryBody) => {
|
||||
return `query TableRows {
|
||||
${queryName} ${clauses && `(${clauses})`} {
|
||||
return getQueryWithNamespace({
|
||||
queryName: 'query TableRows',
|
||||
namespace: namespace,
|
||||
innerQuery: `
|
||||
${queryName} ${clauses && `(${clauses})`}
|
||||
{
|
||||
${getColQuery(
|
||||
view.query.columns,
|
||||
view.curFilter.limit,
|
||||
relationshipInfo,
|
||||
tableConfiguration
|
||||
tableConfiguration,
|
||||
dataSourceCustomization
|
||||
).join('\n')}
|
||||
}
|
||||
${aggregateName} {
|
||||
aggregate {
|
||||
count
|
||||
}
|
||||
}
|
||||
}`;
|
||||
${aggregateName}
|
||||
{
|
||||
aggregate {
|
||||
count
|
||||
}
|
||||
}
|
||||
`,
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
@ -237,10 +263,16 @@ export const processTableRowData = (
|
||||
originalTable: string;
|
||||
currentSchema: string;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}
|
||||
) => {
|
||||
try {
|
||||
const { originalTable, currentSchema, tableConfiguration } = config!;
|
||||
const {
|
||||
originalTable,
|
||||
currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
} = config!;
|
||||
|
||||
const reversedCustomColumns = Object.entries(
|
||||
tableConfiguration?.column_config ?? {}
|
||||
@ -253,9 +285,16 @@ export const processTableRowData = (
|
||||
tableName: originalTable,
|
||||
schema: currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'select',
|
||||
});
|
||||
const results = data?.data[queryName];
|
||||
|
||||
const namespace = dataSourceCustomization?.root_fields?.namespace ?? '';
|
||||
const hasNamespace = !!namespace;
|
||||
|
||||
const results = hasNamespace
|
||||
? data?.data[namespace][queryName]
|
||||
: data?.data[queryName];
|
||||
|
||||
const rows = isEmpty(reversedCustomColumns)
|
||||
? results
|
||||
@ -273,6 +312,7 @@ export const processTableRowData = (
|
||||
tableName: originalTable,
|
||||
schema: currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'select_aggregate',
|
||||
});
|
||||
const estimatedCount =
|
||||
@ -293,7 +333,7 @@ const getInsertRequestBody = (
|
||||
data: Parameters<generateInsertRequestType['getInsertRequestBody']>[0]
|
||||
): ReturnType<generateInsertRequestType['getInsertRequestBody']> => {
|
||||
const { name: tableName, schema } = data.tableDef;
|
||||
const { tableConfiguration } = data;
|
||||
const { tableConfiguration, dataSourceCustomization } = data;
|
||||
const columnConfig = tableConfiguration?.column_config ?? {};
|
||||
|
||||
const processedData: Record<string, any> = {};
|
||||
@ -316,18 +356,21 @@ const getInsertRequestBody = (
|
||||
tableName,
|
||||
schema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'insert',
|
||||
});
|
||||
|
||||
const query = `
|
||||
mutation InsertRow {
|
||||
${queryName}(objects: { ${values} }){
|
||||
returning {
|
||||
${returning}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
const query = getQueryWithNamespace({
|
||||
queryName: 'mutation InsertRow',
|
||||
namespace: dataSourceCustomization?.root_fields?.namespace ?? '',
|
||||
innerQuery: `
|
||||
${queryName}(objects: { ${values} }){
|
||||
returning {
|
||||
${returning}
|
||||
}
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
return {
|
||||
query,
|
||||
@ -342,20 +385,31 @@ type processInsertDataParameter = Parameters<
|
||||
const processInsertData = (
|
||||
result: processInsertDataParameter[0],
|
||||
tableConfiguration: TableConfig,
|
||||
config: processInsertDataParameter[2]
|
||||
dataSourceCustomization: SourceCustomization,
|
||||
config: processInsertDataParameter[3]
|
||||
) => {
|
||||
const { currentTable, currentSchema } = config!;
|
||||
const index = getFullQueryName({
|
||||
tableName: currentTable,
|
||||
schema: currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'insert',
|
||||
});
|
||||
const returnedFields = (
|
||||
result as {
|
||||
data: Record<string, Record<string, any>>;
|
||||
}
|
||||
)?.data?.[index]?.returning;
|
||||
|
||||
const namespace = dataSourceCustomization?.root_fields?.namespace ?? '';
|
||||
const hasNamespace = !!namespace;
|
||||
|
||||
const _result = result as {
|
||||
data: Record<string, Record<string, any>>;
|
||||
};
|
||||
|
||||
const data = hasNamespace
|
||||
? _result?.data[namespace][index]
|
||||
: _result?.data[index];
|
||||
|
||||
const returnedFields = data?.returning;
|
||||
|
||||
return {
|
||||
affectedRows: 1,
|
||||
returnedFields:
|
||||
@ -410,10 +464,11 @@ const getEditRowRequestBody = (data: {
|
||||
source: string;
|
||||
tableDef: QualifiedTable;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
set: Record<string, any>;
|
||||
where: Record<string, any>;
|
||||
}) => {
|
||||
const { tableConfiguration } = data;
|
||||
const { tableConfiguration, dataSourceCustomization } = data;
|
||||
const columnConfig = tableConfiguration?.column_config || {};
|
||||
const whereClause = Object.entries(data.where)
|
||||
.map(
|
||||
@ -437,14 +492,21 @@ const getEditRowRequestBody = (data: {
|
||||
tableName,
|
||||
schema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'update',
|
||||
});
|
||||
|
||||
const query = `mutation {
|
||||
${operationName}(where: {${whereClause}}, _set: {${setClause}}) {
|
||||
affected_rows
|
||||
}
|
||||
}`;
|
||||
const namespace = dataSourceCustomization?.root_fields?.namespace ?? '';
|
||||
const query = getQueryWithNamespace({
|
||||
queryName: 'mutation EditRow',
|
||||
namespace,
|
||||
innerQuery: `
|
||||
${operationName}(where: {${whereClause}}, _set: {${setClause}}) {
|
||||
affected_rows
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
return {
|
||||
query,
|
||||
variables: null,
|
||||
@ -455,19 +517,30 @@ const processEditData = ({
|
||||
data,
|
||||
tableDef,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
}: {
|
||||
tableDef: QualifiedTable;
|
||||
data: any;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}): number => {
|
||||
const { name: tableName, schema } = tableDef;
|
||||
const operationName = getFullQueryName({
|
||||
tableName,
|
||||
schema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'update',
|
||||
});
|
||||
return data?.data[operationName].affected_rows;
|
||||
|
||||
const namespace = dataSourceCustomization?.root_fields?.namespace ?? '';
|
||||
const hasNamespace = !!namespace;
|
||||
|
||||
const results = hasNamespace
|
||||
? data?.data[namespace][operationName]
|
||||
: data?.data[operationName];
|
||||
|
||||
return results.affected_rows;
|
||||
};
|
||||
|
||||
export const generateEditRowRequest = () => ({
|
||||
@ -482,12 +555,14 @@ const getDeleteRowRequestBody = ({
|
||||
schemaName,
|
||||
columnInfo,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
}: {
|
||||
pkClause: WhereClause;
|
||||
tableName: string;
|
||||
schemaName: string;
|
||||
columnInfo: BaseTableColumn[];
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}) => {
|
||||
const columnConfig = tableConfiguration?.column_config || {};
|
||||
|
||||
@ -504,25 +579,46 @@ const getDeleteRowRequestBody = ({
|
||||
tableName,
|
||||
schema: schemaName,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'delete',
|
||||
});
|
||||
const query = `mutation DeleteRows {
|
||||
delete_row: ${identifier}(where: {${args}}) {
|
||||
affected_rows
|
||||
}
|
||||
}`;
|
||||
|
||||
const namespace = dataSourceCustomization?.root_fields?.namespace ?? '';
|
||||
const query = getQueryWithNamespace({
|
||||
queryName: 'mutation DeleteRows',
|
||||
namespace,
|
||||
innerQuery: `
|
||||
delete_row: ${identifier}(where: {${args}}) {
|
||||
affected_rows
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
return {
|
||||
query,
|
||||
variables: null,
|
||||
};
|
||||
};
|
||||
|
||||
const processDeleteRowData = (data: Record<string, any>) => {
|
||||
const processDeleteRowData = (
|
||||
data: Record<string, any>,
|
||||
config: {
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}
|
||||
) => {
|
||||
try {
|
||||
if (data.errors) throw new Error(data.errors[0].message);
|
||||
if (data?.data?.delete_row?.affected_rows) {
|
||||
return data?.data?.delete_row?.affected_rows;
|
||||
}
|
||||
|
||||
const namespace =
|
||||
config.dataSourceCustomization?.root_fields?.namespace ?? '';
|
||||
const hasNamespace = !!namespace;
|
||||
|
||||
const results = hasNamespace
|
||||
? data?.data[namespace]?.delete_row
|
||||
: data?.data?.delete_row;
|
||||
|
||||
if (results?.affected_rows) return results?.affected_rows;
|
||||
|
||||
throw new Error('Invalid response');
|
||||
} catch (err) {
|
||||
if (isConsoleError(err)) {
|
||||
@ -543,18 +639,21 @@ const getBulkDeleteRowRequestBody = ({
|
||||
schemaName,
|
||||
columnInfo,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
}: {
|
||||
pkClauses: WhereClause[];
|
||||
tableName: string;
|
||||
schemaName: string;
|
||||
columnInfo: BaseTableColumn[];
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}) => {
|
||||
const columnConfig = tableConfiguration?.column_config || {};
|
||||
const identifier = getFullQueryName({
|
||||
tableName,
|
||||
schema: schemaName,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'delete',
|
||||
});
|
||||
const topLevelFields = pkClauses.map((pkClause, i) => {
|
||||
@ -570,25 +669,43 @@ const getBulkDeleteRowRequestBody = ({
|
||||
|
||||
return `delete_row_${i}: ${identifier}(where: {${args}}) { affected_rows }`;
|
||||
});
|
||||
const query = `mutation MyMutation {
|
||||
${topLevelFields.join('\n')}
|
||||
}`;
|
||||
|
||||
const namespace = dataSourceCustomization?.root_fields?.namespace ?? '';
|
||||
const query = getQueryWithNamespace({
|
||||
queryName: 'mutation BulkDeleteRows',
|
||||
namespace,
|
||||
innerQuery: `
|
||||
${topLevelFields.join('\n')}
|
||||
`,
|
||||
});
|
||||
|
||||
return {
|
||||
query,
|
||||
variables: null,
|
||||
};
|
||||
};
|
||||
|
||||
const processBulkDeleteRowData = (data: Record<string, any>) => {
|
||||
const processBulkDeleteRowData = (
|
||||
data: Record<string, any>,
|
||||
config: {
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}
|
||||
) => {
|
||||
try {
|
||||
if (data.errors) {
|
||||
throw new Error(data.errors[0].message);
|
||||
}
|
||||
|
||||
if (data.data) {
|
||||
const res = Object.keys(data.data)
|
||||
.filter(key => data.data[key])
|
||||
.map(key => data.data[key].affected_rows)
|
||||
const namespace =
|
||||
config.dataSourceCustomization?.root_fields?.namespace ?? '';
|
||||
const hasNamespace = !!namespace;
|
||||
|
||||
const results = hasNamespace ? data?.data[namespace] : data?.data;
|
||||
|
||||
const res = Object.keys(results)
|
||||
.filter(key => results[key])
|
||||
.map(key => results[key].affected_rows)
|
||||
.reduce((a, b) => a + b, 0);
|
||||
return res;
|
||||
}
|
||||
|
@ -19,9 +19,11 @@ import {
|
||||
getColQuery,
|
||||
getFullQueryNameBase,
|
||||
getGraphQLQueryBase,
|
||||
getQueryWithNamespace,
|
||||
} from '../../common';
|
||||
import { WhereClause } from '../../../components/Common/utils/v1QueryUtils';
|
||||
import { replaceAllStringOccurrences } from '../../common/index';
|
||||
import { SourceCustomization } from '../../../features/hasura-metadata-types';
|
||||
|
||||
type Tables = ReduxState['tables'];
|
||||
|
||||
@ -108,9 +110,11 @@ const getFullQueryName = getFullQueryNameBase('public');
|
||||
export const getRowsCountRequestBody = ({
|
||||
tables,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
}: {
|
||||
tables: Tables;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}) => {
|
||||
const {
|
||||
currentTable: originalTable,
|
||||
@ -123,15 +127,22 @@ export const getRowsCountRequestBody = ({
|
||||
tableName: originalTable,
|
||||
schema: currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'select_aggregate',
|
||||
});
|
||||
return `query TableCount {
|
||||
${queryName} ${clauses && `(${clauses})`} {
|
||||
aggregate {
|
||||
count
|
||||
|
||||
const namespace = dataSourceCustomization?.root_fields?.namespace ?? '';
|
||||
return getQueryWithNamespace({
|
||||
queryName: 'query TableCount',
|
||||
namespace: namespace,
|
||||
innerQuery: `
|
||||
${queryName} ${clauses && `(${clauses})`} {
|
||||
aggregate {
|
||||
count
|
||||
}
|
||||
}
|
||||
}
|
||||
}`;
|
||||
`,
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
@ -155,11 +166,13 @@ const processCount = (c: {
|
||||
currentSchema: string;
|
||||
originalTable: string;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}): number => {
|
||||
const key = getFullQueryName({
|
||||
tableName: c.originalTable,
|
||||
schema: c.currentSchema,
|
||||
tableConfiguration: c.tableConfiguration,
|
||||
dataSourceCustomization: c.dataSourceCustomization,
|
||||
operation: 'select_aggregate',
|
||||
});
|
||||
return c.data?.data[key]?.aggregate?.count;
|
||||
@ -175,10 +188,12 @@ export const getTableRowRequestBody = ({
|
||||
tables,
|
||||
isExport,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
}: {
|
||||
tables: Tables;
|
||||
isExport?: boolean;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}) => {
|
||||
const {
|
||||
currentTable: originalTable,
|
||||
@ -190,30 +205,41 @@ export const getTableRowRequestBody = ({
|
||||
tableName: originalTable,
|
||||
schema: currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'select',
|
||||
});
|
||||
const aggregateName = getFullQueryName({
|
||||
tableName: originalTable,
|
||||
schema: currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'select_aggregate',
|
||||
});
|
||||
|
||||
const namespace = dataSourceCustomization?.root_fields?.namespace ?? '';
|
||||
const queryBody = ({ clauses, relationshipInfo }: QueryBody) => {
|
||||
return `query TableRows {
|
||||
${queryName} ${clauses && `(${clauses})`} {
|
||||
return getQueryWithNamespace({
|
||||
queryName: 'query TableRows',
|
||||
namespace: namespace,
|
||||
innerQuery: `
|
||||
${queryName} ${clauses && `(${clauses})`}
|
||||
{
|
||||
${getColQuery(
|
||||
view.query.columns,
|
||||
view.curFilter.limit,
|
||||
relationshipInfo,
|
||||
tableConfiguration
|
||||
tableConfiguration,
|
||||
dataSourceCustomization
|
||||
).join('\n')}
|
||||
}
|
||||
${aggregateName} {
|
||||
aggregate {
|
||||
count
|
||||
}
|
||||
}
|
||||
}`;
|
||||
${aggregateName}
|
||||
{
|
||||
aggregate {
|
||||
count
|
||||
}
|
||||
}
|
||||
`,
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
@ -238,10 +264,16 @@ export const processTableRowData = (
|
||||
originalTable: string;
|
||||
currentSchema: string;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}
|
||||
) => {
|
||||
try {
|
||||
const { originalTable, currentSchema, tableConfiguration } = config!;
|
||||
const {
|
||||
originalTable,
|
||||
currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
} = config!;
|
||||
|
||||
const reversedCustomColumns = Object.entries(
|
||||
tableConfiguration?.column_config ?? {}
|
||||
@ -254,9 +286,16 @@ export const processTableRowData = (
|
||||
tableName: originalTable,
|
||||
schema: currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'select',
|
||||
});
|
||||
const results = data?.data[queryName];
|
||||
|
||||
const namespace = dataSourceCustomization?.root_fields?.namespace ?? '';
|
||||
const hasNamespace = !!namespace;
|
||||
|
||||
const results = hasNamespace
|
||||
? data?.data[namespace][queryName]
|
||||
: data?.data[queryName];
|
||||
|
||||
const rows = isEmpty(reversedCustomColumns)
|
||||
? results
|
||||
@ -274,6 +313,7 @@ export const processTableRowData = (
|
||||
tableName: originalTable,
|
||||
schema: currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'select_aggregate',
|
||||
});
|
||||
const estimatedCount =
|
||||
@ -294,7 +334,7 @@ const getInsertRequestBody = (
|
||||
data: Parameters<generateInsertRequestType['getInsertRequestBody']>[0]
|
||||
): ReturnType<generateInsertRequestType['getInsertRequestBody']> => {
|
||||
const { name: tableName, schema } = data.tableDef;
|
||||
const { tableConfiguration } = data;
|
||||
const { tableConfiguration, dataSourceCustomization } = data;
|
||||
const columnConfig = tableConfiguration?.column_config ?? {};
|
||||
|
||||
const processedData: Record<string, any> = {};
|
||||
@ -317,18 +357,21 @@ const getInsertRequestBody = (
|
||||
tableName,
|
||||
schema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'insert',
|
||||
});
|
||||
|
||||
const query = `
|
||||
mutation InsertRow {
|
||||
${queryName}(objects: { ${values} }){
|
||||
returning {
|
||||
${returning}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
const query = getQueryWithNamespace({
|
||||
queryName: 'mutation InsertRow',
|
||||
namespace: dataSourceCustomization?.root_fields?.namespace ?? '',
|
||||
innerQuery: `
|
||||
${queryName}(objects: { ${values} }){
|
||||
returning {
|
||||
${returning}
|
||||
}
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
return {
|
||||
query,
|
||||
@ -343,20 +386,30 @@ type processInsertDataParameter = Parameters<
|
||||
const processInsertData = (
|
||||
result: processInsertDataParameter[0],
|
||||
tableConfiguration: TableConfig,
|
||||
config: processInsertDataParameter[2]
|
||||
dataSourceCustomization: SourceCustomization,
|
||||
config: processInsertDataParameter[3]
|
||||
) => {
|
||||
const { currentTable, currentSchema } = config!;
|
||||
const index = getFullQueryName({
|
||||
tableName: currentTable,
|
||||
schema: currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'insert',
|
||||
});
|
||||
const returnedFields = (
|
||||
result as {
|
||||
data: Record<string, Record<string, any>>;
|
||||
}
|
||||
)?.data?.[index]?.returning;
|
||||
|
||||
const namespace = dataSourceCustomization?.root_fields?.namespace ?? '';
|
||||
const hasNamespace = !!namespace;
|
||||
|
||||
const _result = result as {
|
||||
data: Record<string, Record<string, any>>;
|
||||
};
|
||||
|
||||
const data = hasNamespace
|
||||
? _result?.data[namespace][index]
|
||||
: _result?.data[index];
|
||||
|
||||
const returnedFields = data?.returning;
|
||||
return {
|
||||
affectedRows: 1,
|
||||
returnedFields:
|
||||
@ -411,10 +464,11 @@ const getEditRowRequestBody = (data: {
|
||||
source: string;
|
||||
tableDef: QualifiedTable;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
set: Record<string, any>;
|
||||
where: Record<string, any>;
|
||||
}) => {
|
||||
const { tableConfiguration } = data;
|
||||
const { tableConfiguration, dataSourceCustomization } = data;
|
||||
const columnConfig = tableConfiguration?.column_config || {};
|
||||
const whereClause = Object.entries(data.where)
|
||||
.map(
|
||||
@ -438,14 +492,21 @@ const getEditRowRequestBody = (data: {
|
||||
tableName,
|
||||
schema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'update',
|
||||
});
|
||||
|
||||
const query = `mutation {
|
||||
${operationName}(where: {${whereClause}}, _set: {${setClause}}) {
|
||||
affected_rows
|
||||
}
|
||||
}`;
|
||||
const namespace = dataSourceCustomization?.root_fields?.namespace ?? '';
|
||||
const query = getQueryWithNamespace({
|
||||
queryName: 'mutation EditRow',
|
||||
namespace,
|
||||
innerQuery: `
|
||||
${operationName}(where: {${whereClause}}, _set: {${setClause}}) {
|
||||
affected_rows
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
return {
|
||||
query,
|
||||
variables: null,
|
||||
@ -456,19 +517,30 @@ const processEditData = ({
|
||||
data,
|
||||
tableDef,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
}: {
|
||||
tableDef: QualifiedTable;
|
||||
data: any;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}): number => {
|
||||
const { name: tableName, schema } = tableDef;
|
||||
const operationName = getFullQueryName({
|
||||
tableName,
|
||||
schema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'update',
|
||||
});
|
||||
return data?.data[operationName].affected_rows;
|
||||
|
||||
const namespace = dataSourceCustomization?.root_fields?.namespace ?? '';
|
||||
const hasNamespace = !!namespace;
|
||||
|
||||
const results = hasNamespace
|
||||
? data?.data[namespace][operationName]
|
||||
: data?.data[operationName];
|
||||
|
||||
return results.affected_rows;
|
||||
};
|
||||
|
||||
export const generateEditRowRequest = () => ({
|
||||
@ -483,12 +555,14 @@ const getDeleteRowRequestBody = ({
|
||||
schemaName,
|
||||
columnInfo,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
}: {
|
||||
pkClause: WhereClause;
|
||||
tableName: string;
|
||||
schemaName: string;
|
||||
columnInfo: BaseTableColumn[];
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}) => {
|
||||
const columnConfig = tableConfiguration?.column_config || {};
|
||||
|
||||
@ -505,24 +579,45 @@ const getDeleteRowRequestBody = ({
|
||||
tableName,
|
||||
schema: schemaName,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'delete',
|
||||
});
|
||||
const query = `mutation DeleteRows {
|
||||
delete_row: ${identifier}(where: {${args}}) {
|
||||
affected_rows
|
||||
}
|
||||
}`;
|
||||
|
||||
const namespace = dataSourceCustomization?.root_fields?.namespace ?? '';
|
||||
const query = getQueryWithNamespace({
|
||||
queryName: 'mutation DeleteRows',
|
||||
namespace,
|
||||
innerQuery: `
|
||||
delete_row: ${identifier}(where: {${args}}) {
|
||||
affected_rows
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
return {
|
||||
query,
|
||||
variables: null,
|
||||
};
|
||||
};
|
||||
|
||||
const processDeleteRowData = (data: Record<string, any>) => {
|
||||
const processDeleteRowData = (
|
||||
data: Record<string, any>,
|
||||
config: {
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}
|
||||
) => {
|
||||
try {
|
||||
if (data.errors) throw new Error(data.errors[0].message);
|
||||
if (data?.data?.delete_row?.affected_rows)
|
||||
return data?.data?.delete_row?.affected_rows;
|
||||
|
||||
const namespace =
|
||||
config.dataSourceCustomization?.root_fields?.namespace ?? '';
|
||||
const hasNamespace = !!namespace;
|
||||
|
||||
const results = hasNamespace
|
||||
? data?.data[namespace]?.delete_row
|
||||
: data?.data?.delete_row;
|
||||
|
||||
if (results?.affected_rows) return results?.affected_rows;
|
||||
throw new Error('Invalid response');
|
||||
} catch (err) {
|
||||
if (isConsoleError(err)) {
|
||||
@ -543,18 +638,21 @@ const getBulkDeleteRowRequestBody = ({
|
||||
schemaName,
|
||||
columnInfo,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
}: {
|
||||
pkClauses: WhereClause[];
|
||||
tableName: string;
|
||||
schemaName: string;
|
||||
columnInfo: BaseTableColumn[];
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}) => {
|
||||
const columnConfig = tableConfiguration?.column_config || {};
|
||||
const identifier = getFullQueryName({
|
||||
tableName,
|
||||
schema: schemaName,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'delete',
|
||||
});
|
||||
const topLevelFields = pkClauses.map((pkClause, i) => {
|
||||
@ -570,23 +668,41 @@ const getBulkDeleteRowRequestBody = ({
|
||||
|
||||
return `delete_row_${i}: ${identifier}(where: {${args}}) { affected_rows }`;
|
||||
});
|
||||
const query = `mutation MyMutation {
|
||||
${topLevelFields.join('\n')}
|
||||
}`;
|
||||
|
||||
const namespace = dataSourceCustomization?.root_fields?.namespace ?? '';
|
||||
const query = getQueryWithNamespace({
|
||||
queryName: 'mutation BulkDeleteRows',
|
||||
namespace,
|
||||
innerQuery: `
|
||||
${topLevelFields.join('\n')}
|
||||
`,
|
||||
});
|
||||
|
||||
return {
|
||||
query,
|
||||
variables: null,
|
||||
};
|
||||
};
|
||||
|
||||
const processBulkDeleteRowData = (data: Record<string, any>) => {
|
||||
const processBulkDeleteRowData = (
|
||||
data: Record<string, any>,
|
||||
config: {
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}
|
||||
) => {
|
||||
try {
|
||||
if (data.errors) throw new Error(data.errors[0].message);
|
||||
|
||||
if (data.data) {
|
||||
const res = Object.keys(data.data)
|
||||
.filter(key => data.data[key])
|
||||
.map(key => data.data[key].affected_rows)
|
||||
const namespace =
|
||||
config.dataSourceCustomization?.root_fields?.namespace ?? '';
|
||||
const hasNamespace = !!namespace;
|
||||
|
||||
const results = hasNamespace ? data?.data[namespace] : data?.data;
|
||||
|
||||
const res = Object.keys(results)
|
||||
.filter(key => results[key])
|
||||
.map(key => results[key].affected_rows)
|
||||
.reduce((a, b) => a + b, 0);
|
||||
return res;
|
||||
}
|
||||
|
@ -13,15 +13,15 @@ exports[`mssql datasource tests getAddUniqueConstraintSql should generate SQL qu
|
||||
`;
|
||||
|
||||
exports[`mssql datasource tests getAlterColumnCommentSql should generate SQL for modifying column comment 1`] = `
|
||||
"IF EXISTS (SELECT NULL FROM SYS.EXTENDED_PROPERTIES WHERE [major_id] = OBJECT_ID('users') AND [name] = N'column_comment_public_users_id' AND [minor_id] = (SELECT [column_id] FROM SYS.COLUMNS WHERE [name] = 'id' AND [object_id] = OBJECT_ID('users')))
|
||||
EXECUTE sp_dropextendedproperty
|
||||
@name = N'column_comment_public_users_id',
|
||||
"IF EXISTS (SELECT NULL FROM SYS.EXTENDED_PROPERTIES WHERE [major_id] = OBJECT_ID('users') AND [name] = N'column_comment_public_users_id' AND [minor_id] = (SELECT [column_id] FROM SYS.COLUMNS WHERE [name] = 'id' AND [object_id] = OBJECT_ID('users')))
|
||||
EXECUTE sp_dropextendedproperty
|
||||
@name = N'column_comment_public_users_id',
|
||||
@level0type = N'SCHEMA', @level0name = 'public'
|
||||
,@level1type = N'TABLE', @level1name = 'users',@level2type = N'COLUMN', @level2name = 'id';
|
||||
|
||||
exec sys.sp_addextendedproperty
|
||||
@name = N'column_comment_public_users_id',
|
||||
@value = N'user''s comment',
|
||||
exec sys.sp_addextendedproperty
|
||||
@name = N'column_comment_public_users_id',
|
||||
@value = N'user''s comment',
|
||||
@level0type = N'SCHEMA', @level0name = 'public'
|
||||
,@level1type = N'TABLE', @level1name = 'users',@level2type = N'COLUMN', @level2name = 'id'"
|
||||
`;
|
||||
@ -36,7 +36,7 @@ exports[`mssql datasource tests getAlterFKSql should generate SQL query for alte
|
||||
ALTER TABLE "dbo"."user"
|
||||
ADD CONSTRAINT "newConstraint"
|
||||
FOREIGN KEY (id, id2)
|
||||
REFERENCES "dbo"."user1" (id, id2)
|
||||
REFERENCES "dbo"."user1" (id, id2)
|
||||
ON UPDATE cascade ON DELETE cascade;
|
||||
COMMIT transaction;
|
||||
"
|
||||
@ -50,7 +50,7 @@ exports[`mssql datasource tests getAlterFKSql should generate SQL query for alte
|
||||
ALTER TABLE "dbo"."user"
|
||||
ADD CONSTRAINT "newConstraint"
|
||||
FOREIGN KEY (id)
|
||||
REFERENCES "dbo"."user1" (id)
|
||||
REFERENCES "dbo"."user1" (id)
|
||||
ON UPDATE no action ON DELETE cascade;
|
||||
COMMIT transaction;
|
||||
"
|
||||
@ -61,7 +61,7 @@ exports[`mssql datasource tests getAlterPkSql should generate alter operation as
|
||||
ALTER TABLE "public"."users" DROP CONSTRAINT "PK__users__1234";
|
||||
ALTER TABLE "public"."users"
|
||||
ADD CONSTRAINT "PK__users__1234" PRIMARY KEY ("id");
|
||||
|
||||
|
||||
COMMIT TRANSACTION;"
|
||||
`;
|
||||
|
||||
@ -70,7 +70,7 @@ exports[`mssql datasource tests getAlterPkSql should work with multi-column PKs
|
||||
ALTER TABLE "public"."users" DROP CONSTRAINT "test_constraint";
|
||||
ALTER TABLE "public"."users"
|
||||
ADD CONSTRAINT "test_constraint" PRIMARY KEY ("id", "account");
|
||||
|
||||
|
||||
COMMIT TRANSACTION;"
|
||||
`;
|
||||
|
||||
|
@ -528,10 +528,10 @@ FROM sys.objects as obj
|
||||
// add comment to the table using MS_Description property
|
||||
if (tableComment && tableComment !== '') {
|
||||
const commentStr = sqlHandleApostrophe(tableComment);
|
||||
const commentSQL = `EXEC sys.sp_addextendedproperty
|
||||
@name = N'MS_Description',
|
||||
@value = N'${commentStr}',
|
||||
@level0type = N'SCHEMA', @level0name = '${currentSchema}',
|
||||
const commentSQL = `EXEC sys.sp_addextendedproperty
|
||||
@name = N'MS_Description',
|
||||
@value = N'${commentStr}',
|
||||
@level0type = N'SCHEMA', @level0name = '${currentSchema}',
|
||||
@level1type = N'TABLE', @level1name = '${tableName}';`;
|
||||
sqlCreateTable += `${commentSQL}`;
|
||||
}
|
||||
@ -574,7 +574,7 @@ FROM sys.objects as obj
|
||||
ALTER TABLE "${from.schemaName}"."${from.tableName}"
|
||||
ADD CONSTRAINT "${newConstraint}"
|
||||
FOREIGN KEY (${from.columns.join(', ')})
|
||||
REFERENCES "${to.schemaName}"."${to.tableName}" (${to.columns.join(', ')})
|
||||
REFERENCES "${to.schemaName}"."${to.tableName}" (${to.columns.join(', ')})
|
||||
ON UPDATE ${onUpdate} ON DELETE ${onDelete};
|
||||
COMMIT transaction;
|
||||
`;
|
||||
@ -763,7 +763,7 @@ FROM sys.objects as obj
|
||||
ADD CONSTRAINT "${constraintName}" PRIMARY KEY (${selectedPkColumns
|
||||
.map(pkc => `"${pkc}"`)
|
||||
.join(', ')});
|
||||
|
||||
|
||||
COMMIT TRANSACTION;`;
|
||||
},
|
||||
getFunctionDefinitionSql: null,
|
||||
@ -914,13 +914,13 @@ INNER JOIN sys.schemas sch2
|
||||
eventLogTable: QualifiedTable,
|
||||
eventId: string
|
||||
) => {
|
||||
const sql = `SELECT CONVERT(varchar(MAX), original_table.id) AS "id", CONVERT(varchar(MAX), original_table.event_id) AS "event_id",
|
||||
original_table.status, CONVERT(varchar(MAX), original_table.request) AS "request", CONVERT(varchar(MAX), original_table.response) AS "response",
|
||||
CONVERT(varchar(MAX), CAST(original_table.created_at as datetime2)) AS "created_at", CONVERT(varchar(MAX), data_table.id) AS "id", data_table.schema_name,
|
||||
const sql = `SELECT CONVERT(varchar(MAX), original_table.id) AS "id", CONVERT(varchar(MAX), original_table.event_id) AS "event_id",
|
||||
original_table.status, CONVERT(varchar(MAX), original_table.request) AS "request", CONVERT(varchar(MAX), original_table.response) AS "response",
|
||||
CONVERT(varchar(MAX), CAST(original_table.created_at as datetime2)) AS "created_at", CONVERT(varchar(MAX), data_table.id) AS "id", data_table.schema_name,
|
||||
data_table.table_name, data_table.trigger_name, CONVERT(varchar(MAX), data_table.payload) AS "payload", data_table.delivered, data_table.error,
|
||||
data_table.tries, CONVERT(varchar(MAX), CAST(data_table.created_at as datetime2)) AS "created_at", CONVERT(varchar(MAX), data_table.locked) AS "locked",
|
||||
CONVERT(varchar(MAX), data_table.next_retry_at) AS "next_retry_at", data_table.archived
|
||||
FROM "${logTableDef.schema}"."${logTableDef.name}" AS original_table JOIN "${eventLogTable.schema}"."${eventLogTable.name}"
|
||||
data_table.tries, CONVERT(varchar(MAX), CAST(data_table.created_at as datetime2)) AS "created_at", CONVERT(varchar(MAX), data_table.locked) AS "locked",
|
||||
CONVERT(varchar(MAX), data_table.next_retry_at) AS "next_retry_at", data_table.archived
|
||||
FROM "${logTableDef.schema}"."${logTableDef.name}" AS original_table JOIN "${eventLogTable.schema}"."${eventLogTable.name}"
|
||||
AS data_table ON original_table.event_id = data_table.id
|
||||
WHERE original_table.event_id = '${eventId}'
|
||||
ORDER BY original_table.created_at DESC `;
|
||||
@ -998,15 +998,15 @@ WHERE
|
||||
comment,
|
||||
}) => {
|
||||
const commentStr = sqlHandleApostrophe(comment);
|
||||
const dropCommonCommentStatement = `IF EXISTS (SELECT NULL FROM SYS.EXTENDED_PROPERTIES WHERE [major_id] = OBJECT_ID('${tableName}') AND [name] = N'column_comment_${schemaName}_${tableName}_${columnName}' AND [minor_id] = (SELECT [column_id] FROM SYS.COLUMNS WHERE [name] = '${columnName}' AND [object_id] = OBJECT_ID('${tableName}')))
|
||||
EXECUTE sp_dropextendedproperty
|
||||
@name = N'column_comment_${schemaName}_${tableName}_${columnName}',
|
||||
const dropCommonCommentStatement = `IF EXISTS (SELECT NULL FROM SYS.EXTENDED_PROPERTIES WHERE [major_id] = OBJECT_ID('${tableName}') AND [name] = N'column_comment_${schemaName}_${tableName}_${columnName}' AND [minor_id] = (SELECT [column_id] FROM SYS.COLUMNS WHERE [name] = '${columnName}' AND [object_id] = OBJECT_ID('${tableName}')))
|
||||
EXECUTE sp_dropextendedproperty
|
||||
@name = N'column_comment_${schemaName}_${tableName}_${columnName}',
|
||||
@level0type = N'SCHEMA', @level0name = '${schemaName}'
|
||||
`;
|
||||
const commonCommentStatement = `
|
||||
exec sys.sp_addextendedproperty
|
||||
@name = N'column_comment_${schemaName}_${tableName}_${columnName}',
|
||||
@value = N'${commentStr}',
|
||||
exec sys.sp_addextendedproperty
|
||||
@name = N'column_comment_${schemaName}_${tableName}_${columnName}',
|
||||
@value = N'${commentStr}',
|
||||
@level0type = N'SCHEMA', @level0name = '${schemaName}'
|
||||
`;
|
||||
return `${dropCommonCommentStatement},@level1type = N'TABLE', @level1name = '${tableName}',@level2type = N'COLUMN', @level2name = '${columnName}';
|
||||
@ -1022,11 +1022,11 @@ WHERE
|
||||
// https://github.com/hasura/graphql-engine-mono/issues/4641
|
||||
getDataTriggerInvocations: (eventId: string): string => {
|
||||
const eventInvTable = `"hdb_catalog"."event_invocation_logs"`;
|
||||
const sql = `SELECT CONVERT(varchar(MAX), id) AS "id", CONVERT(varchar(MAX), event_id) AS "event_id",
|
||||
status, CONVERT(varchar(MAX), request) AS "request", CONVERT(varchar(MAX), response) AS "response",
|
||||
const sql = `SELECT CONVERT(varchar(MAX), id) AS "id", CONVERT(varchar(MAX), event_id) AS "event_id",
|
||||
status, CONVERT(varchar(MAX), request) AS "request", CONVERT(varchar(MAX), response) AS "response",
|
||||
CONVERT(varchar(MAX), CAST(created_at as datetime2)) AS "created_at"
|
||||
FROM ${eventInvTable}
|
||||
WHERE event_id = '${eventId}'
|
||||
FROM ${eventInvTable}
|
||||
WHERE event_id = '${eventId}'
|
||||
ORDER BY created_at DESC;`;
|
||||
return sql;
|
||||
},
|
||||
|
@ -1,6 +1,7 @@
|
||||
import {
|
||||
getFullQueryNameBase,
|
||||
getGraphQLQueryBase,
|
||||
getQueryWithNamespace,
|
||||
QueryBody,
|
||||
} from './../../common';
|
||||
import { TableConfig } from './../../../metadata/types';
|
||||
@ -8,6 +9,8 @@ import Endpoints from '../../../Endpoints';
|
||||
import { ReduxState } from '../../../types';
|
||||
import { Relationship } from '../../types';
|
||||
import { isEmpty } from '../../../components/Common/utils/jsUtils';
|
||||
import { SourceCustomization } from '../../../features/hasura-metadata-types';
|
||||
import { Column, getQueryName } from '../../common/utils';
|
||||
|
||||
type Tables = ReduxState['tables'];
|
||||
|
||||
@ -81,21 +84,36 @@ const getFormattedValue = (
|
||||
};
|
||||
|
||||
const getColQuery = (
|
||||
cols: (string | { name: string; columns: string[] })[],
|
||||
cols: (string | Column)[],
|
||||
limit: number,
|
||||
relationships: Relationship[],
|
||||
tableConfiguration: TableConfig
|
||||
tableConfiguration: TableConfig,
|
||||
dataSourceCustomization: SourceCustomization
|
||||
): string[] => {
|
||||
return cols.map(c => {
|
||||
return cols.map(column => {
|
||||
const columnConfig = tableConfiguration?.column_config ?? {};
|
||||
if (typeof c === 'string') return columnConfig[c]?.custom_name ?? c;
|
||||
const rel = relationships.find((r: any) => r.rel_name === c.name);
|
||||
return `${columnConfig[c.name]?.custom_name ?? c.name} ${
|
||||
|
||||
if (typeof column === 'string') {
|
||||
return columnConfig[column]?.custom_name ?? column;
|
||||
}
|
||||
|
||||
const queryName = getQueryName({
|
||||
column,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
});
|
||||
|
||||
const rel = relationships.find((r: any) => r.rel_name === column.name);
|
||||
return `${queryName} ${
|
||||
rel?.rel_type === 'array' ? `(limit: ${limit})` : ''
|
||||
} {
|
||||
${getColQuery(c.columns, limit, relationships, tableConfiguration).join(
|
||||
'\n'
|
||||
)} }`;
|
||||
${getColQuery(
|
||||
column.columns,
|
||||
limit,
|
||||
relationships,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization
|
||||
).join('\n')} }`;
|
||||
});
|
||||
};
|
||||
|
||||
@ -103,10 +121,12 @@ export const getTableRowRequestBody = ({
|
||||
tables,
|
||||
isExport,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
}: {
|
||||
tables: Tables;
|
||||
isExport?: boolean;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}) => {
|
||||
const {
|
||||
currentTable: originalTable,
|
||||
@ -119,30 +139,41 @@ export const getTableRowRequestBody = ({
|
||||
tableName,
|
||||
schema: currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'select',
|
||||
});
|
||||
const aggregateName = getFullQueryName({
|
||||
tableName,
|
||||
schema: currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'select_aggregate',
|
||||
});
|
||||
|
||||
const namespace = dataSourceCustomization?.root_fields?.namespace ?? '';
|
||||
const queryBody = ({ clauses, relationshipInfo }: QueryBody) => {
|
||||
return `query TableRows {
|
||||
${queryName} ${clauses && `(${clauses})`} {
|
||||
return getQueryWithNamespace({
|
||||
queryName: 'query TableRows',
|
||||
namespace,
|
||||
innerQuery: `
|
||||
${queryName} ${clauses && `(${clauses})`}
|
||||
{
|
||||
${getColQuery(
|
||||
view.query.columns,
|
||||
view.curFilter.limit,
|
||||
relationshipInfo,
|
||||
tableConfiguration
|
||||
tableConfiguration,
|
||||
dataSourceCustomization
|
||||
).join('\n')}
|
||||
}
|
||||
${aggregateName} {
|
||||
aggregate {
|
||||
count
|
||||
}
|
||||
}
|
||||
}`;
|
||||
${aggregateName}
|
||||
{
|
||||
aggregate {
|
||||
count
|
||||
}
|
||||
}
|
||||
`,
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
@ -167,9 +198,15 @@ const processTableRowData = (
|
||||
originalTable: string;
|
||||
currentSchema: string;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}
|
||||
) => {
|
||||
const { originalTable, currentSchema, tableConfiguration } = config!;
|
||||
const {
|
||||
originalTable,
|
||||
currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
} = config!;
|
||||
|
||||
const reversedCustomColumns = Object.entries(
|
||||
tableConfiguration?.column_config ?? {}
|
||||
@ -183,9 +220,16 @@ const processTableRowData = (
|
||||
tableName,
|
||||
schema: currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'select',
|
||||
});
|
||||
const results = data?.data[queryName];
|
||||
|
||||
const namespace = dataSourceCustomization?.root_fields?.namespace ?? '';
|
||||
const hasNamespace = !!namespace;
|
||||
|
||||
const results = hasNamespace
|
||||
? data?.data[namespace][queryName]
|
||||
: data?.data[queryName];
|
||||
|
||||
const rows = isEmpty(reversedCustomColumns)
|
||||
? results
|
||||
@ -212,9 +256,11 @@ export const generateTableRowRequest = () => ({
|
||||
export const getRowsCountRequestBody = ({
|
||||
tables,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
}: {
|
||||
tables: Tables;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}) => {
|
||||
const {
|
||||
currentTable: originalTable,
|
||||
@ -227,15 +273,22 @@ export const getRowsCountRequestBody = ({
|
||||
tableName: originalTable,
|
||||
schema: currentSchema,
|
||||
tableConfiguration,
|
||||
dataSourceCustomization,
|
||||
operation: 'select_aggregate',
|
||||
});
|
||||
return `query TableCount {
|
||||
${queryName} ${clauses && `(${clauses})`} {
|
||||
aggregate {
|
||||
count
|
||||
|
||||
const namespace = dataSourceCustomization?.root_fields?.namespace ?? '';
|
||||
return getQueryWithNamespace({
|
||||
queryName: 'query TableCount',
|
||||
namespace: namespace,
|
||||
innerQuery: `
|
||||
${queryName} ${clauses && `(${clauses})`} {
|
||||
aggregate {
|
||||
count
|
||||
}
|
||||
}
|
||||
}
|
||||
}`;
|
||||
`,
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
@ -259,12 +312,14 @@ const processCount = (c: {
|
||||
currentSchema: string;
|
||||
originalTable: string;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}): number => {
|
||||
const key = getFullQueryName({
|
||||
tableName: c.originalTable,
|
||||
schema: c.currentSchema,
|
||||
tableConfiguration: c.tableConfiguration,
|
||||
operation: 'select_aggregate',
|
||||
dataSourceCustomization: c.dataSourceCustomization,
|
||||
});
|
||||
return c.data?.data?.[key]?.aggregate?.count;
|
||||
};
|
||||
|
@ -249,7 +249,7 @@ export const getAlterColumnTypeSql = (
|
||||
alter table ${getMySQLNameString(
|
||||
schemaName,
|
||||
tableName
|
||||
)} modify column \`${columnName}\` ${columnType};
|
||||
)} modify column \`${columnName}\` ${columnType};
|
||||
`;
|
||||
|
||||
export const getDropColumnDefaultSql = (
|
||||
|
@ -14,6 +14,7 @@ import {
|
||||
} from '../components/Common/utils/v1QueryUtils';
|
||||
import { Driver } from '.';
|
||||
import { PostgresTrigger } from './services/postgresql/types';
|
||||
import { SourceCustomization } from '../features/hasura-metadata-types';
|
||||
|
||||
export type TableORSchemaArg =
|
||||
| { schemas: string[] }
|
||||
@ -444,6 +445,7 @@ export type generateTableRowRequestType = {
|
||||
tables: Tables;
|
||||
isExport?: boolean;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}) =>
|
||||
| {
|
||||
type: string;
|
||||
@ -464,6 +466,7 @@ export type generateTableRowRequestType = {
|
||||
originalTable: string;
|
||||
currentSchema: string;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}
|
||||
) => { rows: T[]; estimatedCount: number };
|
||||
};
|
||||
@ -475,6 +478,7 @@ export type generateInsertRequestType = {
|
||||
source: string;
|
||||
insertObject: Record<string, any>;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
returning: string[];
|
||||
}) =>
|
||||
| {
|
||||
@ -495,6 +499,7 @@ export type generateInsertRequestType = {
|
||||
| { affectedRows: number; returning: Array<Record<string, any>> }
|
||||
| Record<string, Record<string, any>>,
|
||||
tableConfiguration: TableConfig,
|
||||
dataSourceCustomization: SourceCustomization,
|
||||
config: {
|
||||
currentTable: string;
|
||||
currentSchema: string;
|
||||
@ -513,6 +518,7 @@ export type GenerateRowsCountRequestType = {
|
||||
originalTable: string;
|
||||
currentSchema: string;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}) => number;
|
||||
};
|
||||
|
||||
@ -521,12 +527,14 @@ export type GenerateEditRowRequest = {
|
||||
processEditData: (args: {
|
||||
tableDef: QualifiedTable;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
data: any;
|
||||
}) => number;
|
||||
getEditRowRequestBody: (data: {
|
||||
source: string;
|
||||
tableDef: QualifiedTable;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
set: Record<string, any>;
|
||||
where: Record<string, any>;
|
||||
defaultArray: any[];
|
||||
@ -567,6 +575,7 @@ export type GenerateDeleteRowRequest = {
|
||||
columnInfo: BaseTableColumn[];
|
||||
source: string;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}) =>
|
||||
| {
|
||||
type: string;
|
||||
@ -583,7 +592,12 @@ export type GenerateDeleteRowRequest = {
|
||||
query: string;
|
||||
variables: null;
|
||||
};
|
||||
processDeleteRowData: (data: Record<string, any>) => number;
|
||||
processDeleteRowData: (
|
||||
data: Record<string, any>,
|
||||
config: {
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}
|
||||
) => number;
|
||||
};
|
||||
|
||||
export type GenerateBulkDeleteRowRequest = {
|
||||
@ -595,6 +609,7 @@ export type GenerateBulkDeleteRowRequest = {
|
||||
columnInfo: BaseTableColumn[];
|
||||
source: string;
|
||||
tableConfiguration: TableConfig;
|
||||
dataSourceCustomization: SourceCustomization;
|
||||
}) =>
|
||||
| {
|
||||
type: string;
|
||||
@ -615,7 +630,10 @@ export type GenerateBulkDeleteRowRequest = {
|
||||
query: string;
|
||||
variables: null;
|
||||
};
|
||||
processBulkDeleteRowData: (data: Record<string, any>) => number;
|
||||
processBulkDeleteRowData: (
|
||||
data: Record<string, any>,
|
||||
config: { dataSourceCustomization: SourceCustomization }
|
||||
) => number;
|
||||
};
|
||||
export type ViolationActions =
|
||||
| 'restrict'
|
||||
|
Loading…
Reference in New Issue
Block a user