Browse Source

fix: add updgrader to recover broken links

pull/9684/head
Pranav C 1 month ago
parent
commit
49216a1128
  1. 2
      packages/nocodb/src/providers/init-meta-service.provider.ts
  2. 2
      packages/nocodb/src/version-upgrader/NcUpgrader.ts
  3. 348
      packages/nocodb/src/version-upgrader/upgraders/0227002_ncBrokenLinkRecovery.ts

2
packages/nocodb/src/providers/init-meta-service.provider.ts

@ -31,7 +31,7 @@ export const InitMetaServiceProvider: FactoryProvider = {
const config = await NcConfig.createByEnv(); const config = await NcConfig.createByEnv();
// set version // set version
process.env.NC_VERSION = '0225002'; process.env.NC_VERSION = '0257002';
// set migration jobs version // set migration jobs version
process.env.NC_MIGRATION_JOBS_VERSION = '2'; process.env.NC_MIGRATION_JOBS_VERSION = '2';

2
packages/nocodb/src/version-upgrader/NcUpgrader.ts

@ -12,6 +12,7 @@ import ncXcdbLTARUpgrader from './upgraders/0108002_ncXcdbLTARUpgrader';
import ncXcdbLTARIndexUpgrader from './upgraders/0111002_ncXcdbLTARIndexUpgrader'; import ncXcdbLTARIndexUpgrader from './upgraders/0111002_ncXcdbLTARIndexUpgrader';
import ncXcdbCreatedAndUpdatedSystemFieldsUpgrader from './upgraders/0111005_ncXcdbCreatedAndUpdatedSystemFieldsUpgrader'; import ncXcdbCreatedAndUpdatedSystemFieldsUpgrader from './upgraders/0111005_ncXcdbCreatedAndUpdatedSystemFieldsUpgrader';
import ncDatasourceDecrypt from './upgraders/0225002_ncDatasourceDecrypt'; import ncDatasourceDecrypt from './upgraders/0225002_ncDatasourceDecrypt';
import ncBrokenLinkRecovery from './upgraders/0227002_ncBrokenLinkRecovery';
// import dupColMergeUpgrader from './0205003_dupColMergeUpgrader'; // import dupColMergeUpgrader from './0205003_dupColMergeUpgrader';
import type { MetaService } from '~/meta/meta.service'; import type { MetaService } from '~/meta/meta.service';
import type { NcConfig } from '~/interface/config'; import type { NcConfig } from '~/interface/config';
@ -151,6 +152,7 @@ export default class NcUpgrader {
{ name: '0111002', handler: ncXcdbLTARIndexUpgrader }, { name: '0111002', handler: ncXcdbLTARIndexUpgrader },
{ name: '0111005', handler: ncXcdbCreatedAndUpdatedSystemFieldsUpgrader }, { name: '0111005', handler: ncXcdbCreatedAndUpdatedSystemFieldsUpgrader },
{ name: '0225002', handler: ncDatasourceDecrypt }, { name: '0225002', handler: ncDatasourceDecrypt },
{ name: '0257002', handler: ncBrokenLinkRecovery },
// disable for now // disable for now
// { name: '0227000', handler: dupColMergeUpgrader }, // { name: '0227000', handler: dupColMergeUpgrader },
]; ];

348
packages/nocodb/src/version-upgrader/upgraders/0227002_ncBrokenLinkRecovery.ts

