diff --git a/packages/nocodb-nest/src/modules/datas/data-alias-nested/data-alias-nested.controller.ts b/packages/nocodb-nest/src/modules/datas/data-alias-nested/data-alias-nested.controller.ts index ee69608615..0b367fd190 100644 --- a/packages/nocodb-nest/src/modules/datas/data-alias-nested/data-alias-nested.controller.ts +++ b/packages/nocodb-nest/src/modules/datas/data-alias-nested/data-alias-nested.controller.ts @@ -1,4 +1,158 @@ -import { Controller } from '@nestjs/common'; +import { Controller, Delete, Get, Param, Post, Request } from '@nestjs/common'; +import { Acl } from '../../../middlewares/extract-project-id/extract-project-id.middleware'; +import { DataAliasNestedService } from './data-alias-nested.service'; @Controller('data-alias-nested') -export class DataAliasNestedController {} +class DataAliasNestedController { + constructor(private dataAliasNestedService: DataAliasNestedService) {} + + // todo: handle case where the given column is not ltar + @Get('/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/mm/:columnName') + @Acl('mmList') + async mmList( + @Request() req, + @Param('columnName') columnName: string, + @Param('rowId') rowId: string, + @Param('projectName') projectName: string, + @Param('tableName') tableName: string, + ) { + return await this.dataAliasNestedService.mmList({ + query: req.query, + columnName: columnName, + rowId: rowId, + projectName: projectName, + tableName: tableName, + }); + } + + @Get( + '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/mm/:columnName/exclude', + ) + @Acl('mmExcludedList') + async mmExcludedList( + @Request() req, + @Param('columnName') columnName: string, + @Param('rowId') rowId: string, + @Param('projectName') projectName: string, + @Param('tableName') tableName: string, + ) { + return await this.dataAliasNestedService.mmExcludedList({ + query: req.query, + columnName: columnName, + rowId: rowId, + projectName: projectName, + tableName: tableName, + }); + } + + @Get( + '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/hm/:columnName/exclude', + ) + @Acl('hmExcludedList') + async hmExcludedList( + @Request() req, + @Param('columnName') columnName: string, + @Param('rowId') rowId: string, + @Param('projectName') projectName: string, + @Param('tableName') tableName: string, + ) { + return await this.dataAliasNestedService.hmExcludedList({ + query: req.query, + columnName: columnName, + rowId: rowId, + projectName: projectName, + tableName: tableName, + }); + } + + @Get( + '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/bt/:columnName/exclude', + ) + @Acl('btExcludedList') + async btExcludedList( + @Request() req, + @Param('columnName') columnName: string, + @Param('rowId') rowId: string, + @Param('projectName') projectName: string, + @Param('tableName') tableName: string, + ) { + return await this.dataAliasNestedService.btExcludedList({ + query: req.query, + columnName: columnName, + rowId: rowId, + projectName: projectName, + tableName: tableName, + }); + } + + // todo: handle case where the given column is not ltar + + @Get('/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/hm/:columnName') + @Acl('hmList') + async hmList( + @Request() req, + @Param('columnName') columnName: string, + @Param('rowId') rowId: string, + @Param('projectName') projectName: string, + @Param('tableName') tableName: string, + ) { + return await this.dataAliasNestedService.hmList({ + query: req.query, + columnName: columnName, + rowId: rowId, + projectName: projectName, + tableName: tableName, + }); + } + + @Delete( + '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/:relationType/:columnName/:refRowId', + ) + @Acl('relationDataRemove') + async relationDataRemove( + @Request() req, + @Param('columnName') columnName: string, + @Param('rowId') rowId: string, + @Param('projectName') projectName: string, + @Param('tableName') tableName: string, + @Param('refRowId') refRowId: string, + @Param('relationType') relationType: string, + ) { + await this.dataAliasNestedService.relationDataRemove({ + columnName: columnName, + rowId: rowId, + projectName: projectName, + tableName: tableName, + cookie: req, + refRowId: refRowId, + }); + + return { msg: 'The relation data has been deleted successfully' }; + } + + // todo: Give proper error message when reference row is already related and handle duplicate ref row id in hm + @Post( + '/api/v1/db/data/:orgs/:projectName/:tableName/:rowId/:relationType/:columnName/:refRowId', + ) + @Acl('relationDataAdd') + async relationDataAdd( + @Request() req, + @Param('columnName') columnName: string, + @Param('rowId') rowId: string, + @Param('projectName') projectName: string, + @Param('tableName') tableName: string, + @Param('refRowId') refRowId: string, + @Param('relationType') relationType: string, + ) { + await this.dataAliasNestedService.relationDataAdd({ + columnName: columnName, + rowId: rowId, + projectName: projectName, + tableName: tableName, + cookie: req, + refRowId: refRowId, + }); + + return { msg: 'The relation data has been created successfully' }; + } +} diff --git a/packages/nocodb-nest/src/modules/datas/data-alias-nested/data-alias-nested.service.spec.ts b/packages/nocodb-nest/src/modules/datas/data-alias-nested/data-alias-nested.service.spec.ts new file mode 100644 index 0000000000..05b137a1ab --- /dev/null +++ b/packages/nocodb-nest/src/modules/datas/data-alias-nested/data-alias-nested.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { DataAliasNestedService } from './data-alias-nested.service'; + +describe('DataAliasNestedService', () => { + let service: DataAliasNestedService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [DataAliasNestedService], + }).compile(); + + service = module.get(DataAliasNestedService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/packages/nocodb-nest/src/modules/datas/data-alias-nested/data-alias-nested.service.ts b/packages/nocodb-nest/src/modules/datas/data-alias-nested/data-alias-nested.service.ts new file mode 100644 index 0000000000..0ef4234387 --- /dev/null +++ b/packages/nocodb-nest/src/modules/datas/data-alias-nested/data-alias-nested.service.ts @@ -0,0 +1,282 @@ +import { Injectable } from '@nestjs/common'; +import { NcError } from '../../../helpers/catchError'; +import { PagedResponseImpl } from '../../../helpers/PagedResponse'; +import { Base, Model } from '../../../models'; +import NcConnectionMgrv2 from '../../../utils/common/NcConnectionMgrv2'; +import { + getColumnByIdOrName, + getViewAndModelByAliasOrId, + PathParams, +} from '../helpers'; + +@Injectable() +export class DataAliasNestedService { + // todo: handle case where the given column is not ltar + async mmList( + param: PathParams & { + query: any; + columnName: string; + rowId: string; + }, + ) { + const { model, view } = await getViewAndModelByAliasOrId(param); + + if (!model) NcError.notFound('Table not found'); + + const base = await Base.get(model.base_id); + + const baseModel = await Model.getBaseModelSQL({ + id: model.id, + viewId: view?.id, + dbDriver: await NcConnectionMgrv2.get(base), + }); + + const column = await getColumnByIdOrName(param.columnName, model); + + const data = await baseModel.mmList( + { + colId: column.id, + parentId: param.rowId, + }, + param.query as any, + ); + const count: any = await baseModel.mmListCount({ + colId: column.id, + parentId: param.rowId, + }); + + return new PagedResponseImpl(data, { + count, + ...param.query, + }); + } + + async mmExcludedList( + param: PathParams & { + query: any; + columnName: string; + rowId: string; + }, + ) { + const { model, view } = await getViewAndModelByAliasOrId(param); + if (!model) NcError.notFound('Table not found'); + + const base = await Base.get(model.base_id); + + const baseModel = await Model.getBaseModelSQL({ + id: model.id, + viewId: view?.id, + dbDriver: await NcConnectionMgrv2.get(base), + }); + const column = await getColumnByIdOrName(param.columnName, model); + + const data = await baseModel.getMmChildrenExcludedList( + { + colId: column.id, + pid: param.rowId, + }, + param.query, + ); + + const count = await baseModel.getMmChildrenExcludedListCount( + { + colId: column.id, + pid: param.rowId, + }, + param.query, + ); + + return new PagedResponseImpl(data, { + count, + ...param.query, + }); + } + + async hmExcludedList( + param: PathParams & { + query: any; + columnName: string; + rowId: string; + }, + ) { + const { model, view } = await getViewAndModelByAliasOrId(param); + + if (!model) NcError.notFound('Table not found'); + + const base = await Base.get(model.base_id); + + const baseModel = await Model.getBaseModelSQL({ + id: model.id, + viewId: view?.id, + dbDriver: await NcConnectionMgrv2.get(base), + }); + + const column = await getColumnByIdOrName(param.columnName, model); + + const data = await baseModel.getHmChildrenExcludedList( + { + colId: column.id, + pid: param.rowId, + }, + param.query, + ); + + const count = await baseModel.getHmChildrenExcludedListCount( + { + colId: column.id, + pid: param.rowId, + }, + param.query, + ); + + return new PagedResponseImpl(data, { + count, + ...param.query, + }); + } + + async btExcludedList( + param: PathParams & { + query: any; + columnName: string; + rowId: string; + }, + ) { + const { model, view } = await getViewAndModelByAliasOrId(param); + if (!model) NcError.notFound('Table not found'); + + const base = await Base.get(model.base_id); + + const baseModel = await Model.getBaseModelSQL({ + id: model.id, + viewId: view?.id, + dbDriver: await NcConnectionMgrv2.get(base), + }); + + const column = await getColumnByIdOrName(param.columnName, model); + + const data = await baseModel.getBtChildrenExcludedList( + { + colId: column.id, + cid: param.rowId, + }, + param.query, + ); + + const count = await baseModel.getBtChildrenExcludedListCount( + { + colId: column.id, + cid: param.rowId, + }, + param.query, + ); + + return new PagedResponseImpl(data, { + count, + ...param.query, + }); + } + + // todo: handle case where the given column is not ltar + async hmList( + param: PathParams & { + query: any; + columnName: string; + rowId: string; + }, + ) { + const { model, view } = await getViewAndModelByAliasOrId(param); + + if (!model) NcError.notFound('Table not found'); + + const base = await Base.get(model.base_id); + + const baseModel = await Model.getBaseModelSQL({ + id: model.id, + viewId: view?.id, + dbDriver: await NcConnectionMgrv2.get(base), + }); + + const column = await getColumnByIdOrName(param.columnName, model); + + const data = await baseModel.hmList( + { + colId: column.id, + id: param.rowId, + }, + param.query, + ); + + const count = await baseModel.hmListCount({ + colId: column.id, + id: param.rowId, + }); + + return new PagedResponseImpl(data, { + count, + ...param.query, + } as any); + } + + async relationDataRemove( + param: PathParams & { + columnName: string; + rowId: string; + refRowId: string; + cookie: any; + }, + ) { + const { model, view } = await getViewAndModelByAliasOrId(param); + if (!model) NcError.notFound('Table not found'); + + const base = await Base.get(model.base_id); + + const baseModel = await Model.getBaseModelSQL({ + id: model.id, + viewId: view?.id, + dbDriver: await NcConnectionMgrv2.get(base), + }); + + const column = await getColumnByIdOrName(param.columnName, model); + + await baseModel.removeChild({ + colId: column.id, + childId: param.refRowId, + rowId: param.rowId, + cookie: param.cookie, + }); + + return true; + } + + // todo: Give proper error message when reference row is already related and handle duplicate ref row id in hm + async relationDataAdd( + param: PathParams & { + columnName: string; + rowId: string; + refRowId: string; + cookie: any; + }, + ) { + const { model, view } = await getViewAndModelByAliasOrId(param); + if (!model) NcError.notFound('Table not found'); + + const base = await Base.get(model.base_id); + + const baseModel = await Model.getBaseModelSQL({ + id: model.id, + viewId: view?.id, + dbDriver: await NcConnectionMgrv2.get(base), + }); + + const column = await getColumnByIdOrName(param.columnName, model); + await baseModel.addChild({ + colId: column.id, + childId: param.refRowId, + rowId: param.rowId, + cookie: param.cookie, + }); + + return true; + } +} diff --git a/packages/nocodb-nest/src/modules/datas/datas.module.ts b/packages/nocodb-nest/src/modules/datas/datas.module.ts index 52a29f1441..eb92c8f586 100644 --- a/packages/nocodb-nest/src/modules/datas/datas.module.ts +++ b/packages/nocodb-nest/src/modules/datas/datas.module.ts @@ -6,9 +6,10 @@ import { DataAliasExportController } from './data-alias-export/data-alias-export import { DataAliasNestedController } from './data-alias-nested/data-alias-nested.controller'; import { OldDatasController } from './old-datas/old-datas.controller'; import { BulkDataAliasService } from './bulk-data-alias/bulk-data-alias.service'; +import { DataAliasNestedService } from './data-alias-nested/data-alias-nested.service'; @Module({ controllers: [DatasController, BulkDataAliasController, DataAliasExportController, DataAliasNestedController, OldDatasController], - providers: [DatasService, BulkDataAliasService] + providers: [DatasService, BulkDataAliasService, DataAliasNestedService] }) export class DatasModule {}