-
-
Notifications
You must be signed in to change notification settings - Fork 18
feat: add endpoint to find table categories with associated tables #1597
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,16 @@ | ||||||||||
| import { ApiProperty } from '@nestjs/swagger'; | ||||||||||
| import { FoundTableDs } from '../../table/application/data-structures/found-table.ds.js'; | ||||||||||
|
|
||||||||||
| export class FoundTableCategoriesWithTablesRo { | ||||||||||
| @ApiProperty({ type: String }) | ||||||||||
| category_id: string; | ||||||||||
|
|
||||||||||
| @ApiProperty({ type: String }) | ||||||||||
| category_name: string; | ||||||||||
|
|
||||||||||
| @ApiProperty({ type: String }) | ||||||||||
| category_color: string; | ||||||||||
|
Comment on lines
+11
to
+12
|
||||||||||
| @ApiProperty({ type: String }) | |
| category_color: string; | |
| @ApiProperty({ type: String, nullable: true }) | |
| category_color: string | null; |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -11,7 +11,14 @@ import { SentryInterceptor } from '../../interceptors/sentry.interceptor.js'; | |||||
| import { CreateOrUpdateTableCategoriesDS } from './data-sctructures/create-or-update-table-categories.ds.js'; | ||||||
| import { CreateTableCategoryDto } from './dto/create-table-category.dto.js'; | ||||||
| import { FoundTableCategoryRo } from './dto/found-table-category.ro.js'; | ||||||
| import { ICreateTableCategories, IFindTableCategories } from './use-cases/table-categories-use-cases.interface.js'; | ||||||
| import { | ||||||
| ICreateTableCategories, | ||||||
| IFindTableCategories, | ||||||
| IFindTableCategoriesWithTables, | ||||||
| } from './use-cases/table-categories-use-cases.interface.js'; | ||||||
| import { FoundTableCategoriesWithTablesRo } from './dto/found-table-categories-with-tables.ro.js'; | ||||||
| import { UserId } from '../../decorators/user-id.decorator.js'; | ||||||
| import { FindTablesDs } from '../table/application/data-structures/find-tables.ds.js'; | ||||||
|
|
||||||
| @UseInterceptors(SentryInterceptor) | ||||||
| @Timeout() | ||||||
|
|
@@ -25,6 +32,8 @@ export class TableCategoriesController { | |||||
| private readonly createTableCategoriesUseCase: ICreateTableCategories, | ||||||
| @Inject(UseCaseType.FIND_TABLE_CATEGORIES) | ||||||
| private readonly findTableCategoriesUseCase: IFindTableCategories, | ||||||
| @Inject(UseCaseType.FIND_TABLE_CATEGORIES_WITH_TABLES) | ||||||
| private readonly findTableCategoriesWithTablesUseCase: IFindTableCategoriesWithTables, | ||||||
| ) {} | ||||||
|
|
||||||
| @ApiOperation({ summary: 'Add new table categories' }) | ||||||
|
|
@@ -64,4 +73,28 @@ export class TableCategoriesController { | |||||
| async findTableCategories(@SlugUuid('connectionId') connectionId: string): Promise<Array<FoundTableCategoryRo>> { | ||||||
| return await this.findTableCategoriesUseCase.execute(connectionId); | ||||||
| } | ||||||
|
|
||||||
| @ApiOperation({ summary: 'Find table categories with tables' }) | ||||||
| @ApiResponse({ | ||||||
| status: 200, | ||||||
| description: 'Table categories with tables found.', | ||||||
| type: FoundTableCategoriesWithTablesRo, | ||||||
| isArray: true, | ||||||
| }) | ||||||
| @ApiParam({ name: 'connectionId', required: true }) | ||||||
| @UseGuards(TablesReceiveGuard) | ||||||
| @Get('/v2/:connectionId') | ||||||
| async findTableCategoriesWithTAbles( | ||||||
|
||||||
| async findTableCategoriesWithTAbles( | |
| async findTableCategoriesWithTables( |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,211 @@ | ||||||||||||||||||||||||||||||
| import { HttpException, HttpStatus, Inject, Injectable, Scope } from '@nestjs/common'; | ||||||||||||||||||||||||||||||
| import { getDataAccessObject } from '@rocketadmin/shared-code/dist/src/data-access-layer/shared/create-data-access-object.js'; | ||||||||||||||||||||||||||||||
| import { TableDS } from '@rocketadmin/shared-code/dist/src/data-access-layer/shared/data-structures/table.ds.js'; | ||||||||||||||||||||||||||||||
| import * as Sentry from '@sentry/node'; | ||||||||||||||||||||||||||||||
| import AbstractUseCase from '../../../common/abstract-use.case.js'; | ||||||||||||||||||||||||||||||
| import { IGlobalDatabaseContext } from '../../../common/application/global-database-context.interface.js'; | ||||||||||||||||||||||||||||||
| import { BaseType } from '../../../common/data-injection.tokens.js'; | ||||||||||||||||||||||||||||||
| import { AccessLevelEnum } from '../../../enums/access-level.enum.js'; | ||||||||||||||||||||||||||||||
| import { ExceptionOperations } from '../../../exceptions/custom-exceptions/exception-operation.js'; | ||||||||||||||||||||||||||||||
| import { UnknownSQLException } from '../../../exceptions/custom-exceptions/unknown-sql-exception.js'; | ||||||||||||||||||||||||||||||
| import { Messages } from '../../../exceptions/text/messages.js'; | ||||||||||||||||||||||||||||||
| import { isConnectionTypeAgent } from '../../../helpers/is-connection-entity-agent.js'; | ||||||||||||||||||||||||||||||
| import { isObjectPropertyExists } from '../../../helpers/validators/is-object-property-exists-validator.js'; | ||||||||||||||||||||||||||||||
| import { ConnectionEntity } from '../../connection/connection.entity.js'; | ||||||||||||||||||||||||||||||
| import { ITableAndViewPermissionData } from '../../permission/permission.interface.js'; | ||||||||||||||||||||||||||||||
| import { TableSettingsEntity } from '../../table-settings/common-table-settings/table-settings.entity.js'; | ||||||||||||||||||||||||||||||
| import { FindTablesDs } from '../../table/application/data-structures/find-tables.ds.js'; | ||||||||||||||||||||||||||||||
| import { FoundTableDs } from '../../table/application/data-structures/found-table.ds.js'; | ||||||||||||||||||||||||||||||
| import { FoundTableCategoriesWithTablesRo } from '../dto/found-table-categories-with-tables.ro.js'; | ||||||||||||||||||||||||||||||
| import { IFindTableCategoriesWithTables } from './table-categories-use-cases.interface.js'; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @Injectable({ scope: Scope.REQUEST }) | ||||||||||||||||||||||||||||||
| export class FindTableCategoriesWithTablesUseCase | ||||||||||||||||||||||||||||||
| extends AbstractUseCase<FindTablesDs, Array<FoundTableCategoriesWithTablesRo>> | ||||||||||||||||||||||||||||||
| implements IFindTableCategoriesWithTables | ||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||
| constructor( | ||||||||||||||||||||||||||||||
| @Inject(BaseType.GLOBAL_DB_CONTEXT) | ||||||||||||||||||||||||||||||
| protected _dbContext: IGlobalDatabaseContext, | ||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||
| super(); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| protected async implementation(inputData: FindTablesDs): Promise<Array<FoundTableCategoriesWithTablesRo>> { | ||||||||||||||||||||||||||||||
| const { connectionId, masterPwd, userId } = inputData; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
| const { connectionId, masterPwd, userId } = inputData; | |
| const { connectionId, masterPwd, userId, hiddenTablesOption } = inputData; | |
| if (typeof hiddenTablesOption !== 'undefined' && hiddenTablesOption !== null) { | |
| // This use case intentionally always excludes hidden tables. | |
| // To avoid misleading callers, explicitly reject requests that try to | |
| // control hidden table visibility via `hiddenTablesOption`. | |
| throw new HttpException( | |
| { | |
| message: 'The hiddenTablesOption parameter is not supported for this endpoint.', | |
| }, | |
| HttpStatus.BAD_REQUEST, | |
| ); | |
| } |
Copilot
AI
Feb 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
findTableCategoriesForConnection() has no ORDER BY, so category order in the response can be nondeterministic. To keep the API output stable (and avoid flaky tests), sort the returned categories (e.g., by category_name/category_id) or add an orderBy in the repository query.
Copilot
AI
Feb 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This use case duplicates substantial logic from the existing table listing use cases (e.g., display-name enrichment and permissions calculation). Keeping multiple copies increases the risk of behavior drift when one copy changes. Consider extracting these helpers into a shared service/util or reusing the existing implementation where possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
category_idis returned asnullfor the "All tables" category (see use case), but this response model declares it as non-nullablestring. Update the DTO type tostring | nulland mark it nullable in the Swagger decorator.