Browse Source

Merge pull request #7477 from nocodb/nc-refactor/performance-improvemnt

Nc refactor/performance improvemnt
pull/7485/head
Raju Udava 7 months ago committed by GitHub
parent
commit
97edad8da7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 4
      packages/nocodb/src/db/functionMappings/pg.ts
  2. 23
      packages/nocodb/src/meta/meta.service.ts
  3. 298
      packages/nocodb/src/models/Column.ts
  4. 47
      packages/nocodb/src/models/Model.ts
  5. 400
      packages/nocodb/src/models/View.ts
  6. 36
      packages/nocodb/src/services/forms.service.ts
  7. 31
      packages/nocodb/src/services/galleries.service.ts
  8. 31
      packages/nocodb/src/services/grids.service.ts
  9. 31
      packages/nocodb/src/services/kanbans.service.ts
  10. 32
      packages/nocodb/src/services/maps.service.ts
  11. 3
      packages/nocodb/src/services/tables.service.ts

4
packages/nocodb/src/db/functionMappings/pg.ts

@ -210,7 +210,9 @@ const pg = {
SUBSTR: async ({ fn, knex, pt, colAlias }: MapFnArgs) => {
const str = (await fn(pt.arguments[0])).builder;
const positionFrom = (await fn(pt.arguments[1] ?? 1)).builder;
const numberOfCharacters = pt.arguments[2] ? (await fn(pt.arguments[2])).builder : null;
const numberOfCharacters = pt.arguments[2]
? (await fn(pt.arguments[2])).builder
: null;
return {
builder: knex.raw(
`SUBSTR(${str}::TEXT, ${positionFrom}${

23
packages/nocodb/src/meta/meta.service.ts

@ -118,26 +118,35 @@ export class MetaService {
});
return insertObj;
}
public async bulkMetaInsert(
base_id: string,
source_id: string,
target: string,
data: any[],
data: any | any[],
ignoreIdGeneration?: boolean,
): Promise<any> {
if (Array.isArray(data) ? !data.length : !data) {
return [];
}
const insertObj = [];
const at = this.now();
for (const d of data) {
const commonProps: Record<string, any> = {
created_at: at,
updated_at: at,
};
if (source_id !== null) commonProps.source_id = source_id;
if (base_id !== null) commonProps.base_id = base_id;
for (const d of Array.isArray(data) ? data : [data]) {
const id = d?.id || (await this.genNanoid(target));
const tempObj = {
...d,
...(ignoreIdGeneration ? {} : { id }),
created_at: at,
updated_at: at,
...commonProps,
};
if (source_id !== null) tempObj.source_id = source_id;
if (base_id !== null) tempObj.base_id = base_id;
insertObj.push(tempObj);
}

298
packages/nocodb/src/models/Column.ts

@ -1330,4 +1330,302 @@ export default class Column<T = any> implements ColumnType {
colId,
);
}
static async bulkInsert(
param: {
columns: Column[];
fk_model_id: any;
source_id: string;
base_id: string;
},
ncMeta = Noco.ncMeta,
) {
const extractedColumnMetas = [];
const columns = [];
// add fk_model_id
for (const column of param.columns) {
// pre-populate column meta to use while inserting colOptions
const id = await ncMeta.genNanoid(MetaTable.COLUMNS);
const colWithId = {
...column,
id,
base_id: param.base_id,
source_id: param.source_id,
fk_model_id: param.fk_model_id,
};
const insertObj = extractProps(colWithId as any, [
'id',
'fk_model_id',
'column_name',
'title',
'uidt',
'dt',
'np',
'ns',
'clen',
'cop',
'pk',
'rqd',
'un',
'ct',
'ai',
'unique',
'cdf',
'cc',
'csn',
'dtx',
'dtxp',
'dtxs',
'au',
'pv',
'order',
'base_id',
'source_id',
'system',
'meta',
]);
if (column.meta && typeof column.meta === 'object') {
insertObj.meta = JSON.stringify(column.meta);
}
if (column.validate) {
if (typeof column.validate === 'string')
insertObj.validate = column.validate;
else insertObj.validate = JSON.stringify(column.validate);
}
extractedColumnMetas.push(insertObj);
columns.push(colWithId);
}
// bulk insert columns
await ncMeta.bulkMetaInsert(
null,
null,
MetaTable.COLUMNS,
extractedColumnMetas,
true,
);
// insert column options if any
// for (const column of columns) {
await Column.bulkInsertColOption(columns, ncMeta);
// }
return columns;
}
private static async bulkInsertColOption<T>(
columns: (Partial<T> & { source_id?: string; [p: string]: any })[],
ncMeta = Noco.ncMeta,
) {
const insertGroups = new Map<UITypes, Record<string, any>[]>();
for (const column of columns) {
let insertArr = insertGroups.get(
column.uidt === UITypes.MultiSelect
? UITypes.SingleSelect
: column.uidt,
);
if (!insertArr) {
insertGroups.set(column.uidt, (insertArr = []));
}
switch (column.uidt || column.ui_data_type) {
case UITypes.Lookup:
// LookupColumn.insert()
insertArr.push({
fk_column_id: column.id,
fk_relation_column_id: column.fk_relation_column_id,
fk_lookup_column_id: column.fk_lookup_column_id,
});
break;
case UITypes.Rollup: {
insertArr.push({
fk_column_id: column.id,
fk_relation_column_id: column.fk_relation_column_id,
fk_rollup_column_id: column.fk_rollup_column_id,
rollup_function: column.rollup_function,
});
break;
}
case UITypes.Links:
case UITypes.LinkToAnotherRecord: {
insertArr.push({
fk_column_id: column.id,
type: column.type,
fk_child_column_id: column.fk_child_column_id,
fk_parent_column_id: column.fk_parent_column_id,
fk_mm_model_id: column.fk_mm_model_id,
fk_mm_child_column_id: column.fk_mm_child_column_id,
fk_mm_parent_column_id: column.fk_mm_parent_column_id,
ur: column.ur,
dr: column.dr,
fk_index_name: column.fk_index_name,
fk_related_model_id: column.fk_related_model_id,
virtual: column.virtual,
});
break;
}
case UITypes.QrCode: {
insertArr.push(
{
fk_column_id: column.id,
fk_qr_value_column_id: column.fk_qr_value_column_id,
},
ncMeta,
);
break;
}
case UITypes.Barcode: {
insertArr.push({
fk_column_id: column.id,
fk_barcode_value_column_id: column.fk_barcode_value_column_id,
barcode_format: column.barcode_format,
});
break;
}
case UITypes.Formula: {
insertArr.push({
fk_column_id: column.id,
formula: column.formula,
formula_raw: column.formula_raw,
parsed_tree: column.parsed_tree,
});
break;
}
case UITypes.MultiSelect: {
if (!column.colOptions?.options) {
for (const [i, option] of column.dtxp?.split(',').entries() ||
[].entries()) {
insertArr.push({
fk_column_id: column.id,
title: option.replace(/^'/, '').replace(/'$/, ''),
order: i + 1,
color: selectColors[i % selectColors.length],
});
}
} else {
for (const [i, option] of column.colOptions.options.entries() ||
[].entries()) {
// Trim end of enum/set
if (column.dt === 'enum' || column.dt === 'set') {
option.title = option.title.trimEnd();
}
insertArr.push({
color: selectColors[i % selectColors.length], // in case color is not provided
...extractProps(option, ['title', 'fk_column_id', 'color']),
fk_column_id: column.id,
order: i + 1,
});
}
}
break;
}
case UITypes.SingleSelect: {
if (!column.colOptions?.options) {
for (const [i, option] of column.dtxp?.split(',').entries() ||
[].entries()) {
insertArr.push({
fk_column_id: column.id,
title: option.replace(/^'/, '').replace(/'$/, ''),
order: i + 1,
color: selectColors[i % selectColors.length],
});
}
} else {
for (const [i, option] of column.colOptions.options.entries() ||
[].entries()) {
// Trim end of enum/set
if (column.dt === 'enum' || column.dt === 'set') {
option.title = option.title.trimEnd();
}
insertArr.push({
color: selectColors[i % selectColors.length], // in case color is not provided
...extractProps(option, ['title', 'fk_column_id', 'color']),
fk_column_id: column.id,
order: i + 1,
});
}
}
break;
}
}
}
// bulk insert column options
for (const group of insertGroups.keys()) {
switch (group) {
case UITypes.SingleSelect:
case UITypes.MultiSelect:
await ncMeta.bulkMetaInsert(
null,
null,
MetaTable.COL_SELECT_OPTIONS,
insertGroups.get(group),
);
break;
case UITypes.Lookup:
await ncMeta.bulkMetaInsert(
null,
null,
MetaTable.COL_LOOKUP,
insertGroups.get(group),
);
break;
case UITypes.Rollup:
await ncMeta.bulkMetaInsert(
null,
null,
MetaTable.COL_ROLLUP,
insertGroups.get(group),
);
break;
case UITypes.Links:
case UITypes.LinkToAnotherRecord:
await ncMeta.bulkMetaInsert(
null,
null,
MetaTable.COL_RELATIONS,
insertGroups.get(group),
);
break;
case UITypes.QrCode:
await ncMeta.bulkMetaInsert(
null,
null,
MetaTable.COL_QRCODE,
insertGroups.get(group),
);
break;
case UITypes.Barcode:
await ncMeta.bulkMetaInsert(
null,
null,
MetaTable.COL_BARCODE,
insertGroups.get(group),
);
break;
case UITypes.Formula:
await ncMeta.bulkMetaInsert(
null,
null,
MetaTable.COL_FORMULA,
insertGroups.get(group),
);
break;
}
}
}
}

47
packages/nocodb/src/models/Model.ts

@ -147,37 +147,50 @@ export default class Model implements TableType {
insertObj,
);
const view = await View.insert(
const insertedColumns = await Column.bulkInsert(
{
columns: (model?.columns || []) as Column[],
fk_model_id: id,
source_id: sourceId,
base_id: baseId,
},
ncMeta,
);
await View.insertMetaOnly(
{
fk_model_id: id,
title: model.title || model.table_name,
is_default: true,
type: ViewTypes.GRID,
base_id: baseId,
source_id: sourceId,
},
{
getColumns: async () => insertedColumns,
},
ncMeta,
);
for (const column of model?.columns || []) {
await Column.insert({ ...column, fk_model_id: id, view } as any, ncMeta);
}
const modelRes = await this.getWithInfo({ id }, ncMeta);
return this.getWithInfo({ id }, ncMeta).then(async (model) => {
if (sourceId) {
await NocoCache.appendToList(
CacheScope.MODEL,
[baseId, sourceId],
`${CacheScope.MODEL}:${id}`,
);
}
// cater cases where sourceId is not required
// e.g. xcVisibilityMetaGet
// append to model list since model list cache will be there already
if (sourceId) {
await NocoCache.appendToList(
CacheScope.MODEL,
[baseId],
[baseId, sourceId],
`${CacheScope.MODEL}:${id}`,
);
return model;
});
}
// cater cases where sourceId is not required
// e.g. xcVisibilityMetaGet
await NocoCache.appendToList(
CacheScope.MODEL,
[baseId],
`${CacheScope.MODEL}:${id}`,
);
return modelRes;
}
public static async list(

400
packages/nocodb/src/models/View.ts

@ -388,7 +388,13 @@ export default class View implements ViewType {
for (const sort of sorts) {
await Sort.insert(
{
...sort,
...extractProps(sort, [
'fk_column_id',
'direction',
'base_id',
'source_id',
'order',
]),
fk_view_id: view_id,
id: null,
},
@ -399,7 +405,19 @@ export default class View implements ViewType {
for (const filter of filters.children) {
await Filter.insert(
{
...filter,
...extractProps(filter, [
'id',
'fk_column_id',
'comparison_op',
'comparison_sub_op',
'value',
'fk_parent_id',
'is_group',
'logical_op',
'base_id',
'source_id',
'order',
]),
fk_view_id: view_id,
id: null,
},
@ -1539,4 +1557,382 @@ export default class View implements ViewType {
await NocoCache.del(deleteKeys);
}
static async bulkColumnInsertToViews(
{
columns,
viewColumns,
copyFromView,
}: {
copyFromView?: View;
columns?: ({
order?: number;
show?;
} & Column)[];
viewColumns?: (
| GridViewColumn
| GalleryViewColumn
| FormViewColumn
| KanbanViewColumn
| MapViewColumn
)[];
},
view: View,
ncMeta = Noco.ncMeta,
) {
const insertObjs = [];
if (viewColumns) {
for (let i = 0; i < viewColumns.length; i++) {
const column = viewColumns[i];
insertObjs.push({
...extractProps(column, [
'fk_view_id',
'fk_column_id',
'show',
'base_id',
'source_id',
'order',
'width',
'group_by',
'group_by_order',
'group_by_sort',
]),
fk_view_id: view.id,
base_id: view.base_id,
source_id: view.source_id,
});
}
} else {
if (!columns) {
columns = await Column.list({ fk_model_id: view.fk_model_id });
}
// todo: avoid duplicate code
if (view.type === ViewTypes.KANBAN && !copyFromView) {
// sort by display value & attachment first, then by singleLineText & Number
// so that later we can handle control `show` easily
columns.sort((a, b) => {
const displayValueOrder = +b.pv - +a.pv;
const attachmentOrder =
+(b.uidt === UITypes.Attachment) - +(a.uidt === UITypes.Attachment);
const singleLineTextOrder =
+(b.uidt === UITypes.SingleLineText) -
+(a.uidt === UITypes.SingleLineText);
const numberOrder =
+(b.uidt === UITypes.Number) - +(a.uidt === UITypes.Number);
const defaultOrder = b.order - a.order;
return (
displayValueOrder ||
attachmentOrder ||
singleLineTextOrder ||
numberOrder ||
defaultOrder
);
});
}
let order = 1;
let galleryShowLimit = 0;
let kanbanShowLimit = 0;
for (let i = 0; i < columns.length; i++) {
const column = columns[i];
let show = 'show' in column ? column.show : true;
if (view.type === ViewTypes.GALLERY) {
const galleryView = await GalleryView.get(view.id, ncMeta);
if (
column.id === galleryView.fk_cover_image_col_id ||
column.pv ||
galleryShowLimit < 3
) {
show = true;
galleryShowLimit++;
} else {
show = false;
}
} else if (view.type === ViewTypes.KANBAN && !copyFromView) {
const kanbanView = await KanbanView.get(view.id, ncMeta);
if (column.id === kanbanView?.fk_grp_col_id) {
// include grouping field if it exists
show = true;
} else if (
column.id === kanbanView.fk_cover_image_col_id ||
column.pv
) {
// Show cover image or primary key
show = true;
kanbanShowLimit++;
} else if (kanbanShowLimit < 3 && !isSystemColumn(column)) {
// show at most 3 non-system columns
show = true;
kanbanShowLimit++;
} else {
// other columns will be hidden
show = false;
}
} else if (view.type === ViewTypes.MAP && !copyFromView) {
const mapView = await MapView.get(view.id, ncMeta);
if (column.id === mapView?.fk_geo_data_col_id) {
show = true;
}
} else if (view.type === ViewTypes.FORM && isSystemColumn(column)) {
show = false;
}
insertObjs.push({
fk_column_id: column.id,
order: order++,
show,
fk_view_id: view.id,
base_id: view.base_id,
source_id: view.source_id,
});
}
}
switch (view.type) {
case ViewTypes.GRID:
await ncMeta.bulkMetaInsert(
null,
null,
MetaTable.GRID_VIEW_COLUMNS,
insertObjs,
);
break;
case ViewTypes.GALLERY:
await ncMeta.bulkMetaInsert(
null,
null,
MetaTable.GALLERY_VIEW_COLUMNS,
insertObjs,
);
break;
case ViewTypes.MAP:
await ncMeta.bulkMetaInsert(
null,
null,
MetaTable.MAP_VIEW_COLUMNS,
insertObjs,
);
break;
case ViewTypes.KANBAN:
await ncMeta.bulkMetaInsert(
null,
null,
MetaTable.KANBAN_VIEW_COLUMNS,
insertObjs,
);
break;
case ViewTypes.FORM:
await ncMeta.bulkMetaInsert(
null,
null,
MetaTable.FORM_VIEW_COLUMNS,
insertObjs,
);
break;
}
}
static async insertMetaOnly(
view: Partial<View> &
Partial<FormView | GridView | GalleryView | KanbanView | MapView> & {
copy_from_id?: string;
fk_grp_col_id?: string;
},
model: {
getColumns: () => Promise<Column[]>;
},
ncMeta = Noco.ncMeta,
) {
const insertObj = extractProps(view, [
'id',
'title',
'is_default',
'type',
'fk_model_id',
'base_id',
'source_id',
'meta',
]);
if (!insertObj.order) {
// get order value
insertObj.order = await ncMeta.metaGetNextOrder(MetaTable.VIEWS, {
fk_model_id: view.fk_model_id,
});
}
insertObj.show = true;
if (!insertObj.meta) {
insertObj.meta = {};
}
insertObj.meta = stringifyMetaProp(insertObj);
const copyFromView =
view.copy_from_id && (await View.get(view.copy_from_id, ncMeta));
// get base and base id if missing
if (!(view.base_id && view.source_id)) {
const model = await Model.getByIdOrName({ id: view.fk_model_id }, ncMeta);
insertObj.base_id = model.base_id;
insertObj.source_id = model.source_id;
}
const insertedView = await ncMeta.metaInsert2(
null,
null,
MetaTable.VIEWS,
insertObj,
);
const { id: view_id } = insertedView;
// insert view metadata based on view type
switch (view.type) {
case ViewTypes.GRID:
await GridView.insert(
{
...((copyFromView?.view as GridView) || {}),
...(view as GridView),
fk_view_id: view_id,
},
ncMeta,
);
break;
case ViewTypes.MAP:
await MapView.insert(
{
...(view as MapView),
fk_view_id: view_id,
},
ncMeta,
);
break;
case ViewTypes.GALLERY:
await GalleryView.insert(
{
...(copyFromView?.view || {}),
...view,
fk_view_id: view_id,
},
ncMeta,
);
break;
case ViewTypes.FORM:
await FormView.insert(
{
heading: view.title,
...(copyFromView?.view || {}),
...view,
fk_view_id: view_id,
},
ncMeta,
);
break;
case ViewTypes.KANBAN:
// set grouping field
(view as KanbanView).fk_grp_col_id = view.fk_grp_col_id;
await KanbanView.insert(
{
...(copyFromView?.view || {}),
...view,
fk_view_id: view_id,
},
ncMeta,
);
break;
}
// copy from view
if (copyFromView) {
const sorts = await copyFromView.getSorts(ncMeta);
const filters = await Filter.rootFilterList(
{ viewId: copyFromView.id },
ncMeta,
);
const viewColumns = await copyFromView.getColumns(ncMeta);
const sortInsertObjs = [];
const filterInsertObjs = [];
for (const sort of sorts) {
sortInsertObjs.push({
...extractProps(sort, [
'fk_column_id',
'direction',
'base_id',
'source_id',
]),
fk_view_id: view_id,
id: undefined,
});
}
for (const filter of filters) {
const fn = async (filter, parentId: string = null) => {
const generatedId = await ncMeta.genNanoid(MetaTable.FILTER_EXP);
filterInsertObjs.push({
...extractProps(filter, [
'fk_column_id',
'comparison_op',
'comparison_sub_op',
'value',
'fk_parent_id',
'is_group',
'logical_op',
]),
fk_view_id: view_id,
id: generatedId,
fk_parent_id: parentId,
});
if (filter.is_group)
await Promise.all(
((await filter.getChildren()) || []).map(async (child) => {
await fn(child, generatedId);
}),
);
};
await fn(filter);
}
await ncMeta.bulkMetaInsert(null, null, MetaTable.SORT, sortInsertObjs);
await ncMeta.bulkMetaInsert(
null,
null,
MetaTable.FILTER_EXP,
filterInsertObjs,
true,
);
// populate view columns
await View.bulkColumnInsertToViews(
{ viewColumns, copyFromView },
insertedView,
);
} else {
// populate view columns
await View.bulkColumnInsertToViews(
{ columns: (await model.getColumns()) as any[] },
insertedView,
);
}
await Model.getNonDefaultViewsCountAndReset(
{ modelId: view.fk_model_id },
ncMeta,
);
return insertedView;
}
}

36
packages/nocodb/src/services/forms.service.ts

@ -9,7 +9,9 @@ import type { NcRequest } from '~/interface/config';
import { AppHooksService } from '~/services/app-hooks/app-hooks.service';
import { validatePayload } from '~/helpers';
import { NcError } from '~/helpers/catchError';
import { FormView, View } from '~/models';
import { FormView, Model, View } from '~/models';
import NocoCache from '~/cache/NocoCache';
import { CacheScope } from '~/utils/globals';
@Injectable()
export class FormsService {
@ -31,22 +33,32 @@ export class FormsService {
param.body,
);
const view = await View.insert({
...param.body,
// todo: sanitize
fk_model_id: param.tableId,
type: ViewTypes.FORM,
});
const model = await Model.get(param.tableId);
this.appHooksService.emit(AppEvents.VIEW_CREATE, {
view,
showAs: 'form',
req: param.req,
});
const { id } = await View.insertMetaOnly(
{
...param.body,
// todo: sanitize
fk_model_id: param.tableId,
type: ViewTypes.FORM,
base_id: model.base_id,
source_id: model.source_id,
},
model,
);
// populate cache and add to list since the list cache already exist
const view = await View.get(id);
await NocoCache.appendToList(
CacheScope.VIEW,
[view.fk_model_id],
`${CacheScope.VIEW}:${id}`,
);
this.appHooksService.emit(AppEvents.VIEW_CREATE, {
user: param.user,
view,
showAs: 'form',
req: param.req,
});

31
packages/nocodb/src/services/galleries.service.ts

@ -9,7 +9,9 @@ import type { NcRequest } from '~/interface/config';
import { AppHooksService } from '~/services/app-hooks/app-hooks.service';
import { validatePayload } from '~/helpers';
import { NcError } from '~/helpers/catchError';
import { GalleryView, View } from '~/models';
import { GalleryView, Model, View } from '~/models';
import NocoCache from '~/cache/NocoCache';
import { CacheScope } from '~/utils/globals';
@Injectable()
export class GalleriesService {
@ -31,12 +33,27 @@ export class GalleriesService {
param.gallery,
);
const view = await View.insert({
...param.gallery,
// todo: sanitize
fk_model_id: param.tableId,
type: ViewTypes.GALLERY,
});
const model = await Model.get(param.tableId);
const { id } = await View.insertMetaOnly(
{
...param.gallery,
// todo: sanitize
fk_model_id: param.tableId,
type: ViewTypes.GALLERY,
base_id: model.base_id,
source_id: model.source_id,
},
model,
);
// populate cache and add to list since the list cache already exist
const view = await View.get(id);
await NocoCache.appendToList(
CacheScope.VIEW,
[view.fk_model_id],
`${CacheScope.VIEW}:${id}`,
);
this.appHooksService.emit(AppEvents.VIEW_CREATE, {
view,

31
packages/nocodb/src/services/grids.service.ts

@ -5,7 +5,9 @@ import type { NcRequest } from '~/interface/config';
import { AppHooksService } from '~/services/app-hooks/app-hooks.service';
import { validatePayload } from '~/helpers';
import { NcError } from '~/helpers/catchError';
import { GridView, View } from '~/models';
import { GridView, Model, View } from '~/models';
import NocoCache from '~/cache/NocoCache';
import { CacheScope } from '~/utils/globals';
@Injectable()
export class GridsService {
@ -21,15 +23,30 @@ export class GridsService {
param.grid,
);
const view = await View.insert({
...param.grid,
// todo: sanitize
fk_model_id: param.tableId,
type: ViewTypes.GRID,
});
const model = await Model.get(param.tableId);
const { id } = await View.insertMetaOnly(
{
...param.grid,
// todo: sanitize
fk_model_id: param.tableId,
type: ViewTypes.GRID,
base_id: model.base_id,
source_id: model.source_id,
},
model,
);
// populate cache and add to list since the list cache already exist
const view = await View.get(id);
await NocoCache.appendToList(
CacheScope.VIEW,
[view.fk_model_id],
`${CacheScope.VIEW}:${id}`,
);
this.appHooksService.emit(AppEvents.VIEW_CREATE, {
view,
showAs: 'grid',
req: param.req,
});

31
packages/nocodb/src/services/kanbans.service.ts

@ -9,7 +9,9 @@ import type { NcRequest } from '~/interface/config';
import { AppHooksService } from '~/services/app-hooks/app-hooks.service';
import { validatePayload } from '~/helpers';
import { NcError } from '~/helpers/catchError';
import { KanbanView, View } from '~/models';
import { KanbanView, Model, View } from '~/models';
import NocoCache from '~/cache/NocoCache';
import { CacheScope } from '~/utils/globals';
@Injectable()
export class KanbansService {
@ -30,12 +32,27 @@ export class KanbansService {
param.kanban,
);
const view = await View.insert({
...param.kanban,
// todo: sanitize
fk_model_id: param.tableId,
type: ViewTypes.KANBAN,
});
const model = await Model.get(param.tableId);
const { id } = await View.insertMetaOnly(
{
...param.kanban,
// todo: sanitize
fk_model_id: param.tableId,
type: ViewTypes.KANBAN,
base_id: model.base_id,
source_id: model.source_id,
},
model,
);
// populate cache and add to list since the list cache already exist
const view = await View.get(id);
await NocoCache.appendToList(
CacheScope.VIEW,
[view.fk_model_id],
`${CacheScope.VIEW}:${id}`,
);
this.appHooksService.emit(AppEvents.VIEW_CREATE, {
view,

32
packages/nocodb/src/services/maps.service.ts

@ -5,7 +5,9 @@ import type { NcRequest } from '~/interface/config';
import { AppHooksService } from '~/services/app-hooks/app-hooks.service';
import { validatePayload } from '~/helpers';
import { NcError } from '~/helpers/catchError';
import { MapView, View } from '~/models';
import { MapView, Model, View } from '~/models';
import { CacheScope } from '~/utils/globals';
import NocoCache from '~/cache/NocoCache';
@Injectable()
export class MapsService {
@ -25,12 +27,28 @@ export class MapsService {
'swagger.json#/components/schemas/ViewCreateReq',
param.map,
);
const view = await View.insert({
...param.map,
// todo: sanitize
fk_model_id: param.tableId,
type: ViewTypes.MAP,
});
const model = await Model.get(param.tableId);
const { id } = await View.insertMetaOnly(
{
...param.map,
// todo: sanitize
fk_model_id: param.tableId,
type: ViewTypes.MAP,
base_id: model.base_id,
source_id: model.source_id,
},
model,
);
// populate cache and add to list since the list cache already exist
const view = await View.get(id);
await NocoCache.appendToList(
CacheScope.VIEW,
[view.fk_model_id],
`${CacheScope.VIEW}:${id}`,
);
this.appHooksService.emit(AppEvents.VIEW_CREATE, {
view,

3
packages/nocodb/src/services/tables.service.ts

@ -601,6 +601,7 @@ export class TablesService {
column_name: c.column_name,
})),
);
await sqlMgr.sqlOpPlus(source, 'tableCreate', {
...tableCreatePayLoad,
tn: tableCreatePayLoad.table_name,
@ -612,6 +613,7 @@ export class TablesService {
system?: boolean;
}
>;
if (!source.isMeta()) {
columns = (
await sqlMgr.sqlOpPlus(source, 'columnList', {
@ -620,6 +622,7 @@ export class TablesService {
})
)?.data?.list;
}
const tables = await Model.list({
base_id: base.id,
source_id: source.id,

Loading…
Cancel
Save