[hotfix ]fix: event mapping query race condition (#8258)

* fix: event mapping query race condition

* fixes: duplication dq from lds and gds
This commit is contained in:
Arpit 2023-12-07 18:54:05 +05:30 committed by GitHub
parent c20ec780d7
commit 17983ffb04
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 266 additions and 243 deletions

View file

@ -357,192 +357,203 @@ export class AppImportExportService {
appResourceMappings.appDefaultEnvironmentMapping = appDefaultEnvironmentMapping; appResourceMappings.appDefaultEnvironmentMapping = appDefaultEnvironmentMapping;
appResourceMappings.appVersionMapping = appVersionMapping; appResourceMappings.appVersionMapping = appVersionMapping;
appResourceMappings = await this.setupAppVersionAssociations( /**
manager, * as multiple operations are run within a single transaction using the transaction method provides a convenient way to handle transactions.
importingAppVersions, * The transaction will automatically committed when the function completes without throwing an error.
user, * If an error occurs during the function execution, the transaction will rolled back.
appResourceMappings, */
externalResourceMappings,
importingAppEnvironments,
importingDataSources,
importingDataSourceOptions,
importingDataQueries,
importingDefaultAppEnvironmentId,
importingPages,
importingComponents,
importingEvents
);
if (!isNormalizedAppDefinitionSchema) { await manager.transaction(async (transactionalEntityManager) => {
for (const importingAppVersion of importingAppVersions) { appResourceMappings = await this.setupAppVersionAssociations(
const updatedDefinition = this.replaceDataQueryIdWithinDefinitions( transactionalEntityManager,
importingAppVersion.definition, importingAppVersions,
appResourceMappings.dataQueryMapping user,
); appResourceMappings,
externalResourceMappings,
importingAppEnvironments,
importingDataSources,
importingDataSourceOptions,
importingDataQueries,
importingDefaultAppEnvironmentId,
importingPages,
importingComponents,
importingEvents
);
let updateHomepageId = null; if (!isNormalizedAppDefinitionSchema) {
for (const importingAppVersion of importingAppVersions) {
const updatedDefinition = this.replaceDataQueryIdWithinDefinitions(
importingAppVersion.definition,
appResourceMappings.dataQueryMapping
);
if (updatedDefinition?.pages) { let updateHomepageId = null;
for (const pageId of Object.keys(updatedDefinition?.pages)) {
const page = updatedDefinition.pages[pageId];
const pageEvents = page.events || []; if (updatedDefinition?.pages) {
const componentEvents = []; for (const pageId of Object.keys(updatedDefinition?.pages)) {
const page = updatedDefinition.pages[pageId];
const pagePostionIntheList = Object.keys(updatedDefinition?.pages).indexOf(pageId); const pageEvents = page.events || [];
const componentEvents = [];
const isHompage = (updatedDefinition['homePageId'] as any) === pageId; const pagePostionIntheList = Object.keys(updatedDefinition?.pages).indexOf(pageId);
const pageComponents = page.components; const isHompage = (updatedDefinition['homePageId'] as any) === pageId;
const mappedComponents = transformComponentData( const pageComponents = page.components;
pageComponents,
componentEvents,
appResourceMappings.componentsMapping,
isNormalizedAppDefinitionSchema
);
const componentLayouts = []; const mappedComponents = transformComponentData(
pageComponents,
componentEvents,
appResourceMappings.componentsMapping,
isNormalizedAppDefinitionSchema
);
const newPage = manager.create(Page, { const componentLayouts = [];
name: page.name,
handle: page.handle,
appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
index: pagePostionIntheList,
disabled: page.disabled || false,
hidden: page.hidden || false,
});
const pageCreated = await manager.save(newPage);
appResourceMappings.pagesMapping[pageId] = pageCreated.id; const newPage = transactionalEntityManager.create(Page, {
name: page.name,
handle: page.handle,
appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
index: pagePostionIntheList,
disabled: page.disabled || false,
hidden: page.hidden || false,
});
const pageCreated = await transactionalEntityManager.save(newPage);
mappedComponents.forEach((component) => { appResourceMappings.pagesMapping[pageId] = pageCreated.id;
component.page = pageCreated;
});
const savedComponents = await manager.save(Component, mappedComponents); mappedComponents.forEach((component) => {
component.page = pageCreated;
});
for (const componentId in pageComponents) { const savedComponents = await transactionalEntityManager.save(Component, mappedComponents);
const componentLayout = pageComponents[componentId]['layouts'];
if (componentLayout && appResourceMappings.componentsMapping[componentId]) { for (const componentId in pageComponents) {
for (const type in componentLayout) { const componentLayout = pageComponents[componentId]['layouts'];
const layout = componentLayout[type];
const newLayout = new Layout();
newLayout.type = type;
newLayout.top = layout.top;
newLayout.left = layout.left;
newLayout.width = layout.width;
newLayout.height = layout.height;
newLayout.componentId = appResourceMappings.componentsMapping[componentId];
componentLayouts.push(newLayout); if (componentLayout && appResourceMappings.componentsMapping[componentId]) {
for (const type in componentLayout) {
const layout = componentLayout[type];
const newLayout = new Layout();
newLayout.type = type;
newLayout.top = layout.top;
newLayout.left = layout.left;
newLayout.width = layout.width;
newLayout.height = layout.height;
newLayout.componentId = appResourceMappings.componentsMapping[componentId];
componentLayouts.push(newLayout);
}
} }
} }
}
await manager.save(Layout, componentLayouts); await transactionalEntityManager.save(Layout, componentLayouts);
//Event handlers //Event handlers
if (pageEvents.length > 0) { if (pageEvents.length > 0) {
pageEvents.forEach(async (event, index) => { pageEvents.forEach(async (event, index) => {
const newEvent = { const newEvent = {
name: event.eventId, name: event.eventId,
sourceId: pageCreated.id, sourceId: pageCreated.id,
target: Target.page, target: Target.page,
event: event, event: event,
index: pageEvents.index || index, index: pageEvents.index || index,
appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id], appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
}; };
await manager.save(EventHandler, newEvent); await transactionalEntityManager.save(EventHandler, newEvent);
});
}
componentEvents.forEach((eventObj) => {
if (eventObj.event?.length === 0) return;
eventObj.event.forEach(async (event, index) => {
const newEvent = await manager.create(EventHandler, {
name: event.eventId,
sourceId: appResourceMappings.componentsMapping[eventObj.componentId],
target: Target.component,
event: event,
index: eventObj.index || index,
appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
}); });
await manager.save(EventHandler, newEvent);
});
});
savedComponents.forEach(async (component) => {
if (component.type === 'Table') {
const tableActions = component.properties?.actions?.value || [];
const tableColumns = component.properties?.columns?.value || [];
const tableActionAndColumnEvents = [];
tableActions.forEach((action) => {
const actionEvents = action.events || [];
actionEvents.forEach((event, index) => {
tableActionAndColumnEvents.push({
name: event.eventId,
sourceId: component.id,
target: Target.tableAction,
event: { ...event, ref: action.name },
index: event.index ?? index,
appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
});
});
});
tableColumns.forEach((column) => {
if (column?.columnType !== 'toggle') return;
const columnEvents = column.events || [];
columnEvents.forEach((event, index) => {
tableActionAndColumnEvents.push({
name: event.eventId,
sourceId: component.id,
target: Target.tableColumn,
event: { ...event, ref: column.name },
index: event.index ?? index,
appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
});
});
});
await manager.save(EventHandler, tableActionAndColumnEvents);
} }
});
if (isHompage) { componentEvents.forEach((eventObj) => {
updateHomepageId = pageCreated.id; if (eventObj.event?.length === 0) return;
eventObj.event.forEach(async (event, index) => {
const newEvent = transactionalEntityManager.create(EventHandler, {
name: event.eventId,
sourceId: appResourceMappings.componentsMapping[eventObj.componentId],
target: Target.component,
event: event,
index: eventObj.index || index,
appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
});
await transactionalEntityManager.save(EventHandler, newEvent);
});
});
savedComponents.forEach(async (component) => {
if (component.type === 'Table') {
const tableActions = component.properties?.actions?.value || [];
const tableColumns = component.properties?.columns?.value || [];
const tableActionAndColumnEvents = [];
tableActions.forEach((action) => {
const actionEvents = action.events || [];
actionEvents.forEach((event, index) => {
tableActionAndColumnEvents.push({
name: event.eventId,
sourceId: component.id,
target: Target.tableAction,
event: { ...event, ref: action.name },
index: event.index ?? index,
appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
});
});
});
tableColumns.forEach((column) => {
if (column?.columnType !== 'toggle') return;
const columnEvents = column.events || [];
columnEvents.forEach((event, index) => {
tableActionAndColumnEvents.push({
name: event.eventId,
sourceId: component.id,
target: Target.tableColumn,
event: { ...event, ref: column.name },
index: event.index ?? index,
appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
});
});
});
await transactionalEntityManager.save(EventHandler, tableActionAndColumnEvents);
}
});
if (isHompage) {
updateHomepageId = pageCreated.id;
}
} }
} }
await transactionalEntityManager.update(
AppVersion,
{ id: appResourceMappings.appVersionMapping[importingAppVersion.id] },
{
definition: updatedDefinition,
homePageId: updateHomepageId,
}
);
} }
await manager.update(
AppVersion,
{ id: appResourceMappings.appVersionMapping[importingAppVersion.id] },
{
definition: updatedDefinition,
homePageId: updateHomepageId,
}
);
await this.updateEventActionsForNewVersionWithNewMappingIds(
manager,
appResourceMappings.appVersionMapping[importingAppVersion.id],
appResourceMappings.dataQueryMapping,
appResourceMappings.componentsMapping,
appResourceMappings.pagesMapping,
isNormalizedAppDefinitionSchema
);
} }
});
const appVersionIds = Object.values(appResourceMappings.appVersionMapping);
for (const appVersionId of appVersionIds) {
await this.updateEventActionsForNewVersionWithNewMappingIds(
manager,
appVersionId,
appResourceMappings.dataQueryMapping,
appResourceMappings.componentsMapping,
appResourceMappings.pagesMapping
);
} }
await this.setEditingVersionAsLatestVersion(manager, appResourceMappings.appVersionMapping, importingAppVersions); await this.setEditingVersionAsLatestVersion(manager, appResourceMappings.appVersionMapping, importingAppVersions);
@ -741,13 +752,14 @@ export class AppImportExportService {
if (componentEvents.length > 0) { if (componentEvents.length > 0) {
componentEvents.forEach(async (componentEvent) => { componentEvents.forEach(async (componentEvent) => {
const newEvent = new EventHandler(); const newEvent = await manager.create(EventHandler, {
newEvent.name = componentEvent.name; name: componentEvent.name,
newEvent.sourceId = savedComponent.id; sourceId: savedComponent.id,
newEvent.target = componentEvent.target; target: componentEvent.target,
newEvent.event = componentEvent.event; event: componentEvent.event,
newEvent.index = componentEvent.index; index: componentEvent.index,
newEvent.appVersionId = appResourceMappings.appVersionMapping[importingAppVersion.id]; appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
});
await manager.save(EventHandler, newEvent); await manager.save(EventHandler, newEvent);
}); });
@ -759,14 +771,14 @@ export class AppImportExportService {
if (pageEvents.length > 0) { if (pageEvents.length > 0) {
pageEvents.forEach(async (pageEvent) => { pageEvents.forEach(async (pageEvent) => {
const newEvent = { const newEvent = await manager.create(EventHandler, {
name: pageEvent.name, name: pageEvent.name,
sourceId: pageCreated.id, sourceId: pageCreated.id,
target: pageEvent.target, target: pageEvent.target,
event: pageEvent.event, event: pageEvent.event,
index: pageEvent.index, index: pageEvent.index,
appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id], appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
}; });
await manager.save(EventHandler, newEvent); await manager.save(EventHandler, newEvent);
}); });
@ -790,14 +802,14 @@ export class AppImportExportService {
if (importingQueryEvents.length > 0) { if (importingQueryEvents.length > 0) {
importingQueryEvents.forEach(async (dataQueryEvent) => { importingQueryEvents.forEach(async (dataQueryEvent) => {
const newEvent = { const newEvent = await manager.create(EventHandler, {
name: dataQueryEvent.name, name: dataQueryEvent.name,
sourceId: mappedNewDataQuery.id, sourceId: mappedNewDataQuery.id,
target: dataQueryEvent.target, target: dataQueryEvent.target,
event: dataQueryEvent.event, event: dataQueryEvent.event,
index: dataQueryEvent.index, index: dataQueryEvent.index,
appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id], appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
}; });
await manager.save(EventHandler, newEvent); await manager.save(EventHandler, newEvent);
}); });
@ -812,14 +824,14 @@ export class AppImportExportService {
if (queryEvents.length > 0) { if (queryEvents.length > 0) {
queryEvents.forEach(async (event, index) => { queryEvents.forEach(async (event, index) => {
const newEvent = { const newEvent = await manager.create(EventHandler, {
name: event.eventId, name: event.eventId,
sourceId: mappedNewDataQuery.id, sourceId: mappedNewDataQuery.id,
target: Target.dataQuery, target: Target.dataQuery,
event: event, event: event,
index: queryEvents.index || index, index: event.index ?? index,
appVersionId: mappedNewDataQuery.appVersionId, appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
}; });
await manager.save(EventHandler, newEvent); await manager.save(EventHandler, newEvent);
}); });
@ -838,18 +850,17 @@ export class AppImportExportService {
); );
} }
const appVersionIds = Object.values(appResourceMappings.appVersionMapping); // const appVersionIds = Object.values(appResourceMappings.appVersionMapping);
for (const appVersionId of appVersionIds) { // for (const appVersionId of appVersionIds) {
await this.updateEventActionsForNewVersionWithNewMappingIds( // await this.updateEventActionsForNewVersionWithNewMappingIds(
manager, // manager,
appVersionId, // appVersionId,
appResourceMappings.dataQueryMapping, // appResourceMappings.dataQueryMapping,
appResourceMappings.componentsMapping, // appResourceMappings.componentsMapping,
appResourceMappings.pagesMapping, // appResourceMappings.pagesMapping
true // );
); // }
}
return appResourceMappings; return appResourceMappings;
} }
@ -1513,29 +1524,35 @@ export class AppImportExportService {
versionId: string, versionId: string,
oldDataQueryToNewMapping: Record<string, unknown>, oldDataQueryToNewMapping: Record<string, unknown>,
oldComponentToNewComponentMapping: Record<string, unknown>, oldComponentToNewComponentMapping: Record<string, unknown>,
oldPageToNewPageMapping: Record<string, unknown>, oldPageToNewPageMapping: Record<string, unknown>
isNormalizedAppDefinitionSchema: boolean
) { ) {
const allEvents = await manager.find(EventHandler, { const allEvents = await manager
where: { appVersionId: versionId }, .createQueryBuilder(EventHandler, 'event')
}); .where('event.appVersionId = :versionId', { versionId })
.getMany();
for (const event of allEvents) { for (const event of allEvents) {
const eventDefinition = event.event; const eventDefinition = event.event;
if (isNormalizedAppDefinitionSchema && eventDefinition?.actionId === 'run-query') { if (eventDefinition?.actionId === 'run-query' && oldDataQueryToNewMapping[eventDefinition.queryId]) {
eventDefinition.queryId = oldDataQueryToNewMapping[eventDefinition.queryId]; eventDefinition.queryId = oldDataQueryToNewMapping[eventDefinition.queryId];
} }
if (eventDefinition?.actionId === 'control-component') { if (
eventDefinition?.actionId === 'control-component' &&
oldComponentToNewComponentMapping[eventDefinition.componentId]
) {
eventDefinition.componentId = oldComponentToNewComponentMapping[eventDefinition.componentId]; eventDefinition.componentId = oldComponentToNewComponentMapping[eventDefinition.componentId];
} }
if (eventDefinition?.actionId === 'switch-page') { if (eventDefinition?.actionId === 'switch-page' && oldPageToNewPageMapping[eventDefinition.pageId]) {
eventDefinition.pageId = oldPageToNewPageMapping[eventDefinition.pageId]; eventDefinition.pageId = oldPageToNewPageMapping[eventDefinition.pageId];
} }
if (eventDefinition?.actionId == 'show-modal' || eventDefinition?.actionId === 'close-modal') { if (
(eventDefinition?.actionId == 'show-modal' || eventDefinition?.actionId === 'close-modal') &&
oldComponentToNewComponentMapping[eventDefinition.modal]
) {
eventDefinition.modal = oldComponentToNewComponentMapping[eventDefinition.modal]; eventDefinition.modal = oldComponentToNewComponentMapping[eventDefinition.modal];
} }

View file

@ -685,65 +685,71 @@ export class AppsService {
newDataQueries.push(newQuery); newDataQueries.push(newQuery);
} }
} }
}
if (globalQueries?.length > 0) { if (globalQueries?.length > 0) {
for (const globalQuery of globalQueries) { for (const globalQuery of globalQueries) {
const dataQueryParams = { const dataQueryParams = {
name: globalQuery.name, name: globalQuery.name,
options: globalQuery.options, options: globalQuery.options,
dataSourceId: globalQuery.dataSourceId, dataSourceId: globalQuery.dataSourceId,
appVersionId: appVersion.id, appVersionId: appVersion.id,
}; };
const newQuery = await manager.save(manager.create(DataQuery, dataQueryParams)); const newQuery = await manager.save(manager.create(DataQuery, dataQueryParams));
const dataQueryEvents = allEvents.filter((event) => event.sourceId === globalQuery.id); const dataQueryEvents = allEvents.filter((event) => event.sourceId === globalQuery.id);
dataQueryEvents.forEach(async (event, index) => { dataQueryEvents.forEach(async (event, index) => {
const newEvent = new EventHandler(); const newEvent = new EventHandler();
newEvent.id = uuid.v4(); newEvent.id = uuid.v4();
newEvent.name = event.name; newEvent.name = event.name;
newEvent.sourceId = newQuery.id; newEvent.sourceId = newQuery.id;
newEvent.target = event.target; newEvent.target = event.target;
newEvent.event = event.event; newEvent.event = event.event;
newEvent.index = event.index ?? index; newEvent.index = event.index ?? index;
newEvent.appVersionId = appVersion.id; newEvent.appVersionId = appVersion.id;
await manager.save(newEvent); await manager.save(newEvent);
}); });
oldDataQueryToNewMapping[globalQuery.id] = newQuery.id; oldDataQueryToNewMapping[globalQuery.id] = newQuery.id;
newDataQueries.push(newQuery); newDataQueries.push(newQuery);
}
} }
}
for (const newQuery of newDataQueries) { for (const newQuery of newDataQueries) {
const newOptions = this.replaceDataQueryOptionsWithNewDataQueryIds(newQuery.options, oldDataQueryToNewMapping); const newOptions = this.replaceDataQueryOptionsWithNewDataQueryIds(
newQuery.options = newOptions; newQuery.options,
oldDataQueryToNewMapping
await manager.save(newQuery);
}
appVersion.definition = this.replaceDataQueryIdWithinDefinitions(appVersion.definition, oldDataQueryToNewMapping);
await manager.save(appVersion);
for (const appEnvironment of appEnvironments) {
for (const dataSource of dataSources) {
const dataSourceOption = await manager.findOneOrFail(DataSourceOptions, {
where: { dataSourceId: dataSource.id, environmentId: appEnvironment.id },
});
const convertedOptions = this.convertToArrayOfKeyValuePairs(dataSourceOption.options);
const newOptions = await this.dataSourcesService.parseOptionsForCreate(convertedOptions, false, manager);
await this.setNewCredentialValueFromOldValue(newOptions, convertedOptions, manager);
await manager.save(
manager.create(DataSourceOptions, {
options: newOptions,
dataSourceId: dataSourceMapping[dataSource.id],
environmentId: appEnvironment.id,
})
); );
newQuery.options = newOptions;
await manager.save(newQuery);
}
appVersion.definition = this.replaceDataQueryIdWithinDefinitions(
appVersion.definition,
oldDataQueryToNewMapping
);
await manager.save(appVersion);
for (const appEnvironment of appEnvironments) {
for (const dataSource of dataSources) {
const dataSourceOption = await manager.findOneOrFail(DataSourceOptions, {
where: { dataSourceId: dataSource.id, environmentId: appEnvironment.id },
});
const convertedOptions = this.convertToArrayOfKeyValuePairs(dataSourceOption.options);
const newOptions = await this.dataSourcesService.parseOptionsForCreate(convertedOptions, false, manager);
await this.setNewCredentialValueFromOldValue(newOptions, convertedOptions, manager);
await manager.save(
manager.create(DataSourceOptions, {
options: newOptions,
dataSourceId: dataSourceMapping[dataSource.id],
environmentId: appEnvironment.id,
})
);
}
} }
} }
} }