mirror of https://github.com/nocodb/nocodb
12 changed files with 1162 additions and 99 deletions
@ -0,0 +1,570 @@ |
|||||||
|
import BaseApiBuilder, { XcTablesPopulateParams } from '../BaseApiBuilder'; |
||||||
|
import xcMetaDiff, { |
||||||
|
NcMetaDiff as NcMetaDiffType, |
||||||
|
XcMetaDiffType |
||||||
|
} from '../../meta/handlers/xcMetaDiff'; |
||||||
|
import XcCache from '../../plugins/adapters/cache/XcCache'; |
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
export default async function(this: BaseApiBuilder<any> | any) { |
||||||
|
const changes: Array<NcMetaDiffType> = await xcMetaDiff.call( |
||||||
|
{ |
||||||
|
projectGetSqlClient: () => { |
||||||
|
return this.getSqlClient(); |
||||||
|
}, |
||||||
|
getProjectId: () => this.getProjectId(), |
||||||
|
getDbAlias: () => this.getDbAlias(), |
||||||
|
xcMeta: this.xcMeta |
||||||
|
}, |
||||||
|
{} |
||||||
|
); |
||||||
|
|
||||||
|
const populateParams: XcTablesPopulateParams = { |
||||||
|
tableNames: [], |
||||||
|
type: 'table', |
||||||
|
columns: {}, |
||||||
|
oldMetas: {} |
||||||
|
}; |
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const tableList = (await this.getSqlClient().tableList())?.data?.list; |
||||||
|
// @ts-ignore
|
||||||
|
const relationList = (await this.getSqlClient().tableList())?.data?.list; |
||||||
|
|
||||||
|
const oldModels = await this.xcMeta.metaList( |
||||||
|
this.getProjectId(), |
||||||
|
this.getDbAlias(), |
||||||
|
'nc_models', |
||||||
|
{ condition: { type: 'table' } } |
||||||
|
); |
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const oldMetas = oldModels.map(m => { |
||||||
|
const meta = JSON.parse(m.meta); |
||||||
|
XcCache.del([this.projectId, this.dbAlias, 'table', meta.tn].join('::')); |
||||||
|
meta.id = m.id; |
||||||
|
return meta; |
||||||
|
}); |
||||||
|
const oldQueryParams = oldModels.map(m => JSON.parse(m.query_params)); |
||||||
|
|
||||||
|
const relationTableMetas = new Set(); |
||||||
|
for (const { tn, detectedChanges } of changes) { |
||||||
|
if (!detectedChanges?.length) continue; |
||||||
|
|
||||||
|
for (const change of detectedChanges) { |
||||||
|
switch (change.type) { |
||||||
|
case XcMetaDiffType.TABLE_NEW: |
||||||
|
// add table to list
|
||||||
|
|
||||||
|
populateParams.tableNames.push({ tn }); |
||||||
|
|
||||||
|
break; |
||||||
|
case XcMetaDiffType.TABLE_REMOVE: |
||||||
|
{ |
||||||
|
// delete table meta and views
|
||||||
|
// delete lookup relation etc
|
||||||
|
|
||||||
|
// todo: enable
|
||||||
|
|
||||||
|
await this.deleteTableNameInACL(tn); |
||||||
|
|
||||||
|
await this.xcMeta.metaDelete( |
||||||
|
this.projectId, |
||||||
|
this.dbAlias, |
||||||
|
'nc_shared_views', |
||||||
|
{ |
||||||
|
model_name: tn |
||||||
|
} |
||||||
|
); |
||||||
|
await this.xcMeta.metaDelete( |
||||||
|
this.projectId, |
||||||
|
this.dbAlias, |
||||||
|
'nc_models', |
||||||
|
{ |
||||||
|
title: tn |
||||||
|
} |
||||||
|
); |
||||||
|
if (delete this.metas[tn]) delete this.metas[tn]; |
||||||
|
if (delete this.models[tn]) delete this.models[tn]; |
||||||
|
} |
||||||
|
break; |
||||||
|
case XcMetaDiffType.TABLE_COLUMN_ADD: |
||||||
|
// update old
|
||||||
|
populateParams.tableNames.push({ tn }); |
||||||
|
populateParams.oldMetas[tn] = oldMetas.find(m => m.tn === tn); |
||||||
|
|
||||||
|
break; |
||||||
|
case XcMetaDiffType.TABLE_COLUMN_TYPE_CHANGE: |
||||||
|
// update type in old meta
|
||||||
|
|
||||||
|
populateParams.oldMetas[tn] = oldMetas.find(m => m.tn === tn); |
||||||
|
populateParams.tableNames.push({ |
||||||
|
tn, |
||||||
|
_tn: populateParams.oldMetas[tn]?._tn |
||||||
|
}); |
||||||
|
|
||||||
|
break; |
||||||
|
case XcMetaDiffType.TABLE_COLUMN_REMOVE: |
||||||
|
{ |
||||||
|
const oldMetaIdx = oldMetas.findIndex(m => m.tn === tn); |
||||||
|
if (oldMetaIdx === -1) |
||||||
|
throw new Error('Old meta not found : ' + tn); |
||||||
|
|
||||||
|
const oldMeta = oldMetas[oldMetaIdx]; |
||||||
|
|
||||||
|
populateParams.oldMetas[tn] = oldMeta; |
||||||
|
populateParams.tableNames.push({ |
||||||
|
tn, |
||||||
|
_tn: populateParams.oldMetas[tn]?._tn |
||||||
|
}); |
||||||
|
|
||||||
|
const queryParams = oldQueryParams[oldMetaIdx]; |
||||||
|
|
||||||
|
const oldColumn = oldMeta.columns.find(c => c.cn === change?.cn); |
||||||
|
|
||||||
|
const { |
||||||
|
// virtualViews,
|
||||||
|
virtualViewsParamsArr |
||||||
|
// @ts-ignore
|
||||||
|
} = await this.extractSharedAndVirtualViewsParams(tn); |
||||||
|
// virtual views param update
|
||||||
|
for (const qp of [queryParams, ...virtualViewsParamsArr]) { |
||||||
|
if (!qp) continue; |
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const { |
||||||
|
filters = {}, |
||||||
|
sortList = [], |
||||||
|
showFields = {}, |
||||||
|
fieldsOrder = [], |
||||||
|
extraViewParams = {} |
||||||
|
} = qp; |
||||||
|
|
||||||
|
/* update sort field */ |
||||||
|
/* const sIndex = (sortList || []).findIndex( |
||||||
|
v => v.field === oldColumn._cn |
||||||
|
); |
||||||
|
if (sIndex > -1) { |
||||||
|
sortList.splice(sIndex, 1); |
||||||
|
}*/ |
||||||
|
for (const sort of sortList || []) { |
||||||
|
if ( |
||||||
|
sort?.field === oldColumn.cn || |
||||||
|
sort?.field === oldColumn._cn |
||||||
|
) { |
||||||
|
sortList.splice(sortList.indexOf(sort), 1); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* update show field */ |
||||||
|
if (oldColumn.cn in showFields || oldColumn._cn in showFields) { |
||||||
|
delete showFields[oldColumn.cn]; |
||||||
|
delete showFields[oldColumn._cn]; |
||||||
|
} |
||||||
|
/* update filters */ |
||||||
|
// todo: remove only corresponding filter and compare field name
|
||||||
|
/* if ( |
||||||
|
filters && |
||||||
|
(JSON.stringify(filters)?.includes(`"${oldColumn.cn}"`) || |
||||||
|
JSON.stringify(filters)?.includes(`"${oldColumn._cn}"`)) |
||||||
|
) { |
||||||
|
filters.splice(0, filters.length); |
||||||
|
}*/ |
||||||
|
for (const filter of filters) { |
||||||
|
if ( |
||||||
|
filter?.field === oldColumn.cn || |
||||||
|
filter?.field === oldColumn._cn |
||||||
|
) { |
||||||
|
filters.splice(filters.indexOf(filter), 1); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* update fieldsOrder */ |
||||||
|
let index = fieldsOrder.indexOf(oldColumn.cn); |
||||||
|
if (index > -1) { |
||||||
|
fieldsOrder.splice(index, 1); |
||||||
|
} |
||||||
|
index = fieldsOrder.indexOf(oldColumn._cn); |
||||||
|
if (index > -1) { |
||||||
|
fieldsOrder.splice(index, 1); |
||||||
|
} |
||||||
|
|
||||||
|
/* update formView params */ |
||||||
|
// extraViewParams.formParams.fields
|
||||||
|
if (extraViewParams?.formParams?.fields?.[oldColumn.cn]) { |
||||||
|
delete extraViewParams.formParams.fields[oldColumn.cn]; |
||||||
|
} |
||||||
|
if (extraViewParams?.formParams?.fields?.[oldColumn._cn]) { |
||||||
|
delete extraViewParams.formParams.fields[oldColumn._cn]; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Delete lookup columns mapping to current column
|
||||||
|
// update column name in belongs to
|
||||||
|
if (oldMeta.belongsTo?.length) { |
||||||
|
for (const bt of oldMeta.belongsTo) { |
||||||
|
// filter out lookup columns which maps to current col
|
||||||
|
this.metas[bt.rtn].v = this.metas[bt.rtn].v?.filter(v => { |
||||||
|
if (v.lk && v.lk.ltn === tn && v.lk.lcn === oldColumn.cn) { |
||||||
|
relationTableMetas.add(this.metas[bt.rtn]); |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// update column name in has many
|
||||||
|
if (oldMeta.hasMany?.length) { |
||||||
|
for (const hm of oldMeta.hasMany) { |
||||||
|
// filter out lookup columns which maps to current col
|
||||||
|
this.metas[hm.tn].v = this.metas[hm.tn].v?.filter(v => { |
||||||
|
if (v.lk && v.lk.ltn === tn && v.lk.lcn === change.cn) { |
||||||
|
relationTableMetas.add(this.metas[hm.tn]); |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// update column name in many to many
|
||||||
|
if (oldMeta.manyToMany?.length) { |
||||||
|
for (const mm of oldMeta.manyToMany) { |
||||||
|
// filter out lookup columns which maps to current col
|
||||||
|
this.metas[mm.rtn].v = this.metas[mm.rtn].v?.filter(v => { |
||||||
|
if (v.lk && v.lk.ltn === tn && v.lk.lcn === change.cn) { |
||||||
|
relationTableMetas.add(this.metas[mm.rtn]); |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
break; |
||||||
|
case XcMetaDiffType.TABLE_RELATION_ADD: |
||||||
|
{ |
||||||
|
if (change.tn === tn) |
||||||
|
// todo : enable
|
||||||
|
// ignore duplicate
|
||||||
|
await this.xcMeta.metaInsert( |
||||||
|
this.projectId, |
||||||
|
this.dbAlias, |
||||||
|
'nc_relations', |
||||||
|
{ |
||||||
|
tn: change.tn, |
||||||
|
_tn: this.getTableNameAlias(change.tn), |
||||||
|
cn: change.cn, |
||||||
|
rtn: change.rtn, |
||||||
|
_rtn: this.getTableNameAlias(change.rtn), |
||||||
|
rcn: change.rcn, |
||||||
|
type: 'real', |
||||||
|
db_type: this.connectionConfig?.client |
||||||
|
// todo: get these info
|
||||||
|
/* dr: , |
||||||
|
ur: onUpdate, |
||||||
|
fkn*/ |
||||||
|
} |
||||||
|
); |
||||||
|
} |
||||||
|
break; |
||||||
|
case XcMetaDiffType.TABLE_RELATION_REMOVE: |
||||||
|
{ |
||||||
|
// todo: remove from nc_relations
|
||||||
|
// todo:enable
|
||||||
|
await this.xcMeta.metaDelete( |
||||||
|
this.projectId, |
||||||
|
this.dbAlias, |
||||||
|
'nc_relations', |
||||||
|
{ |
||||||
|
tn: change.tn, |
||||||
|
cn: change.cn, |
||||||
|
rtn: change.rtn, |
||||||
|
rcn: change.rcn, |
||||||
|
type: 'real' |
||||||
|
// db_type: this.connectionConfig?.client
|
||||||
|
} |
||||||
|
); |
||||||
|
|
||||||
|
await this.deleteRelationInACL(change.rtn, change.tn); |
||||||
|
|
||||||
|
for (const tn of [change.tn, change.rtn]) { |
||||||
|
const { |
||||||
|
// @ts-ignore
|
||||||
|
virtualViews, |
||||||
|
virtualViewsParamsArr |
||||||
|
} = await this.extractSharedAndVirtualViewsParams(tn); |
||||||
|
|
||||||
|
const oldMeta = oldMetas.find(m => m.tn === tn); |
||||||
|
populateParams.oldMetas[tn] = oldMeta; |
||||||
|
populateParams.tableNames.push({ |
||||||
|
tn, |
||||||
|
_tn: populateParams.oldMetas[tn]?._tn |
||||||
|
}); |
||||||
|
|
||||||
|
// extract alias of relation virtual column
|
||||||
|
const relation = change.tn === tn ? 'bt' : 'hm'; |
||||||
|
const alias = oldMeta?.v?.find( |
||||||
|
v => |
||||||
|
v?.[relation]?.tn === change.tn && |
||||||
|
v?.[relation]?.rtn === change.rtn |
||||||
|
)?._cn; |
||||||
|
|
||||||
|
// virtual views param update
|
||||||
|
for (const qp of virtualViewsParamsArr) { |
||||||
|
// @ts-ignore
|
||||||
|
const { |
||||||
|
showFields = {}, |
||||||
|
fieldsOrder, |
||||||
|
extraViewParams = {} |
||||||
|
} = qp; |
||||||
|
|
||||||
|
/* update show field */ |
||||||
|
if (alias in showFields) { |
||||||
|
delete showFields[alias]; |
||||||
|
} |
||||||
|
|
||||||
|
/* update fieldsOrder */ |
||||||
|
const index = fieldsOrder.indexOf(alias); |
||||||
|
if (index > -1) { |
||||||
|
fieldsOrder.splice(index, 1); |
||||||
|
} |
||||||
|
|
||||||
|
/* update formView params */ |
||||||
|
if (extraViewParams?.formParams?.fields?.[alias]) { |
||||||
|
delete extraViewParams.formParams.fields[alias]; |
||||||
|
} |
||||||
|
} |
||||||
|
// todo: enable
|
||||||
|
await this.updateSharedAndVirtualViewsParams( |
||||||
|
virtualViewsParamsArr, |
||||||
|
virtualViews |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
// todo: bt
|
||||||
|
const childMeta = oldMetas.find(m => m.tn === change.tn); |
||||||
|
Object.assign(childMeta, { |
||||||
|
v: childMeta.v.filter( |
||||||
|
({ bt, lk }) => |
||||||
|
(!bt || bt.rtn !== change.rtn || bt.tn !== change.tn) && |
||||||
|
!( |
||||||
|
lk && |
||||||
|
lk.type === 'bt' && |
||||||
|
lk.rtn === change.rtn && |
||||||
|
lk.tn === change.tn |
||||||
|
) |
||||||
|
) |
||||||
|
}); |
||||||
|
// todo: hm
|
||||||
|
const parentMeta = oldMetas.find(m => m.tn === change.rtn); |
||||||
|
Object.assign(parentMeta, { |
||||||
|
v: parentMeta.v.filter( |
||||||
|
({ hm, lk, rl }) => |
||||||
|
(!hm || hm.rtn !== change.rtn || hm.tn !== change.tn) && |
||||||
|
!( |
||||||
|
lk && |
||||||
|
lk.type === 'hm' && |
||||||
|
lk.rtn === change.rtn && |
||||||
|
lk.tn === change.tn |
||||||
|
) && |
||||||
|
!( |
||||||
|
rl && |
||||||
|
rl.type === 'hm' && |
||||||
|
rl.rtn === change.rtn && |
||||||
|
rl.tn === change.tn |
||||||
|
) |
||||||
|
) |
||||||
|
}); |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// todo: optimize
|
||||||
|
// remove duplicate from list
|
||||||
|
populateParams.tableNames = populateParams.tableNames?.filter(t => { |
||||||
|
return t === populateParams.tableNames.find(t1 => t1.tn === t.tn); |
||||||
|
}); |
||||||
|
|
||||||
|
await this.xcTablesPopulate(populateParams); |
||||||
|
|
||||||
|
return populateParams; |
||||||
|
} |
||||||
|
|
||||||
|
// public async onTableMetaRecreate(tableName: string): Promise<void> {
|
||||||
|
// this.baseLog(`onTableMetaRecreate : '%s'`, tableName);
|
||||||
|
// const oldMeta = this.getMeta(tableName);
|
||||||
|
//
|
||||||
|
// const virtualRelations = await this.xcMeta.metaList(
|
||||||
|
// this.projectId,
|
||||||
|
// this.dbAlias,
|
||||||
|
// 'nc_relations',
|
||||||
|
// {
|
||||||
|
// xcCondition: {
|
||||||
|
// _or: [
|
||||||
|
// {
|
||||||
|
// tn: {
|
||||||
|
// eq: tableName
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// rtn: {
|
||||||
|
// eq: tableName
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
// const colListRef = {};
|
||||||
|
// const tableList =
|
||||||
|
// (await this.getSqlClient()?.tableList())?.data?.list || [];
|
||||||
|
//
|
||||||
|
// colListRef[tableName] = await this.getColumnList(tableName);
|
||||||
|
//
|
||||||
|
// // @ts-ignore
|
||||||
|
// const relations = await this.getRelationList();
|
||||||
|
//
|
||||||
|
// for (const vCol of oldMeta.v || []) {
|
||||||
|
// if (vCol.lk) {
|
||||||
|
// }
|
||||||
|
// if (vCol.rl) {
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// for (const rel of virtualRelations) {
|
||||||
|
// colListRef[rel.tn] =
|
||||||
|
// colListRef[rel.tn] || (await this.getColumnList(rel.tn));
|
||||||
|
// colListRef[rel.rtn] =
|
||||||
|
// colListRef[rel.rtn] || (await this.getColumnList(rel.rtn));
|
||||||
|
//
|
||||||
|
// // todo: compare with real relation list
|
||||||
|
// if (
|
||||||
|
// !(
|
||||||
|
// tableList.find(t => t.tn === rel.rtn) &&
|
||||||
|
// tableList.find(t => t.tn === rel.tn) &&
|
||||||
|
// colListRef[rel.tn].find(t => t.cn === rel.cn) &&
|
||||||
|
// colListRef[rel.rtn].find(t => t.cn === rel.rcn)
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
// await this.xcMeta.metaDelete(
|
||||||
|
// this.projectId,
|
||||||
|
// this.dbAlias,
|
||||||
|
// 'nc_relations',
|
||||||
|
// rel.id
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // todo : handle query params
|
||||||
|
// const oldModelRow = await this.xcMeta.metaGet(
|
||||||
|
// this.projectId,
|
||||||
|
// this.dbAlias,
|
||||||
|
// 'nc_models',
|
||||||
|
// { title: tableName }
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// await this.onTableDelete(tableName, {
|
||||||
|
// ignoreRelations: true,
|
||||||
|
// ignoreViews: true
|
||||||
|
// } as any);
|
||||||
|
//
|
||||||
|
// let queryParams: any;
|
||||||
|
// try {
|
||||||
|
// queryParams = JSON.parse(oldModelRow.query_params);
|
||||||
|
// } catch (e) {
|
||||||
|
// queryParams = {};
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// const {
|
||||||
|
// virtualViews,
|
||||||
|
// virtualViewsParamsArr
|
||||||
|
// } = await this.extractSharedAndVirtualViewsParams(tableName);
|
||||||
|
//
|
||||||
|
// for (const oldColumn of oldMeta.columns) {
|
||||||
|
// if (colListRef[tableName].find(c => c.cn === oldColumn.cn)) continue;
|
||||||
|
// addErrorOnColumnDeleteInFormula({
|
||||||
|
// virtualColumns: oldMeta.v,
|
||||||
|
// columnName: oldColumn.cn
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// await this.onTableCreate(tableName, { oldMeta });
|
||||||
|
//
|
||||||
|
// const meta = this.getMeta(tableName);
|
||||||
|
//
|
||||||
|
// for (const oldColumn of oldMeta.columns) {
|
||||||
|
// if (meta.columns.find(c => c.cn === oldColumn.cn)) continue;
|
||||||
|
//
|
||||||
|
// // virtual views param update
|
||||||
|
// for (const qp of [queryParams, ...virtualViewsParamsArr]) {
|
||||||
|
// if (!qp) continue;
|
||||||
|
//
|
||||||
|
// // @ts-ignore
|
||||||
|
// const {
|
||||||
|
// filters = {},
|
||||||
|
// sortList = [],
|
||||||
|
// showFields = {},
|
||||||
|
// fieldsOrder = [],
|
||||||
|
// extraViewParams = {}
|
||||||
|
// } = qp;
|
||||||
|
//
|
||||||
|
// /* update sort field */
|
||||||
|
// const sIndex = (sortList || []).findIndex(
|
||||||
|
// v => v.field === oldColumn._cn
|
||||||
|
// );
|
||||||
|
// if (sIndex > -1) {
|
||||||
|
// sortList.splice(sIndex, 1);
|
||||||
|
// }
|
||||||
|
// /* update show field */
|
||||||
|
// if (oldColumn.cn in showFields || oldColumn._cn in showFields) {
|
||||||
|
// delete showFields[oldColumn.cn];
|
||||||
|
// delete showFields[oldColumn._cn];
|
||||||
|
// }
|
||||||
|
// /* update filters */
|
||||||
|
// // todo: remove only corresponding filter and compare field name
|
||||||
|
// if (
|
||||||
|
// filters &&
|
||||||
|
// (JSON.stringify(filters)?.includes(`"${oldColumn.cn}"`) ||
|
||||||
|
// JSON.stringify(filters)?.includes(`"${oldColumn._cn}"`))
|
||||||
|
// ) {
|
||||||
|
// filters.splice(0, filters.length);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /* update fieldsOrder */
|
||||||
|
// let index = fieldsOrder.indexOf(oldColumn.cn);
|
||||||
|
// if (index > -1) {
|
||||||
|
// fieldsOrder.splice(index, 1);
|
||||||
|
// }
|
||||||
|
// index = fieldsOrder.indexOf(oldColumn._cn);
|
||||||
|
// if (index > -1) {
|
||||||
|
// fieldsOrder.splice(index, 1);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /* update formView params */
|
||||||
|
// // extraViewParams.formParams.fields
|
||||||
|
// if (extraViewParams?.formParams?.fields?.[oldColumn.cn]) {
|
||||||
|
// delete extraViewParams.formParams.fields[oldColumn.cn];
|
||||||
|
// }
|
||||||
|
// if (extraViewParams?.formParams?.fields?.[oldColumn._cn]) {
|
||||||
|
// delete extraViewParams.formParams.fields[oldColumn._cn];
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// await this.updateSharedAndVirtualViewsParams(
|
||||||
|
// virtualViewsParamsArr,
|
||||||
|
// virtualViews
|
||||||
|
// );
|
||||||
|
// await this.xcMeta.metaUpdate(
|
||||||
|
// this.projectId,
|
||||||
|
// this.dbAlias,
|
||||||
|
// 'nc_models',
|
||||||
|
// {
|
||||||
|
// query_params: JSON.stringify(queryParams)
|
||||||
|
// },
|
||||||
|
// { title: tableName, type: 'table' }
|
||||||
|
// );
|
||||||
|
// }
|
@ -0,0 +1,202 @@ |
|||||||
|
import NcMetaMgr from '../NcMetaMgr'; |
||||||
|
|
||||||
|
enum XcMetaDiffType { |
||||||
|
TABLE_NEW = 'TABLE_NEW', |
||||||
|
TABLE_REMOVE = 'TABLE_REMOVE', |
||||||
|
TABLE_COLUMN_ADD = 'TABLE_COLUMN_ADD', |
||||||
|
TABLE_COLUMN_TYPE_CHANGE = 'TABLE_COLUMN_TYPE_CHANGE', |
||||||
|
TABLE_COLUMN_REMOVE = 'TABLE_COLUMN_REMOVE', |
||||||
|
TABLE_RELATION_ADD = 'TABLE_RELATION_ADD', |
||||||
|
TABLE_RELATION_REMOVE = 'TABLE_RELATION_REMOVE', |
||||||
|
TABLE_VIRTUAL_RELATION_ADD = 'TABLE_VIRTUAL_RELATION_ADD', |
||||||
|
TABLE_VIRTUAL_RELATION_DELETE = 'TABLE_VIRTUAL_RELATION_DELETE' |
||||||
|
} |
||||||
|
|
||||||
|
interface NcMetaDiff { |
||||||
|
tn: string; |
||||||
|
detectedChanges: Array<{ |
||||||
|
type: XcMetaDiffType; |
||||||
|
msg?: string; |
||||||
|
[key: string]: any; |
||||||
|
}>; |
||||||
|
} |
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
export default async function( |
||||||
|
this: NcMetaMgr, |
||||||
|
{ args }: { args: any; req: any } |
||||||
|
): Promise<Array<NcMetaDiff>> { |
||||||
|
const changes = []; |
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const sqlClient = this.projectGetSqlClient(args); |
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const tableList = (await sqlClient.tableList())?.data?.list; |
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const oldMetas = ( |
||||||
|
await this.xcMeta.metaList( |
||||||
|
this.getProjectId(args), |
||||||
|
this.getDbAlias(args), |
||||||
|
'nc_models', |
||||||
|
{ condition: { type: 'table' } } |
||||||
|
) |
||||||
|
).map(m => JSON.parse(m.meta)); |
||||||
|
|
||||||
|
for (const table of tableList) { |
||||||
|
if (table.tn === 'nc_evolutions') continue; |
||||||
|
|
||||||
|
const oldMetaIdx = oldMetas.findIndex(m => m.tn === table.tn); |
||||||
|
|
||||||
|
// new table
|
||||||
|
if (oldMetaIdx === -1) { |
||||||
|
changes.push({ |
||||||
|
tn: table.tn, |
||||||
|
detectedChanges: [ |
||||||
|
{ |
||||||
|
type: XcMetaDiffType.TABLE_NEW, |
||||||
|
msg: `New table` |
||||||
|
} |
||||||
|
] |
||||||
|
}); |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
const oldMeta = oldMetas[oldMetaIdx]; |
||||||
|
oldMetas.splice(oldMetaIdx, 1); |
||||||
|
|
||||||
|
const tableProp = { |
||||||
|
tn: table.tn, |
||||||
|
detectedChanges: [] |
||||||
|
}; |
||||||
|
changes.push(tableProp); |
||||||
|
|
||||||
|
// check for column change
|
||||||
|
const columnList = (await sqlClient.columnList({ tn: table.tn }))?.data |
||||||
|
?.list; |
||||||
|
|
||||||
|
for (const column of columnList) { |
||||||
|
const oldColIdx = oldMeta.columns.findIndex(c => c.cn === column.cn); |
||||||
|
|
||||||
|
// new table
|
||||||
|
if (oldColIdx === -1) { |
||||||
|
tableProp.detectedChanges.push({ |
||||||
|
type: XcMetaDiffType.TABLE_COLUMN_ADD, |
||||||
|
msg: `New column(${column.cn})`, |
||||||
|
cn: column.cn |
||||||
|
}); |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
const oldCol = oldMeta.columns[oldColIdx]; |
||||||
|
oldMeta.columns.splice(oldColIdx, 1); |
||||||
|
|
||||||
|
if (oldCol.dt !== column.dt) { |
||||||
|
tableProp.detectedChanges.push({ |
||||||
|
type: XcMetaDiffType.TABLE_COLUMN_TYPE_CHANGE, |
||||||
|
msg: `Column type changed(${column.cn})`, |
||||||
|
cn: oldCol.cn |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
for (const { cn } of oldMeta.columns) { |
||||||
|
tableProp.detectedChanges.push({ |
||||||
|
type: XcMetaDiffType.TABLE_COLUMN_REMOVE, |
||||||
|
msg: `Column removed(${cn})`, |
||||||
|
cn |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
for (const { tn } of oldMetas) { |
||||||
|
changes.push({ |
||||||
|
tn: tn, |
||||||
|
detectedChanges: [ |
||||||
|
{ |
||||||
|
type: XcMetaDiffType.TABLE_REMOVE, |
||||||
|
msg: `Table removed` |
||||||
|
} |
||||||
|
] |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const relationList = (await sqlClient.relationListAll())?.data?.list; |
||||||
|
|
||||||
|
// todo: handle virtual
|
||||||
|
const oldRelations = await this.xcMeta.metaList( |
||||||
|
this.getProjectId(args), |
||||||
|
this.getDbAlias(args), |
||||||
|
'nc_relations', |
||||||
|
{ |
||||||
|
condition: { |
||||||
|
type: 'real' |
||||||
|
} |
||||||
|
} |
||||||
|
); |
||||||
|
|
||||||
|
// check relations
|
||||||
|
for (const rel of relationList) { |
||||||
|
const oldRelIdx = oldRelations.findIndex(oldRel => { |
||||||
|
return ( |
||||||
|
rel.tn === oldRel.tn && |
||||||
|
rel.rtn === oldRel.rtn && |
||||||
|
rel.cn === oldRel.cn && |
||||||
|
rel.rcn === oldRel.rcn |
||||||
|
); |
||||||
|
}); |
||||||
|
|
||||||
|
// new table
|
||||||
|
if (oldRelIdx === -1) { |
||||||
|
changes |
||||||
|
.find(t => t.tn === rel.tn) |
||||||
|
?.detectedChanges.push({ |
||||||
|
type: XcMetaDiffType.TABLE_RELATION_ADD, |
||||||
|
tn: rel.tn, |
||||||
|
rtn: rel.rtn, |
||||||
|
cn: rel.cn, |
||||||
|
rcn: rel.rcn, |
||||||
|
msg: `New relation added` |
||||||
|
}); |
||||||
|
changes |
||||||
|
.find(t => t.tn === rel.rtn) |
||||||
|
?.detectedChanges.push({ |
||||||
|
type: XcMetaDiffType.TABLE_RELATION_ADD, |
||||||
|
tn: rel.tn, |
||||||
|
rtn: rel.rtn, |
||||||
|
cn: rel.cn, |
||||||
|
rcn: rel.rcn, |
||||||
|
msg: `New relation added` |
||||||
|
}); |
||||||
|
continue; |
||||||
|
} |
||||||
|
oldRelations.splice(oldRelIdx, 1); |
||||||
|
} |
||||||
|
|
||||||
|
for (const oldRel of oldRelations) { |
||||||
|
changes |
||||||
|
.find(t => t.tn === oldRel.tn) |
||||||
|
?.detectedChanges.push({ |
||||||
|
type: XcMetaDiffType.TABLE_RELATION_REMOVE, |
||||||
|
tn: oldRel.tn, |
||||||
|
rtn: oldRel.rtn, |
||||||
|
cn: oldRel.cn, |
||||||
|
rcn: oldRel.rcn, |
||||||
|
msg: `Relation removed` |
||||||
|
}); |
||||||
|
changes |
||||||
|
.find(t => t.tn === oldRel.rtn) |
||||||
|
?.detectedChanges.push({ |
||||||
|
type: XcMetaDiffType.TABLE_RELATION_REMOVE, |
||||||
|
tn: oldRel.tn, |
||||||
|
rtn: oldRel.rtn, |
||||||
|
cn: oldRel.cn, |
||||||
|
rcn: oldRel.rcn, |
||||||
|
msg: `Relation removed` |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
return changes; |
||||||
|
} |
||||||
|
export { XcMetaDiffType, NcMetaDiff }; |
@ -0,0 +1,54 @@ |
|||||||
|
const init = `CREATE TABLE \`table_col_delete\` (
|
||||||
|
\`id\` int NOT NULL AUTO_INCREMENT,
|
||||||
|
\`title\` varchar(45) DEFAULT NULL,
|
||||||
|
PRIMARY KEY (\`id\`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; |
||||||
|
|
||||||
|
CREATE TABLE \`table_to_col_add\` (
|
||||||
|
\`id\` int NOT NULL AUTO_INCREMENT,
|
||||||
|
PRIMARY KEY (\`id\`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; |
||||||
|
|
||||||
|
CREATE TABLE \`table_to_rel_add_child\` (
|
||||||
|
\`id\` int NOT NULL AUTO_INCREMENT,
|
||||||
|
PRIMARY KEY (\`id\`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; |
||||||
|
|
||||||
|
CREATE TABLE \`table_to_rel_add_parent\` (
|
||||||
|
\`id\` int NOT NULL AUTO_INCREMENT,
|
||||||
|
PRIMARY KEY (\`id\`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; |
||||||
|
|
||||||
|
CREATE TABLE \`table_to_rel_remove_child\` (
|
||||||
|
\`id\` int NOT NULL AUTO_INCREMENT,
|
||||||
|
\`table_to_rel_remove_parent_id\` int DEFAULT NULL,
|
||||||
|
PRIMARY KEY (\`id\`),
|
||||||
|
KEY \`table_to_rel_remove_parent_fk_idx\` (\`table_to_rel_remove_parent_id\`),
|
||||||
|
CONSTRAINT \`table_to_rel_remove_parent_fk\` FOREIGN KEY (\`table_to_rel_remove_parent_id\`) REFERENCES \`table_to_rel_remove_parent\` (\`id\`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; |
||||||
|
|
||||||
|
CREATE TABLE \`table_to_rel_remove_parent\` (
|
||||||
|
\`id\` int NOT NULL AUTO_INCREMENT,
|
||||||
|
PRIMARY KEY (\`id\`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; |
||||||
|
|
||||||
|
CREATE TABLE \`table_to_remove\` (
|
||||||
|
\`id\` int NOT NULL AUTO_INCREMENT,
|
||||||
|
\`table_to_removecol\` varchar(45) NOT NULL,
|
||||||
|
PRIMARY KEY (\`id\`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; |
||||||
|
` |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const colDel = `ALTER TABLE \`sakila\`.\`table_col_delete\`
|
||||||
|
DROP COLUMN \`title\`;` |
||||||
|
|
||||||
|
const relDel =`ALTER TABLE \`sakila\`.\`table_to_rel_remove_child\`
|
||||||
|
DROP FOREIGN KEY \`table_to_rel_remove_parent_fk\`;
|
||||||
|
ALTER TABLE \`sakila\`.\`table_to_rel_remove_child\`
|
||||||
|
DROP COLUMN \`table_to_rel_remove_parent_id\`,
|
||||||
|
DROP INDEX \`table_to_rel_remove_parent_fk_idx\` ;
|
||||||
|
; |
||||||
|
` |
||||||
|
const tableDel =`DROP TABLE \`sakila\`.\`table_to_remove\`;` |
Loading…
Reference in new issue