mirror of https://github.com/nocodb/nocodb
Wing-Kam Wong
2 years ago
27 changed files with 785 additions and 581 deletions
@ -0,0 +1,34 @@
|
||||
name: cleanup caches by branch |
||||
on: |
||||
pull_request: |
||||
types: |
||||
- closed |
||||
jobs: |
||||
cleanup: |
||||
runs-on: ubuntu-latest |
||||
steps: |
||||
- name: Check out code |
||||
uses: actions/checkout@v3 |
||||
|
||||
- name: Cleanup |
||||
run: | |
||||
gh extension install actions/gh-actions-cache |
||||
|
||||
REPO=${{ github.repository }} |
||||
|
||||
# get the branch |
||||
BRANCH="refs/pull/${{ github.event.pull_request.number }}/merge" |
||||
|
||||
# fetch list of cache key |
||||
cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 ) |
||||
|
||||
# set this to not fail the workflow while deleting cache keys |
||||
set +e |
||||
|
||||
# delete cache key |
||||
for cacheKey in $cacheKeysForPR |
||||
do |
||||
gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm |
||||
done |
||||
env: |
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
@ -0,0 +1,3 @@
|
||||
import { populateMeta } from './populateMeta'; |
||||
|
||||
export { populateMeta }; |
@ -0,0 +1,278 @@
|
||||
import Project from '../../../models/Project'; |
||||
import Column from '../../../models/Column'; |
||||
import Model from '../../../models/Model'; |
||||
import NcHelp from '../../../utils/NcHelp'; |
||||
import Base from '../../../models/Base'; |
||||
import View from '../../../models/View'; |
||||
import NcConnectionMgrv2 from '../../../utils/common/NcConnectionMgrv2'; |
||||
import getTableNameAlias, { |
||||
getColumnNameAlias, |
||||
} from '../../helpers/getTableName'; |
||||
import LinkToAnotherRecordColumn from '../../../models/LinkToAnotherRecordColumn'; |
||||
import getColumnUiType from '../../helpers/getColumnUiType'; |
||||
import mapDefaultPrimaryValue from '../../helpers/mapDefaultPrimaryValue'; |
||||
import { extractAndGenerateManyToManyRelations } from '../metaDiffApis'; |
||||
import { ModelTypes, UITypes, ViewTypes } from 'nocodb-sdk'; |
||||
import { IGNORE_TABLES } from '../../../utils/common/BaseApiBuilder'; |
||||
|
||||
export async function populateMeta(base: Base, project: Project): Promise<any> { |
||||
const info = { |
||||
type: 'rest', |
||||
apiCount: 0, |
||||
tablesCount: 0, |
||||
relationsCount: 0, |
||||
viewsCount: 0, |
||||
client: base?.getConnectionConfig()?.client, |
||||
timeTaken: 0, |
||||
}; |
||||
|
||||
const t = process.hrtime(); |
||||
const sqlClient = await NcConnectionMgrv2.getSqlClient(base); |
||||
let order = 1; |
||||
const models2: { [tableName: string]: Model } = {}; |
||||
|
||||
const virtualColumnsInsert = []; |
||||
|
||||
/* Get all relations */ |
||||
const relations = (await sqlClient.relationListAll())?.data?.list; |
||||
|
||||
info.relationsCount = relations.length; |
||||
|
||||
let tables = (await sqlClient.tableList())?.data?.list |
||||
?.filter(({ tn }) => !IGNORE_TABLES.includes(tn)) |
||||
?.map((t) => { |
||||
t.order = ++order; |
||||
t.title = getTableNameAlias(t.tn, project.prefix, base); |
||||
t.table_name = t.tn; |
||||
return t; |
||||
}); |
||||
|
||||
/* filter based on prefix */ |
||||
if (base.is_meta && project?.prefix) { |
||||
tables = tables.filter((t) => { |
||||
return t?.tn?.startsWith(project?.prefix); |
||||
}); |
||||
} |
||||
|
||||
info.tablesCount = tables.length; |
||||
|
||||
tables.forEach((t) => { |
||||
t.title = getTableNameAlias(t.tn, project.prefix, base); |
||||
}); |
||||
|
||||
relations.forEach((r) => { |
||||
r.title = getTableNameAlias(r.tn, project.prefix, base); |
||||
r.rtitle = getTableNameAlias(r.rtn, project.prefix, base); |
||||
}); |
||||
|
||||
// await this.syncRelations();
|
||||
|
||||
const tableMetasInsert = tables.map((table) => { |
||||
return async () => { |
||||
/* filter relation where this table is present */ |
||||
const tableRelations = relations.filter( |
||||
(r) => r.tn === table.tn || r.rtn === table.tn |
||||
); |
||||
|
||||
const columns: Array< |
||||
Omit<Column, 'column_name' | 'title'> & { |
||||
cn: string; |
||||
system?: boolean; |
||||
} |
||||
> = (await sqlClient.columnList({ tn: table.tn }))?.data?.list; |
||||
|
||||
const hasMany = |
||||
table.type === 'view' |
||||
? [] |
||||
: tableRelations.filter((r) => r.rtn === table.tn); |
||||
const belongsTo = |
||||
table.type === 'view' |
||||
? [] |
||||
: tableRelations.filter((r) => r.tn === table.tn); |
||||
|
||||
mapDefaultPrimaryValue(columns); |
||||
|
||||
// add vitual columns
|
||||
const virtualColumns = [ |
||||
...hasMany.map((hm) => { |
||||
return { |
||||
uidt: UITypes.LinkToAnotherRecord, |
||||
type: 'hm', |
||||
hm, |
||||
title: `${hm.title} List`, |
||||
}; |
||||
}), |
||||
...belongsTo.map((bt) => { |
||||
// find and mark foreign key column
|
||||
const fkColumn = columns.find((c) => c.cn === bt.cn); |
||||
if (fkColumn) { |
||||
fkColumn.uidt = UITypes.ForeignKey; |
||||
fkColumn.system = true; |
||||
} |
||||
|
||||
return { |
||||
uidt: UITypes.LinkToAnotherRecord, |
||||
type: 'bt', |
||||
bt, |
||||
title: `${bt.rtitle}`, |
||||
}; |
||||
}), |
||||
]; |
||||
|
||||
// await Model.insert(project.id, base.id, meta);
|
||||
|
||||
/* create nc_models and its rows if it doesn't exists */ |
||||
models2[table.table_name] = await Model.insert(project.id, base.id, { |
||||
table_name: table.tn || table.table_name, |
||||
title: table.title, |
||||
type: table.type || 'table', |
||||
order: table.order, |
||||
}); |
||||
|
||||
// table crud apis
|
||||
info.apiCount += 5; |
||||
|
||||
let colOrder = 1; |
||||
|
||||
for (const column of columns) { |
||||
await Column.insert({ |
||||
uidt: column.uidt || getColumnUiType(base, column), |
||||
fk_model_id: models2[table.tn].id, |
||||
...column, |
||||
title: getColumnNameAlias(column.cn, base), |
||||
column_name: column.cn, |
||||
order: colOrder++, |
||||
}); |
||||
} |
||||
virtualColumnsInsert.push(async () => { |
||||
const columnNames = {}; |
||||
for (const column of virtualColumns) { |
||||
// generate unique name if there is any duplicate column name
|
||||
let c = 0; |
||||
while (`${column.title}${c || ''}` in columnNames) { |
||||
c++; |
||||
} |
||||
column.title = `${column.title}${c || ''}`; |
||||
columnNames[column.title] = true; |
||||
|
||||
const rel = column.hm || column.bt; |
||||
|
||||
const rel_column_id = (await models2?.[rel.tn]?.getColumns())?.find( |
||||
(c) => c.column_name === rel.cn |
||||
)?.id; |
||||
|
||||
const tnId = models2?.[rel.tn]?.id; |
||||
|
||||
const ref_rel_column_id = ( |
||||
await models2?.[rel.rtn]?.getColumns() |
||||
)?.find((c) => c.column_name === rel.rcn)?.id; |
||||
|
||||
const rtnId = models2?.[rel.rtn]?.id; |
||||
|
||||
try { |
||||
await Column.insert<LinkToAnotherRecordColumn>({ |
||||
project_id: project.id, |
||||
db_alias: base.id, |
||||
fk_model_id: models2[table.tn].id, |
||||
cn: column.cn, |
||||
title: column.title, |
||||
uidt: column.uidt, |
||||
type: column.hm ? 'hm' : column.mm ? 'mm' : 'bt', |
||||
// column_id,
|
||||
fk_child_column_id: rel_column_id, |
||||
fk_parent_column_id: ref_rel_column_id, |
||||
fk_index_name: rel.cstn, |
||||
ur: rel.ur, |
||||
dr: rel.dr, |
||||
order: colOrder++, |
||||
fk_related_model_id: column.hm ? tnId : rtnId, |
||||
system: column.system, |
||||
}); |
||||
|
||||
// nested relations data apis
|
||||
info.apiCount += 5; |
||||
} catch (e) { |
||||
console.log(e); |
||||
} |
||||
} |
||||
}); |
||||
}; |
||||
}); |
||||
|
||||
/* handle xc_tables update in parallel */ |
||||
await NcHelp.executeOperations(tableMetasInsert, base.type); |
||||
await NcHelp.executeOperations(virtualColumnsInsert, base.type); |
||||
await extractAndGenerateManyToManyRelations(Object.values(models2)); |
||||
|
||||
let views: Array<{ order: number; table_name: string; title: string }> = ( |
||||
await sqlClient.viewList() |
||||
)?.data?.list |
||||
// ?.filter(({ tn }) => !IGNORE_TABLES.includes(tn))
|
||||
?.map((v) => { |
||||
v.order = ++order; |
||||
v.table_name = v.view_name; |
||||
v.title = getTableNameAlias(v.view_name, project.prefix, base); |
||||
return v; |
||||
}); |
||||
|
||||
/* filter based on prefix */ |
||||
if (base.is_meta && project?.prefix) { |
||||
views = tables.filter((t) => { |
||||
return t?.tn?.startsWith(project?.prefix); |
||||
}); |
||||
} |
||||
|
||||
info.viewsCount = views.length; |
||||
|
||||
const viewMetasInsert = views.map((table) => { |
||||
return async () => { |
||||
const columns = (await sqlClient.columnList({ tn: table.table_name })) |
||||
?.data?.list; |
||||
|
||||
/* create nc_models and its rows if it doesn't exists */ |
||||
models2[table.table_name] = await Model.insert(project.id, base.id, { |
||||
table_name: table.table_name, |
||||
title: getTableNameAlias(table.table_name, project.prefix, base), |
||||
// todo: sanitize
|
||||
type: ModelTypes.VIEW, |
||||
order: table.order, |
||||
}); |
||||
|
||||
let colOrder = 1; |
||||
|
||||
// view apis
|
||||
info.apiCount += 2; |
||||
|
||||
for (const column of columns) { |
||||
await Column.insert({ |
||||
fk_model_id: models2[table.table_name].id, |
||||
...column, |
||||
title: getColumnNameAlias(column.cn, base), |
||||
order: colOrder++, |
||||
uidt: getColumnUiType(base, column), |
||||
}); |
||||
} |
||||
}; |
||||
}); |
||||
|
||||
await NcHelp.executeOperations(viewMetasInsert, base.type); |
||||
|
||||
// fix pv column for created grid views
|
||||
const models = await Model.list({ project_id: project.id, base_id: base.id }); |
||||
|
||||
for (const model of models) { |
||||
const views = await model.getViews(); |
||||
for (const view of views) { |
||||
if (view.type === ViewTypes.GRID) { |
||||
await View.fixPVColumnForView(view.id); |
||||
} |
||||
} |
||||
} |
||||
|
||||
const t1 = process.hrtime(t); |
||||
const t2 = t1[0] + t1[1] / 1000000000; |
||||
|
||||
(info as any).timeTaken = t2.toFixed(1); |
||||
|
||||
return info; |
||||
} |
@ -0,0 +1,90 @@
|
||||
import { NcUpgraderCtx } from './NcUpgrader'; |
||||
import { MetaTable } from '../utils/globals'; |
||||
|
||||
// before 0.104.3, primary value column can be in any position in table
|
||||
// with this upgrade we introduced sticky primary column feature
|
||||
// this upgrader will make primary value column first column in grid views
|
||||
|
||||
export default async function ({ ncMeta }: NcUpgraderCtx) { |
||||
const grid_columns = await ncMeta.metaList2( |
||||
null, |
||||
null, |
||||
MetaTable.GRID_VIEW_COLUMNS |
||||
); |
||||
const grid_views = [...new Set(grid_columns.map((col) => col.fk_view_id))]; |
||||
|
||||
for (const view_id of grid_views) { |
||||
// get a list of view columns sorted by order
|
||||
const view_columns = await ncMeta.metaList2( |
||||
null, |
||||
null, |
||||
MetaTable.GRID_VIEW_COLUMNS, |
||||
{ |
||||
condition: { |
||||
fk_view_id: view_id, |
||||
}, |
||||
orderBy: { |
||||
order: 'asc', |
||||
}, |
||||
} |
||||
); |
||||
const view_columns_meta = []; |
||||
|
||||
// get column meta for each view column
|
||||
for (const col of view_columns) { |
||||
const col_meta = await ncMeta.metaGet(null, null, MetaTable.COLUMNS, { |
||||
id: col.fk_column_id, |
||||
}); |
||||
view_columns_meta.push(col_meta); |
||||
} |
||||
|
||||
const primary_value_column_meta = view_columns_meta.find((col) => col.pv); |
||||
|
||||
if (primary_value_column_meta) { |
||||
const primary_value_column = view_columns.find( |
||||
(col) => col.fk_column_id === primary_value_column_meta.id |
||||
); |
||||
const primary_value_column_index = view_columns.findIndex( |
||||
(col) => col.fk_column_id === primary_value_column_meta.id |
||||
); |
||||
const view_orders = view_columns.map((col) => col.order); |
||||
const view_min_order = Math.min(...view_orders); |
||||
|
||||
// if primary_value_column is not visible, make it visible
|
||||
if (!primary_value_column.show) { |
||||
await ncMeta.metaUpdate( |
||||
null, |
||||
null, |
||||
MetaTable.GRID_VIEW_COLUMNS, |
||||
{ show: true }, |
||||
primary_value_column.id |
||||
); |
||||
} |
||||
|
||||
if ( |
||||
primary_value_column.order === view_min_order && |
||||
view_orders.filter((o) => o === view_min_order).length === 1 |
||||
) { |
||||
// if primary_value_column is in first order do nothing
|
||||
continue; |
||||
} else { |
||||
// if primary_value_column not in first order, move it to the start of array
|
||||
if (primary_value_column_index !== 0) { |
||||
const temp_pv = view_columns.splice(primary_value_column_index, 1); |
||||
view_columns.unshift(...temp_pv); |
||||
} |
||||
|
||||
// update order of all columns in view to match the order in array
|
||||
for (let i = 0; i < view_columns.length; i++) { |
||||
await ncMeta.metaUpdate( |
||||
null, |
||||
null, |
||||
MetaTable.GRID_VIEW_COLUMNS, |
||||
{ order: i + 1 }, |
||||
view_columns[i].id |
||||
); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue