[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.appVersionMapping = appVersionMapping;
appResourceMappings = await this.setupAppVersionAssociations(
manager,
importingAppVersions,
user,
appResourceMappings,
externalResourceMappings,
importingAppEnvironments,
importingDataSources,
importingDataSourceOptions,
importingDataQueries,
importingDefaultAppEnvironmentId,
importingPages,
importingComponents,
importingEvents
);
/**
* as multiple operations are run within a single transaction using the transaction method provides a convenient way to handle transactions.
* The transaction will automatically committed when the function completes without throwing an error.
* If an error occurs during the function execution, the transaction will rolled back.
*/
if (!isNormalizedAppDefinitionSchema) {
for (const importingAppVersion of importingAppVersions) {
const updatedDefinition = this.replaceDataQueryIdWithinDefinitions(
importingAppVersion.definition,
appResourceMappings.dataQueryMapping
);
await manager.transaction(async (transactionalEntityManager) => {
appResourceMappings = await this.setupAppVersionAssociations(
transactionalEntityManager,
importingAppVersions,
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) {
for (const pageId of Object.keys(updatedDefinition?.pages)) {
const page = updatedDefinition.pages[pageId];
let updateHomepageId = null;
const pageEvents = page.events || [];
const componentEvents = [];
if (updatedDefinition?.pages) {
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(
pageComponents,
componentEvents,
appResourceMappings.componentsMapping,
isNormalizedAppDefinitionSchema
);
const pageComponents = page.components;
const componentLayouts = [];
const mappedComponents = transformComponentData(
pageComponents,
componentEvents,
appResourceMappings.componentsMapping,
isNormalizedAppDefinitionSchema
);
const newPage = manager.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 manager.save(newPage);
const componentLayouts = [];
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) => {
component.page = pageCreated;
});
appResourceMappings.pagesMapping[pageId] = pageCreated.id;
const savedComponents = await manager.save(Component, mappedComponents);
mappedComponents.forEach((component) => {
component.page = pageCreated;
});
for (const componentId in pageComponents) {
const componentLayout = pageComponents[componentId]['layouts'];
const savedComponents = await transactionalEntityManager.save(Component, mappedComponents);
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];
for (const componentId in pageComponents) {
const componentLayout = pageComponents[componentId]['layouts'];
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) {
pageEvents.forEach(async (event, index) => {
const newEvent = {
name: event.eventId,
sourceId: pageCreated.id,
target: Target.page,
event: event,
index: pageEvents.index || index,
appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
};
if (pageEvents.length > 0) {
pageEvents.forEach(async (event, index) => {
const newEvent = {
name: event.eventId,
sourceId: pageCreated.id,
target: Target.page,
event: event,
index: pageEvents.index || index,
appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
};
await manager.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 transactionalEntityManager.save(EventHandler, newEvent);
});
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) {
updateHomepageId = pageCreated.id;
componentEvents.forEach((eventObj) => {
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);
@ -741,13 +752,14 @@ export class AppImportExportService {
if (componentEvents.length > 0) {
componentEvents.forEach(async (componentEvent) => {
const newEvent = new EventHandler();
newEvent.name = componentEvent.name;
newEvent.sourceId = savedComponent.id;
newEvent.target = componentEvent.target;
newEvent.event = componentEvent.event;
newEvent.index = componentEvent.index;
newEvent.appVersionId = appResourceMappings.appVersionMapping[importingAppVersion.id];
const newEvent = await manager.create(EventHandler, {
name: componentEvent.name,
sourceId: savedComponent.id,
target: componentEvent.target,
event: componentEvent.event,
index: componentEvent.index,
appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
});
await manager.save(EventHandler, newEvent);
});
@ -759,14 +771,14 @@ export class AppImportExportService {
if (pageEvents.length > 0) {
pageEvents.forEach(async (pageEvent) => {
const newEvent = {
const newEvent = await manager.create(EventHandler, {
name: pageEvent.name,
sourceId: pageCreated.id,
target: pageEvent.target,
event: pageEvent.event,
index: pageEvent.index,
appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
};
});
await manager.save(EventHandler, newEvent);
});
@ -790,14 +802,14 @@ export class AppImportExportService {
if (importingQueryEvents.length > 0) {
importingQueryEvents.forEach(async (dataQueryEvent) => {
const newEvent = {
const newEvent = await manager.create(EventHandler, {
name: dataQueryEvent.name,
sourceId: mappedNewDataQuery.id,
target: dataQueryEvent.target,
event: dataQueryEvent.event,
index: dataQueryEvent.index,
appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
};
});
await manager.save(EventHandler, newEvent);
});
@ -812,14 +824,14 @@ export class AppImportExportService {
if (queryEvents.length > 0) {
queryEvents.forEach(async (event, index) => {
const newEvent = {
const newEvent = await manager.create(EventHandler, {
name: event.eventId,
sourceId: mappedNewDataQuery.id,
target: Target.dataQuery,
event: event,
index: queryEvents.index || index,
appVersionId: mappedNewDataQuery.appVersionId,
};
index: event.index ?? index,
appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
});
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) {
await this.updateEventActionsForNewVersionWithNewMappingIds(
manager,
appVersionId,
appResourceMappings.dataQueryMapping,
appResourceMappings.componentsMapping,
appResourceMappings.pagesMapping,
true
);
}
// for (const appVersionId of appVersionIds) {
// await this.updateEventActionsForNewVersionWithNewMappingIds(
// manager,
// appVersionId,
// appResourceMappings.dataQueryMapping,
// appResourceMappings.componentsMapping,
// appResourceMappings.pagesMapping
// );
// }
return appResourceMappings;
}
@ -1513,29 +1524,35 @@ export class AppImportExportService {
versionId: string,
oldDataQueryToNewMapping: Record<string, unknown>,
oldComponentToNewComponentMapping: Record<string, unknown>,
oldPageToNewPageMapping: Record<string, unknown>,
isNormalizedAppDefinitionSchema: boolean
oldPageToNewPageMapping: Record<string, unknown>
) {
const allEvents = await manager.find(EventHandler, {
where: { appVersionId: versionId },
});
const allEvents = await manager
.createQueryBuilder(EventHandler, 'event')
.where('event.appVersionId = :versionId', { versionId })
.getMany();
for (const event of allEvents) {
const eventDefinition = event.event;
if (isNormalizedAppDefinitionSchema && eventDefinition?.actionId === 'run-query') {
if (eventDefinition?.actionId === 'run-query' && 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];
}
if (eventDefinition?.actionId === 'switch-page') {
if (eventDefinition?.actionId === 'switch-page' && 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];
}

View file

@ -685,65 +685,71 @@ export class AppsService {
newDataQueries.push(newQuery);
}
}
}
if (globalQueries?.length > 0) {
for (const globalQuery of globalQueries) {
const dataQueryParams = {
name: globalQuery.name,
options: globalQuery.options,
dataSourceId: globalQuery.dataSourceId,
appVersionId: appVersion.id,
};
if (globalQueries?.length > 0) {
for (const globalQuery of globalQueries) {
const dataQueryParams = {
name: globalQuery.name,
options: globalQuery.options,
dataSourceId: globalQuery.dataSourceId,
appVersionId: appVersion.id,
};
const newQuery = await manager.save(manager.create(DataQuery, dataQueryParams));
const dataQueryEvents = allEvents.filter((event) => event.sourceId === globalQuery.id);
const newQuery = await manager.save(manager.create(DataQuery, dataQueryParams));
const dataQueryEvents = allEvents.filter((event) => event.sourceId === globalQuery.id);
dataQueryEvents.forEach(async (event, index) => {
const newEvent = new EventHandler();
dataQueryEvents.forEach(async (event, index) => {
const newEvent = new EventHandler();
newEvent.id = uuid.v4();
newEvent.name = event.name;
newEvent.sourceId = newQuery.id;
newEvent.target = event.target;
newEvent.event = event.event;
newEvent.index = event.index ?? index;
newEvent.appVersionId = appVersion.id;
newEvent.id = uuid.v4();
newEvent.name = event.name;
newEvent.sourceId = newQuery.id;
newEvent.target = event.target;
newEvent.event = event.event;
newEvent.index = event.index ?? index;
newEvent.appVersionId = appVersion.id;
await manager.save(newEvent);
});
oldDataQueryToNewMapping[globalQuery.id] = newQuery.id;
newDataQueries.push(newQuery);
await manager.save(newEvent);
});
oldDataQueryToNewMapping[globalQuery.id] = newQuery.id;
newDataQueries.push(newQuery);
}
}
}
for (const newQuery of newDataQueries) {
const newOptions = this.replaceDataQueryOptionsWithNewDataQueryIds(newQuery.options, oldDataQueryToNewMapping);
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,
})
for (const newQuery of newDataQueries) {
const newOptions = this.replaceDataQueryOptionsWithNewDataQueryIds(
newQuery.options,
oldDataQueryToNewMapping
);
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,
})
);
}
}
}
}