From 2f9ba540d590efcf88a9cd4ed436889e47179254 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Fri, 7 Apr 2023 22:20:05 +0530 Subject: [PATCH] feat: add sort and filter apis - WIP Signed-off-by: Pranav C --- packages/nocodb-nest/src/app.module.ts | 4 +- .../filters/filters.controller.spec.ts | 20 +++ .../src/modules/filters/filters.controller.ts | 127 ++++++++++++++++++ .../src/modules/filters/filters.module.ts | 9 ++ .../modules/filters/filters.service.spec.ts | 18 +++ .../src/modules/filters/filters.service.ts | 69 ++++++++++ .../modules/sorts/sorts.controller.spec.ts | 20 +++ .../src/modules/sorts/sorts.controller.ts | 79 +++++++++++ .../src/modules/sorts/sorts.module.ts | 9 ++ .../src/modules/sorts/sorts.service.spec.ts | 18 +++ .../src/modules/sorts/sorts.service.ts | 41 ++++++ 11 files changed, 413 insertions(+), 1 deletion(-) create mode 100644 packages/nocodb-nest/src/modules/filters/filters.controller.spec.ts create mode 100644 packages/nocodb-nest/src/modules/filters/filters.controller.ts create mode 100644 packages/nocodb-nest/src/modules/filters/filters.module.ts create mode 100644 packages/nocodb-nest/src/modules/filters/filters.service.spec.ts create mode 100644 packages/nocodb-nest/src/modules/filters/filters.service.ts create mode 100644 packages/nocodb-nest/src/modules/sorts/sorts.controller.spec.ts create mode 100644 packages/nocodb-nest/src/modules/sorts/sorts.controller.ts create mode 100644 packages/nocodb-nest/src/modules/sorts/sorts.module.ts create mode 100644 packages/nocodb-nest/src/modules/sorts/sorts.service.spec.ts create mode 100644 packages/nocodb-nest/src/modules/sorts/sorts.service.ts diff --git a/packages/nocodb-nest/src/app.module.ts b/packages/nocodb-nest/src/app.module.ts index f520d12c32..a966425139 100644 --- a/packages/nocodb-nest/src/app.module.ts +++ b/packages/nocodb-nest/src/app.module.ts @@ -11,9 +11,11 @@ import { JwtStrategy } from './strategies/jwt.strategy'; import { AuthGuard } from '@nestjs/passport'; import { TablesModule } from './modules/tables/tables.module'; import { ViewsModule } from './modules/views/views.module'; +import { FiltersModule } from './modules/filters/filters.module'; +import { SortsModule } from './modules/sorts/sorts.module'; @Module({ - imports: [AuthModule, UsersModule, UtilsModule, ProjectsModule, TablesModule, ViewsModule], + imports: [AuthModule, UsersModule, UtilsModule, ProjectsModule, TablesModule, ViewsModule, FiltersModule, SortsModule], controllers: [], providers: [Connection, MetaService, JwtStrategy, ExtractProjectIdMiddleware], exports: [Connection, MetaService], diff --git a/packages/nocodb-nest/src/modules/filters/filters.controller.spec.ts b/packages/nocodb-nest/src/modules/filters/filters.controller.spec.ts new file mode 100644 index 0000000000..3d1a7f3548 --- /dev/null +++ b/packages/nocodb-nest/src/modules/filters/filters.controller.spec.ts @@ -0,0 +1,20 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { FiltersController } from './filters.controller'; +import { FiltersService } from './filters.service'; + +describe('FiltersController', () => { + let controller: FiltersController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [FiltersController], + providers: [FiltersService], + }).compile(); + + controller = module.get(FiltersController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/packages/nocodb-nest/src/modules/filters/filters.controller.ts b/packages/nocodb-nest/src/modules/filters/filters.controller.ts new file mode 100644 index 0000000000..9aca31710a --- /dev/null +++ b/packages/nocodb-nest/src/modules/filters/filters.controller.ts @@ -0,0 +1,127 @@ +import { Controller, Get, Param, UseGuards } from '@nestjs/common'; +import { AuthGuard } from '@nestjs/passport'; +import { PagedResponseImpl } from '../../helpers/PagedResponse'; +import { + ExtractProjectIdMiddleware, + UseAclMiddleware, +} from '../../middlewares/extract-project-id/extract-project-id.middleware'; +import { FiltersService } from './filters.service'; + +@Controller() +@UseGuards(ExtractProjectIdMiddleware, AuthGuard('jwt')) +export class FiltersController { + constructor(private readonly filtersService: FiltersService) {} + + @Get('/api/v1/db/meta/views/:viewId/filters') + @UseAclMiddleware({ + permissionName: 'filterList', + }) + async filterList(@Param('viewId') viewId: string) { + return new PagedResponseImpl( + await this.filtersService.filterList({ + viewId, + }), + ); + } +} + +/* +export async function filterGet(req: Request, res: Response) { + res.json(await filterService.filterGet({ filterId: req.params.filterId })); +} + + +export async function filterChildrenRead(req: Request, res: Response) { + res.json( + new PagedResponseImpl( + await filterService.filterChildrenList({ + filterId: req.params.filterParentId, + }) + ) + ); +} + +export async function filterCreate(req: Request, res) { + const filter = await filterService.filterCreate({ + filter: req.body, + viewId: req.params.viewId, + }); + res.json(filter); +} + +export async function filterUpdate(req, res) { + const filter = await filterService.filterUpdate({ + filterId: req.params.filterId, + filter: req.body, + }); + res.json(filter); +} + +export async function filterDelete(req: Request, res: Response) { + const filter = await filterService.filterDelete({ + filterId: req.params.filterId, + }); + res.json(filter); +} + +export async function hookFilterList(req: Request, res: Response) { + res.json( + new PagedResponseImpl( + await filterService.hookFilterList({ + hookId: req.params.hookId, + }) + ) + ); +} + +export async function hookFilterCreate( + req: Request, + res +) { + const filter = await filterService.hookFilterCreate({ + filter: req.body, + hookId: req.params.hookId, + }); + res.json(filter); +} + +const router = Router({ mergeParams: true }); + +router.post( + '/api/v1/db/meta/views/:viewId/filters', + metaApiMetrics, + ncMetaAclMw(filterCreate, 'filterCreate') +); + +router.get( + '/api/v1/db/meta/hooks/:hookId/filters', + ncMetaAclMw(hookFilterList, 'filterList') +); +router.post( + '/api/v1/db/meta/hooks/:hookId/filters', + metaApiMetrics, + ncMetaAclMw(hookFilterCreate, 'filterCreate') +); + +router.get( + '/api/v1/db/meta/filters/:filterId', + metaApiMetrics, + ncMetaAclMw(filterGet, 'filterGet') +); +router.patch( + '/api/v1/db/meta/filters/:filterId', + metaApiMetrics, + ncMetaAclMw(filterUpdate, 'filterUpdate') +); +router.delete( + '/api/v1/db/meta/filters/:filterId', + metaApiMetrics, + ncMetaAclMw(filterDelete, 'filterDelete') +); +router.get( + '/api/v1/db/meta/filters/:filterParentId/children', + metaApiMetrics, + ncMetaAclMw(filterChildrenRead, 'filterChildrenRead') +); +export default router; +* */ diff --git a/packages/nocodb-nest/src/modules/filters/filters.module.ts b/packages/nocodb-nest/src/modules/filters/filters.module.ts new file mode 100644 index 0000000000..d16e9b19ef --- /dev/null +++ b/packages/nocodb-nest/src/modules/filters/filters.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { FiltersService } from './filters.service'; +import { FiltersController } from './filters.controller'; + +@Module({ + controllers: [FiltersController], + providers: [FiltersService] +}) +export class FiltersModule {} diff --git a/packages/nocodb-nest/src/modules/filters/filters.service.spec.ts b/packages/nocodb-nest/src/modules/filters/filters.service.spec.ts new file mode 100644 index 0000000000..6ea7488076 --- /dev/null +++ b/packages/nocodb-nest/src/modules/filters/filters.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { FiltersService } from './filters.service'; + +describe('FiltersService', () => { + let service: FiltersService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [FiltersService], + }).compile(); + + service = module.get(FiltersService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/packages/nocodb-nest/src/modules/filters/filters.service.ts b/packages/nocodb-nest/src/modules/filters/filters.service.ts new file mode 100644 index 0000000000..4e747d46bf --- /dev/null +++ b/packages/nocodb-nest/src/modules/filters/filters.service.ts @@ -0,0 +1,69 @@ +import { Injectable } from '@nestjs/common'; +import { FilterReqType } from 'nocodb-sdk'; +import { validatePayload } from '../../helpers'; +import { Filter } from '../../models'; +import { T } from 'nc-help'; + +@Injectable() +export class FiltersService { + async hookFilterCreate(param: { filter: FilterReqType; hookId: any }) { + validatePayload('swagger.json#/components/schemas/FilterReq', param.filter); + + const filter = await Filter.insert({ + ...param.filter, + fk_hook_id: param.hookId, + }); + + T.emit('evt', { evt_type: 'hookFilter:created' }); + return filter; + } + + async hookFilterList(param: { hookId: any }) { + return Filter.rootFilterListByHook({ hookId: param.hookId }); + } + + async filterDelete(param: { filterId: string }) { + await Filter.delete(param.filterId); + T.emit('evt', { evt_type: 'filter:deleted' }); + return true; + } + + async filterCreate(param: { filter: FilterReqType; viewId: string }) { + validatePayload('swagger.json#/components/schemas/FilterReq', param.filter); + + const filter = await Filter.insert({ + ...param.filter, + fk_view_id: param.viewId, + }); + + T.emit('evt', { evt_type: 'filter:created' }); + + return filter; + } + async filterUpdate(param: { filter: FilterReqType; filterId: string }) { + validatePayload('swagger.json#/components/schemas/FilterReq', param.filter); + + // todo: type correction + const filter = await Filter.update(param.filterId, param.filter as Filter); + + T.emit('evt', { evt_type: 'filter:updated' }); + + return filter; + } + + async filterChildrenList(param: { filterId: any }) { + return Filter.parentFilterList({ + parentId: param.filterId, + }); + } + + async filterGet(param: { filterId: string }) { + const filter = await Filter.get(param.filterId); + return filter; + } + + async filterList(param: { viewId: string }) { + const filter = await Filter.rootFilterList({ viewId: param.viewId }); + return filter; + } +} diff --git a/packages/nocodb-nest/src/modules/sorts/sorts.controller.spec.ts b/packages/nocodb-nest/src/modules/sorts/sorts.controller.spec.ts new file mode 100644 index 0000000000..3255c7fba6 --- /dev/null +++ b/packages/nocodb-nest/src/modules/sorts/sorts.controller.spec.ts @@ -0,0 +1,20 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { SortsController } from './sorts.controller'; +import { SortsService } from './sorts.service'; + +describe('SortsController', () => { + let controller: SortsController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [SortsController], + providers: [SortsService], + }).compile(); + + controller = module.get(SortsController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/packages/nocodb-nest/src/modules/sorts/sorts.controller.ts b/packages/nocodb-nest/src/modules/sorts/sorts.controller.ts new file mode 100644 index 0000000000..7e56b8af7a --- /dev/null +++ b/packages/nocodb-nest/src/modules/sorts/sorts.controller.ts @@ -0,0 +1,79 @@ +import { Controller, Get, Param } from '@nestjs/common'; +import { PagedResponseImpl } from '../../helpers/PagedResponse'; +import { SortsService } from './sorts.service'; + +@Controller('sorts') +export class SortsController { + constructor(private readonly sortsService: SortsService) {} + + @Get('/api/v1/db/meta/views/:viewId/sorts/') + async sortList(@Param('viewId') viewId: string) { + return; + new PagedResponseImpl( + await this.sortsService.sortList({ + viewId, + }), + ); + } +} + +/* + + +export async function sortCreate(req: Request, res) { + const sort = await sortService.sortCreate({ + sort: req.body, + viewId: req.params.viewId, + }); + res.json(sort); +} + +export async function sortUpdate(req, res) { + const sort = await sortService.sortUpdate({ + sortId: req.params.sortId, + sort: req.body, + }); + res.json(sort); +} + +export async function sortDelete(req: Request, res: Response) { + const sort = await sortService.sortDelete({ + sortId: req.params.sortId, + }); + res.json(sort); +} + +export async function sortGet(req: Request, res: Response) { + const sort = await sortService.sortGet({ + sortId: req.params.sortId, + }); + res.json(sort); +} + +const router = Router({ mergeParams: true }); + +router.post( + '/api/v1/db/meta/views/:viewId/sorts/', + metaApiMetrics, + ncMetaAclMw(sortCreate, 'sortCreate') +); + +router.get( + '/api/v1/db/meta/sorts/:sortId', + metaApiMetrics, + ncMetaAclMw(sortGet, 'sortGet') +); + +router.patch( + '/api/v1/db/meta/sorts/:sortId', + metaApiMetrics, + ncMetaAclMw(sortUpdate, 'sortUpdate') +); +router.delete( + '/api/v1/db/meta/sorts/:sortId', + metaApiMetrics, + ncMetaAclMw(sortDelete, 'sortDelete') +); +export default router; + +* */ diff --git a/packages/nocodb-nest/src/modules/sorts/sorts.module.ts b/packages/nocodb-nest/src/modules/sorts/sorts.module.ts new file mode 100644 index 0000000000..c634ccaf0f --- /dev/null +++ b/packages/nocodb-nest/src/modules/sorts/sorts.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { SortsService } from './sorts.service'; +import { SortsController } from './sorts.controller'; + +@Module({ + controllers: [SortsController], + providers: [SortsService] +}) +export class SortsModule {} diff --git a/packages/nocodb-nest/src/modules/sorts/sorts.service.spec.ts b/packages/nocodb-nest/src/modules/sorts/sorts.service.spec.ts new file mode 100644 index 0000000000..711c36f406 --- /dev/null +++ b/packages/nocodb-nest/src/modules/sorts/sorts.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { SortsService } from './sorts.service'; + +describe('SortsService', () => { + let service: SortsService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [SortsService], + }).compile(); + + service = module.get(SortsService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/packages/nocodb-nest/src/modules/sorts/sorts.service.ts b/packages/nocodb-nest/src/modules/sorts/sorts.service.ts new file mode 100644 index 0000000000..62a0c67948 --- /dev/null +++ b/packages/nocodb-nest/src/modules/sorts/sorts.service.ts @@ -0,0 +1,41 @@ +import { Injectable } from '@nestjs/common'; +import { SortReqType } from 'nocodb-sdk'; +import { validatePayload } from '../../helpers'; +import { Sort } from '../../models'; +import { T } from 'nc-help'; + +@Injectable() +export class SortsService { + async sortGet(param: { sortId: string }) { + return Sort.get(param.sortId); + } + + async sortDelete(param: { sortId: string }) { + await Sort.delete(param.sortId); + T.emit('evt', { evt_type: 'sort:deleted' }); + return true; + } + + async sortUpdate(param: { sortId: any; sort: SortReqType }) { + validatePayload('swagger.json#/components/schemas/SortReq', param.sort); + + const sort = await Sort.update(param.sortId, param.sort); + T.emit('evt', { evt_type: 'sort:updated' }); + return sort; + } + + async sortCreate(param: { viewId: any; sort: SortReqType }) { + validatePayload('swagger.json#/components/schemas/SortReq', param.sort); + + const sort = await Sort.insert({ + ...param.sort, + fk_view_id: param.viewId, + } as Sort); + T.emit('evt', { evt_type: 'sort:created' }); + return sort; + } + + async sortList(param: { viewId: string }) { + return Sort.list({ viewId: param.viewId }); + } +}