Browse Source

Merge pull request #4961 from nocodb/fix/4819-upgrader-error

fix: upgrader errors
pull/4966/head
mertmit 2 years ago committed by GitHub
parent
commit
0df8b99953
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 184
      packages/nocodb/src/lib/version-upgrader/ncAttachmentUpgrader.ts

184
packages/nocodb/src/lib/version-upgrader/ncAttachmentUpgrader.ts

@ -1,3 +1,4 @@
import { Knex } from 'knex';
import { NcUpgraderCtx } from './NcUpgrader'; import { NcUpgraderCtx } from './NcUpgrader';
import { MetaTable } from '../utils/globals'; import { MetaTable } from '../utils/globals';
import Base from '../models/Base'; import Base from '../models/Base';
@ -29,7 +30,7 @@ function getTnPath(knex: XKnex, tb: Model) {
const schema = (knex as any).searchPath?.(); const schema = (knex as any).searchPath?.();
const clientType = knex.clientType(); const clientType = knex.clientType();
if (clientType === 'mssql' && schema) { if (clientType === 'mssql' && schema) {
return knex.raw('??.??', [schema, tb.table_name]); return knex.raw('??.??', [schema, tb.table_name]).toQuery();
} else if (clientType === 'snowflake') { } else if (clientType === 'snowflake') {
return [ return [
knex.client.config.connection.database, knex.client.config.connection.database,
@ -45,82 +46,133 @@ export default async function ({ ncMeta }: NcUpgraderCtx) {
const bases: BaseType[] = await ncMeta.metaList2(null, null, MetaTable.BASES); const bases: BaseType[] = await ncMeta.metaList2(null, null, MetaTable.BASES);
for (const _base of bases) { for (const _base of bases) {
const base = new Base(_base); const base = new Base(_base);
const knex: XKnex = base.is_meta
// skip if the prodect_id is missing
if (!base.project_id) {
continue;
}
const project = await ncMeta.metaGet2(null, null, MetaTable.PROJECT, {
id: base.project_id,
});
// skip if the project is missing
if (!project) {
continue;
}
const isProjectDeleted = project.deleted;
const knex: Knex = base.is_meta
? ncMeta.knexConnection ? ncMeta.knexConnection
: NcConnectionMgrv2.get(base); : NcConnectionMgrv2.get(base);
const models = await base.getModels(ncMeta); const models = await base.getModels(ncMeta);
for (const model of models) { for (const model of models) {
const updateRecords = []; try {
const columns = await ( // if the table is missing in database, skip
await Model.get(model.id, ncMeta) if (!(await knex.schema.hasTable(getTnPath(knex, model)))) {
).getColumns(ncMeta); continue;
const attachmentColumns = columns }
.filter((c) => c.uidt === UITypes.Attachment)
.map((c) => c.column_name);
if (attachmentColumns.length === 0) {
continue;
}
const primaryKeys = columns.filter((c) => c.pk).map((c) => c.column_name);
const records = await knex(getTnPath(knex, model)).select([
...primaryKeys,
...attachmentColumns,
]);
for (const record of records) {
for (const attachmentColumn of attachmentColumns) {
let attachmentMeta: Array<{
url: string;
}>;
// if parsing failed ignore the cell
try {
attachmentMeta =
typeof record[attachmentColumn] === 'string'
? JSON.parse(record[attachmentColumn])
: record[attachmentColumn];
} catch {}
// if cell data is not an array, ignore it
if (!Array.isArray(attachmentMeta)) {
continue;
}
if (attachmentMeta) { const updateRecords = [];
const newAttachmentMeta = [];
for (const attachment of attachmentMeta) { // get all attachment & primary key columns
if ('url' in attachment && typeof attachment.url === 'string') { // and filter out the columns that are missing in database
const match = attachment.url.match(/^(.*)\/download\/(.*)$/); const columns = await (await Model.get(model.id, ncMeta))
if (match) { .getColumns(ncMeta)
// e.g. http://localhost:8080/download/noco/xcdb/Sheet-1/title5/ee2G8p_nute_gunray.png .then(async (columns) => {
// match[1] = http://localhost:8080 const filteredColumns = [];
// match[2] = download/noco/xcdb/Sheet-1/title5/ee2G8p_nute_gunray.png
const path = `download/${match[2]}`; for (const column of columns) {
if (column.uidt !== UITypes.Attachment && !column.pk) continue;
newAttachmentMeta.push({ if (
...attachment, !(await knex.schema.hasColumn(
path, getTnPath(knex, model),
}); column.column_name
} else { ))
// keep it as it is )
newAttachmentMeta.push(attachment); continue;
filteredColumns.push(column);
}
return filteredColumns;
});
const attachmentColumns = columns
.filter((c) => c.uidt === UITypes.Attachment)
.map((c) => c.column_name);
if (attachmentColumns.length === 0) {
continue;
}
const primaryKeys = columns
.filter((c) => c.pk)
.map((c) => c.column_name);
const records = await knex(getTnPath(knex, model)).select();
for (const record of records) {
for (const attachmentColumn of attachmentColumns) {
let attachmentMeta: Array<{
url: string;
}>;
// if parsing failed ignore the cell
try {
attachmentMeta =
typeof record[attachmentColumn] === 'string'
? JSON.parse(record[attachmentColumn])
: record[attachmentColumn];
} catch {}
// if cell data is not an array, ignore it
if (!Array.isArray(attachmentMeta)) {
continue;
}
if (attachmentMeta) {
const newAttachmentMeta = [];
for (const attachment of attachmentMeta) {
if ('url' in attachment && typeof attachment.url === 'string') {
const match = attachment.url.match(/^(.*)\/download\/(.*)$/);
if (match) {
// e.g. http://localhost:8080/download/noco/xcdb/Sheet-1/title5/ee2G8p_nute_gunray.png
// match[1] = http://localhost:8080
// match[2] = download/noco/xcdb/Sheet-1/title5/ee2G8p_nute_gunray.png
const path = `download/${match[2]}`;
newAttachmentMeta.push({
...attachment,
path,
});
} else {
// keep it as it is
newAttachmentMeta.push(attachment);
}
} }
} }
} const where = primaryKeys
const where = primaryKeys .map((key) => {
.map((key) => { return { [key]: record[key] };
return { [key]: record[key] };
})
.reduce((acc, val) => Object.assign(acc, val), {});
updateRecords.push(
await knex(getTnPath(knex, model))
.update({
[attachmentColumn]: JSON.stringify(newAttachmentMeta),
}) })
.where(where) .reduce((acc, val) => Object.assign(acc, val), {});
); updateRecords.push(
await knex(getTnPath(knex, model))
.update({
[attachmentColumn]: JSON.stringify(newAttachmentMeta),
})
.where(where)
);
}
} }
} }
await Promise.all(updateRecords);
} catch (e) {
// ignore the error related to deleted project
if (!isProjectDeleted) {
throw e;
}
} }
await Promise.all(updateRecords);
} }
} }
} }

Loading…
Cancel
Save