@ -1,7 +1,8 @@
import { RelationTypes, UITypes } from 'nocodb-sdk'; import { RelationTypes, UITypes } from 'nocodb-sdk';
import type { NcUpgraderCtx } from '~/version-upgrader/NcUpgrader'; import type { NcUpgraderCtx } from '~/version-upgrader/NcUpgrader';
import type { MetaService } from '~/meta/meta.service';
import { MetaTable } from '~/utils/globals'; import { MetaTable } from '~/utils/globals';
import {MetaService} from "~/meta/meta.service"; import { Column } from '~/models';
/** /**
* This upgrader look for any broken link and try to recover it * This upgrader look for any broken link and try to recover it
@ -25,7 +26,7 @@ export default async function ({ ncMeta }: NcUpgraderCtx) {
.leftJoin( .leftJoin(
MetaTable.COL_RELATIONS, MetaTable.COL_RELATIONS,
`${MetaTable.COLUMNS}.id`, `${MetaTable.COLUMNS}.id`,
`${MetaTable.COL_SELECT_OPTIONS}.fk_column_id`, `${MetaTable.COL_RELATIONS}.fk_column_id`,
) )
.where(`${MetaTable.COLUMNS}.uidt`, UITypes.LinkToAnotherRecord) .where(`${MetaTable.COLUMNS}.uidt`, UITypes.LinkToAnotherRecord)
.whereNull(`${MetaTable.COL_RELATIONS}.id`); .whereNull(`${MetaTable.COL_RELATIONS}.id`);
@ -78,7 +79,10 @@ export default async function ({ ncMeta }: NcUpgraderCtx) {
const linksQb = ncMeta const linksQb = ncMeta
.knex(MetaTable.COL_RELATIONS) .knex(MetaTable.COL_RELATIONS)
.select(`${MetaTable.COL_RELATIONS}.*`) .select(`${MetaTable.COL_RELATIONS}.*`)
.where(`${MetaTable.COL_RELATIONS}.fk_related_model_id`, column.fk_model_id); .where(
`${MetaTable.COL_RELATIONS}.fk_related_model_id`,
column.fk_model_id,
);
if (relatedTableId) { if (relatedTableId) {
linksQb linksQb
.join( .join(
@ -87,163 +91,197 @@ export default async function ({ ncMeta }: NcUpgraderCtx) {
`${MetaTable.COLUMNS}.id`, `${MetaTable.COLUMNS}.id`,
) )
.where(`${MetaTable.COLUMNS}.fk_model_id`, relatedTableId); .where(`${MetaTable.COLUMNS}.fk_model_id`, relatedTableId);
} }
const links = await linksQb;
// iterate over all links which is related to current table and if found relation which doesn't have link in the related table then use it to populate colOptions
for (const link of links) {
let columnInCurrTable = null;
if (link.type === RelationTypes.HAS_MANY) {
// check for bt column in current table
columnInCurrTable = await ncMeta
.knex(MetaTable.COL_RELATIONS)
.join(
MetaTable.COLUMNS,
`${MetaTable.COL_RELATIONS}.fk_column_id`,
`${MetaTable.COLUMNS}.id`,
)
.where(`${MetaTable.COL_RELATIONS}.fk_model_id`, currentTableId)
.where(
`${MetaTable.COL_RELATIONS}.fk_related_model_id`,
relatedTableId,
)
.where(`${MetaTable.COL_RELATIONS}.type`, RelationTypes.BELONGS_TO)
.where(
`${MetaTable.COL_RELATIONS}.fk_child_column_id`,
link.fk_child_column_id,
)
.where(
`${MetaTable.COL_RELATIONS}.fk_parent_column_id`,
link.fk_parent_column_id,
);
} else if (link.type === RelationTypes.ONE_TO_ONE) {
// check for one to one column in current table and confirm type in meta
columnInCurrTable = await ncMeta
.knex(MetaTable.COL_RELATIONS)
.join(
MetaTable.COLUMNS,
`${MetaTable.COL_RELATIONS}.fk_column_id`,
`${MetaTable.COLUMNS}.id`,
)
.where(`${MetaTable.COL_RELATIONS}.fk_model_id`, currentTableId)
.where(
`${MetaTable.COL_RELATIONS}.fk_related_model_id`,
relatedTableId,
)
.where(`${MetaTable.COL_RELATIONS}.type`, RelationTypes.ONE_TO_ONE)
.where(
`${MetaTable.COL_RELATIONS}.fk_child_column_id`,
link.fk_child_column_id,
)
.where(
`${MetaTable.COL_RELATIONS}.fk_parent_column_id`,
link.fk_parent_column_id,
);
} else if (link.type === RelationTypes.BELONGS_TO) {
// check for hm column in current table
columnInCurrTable = await ncMeta
.knex(MetaTable.COL_RELATIONS)
.join(
MetaTable.COLUMNS,
`${MetaTable.COL_RELATIONS}.fk_column_id`,
`${MetaTable.COLUMNS}.id`,
)
.where(`${MetaTable.COL_RELATIONS}.fk_model_id`, currentTableId)
.where(
`${MetaTable.COL_RELATIONS}.fk_related_model_id`,
relatedTableId,
)
.where(`${MetaTable.COL_RELATIONS}.type`, RelationTypes.HAS_MANY)
.where(
`${MetaTable.COL_RELATIONS}.fk_child_column_id`,
link.fk_child_column_id,
)
.where(
`${MetaTable.COL_RELATIONS}.fk_parent_column_id`,
link.fk_parent_column_id,
);
} else if (link.type === RelationTypes.MANY_TO_MANY) {
// check for mtm column in current table
columnInCurrTable = await ncMeta
.knex(MetaTable.COL_RELATIONS)
.join(
MetaTable.COLUMNS,
`${MetaTable.COL_RELATIONS}.fk_column_id`,
`${MetaTable.COLUMNS}.id`,
)
.where(`${MetaTable.COL_RELATIONS}.fk_model_id`, currentTableId)
.where(
`${MetaTable.COL_RELATIONS}.fk_related_model_id`,
relatedTableId,
)
.where(`${MetaTable.COL_RELATIONS}.type`, RelationTypes.BELONGS_TO)
.where(
`${MetaTable.COL_RELATIONS}.fk_child_column_id`,
link.fk_parent_column_id,
)
.where(
`${MetaTable.COL_RELATIONS}.fk_parent_column_id`,
link.fk_parent_column_id,
)
.where(
`${MetaTable.COL_RELATIONS}.fk_mm_model_id`,
link.fk_mm_model_id,
)
.where(
`${MetaTable.COL_RELATIONS}.fk_mm_child_column_id`,
link.fk_mm_parent_column_id,
)
.where(
`${MetaTable.COL_RELATIONS}.fk_mm_parent_column_id`,
link.fk_mm_child_column_id,
);
}
if (!columnInCurrTable) {
// generate meta and insert into colOptions
const commonProps = {
id: (ncMeta as MetaService).genNanoid(MetaTable.COL_RELATIONS),
fk_column_id: column.id,
fk_related_model_id: relatedTableId,
created_at: link.created_at,
updated_at: link.updated_at,
virtual: link.virtual,
};
// based on type insert data into colOptions
switch (link.type) {
const links = await linksQb; case RelationTypes.HAS_MANY:
// insert data into colOptions
ncMeta.knex(MetaTable.COL_RELATIONS).insert({
// iterate over all links which is related to current table and if found relation which doesn't have link in the related table then use it to populate colOptions ...commonProps,
for (const link of links) { type: RelationTypes.BELONGS_TO,
let columnInCurrTable null; fk_child_column_id: link.fk_child_column_id,
if (link.type === RelationTypes.HAS_MANY) { fk_parent_column_id: link.fk_parent_column_id,
// check for bt column in current table });
columnInCurrTable = await ncMeta break;
.knex(MetaTable.COL_RELATIONS) case RelationTypes.ONE_TO_ONE:
.join( // todo:
MetaTable.COLUMNS, const meta = {
`${MetaTable.COL_RELATIONS}.fk_column_id`, bt: false,
`${MetaTable.COLUMNS}.id`, };
) // insert data into colOptions
.where(`${MetaTable.COL_RELATIONS}.fk_model_id`, currentTableId) ncMeta.knex(MetaTable.COL_RELATIONS).insert({
.where( ...commonProps,
`${MetaTable.COL_RELATIONS}.fk_related_model_id`, type: RelationTypes.ONE_TO_ONE,
relatedTableId, fk_child_column_id: link.fk_child_column_id,
) fk_parent_column_id: link.fk_parent_column_id,
.where(`${MetaTable.COL_RELATIONS}.type`, RelationTypes.BELONGS_TO) meta,
.where( });
`${MetaTable.COL_RELATIONS}.fk_child_column_id`, break;
link.fk_child_column_id, case RelationTypes.BELONGS_TO:
) // insert data into colOptions
.where(
`${MetaTable.COL_RELATIONS}.fk_parent_column_id`, ncMeta.knex(MetaTable.COL_RELATIONS).insert({
link.fk_parent_column_id, ...commonProps,
); type: RelationTypes.HAS_MANY,
} else if (link.type === RelationTypes.ONE_TO_ONE) { fk_child_column_id: link.fk_child_column_id,
// check for one to one column in current table and confirm type in meta fk_parent_column_id: link.fk_parent_column_id,
columnInCurrTable = await ncMeta });
.knex(MetaTable.COL_RELATIONS) break;
.join( case RelationTypes.MANY_TO_MANY:
MetaTable.COLUMNS, // insert data into colOptions
`${MetaTable.COL_RELATIONS}.fk_column_id`,
`${MetaTable.COLUMNS}.id`, ncMeta.knex(MetaTable.COL_RELATIONS).insert({
) ...commonProps,
.where(`${MetaTable.COL_RELATIONS}.fk_model_id`, currentTableId) type: RelationTypes.ONE_TO_ONE,
.where( fk_child_column_id: link.fk_parent_column_id,
`${MetaTable.COL_RELATIONS}.fk_related_model_id`, fk_parent_column_id: link.fk_child_column_id,
relatedTableId,
) fk_mm_model_id: link.fk_mm_model_id,
.where(`${MetaTable.COL_RELATIONS}.type`, RelationTypes.ONE_TO_ONE) fk_mm_child_column_id: link.fk_mm_parent_column_id,
.where( fk_mm_parent_column_id: link.fk_mm_child_column_id,
`${MetaTable.COL_RELATIONS}.fk_child_column_id`, });
link.fk_child_column_id, break;
)
.where(
`${MetaTable.COL_RELATIONS}.fk_parent_column_id`,
link.fk_parent_column_id,
);
} else if (link.type === RelationTypes.BELONGS_TO) {
// check for hm column in current table
columnInCurrTable = await ncMeta
.knex(MetaTable.COL_RELATIONS)
.join(
MetaTable.COLUMNS,
`${MetaTable.COL_RELATIONS}.fk_column_id`,
`${MetaTable.COLUMNS}.id`,
)
.where(`${MetaTable.COL_RELATIONS}.fk_model_id`, currentTableId)
.where(
`${MetaTable.COL_RELATIONS}.fk_related_model_id`,
relatedTableId,
)
.where(`${MetaTable.COL_RELATIONS}.type`, RelationTypes.HAS_MANY)
.where(
`${MetaTable.COL_RELATIONS}.fk_child_column_id`,
link.fk_child_column_id,
)
.where(
`${MetaTable.COL_RELATIONS}.fk_parent_column_id`,
link.fk_parent_column_id,
);
} else if (link.type === RelationTypes.MANY_TO_MANY) {
// check for mtm column in current table
columnInCurrTable = await ncMeta
.knex(MetaTable.COL_RELATIONS)
.join(
MetaTable.COLUMNS,
`${MetaTable.COL_RELATIONS}.fk_column_id`,
`${MetaTable.COLUMNS}.id`,
)
.where(`${MetaTable.COL_RELATIONS}.fk_model_id`, currentTableId)
.where(
`${MetaTable.COL_RELATIONS}.fk_related_model_id`,
relatedTableId,
)
.where(`${MetaTable.COL_RELATIONS}.type`, RelationTypes.BELONGS_TO)
.where(
`${MetaTable.COL_RELATIONS}.fk_child_column_id`,
link.fk_parent_column_id,
)
.where(
`${MetaTable.COL_RELATIONS}.fk_parent_column_id`,
link.fk_parent_column_id,
)
.where(
`${MetaTable.COL_RELATIONS}.fk_mm_model_id`,
link.fk_mm_model_id,
)
.where(
`${MetaTable.COL_RELATIONS}.fk_mm_child_column_id`,
link.fk_mm_parent_column_id,
)
.where(
`${MetaTable.COL_RELATIONS}.fk_mm_parent_column_id`,
link.fk_mm_child_column_id,
);
} }
if(!columnInCurrTable) { break;
} else {
// generate meta and insert into colOptions logger.error(
`Couldn't find any column in current table which is related to the link '${link.id}'.`,
// based on type insert data into colOptions );
switch (link.type) {
case RelationTypes.HAS_MANY: // delete the link column since it's not useful anymore and not recoverable
// insert data into colOptions await Column.delete(
ncMeta.knex(MetaTable.COL_RELATIONS).insert({ {
id: (ncMeta as MetaService).genNanoid(MetaTable.COL_RELATIONS), workspace_id: column.workspace_id,
type: RelationTypes.BELONGS_TO, base_id: column.base_id,
fk_column_id: column.id, },
fk_related_model_id: relatedTableId, column.id,
break; ncMeta,
case RelationTypes.ONE_TO_ONE: );
// insert data into colOptions
break;
case RelationTypes.BELONGS_TO:
// insert data into colOptions
break;
case RelationTypes.MANY_TO_MANY:
// insert data into colOptions
break;
}
break;
}
} }
} }
} }

Loading…
Cancel
Save