From 919a04bfcf3830de7ce2e2674519b5ffe3510d0f Mon Sep 17 00:00:00 2001 From: Artem Niehrieiev Date: Thu, 27 Aug 2026 14:25:52 +0000 Subject: [PATCH] Remove IBM Db2 support from RocketAdmin Agent - Updated main.ts to remove Db2 from the list of supported database types. - Deleted wait-for-db2.js and wait-for-db2.sh scripts as they are no longer needed. - Removed optional dependency on ibm_db from package.json. - Cleaned up caching constants and removed Db2 related cache options. - Eliminated Db2 related code from caching and data access layers. - Removed DataAccessObjectIbmDb2 and its references throughout the codebase. - Updated connection parameters and enums to exclude Db2. --- AGENTS.md | 132 +- CLAUDE.md | 7 +- backend/package.json | 3 +- backend/src/ai-core/tools/prompts.ts | 3 - backend/src/ai-core/tools/query-validators.ts | 3 - .../custom-agent-repository-extension.ts | 2 - .../utils/is-sql-connection-type.util.ts | 2 - .../table-schema/ai/schema-change-prompts.ts | 3 +- .../utils/assert-dialect-supported.ts | 5 +- .../export-csv-from-table.use.case.ts | 1 - .../panel/utils/check-query-is-safe.util.ts | 2 - backend/src/helpers/constants/constants.ts | 5 +- .../src/helpers/is-connection-entity-agent.ts | 2 - backend/src/shared/config/app-config.ts | 16 - .../complex-ibmdb2-table-e2e.test.ts | 1168 ----- .../non-saas-table-ibmdb2-e2e.test.ts | 3791 ---------------- .../non-saas-table-schema-ibmdb2-e2e.test.ts | 330 -- .../saas-tests/table-ibmdb2-agent-e2e.test.ts | 2950 ------------ .../saas-tests/table-ibmdb2-e2e.test.ts | 3967 ----------------- .../saas-tests/table-widgets-e2e.test.ts | 172 - backend/test/mock.factory.ts | 21 - backend/test/utils/create-test-table.ts | 89 - backend/test/utils/get-test-data.ts | 4 - .../create-test-ibmdb2-tables.ts | 573 --- docker-compose.yml | 45 - frontend/CLAUDE.md | 1 - frontend/src/app/app.component.ts | 4 - .../connect-db/connect-db.component.ts | 5 +- .../db2-credentials-form.component.css | 14 - .../db2-credentials-form.component.html | 210 - .../db2-credentials-form.component.spec.ts | 38 - .../db2-credentials-form.component.stories.ts | 50 - .../db2-credentials-form.component.ts | 32 - .../own-connections.component.ts | 1 - .../components/upgrade/upgrade.component.ts | 6 - frontend/src/app/consts/databases.ts | 2 - frontend/src/app/models/connection.ts | 1 - .../validators/connection-string.validator.ts | 3 - .../src/assets/icons/db-logos/db2_logo.svg | 937 ---- justfile | 4 +- package.json | 8 - pnpm-lock.yaml | 559 --- .../.ibmdb2_test_agent_config.txt | 23 - rocketadmin-agent/Dockerfile | 2 - .../src/helpers/cli/interactive-prompts.ts | 828 ++-- rocketadmin-agent/src/main.ts | 324 +- rocketadmin-agent/wait-for-db2.js | 75 - rocketadmin-agent/wait-for-db2.sh | 12 - shared-code/package.json | 3 - shared-code/src/caching/caching-constants.ts | 13 +- shared-code/src/caching/lru-storage.ts | 16 +- .../basic-data-access-object.ts | 5 - .../data-access-object-ibmdb2.ts | 836 ---- .../shared/create-data-access-object.ts | 13 +- .../data-structures/connections-params.ds.ts | 1 - .../src/shared/enums/connection-types-enum.ts | 4 - 56 files changed, 721 insertions(+), 16605 deletions(-) mode change 120000 => 100644 AGENTS.md delete mode 100644 backend/test/ava-tests/complex-table-tests/complex-ibmdb2-table-e2e.test.ts delete mode 100644 backend/test/ava-tests/non-saas-tests/non-saas-table-ibmdb2-e2e.test.ts delete mode 100644 backend/test/ava-tests/non-saas-tests/non-saas-table-schema-ibmdb2-e2e.test.ts delete mode 100644 backend/test/ava-tests/saas-tests/table-ibmdb2-agent-e2e.test.ts delete mode 100644 backend/test/ava-tests/saas-tests/table-ibmdb2-e2e.test.ts delete mode 100644 backend/test/utils/test-utilities/create-test-ibmdb2-tables.ts delete mode 100644 frontend/src/app/components/connect-db/db-credentials-forms/db2-credentials-form/db2-credentials-form.component.css delete mode 100644 frontend/src/app/components/connect-db/db-credentials-forms/db2-credentials-form/db2-credentials-form.component.html delete mode 100644 frontend/src/app/components/connect-db/db-credentials-forms/db2-credentials-form/db2-credentials-form.component.spec.ts delete mode 100644 frontend/src/app/components/connect-db/db-credentials-forms/db2-credentials-form/db2-credentials-form.component.stories.ts delete mode 100644 frontend/src/app/components/connect-db/db-credentials-forms/db2-credentials-form/db2-credentials-form.component.ts delete mode 100644 frontend/src/assets/icons/db-logos/db2_logo.svg delete mode 100644 rocketadmin-agent/.ibmdb2_test_agent_config.txt delete mode 100644 rocketadmin-agent/wait-for-db2.js delete mode 100755 rocketadmin-agent/wait-for-db2.sh delete mode 100644 shared-code/src/data-access-layer/data-access-objects/data-access-object-ibmdb2.ts diff --git a/AGENTS.md b/AGENTS.md deleted file mode 120000 index 681311eb9..000000000 --- a/AGENTS.md +++ /dev/null @@ -1 +0,0 @@ -CLAUDE.md \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..e31e8cda0 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,131 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +RocketAdmin is a database administration panel that allows users to manage database connections, tables, and data. It consists of multiple components in a monorepo structure: + +- **backend/** - NestJS API server (TypeScript, ES modules) +- **frontend/** - Angular 19 web application (standalone components) +- **rocketadmin-agent/** - NestJS agent for connecting to databases behind firewalls +- **autoadmin-ws-server/** - WebSocket server for agent communication +- **shared-code/** - Shared data access layer and utilities used by backend and agent + +## Development Commands + +### Backend + +```bash +cd backend +pnpm start:dev # Start dev server with hot reload +pnpm build # Build for production +pnpm lint # ESLint with auto-fix +pnpm test # Run non-saas AVA tests (serial) +pnpm test-all # Run all AVA tests (5min timeout, serial) +pnpm test-saas # Run SaaS-specific tests +``` + +### Frontend + +```bash +cd frontend +yarn start # Start Angular dev server +yarn build # Production build +yarn test:ci # Run tests headlessly (CI mode) +yarn test --browsers=ChromeHeadlessCustom --no-watch --no-progress # Headless tests +yarn lint # TSLint (deprecated, needs ESLint migration) +``` + +### Running Backend Tests with Docker + +The project uses `just` for test orchestration: + +```bash +just test # Run all backend tests with Docker Compose +just test "path/to/test.ts" # Run specific test file +``` + +This spins up test databases (MySQL, PostgreSQL, MSSQL, Oracle, MongoDB, DynamoDB) via `docker-compose.tst.yml`. + +### Migrations + +```bash +cd backend +pnpm build # Must build first +pnpm migration:generate src/migrations/MigrationName # Generate migration +pnpm migration:run # Run pending migrations +pnpm migration:revert # Revert last migration +``` + +## Architecture + +### Monorepo Structure + +- Uses pnpm workspaces with packages: `backend`, `rocketadmin-agent`, `shared-code` +- `shared-code` is imported as `@rocketadmin/shared-code` workspace dependency +- Frontend is a separate Angular project (not a workspace member) + +### Backend (NestJS) + +- **Entities pattern**: Each entity has its own directory under `src/entities/` containing: + - `*.entity.ts` - TypeORM entity + - `*.module.ts` - NestJS module + - `*.controller.ts` - REST endpoints + - `*.service.ts` - Business logic (use cases) + - `dto/` - Request/response DTOs with class-validator decorators + - `*.controller.ee.ts` - Enterprise edition controllers (SaaS features) +- **Guards**: Authentication and authorization in `src/guards/` +- **Data access**: Uses `shared-code` for database operations via Knex +- **Testing**: AVA test framework with tests in `test/ava-tests/` + - `non-saas-tests/` - Core functionality tests + - `saas-tests/` - SaaS-specific feature tests + - `complex-table-tests/` - Complex table operation tests + +### Frontend (Angular 19) + +See `frontend/CLAUDE.md` for detailed frontend architecture. + +Key points: +- Standalone components (no NgModules) +- BehaviorSubject-based state management (no NgRx) +- Multi-environment builds (development, production, saas, saas-production) +- Jasmine/Karma testing with ChromeHeadless + +### Shared Code + +Located in `shared-code/src/`: +- `data-access-layer/` - Database abstraction supporting MySQL, PostgreSQL, MSSQL, Oracle, MongoDB, DynamoDB, Cassandra, Elasticsearch +- `knex-manager/` - Knex connection management +- `caching/` - LRU cache utilities +- `helpers/` - Shared utilities + +### Agent Architecture + +The rocketadmin-agent connects to databases in private networks: +1. Agent runs inside customer's network +2. Connects to `autoadmin-ws-server` via WebSocket +3. Backend communicates with agent through WebSocket server +4. Agent executes database queries and returns results + +## Database Support + +The application supports: MySQL, PostgreSQL, MongoDB, DynamoDB, Cassandra, OracleDB, MSSQL, Elasticsearch, Redis + +Database-specific DAOs are in `shared-code/src/data-access-layer/`. + +## Testing Database Connections + +Test databases are defined in `docker-compose.tst.yml`: +- MySQL: `testMySQL-e2e-testing:3306` +- PostgreSQL: `testPg-e2e-testing:5432` +- MSSQL: `mssql-e2e-testing:1433` +- Oracle: `test-oracle-e2e-testing:1521` +- MongoDB: `test-mongo-e2e-testing:27017` +- DynamoDB: `test-dynamodb-e2e-testing:8000` + +## Coding Conventions + +### Class Member Ordering + +- Private methods must be placed at the end of the class, after all public methods diff --git a/CLAUDE.md b/CLAUDE.md index 56edf0d53..e31e8cda0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -46,7 +46,7 @@ just test # Run all backend tests with Docker Compose just test "path/to/test.ts" # Run specific test file ``` -This spins up test databases (MySQL, PostgreSQL, MSSQL, Oracle, IBM DB2, MongoDB, DynamoDB) via `docker-compose.tst.yml`. +This spins up test databases (MySQL, PostgreSQL, MSSQL, Oracle, MongoDB, DynamoDB) via `docker-compose.tst.yml`. ### Migrations @@ -95,7 +95,7 @@ Key points: ### Shared Code Located in `shared-code/src/`: -- `data-access-layer/` - Database abstraction supporting MySQL, PostgreSQL, MSSQL, Oracle, MongoDB, DynamoDB, IBM DB2, Cassandra, Elasticsearch +- `data-access-layer/` - Database abstraction supporting MySQL, PostgreSQL, MSSQL, Oracle, MongoDB, DynamoDB, Cassandra, Elasticsearch - `knex-manager/` - Knex connection management - `caching/` - LRU cache utilities - `helpers/` - Shared utilities @@ -110,7 +110,7 @@ The rocketadmin-agent connects to databases in private networks: ## Database Support -The application supports: MySQL, PostgreSQL, MongoDB, DynamoDB, Cassandra, OracleDB, MSSQL, IBM DB2, Elasticsearch, Redis +The application supports: MySQL, PostgreSQL, MongoDB, DynamoDB, Cassandra, OracleDB, MSSQL, Elasticsearch, Redis Database-specific DAOs are in `shared-code/src/data-access-layer/`. @@ -121,7 +121,6 @@ Test databases are defined in `docker-compose.tst.yml`: - PostgreSQL: `testPg-e2e-testing:5432` - MSSQL: `mssql-e2e-testing:1433` - Oracle: `test-oracle-e2e-testing:1521` -- IBM DB2: `test-ibm-db2-e2e-testing:50000` - MongoDB: `test-mongo-e2e-testing:27017` - DynamoDB: `test-dynamodb-e2e-testing:8000` diff --git a/backend/package.json b/backend/package.json index bbdaddcd3..e4262d2dd 100644 --- a/backend/package.json +++ b/backend/package.json @@ -19,7 +19,7 @@ "test-all": "node _run-with-timing.mjs ava --timeout=5m", "test-all-parallel": "AVA_CONCURRENCY=8 node _run-with-timing.mjs ava --timeout=5m", "test-saas": "node _run-with-timing.mjs ava test/ava-tests/saas-tests/*", - "test-fast": "AVA_CONCURRENCY=6 node _run-with-timing.mjs ava --timeout=5m 'test/ava-tests/non-saas-tests/!(*oracle*|*ibmdb2*|*cassandra*|*elasticsearch*).test.ts' 'test/ava-tests/saas-tests/!(*oracle*|*ibmdb2*|*cassandra*|*elasticsearch*).test.ts'", + "test-fast": "AVA_CONCURRENCY=6 node _run-with-timing.mjs ava --timeout=5m 'test/ava-tests/non-saas-tests/!(*oracle*|*cassandra*|*elasticsearch*).test.ts' 'test/ava-tests/saas-tests/!(*oracle*|*cassandra*|*elasticsearch*).test.ts'", "typeorm": "ts-node -r tsconfig-paths/register ../node_modules/.bin/typeorm", "migration:generate": "pnpm run typeorm migration:generate -d dist/src/shared/config/datasource.config.js", "migration:create": "pnpm run typeorm migration:create -d dist/src/shared/config/datasource.config.js", @@ -109,7 +109,6 @@ "@types/body-parser": "^1.19.6", "@types/cookie-parser": "^1.4.10", "@types/express": "^5.0.6", - "@types/ibm_db": "^3.2.0", "@types/json2csv": "^5.0.7", "@types/node": "^24.10.1", "@types/supertest": "^7.2.0", diff --git a/backend/src/ai-core/tools/prompts.ts b/backend/src/ai-core/tools/prompts.ts index 18f09997b..6a0e71f82 100644 --- a/backend/src/ai-core/tools/prompts.ts +++ b/backend/src/ai-core/tools/prompts.ts @@ -59,9 +59,6 @@ export function convertDbTypeToReadableString(dataType: ConnectionTypesEnum): st case ConnectionTypesEnum.oracledb: case ConnectionTypesEnum.agent_oracledb: return 'Oracle DB'; - case ConnectionTypesEnum.ibmdb2: - case ConnectionTypesEnum.agent_ibmdb2: - return 'IBM DB2'; case ConnectionTypesEnum.clickhouse: case ConnectionTypesEnum.agent_clickhouse: return 'ClickHouse'; diff --git a/backend/src/ai-core/tools/query-validators.ts b/backend/src/ai-core/tools/query-validators.ts index a4870e847..925206cdf 100644 --- a/backend/src/ai-core/tools/query-validators.ts +++ b/backend/src/ai-core/tools/query-validators.ts @@ -103,9 +103,6 @@ export function wrapQueryWithLimit(query: string, databaseType: ConnectionTypesE case ConnectionTypesEnum.mssql: case ConnectionTypesEnum.agent_mssql: return `SELECT * FROM (${queryWithoutSemicolon}) AS ai_query LIMIT ${limit}`; - case ConnectionTypesEnum.ibmdb2: - case ConnectionTypesEnum.agent_ibmdb2: - return `SELECT * FROM (${queryWithoutSemicolon}) AS ai_query FETCH FIRST ${limit} ROWS ONLY`; case ConnectionTypesEnum.oracledb: case ConnectionTypesEnum.agent_oracledb: return `SELECT * FROM (${queryWithoutSemicolon}) WHERE ROWNUM <= ${limit}`; diff --git a/backend/src/entities/agent/repository/custom-agent-repository-extension.ts b/backend/src/entities/agent/repository/custom-agent-repository-extension.ts index 1d7388bce..78b7b2f6f 100644 --- a/backend/src/entities/agent/repository/custom-agent-repository-extension.ts +++ b/backend/src/entities/agent/repository/custom-agent-repository-extension.ts @@ -52,8 +52,6 @@ export const customAgentRepositoryExtension: IAgentRepository = { return 'MYSQL-TEST-AGENT-TOKEN'; case ConnectionTypeTestEnum.agent_postgres: return 'POSTGRES-TEST-AGENT-TOKEN'; - case ConnectionTypeTestEnum.agent_ibmdb2: - return 'IBMDB2-TEST-AGENT-TOKEN'; case ConnectionTypeTestEnum.agent_mongodb: return 'MONGODB-TEST-AGENT-TOKEN'; case ConnectionTypeTestEnum.agent_redis: diff --git a/backend/src/entities/connection/utils/is-sql-connection-type.util.ts b/backend/src/entities/connection/utils/is-sql-connection-type.util.ts index 9c41a7d4a..feca49e0b 100644 --- a/backend/src/entities/connection/utils/is-sql-connection-type.util.ts +++ b/backend/src/entities/connection/utils/is-sql-connection-type.util.ts @@ -6,13 +6,11 @@ const SQL_CONNECTION_TYPES: ReadonlySet = new Set([ ConnectionTypesEnum.mysql2, ConnectionTypesEnum.oracledb, ConnectionTypesEnum.mssql, - ConnectionTypesEnum.ibmdb2, ConnectionTypesEnum.clickhouse, ConnectionTypesEnum.agent_postgres, ConnectionTypesEnum.agent_mysql, ConnectionTypesEnum.agent_oracledb, ConnectionTypesEnum.agent_mssql, - ConnectionTypesEnum.agent_ibmdb2, ConnectionTypesEnum.agent_clickhouse, ]); diff --git a/backend/src/entities/table-schema/ai/schema-change-prompts.ts b/backend/src/entities/table-schema/ai/schema-change-prompts.ts index c2de72ec9..97d5884e3 100644 --- a/backend/src/entities/table-schema/ai/schema-change-prompts.ts +++ b/backend/src/entities/table-schema/ai/schema-change-prompts.ts @@ -46,10 +46,9 @@ Multi-proposal rules: - For a single-change request, supply a "proposals" array of length 1 — same content as before. Rules for the generated SQL: -- Target dialect is ${dialect}. Use the correct identifier quoting (double quotes for PostgreSQL/Oracle/DB2, backticks for MySQL/ClickHouse, square brackets or double quotes for Microsoft SQL Server) and the correct syntax for data types, autoincrement, and constraints. +- Target dialect is ${dialect}. Use the correct identifier quoting (double quotes for PostgreSQL/Oracle, backticks for MySQL/ClickHouse, square brackets or double quotes for Microsoft SQL Server) and the correct syntax for data types, autoincrement, and constraints. - For Microsoft SQL Server, use IDENTITY for autoincrement, NVARCHAR/VARCHAR for strings, and name primary/foreign keys explicitly (e.g. CONSTRAINT PK_tbl PRIMARY KEY ...) so they are referenceable in rollback DROP CONSTRAINT statements. - For Oracle DB, use NUMBER/VARCHAR2, and GENERATED BY DEFAULT AS IDENTITY for autoincrement. ALTER TABLE ... MODIFY is the column-change syntax. -- For IBM DB2, use BIGINT GENERATED BY DEFAULT AS IDENTITY and VARCHAR. ALTER TABLE ... ALTER COLUMN ... SET DATA TYPE is the column-change syntax. - For ClickHouse: every CREATE TABLE MUST include a table engine (prefer \`ENGINE = MergeTree()\`) followed by an \`ORDER BY ()\` clause — ClickHouse has no conventional PRIMARY KEY; the sort/primary key is the \`ORDER BY\` tuple. Use types like \`UInt32\`, \`UInt64\`, \`Int64\`, \`String\`, \`Float64\`, \`DateTime\`, \`Date\`, \`UUID\`, \`Nullable(T)\` (wrap a type to allow NULL). There is no autoincrement — use a plain numeric type the user populates. Column additions use \`ALTER TABLE t ADD COLUMN c T\`, drops use \`ALTER TABLE t DROP COLUMN c\`, type changes use \`ALTER TABLE t MODIFY COLUMN c T\`. Do NOT emit \`ON CLUSTER\` clauses; the target is a single-node server. There are NO true transactions, so rollback is a best-effort compensating DDL (e.g. add-column forward / drop-column rollback). Do NOT propose foreign keys (ClickHouse does not enforce them). Indexes in ClickHouse are DATA SKIPPING indexes created with \`ALTER TABLE t ADD INDEX idx_name col TYPE minmax GRANULARITY 4\`; rollback is \`ALTER TABLE t DROP INDEX idx_name\`. Avoid \`DROP TABLE IF EXISTS\` unless the user asked. - For Cassandra (CQL): every CREATE TABLE MUST declare a \`PRIMARY KEY\` inline, either as a column-level \`PRIMARY KEY\` on one column or as a trailing \`PRIMARY KEY ((partition_key_cols), clustering_key_cols)\` clause. Use CQL types: \`UUID\`, \`TIMEUUID\`, \`TEXT\`, \`VARCHAR\`, \`ASCII\`, \`INT\`, \`BIGINT\`, \`SMALLINT\`, \`TINYINT\`, \`FLOAT\`, \`DOUBLE\`, \`DECIMAL\`, \`BOOLEAN\`, \`TIMESTAMP\`, \`DATE\`, \`TIME\`, \`BLOB\`, \`INET\`, \`LIST\`, \`SET\`, \`MAP\`. There is NO autoincrement — prefer \`UUID\` partition keys. Do NOT propose foreign keys (Cassandra does not enforce them). Do NOT propose \`ALTER COLUMN\` type-change DDL — CQL only supports renaming primary-key columns and adding/dropping non-primary-key columns. Column additions use \`ALTER TABLE t ADD c T\` (no \`COLUMN\` keyword), drops use \`ALTER TABLE t DROP c\`. Indexes are \`CREATE INDEX idx_name ON t (col)\` with rollback \`DROP INDEX idx_name\`. There are NO transactions; rollback is a best-effort compensating DDL. Do NOT emit \`CREATE KEYSPACE\`, \`DROP KEYSPACE\`, \`USE\`, or materialized-view DDL. - Both forwardSql and rollbackSql MUST be single DDL statements. No semicolons terminating a chain. No multi-statement scripts. diff --git a/backend/src/entities/table-schema/utils/assert-dialect-supported.ts b/backend/src/entities/table-schema/utils/assert-dialect-supported.ts index 11d5a47c7..51306a23c 100644 --- a/backend/src/entities/table-schema/utils/assert-dialect-supported.ts +++ b/backend/src/entities/table-schema/utils/assert-dialect-supported.ts @@ -7,7 +7,6 @@ const SUPPORTED_DIALECTS: ReadonlySet = new Set([ ConnectionTypesEnum.mysql2, ConnectionTypesEnum.mssql, ConnectionTypesEnum.oracledb, - ConnectionTypesEnum.ibmdb2, ConnectionTypesEnum.mongodb, ConnectionTypesEnum.clickhouse, ConnectionTypesEnum.agent_clickhouse, @@ -24,7 +23,7 @@ export function isDialectSupported(connectionType: ConnectionTypesEnum): boolean export function assertDialectSupported(connectionType: ConnectionTypesEnum): void { if (!isDialectSupported(connectionType)) { throw new BadRequestException( - `Schema changes via AI are not yet supported for "${connectionType}". Supported: PostgreSQL, MySQL, Microsoft SQL Server, Oracle DB, IBM DB2, MongoDB, ClickHouse, DynamoDB, Cassandra, Elasticsearch.`, + `Schema changes via AI are not yet supported for "${connectionType}". Supported: PostgreSQL, MySQL, Microsoft SQL Server, Oracle DB, MongoDB, ClickHouse, DynamoDB, Cassandra, Elasticsearch.`, ); } } @@ -57,8 +56,6 @@ const SQL_PARSER_DIALECTS: Record = { [ConnectionTypesEnum.agent_mysql]: 'MySQL', [ConnectionTypesEnum.mssql]: 'TransactSQL', [ConnectionTypesEnum.agent_mssql]: 'TransactSQL', - [ConnectionTypesEnum.ibmdb2]: 'DB2', - [ConnectionTypesEnum.agent_ibmdb2]: 'DB2', }; export function connectionTypeToParserDialect(connectionType: ConnectionTypesEnum): string { diff --git a/backend/src/entities/table/use-cases/export-csv-from-table.use.case.ts b/backend/src/entities/table/use-cases/export-csv-from-table.use.case.ts index 9e11ac42d..2cc3e1b46 100644 --- a/backend/src/entities/table/use-cases/export-csv-from-table.use.case.ts +++ b/backend/src/entities/table/use-cases/export-csv-from-table.use.case.ts @@ -140,7 +140,6 @@ export class ExportCSVFromTableUseCase //todo: transfer data as a stream from clint to server if ( connection.type === 'oracledb' || - connection.type === 'ibmdb2' || connection.type === 'mongodb' || connection.type === 'dynamodb' || connection.type === 'elasticsearch' || diff --git a/backend/src/entities/visualizations/panel/utils/check-query-is-safe.util.ts b/backend/src/entities/visualizations/panel/utils/check-query-is-safe.util.ts index a86bbfacd..5c664df97 100644 --- a/backend/src/entities/visualizations/panel/utils/check-query-is-safe.util.ts +++ b/backend/src/entities/visualizations/panel/utils/check-query-is-safe.util.ts @@ -102,8 +102,6 @@ const SQL_CONNECTION_TYPES: ConnectionTypesEnum[] = [ ConnectionTypesEnum.agent_mssql, ConnectionTypesEnum.oracledb, ConnectionTypesEnum.agent_oracledb, - ConnectionTypesEnum.ibmdb2, - ConnectionTypesEnum.agent_ibmdb2, ConnectionTypesEnum.clickhouse, ConnectionTypesEnum.agent_clickhouse, ConnectionTypesEnum.cassandra, diff --git a/backend/src/helpers/constants/constants.ts b/backend/src/helpers/constants/constants.ts index b429cfb7b..437cc436f 100644 --- a/backend/src/helpers/constants/constants.ts +++ b/backend/src/helpers/constants/constants.ts @@ -20,7 +20,6 @@ export type TestConnectionsFromJSON = { 'test-mssql': string; 'test-oracle': string; 'test-mongo': string; - 'test-ibmdb2': string; }; export const Constants = { @@ -57,11 +56,11 @@ export const Constants = { MORNING_CRON_KEY: 2, CONNECTION_KEYS_NONE_PERMISSION: ['id', 'title', 'database', 'type', 'connection_properties', 'isTestConnection'], FREE_PLAN_USERS_COUNT: 3, - NON_FREE_PLAN_CONNECTION_TYPES: [ConnectionTypesEnum.ibmdb2, ConnectionTypesEnum.mssql, ConnectionTypesEnum.oracledb], + NON_FREE_PLAN_CONNECTION_TYPES: [ConnectionTypesEnum.mssql, ConnectionTypesEnum.oracledb], MAX_FILE_SIZE_IN_BYTES: 10485760, MAX_COMPANY_LOGO_SIZE: 5242880, MAX_COMPANY_FAVICON_SIZE: 5242880, - PAID_CONNECTIONS_TYPES: [ConnectionTypesEnum.oracledb, ConnectionTypesEnum.ibmdb2, ConnectionTypesEnum.mssql], + PAID_CONNECTIONS_TYPES: [ConnectionTypesEnum.oracledb, ConnectionTypesEnum.mssql], VERIFICATION_STRING_WHITELIST: () => { const numbers = [...Array(10).keys()].map((num) => num.toString()); diff --git a/backend/src/helpers/is-connection-entity-agent.ts b/backend/src/helpers/is-connection-entity-agent.ts index b6af43963..f41d84d8c 100644 --- a/backend/src/helpers/is-connection-entity-agent.ts +++ b/backend/src/helpers/is-connection-entity-agent.ts @@ -11,7 +11,6 @@ export function isConnectionEntityAgent(connection: ConnectionEntity | CreateCon ConnectionTypesEnum.agent_mysql, ConnectionTypesEnum.agent_oracledb, ConnectionTypesEnum.agent_mssql, - ConnectionTypesEnum.agent_ibmdb2, ConnectionTypesEnum.agent_mongodb, ConnectionTypesEnum.agent_cassandra, ConnectionTypesEnum.agent_redis, @@ -27,7 +26,6 @@ export function isConnectionTypeAgent(type: ConnectionTypesEnum | string | null ConnectionTypeTestEnum.agent_mysql, ConnectionTypeTestEnum.agent_oracledb, ConnectionTypeTestEnum.agent_mssql, - ConnectionTypeTestEnum.agent_ibmdb2, ConnectionTypeTestEnum.agent_mongodb, ConnectionTypeTestEnum.agent_cassandra, ConnectionTypesEnum.agent_redis, diff --git a/backend/src/shared/config/app-config.ts b/backend/src/shared/config/app-config.ts index a3bfd33c5..69f8858f9 100644 --- a/backend/src/shared/config/app-config.ts +++ b/backend/src/shared/config/app-config.ts @@ -96,14 +96,6 @@ export interface TestDbConfig { database: string | null; authSource: string | null; }; - ibmdb2: { - host: string | null; - port: number | null; - username: string | null; - password: string | null; - database: string | null; - schema: string | null; - }; } const AUTOADMIN_SUPPORT_MAIL = 'support@autoadmin.org'; @@ -220,14 +212,6 @@ export class AppConfig { database: readString('MONGO_CONNECTION_DATABASE'), authSource: readString('MONGO_CONNECTION_AUTH_SOURCE'), }), - ibmdb2: Object.freeze({ - host: readString('IBM_DB2_CONNECTION_HOST'), - port: readInt('IBM_DB2_CONNECTION_PORT'), - username: readString('IBM_DB2_CONNECTION_USERNAME'), - password: readString('IBM_DB2_CONNECTION_PASSWORD'), - database: readString('IBM_DB2_CONNECTION_DATABASE'), - schema: readString('IBM_DB2_CONNECTION_SCHEMA'), - }), }); Object.freeze(this); diff --git a/backend/test/ava-tests/complex-table-tests/complex-ibmdb2-table-e2e.test.ts b/backend/test/ava-tests/complex-table-tests/complex-ibmdb2-table-e2e.test.ts deleted file mode 100644 index 26f8da8b3..000000000 --- a/backend/test/ava-tests/complex-table-tests/complex-ibmdb2-table-e2e.test.ts +++ /dev/null @@ -1,1168 +0,0 @@ -import { INestApplication, ValidationPipe } from '@nestjs/common'; -import { Test } from '@nestjs/testing'; -import test from 'ava'; -import { ValidationError } from 'class-validator'; -import cookieParser from 'cookie-parser'; -import path from 'path'; -import request from 'supertest'; -import { fileURLToPath } from 'url'; -import { ApplicationModule } from '../../../src/app.module.js'; -import { WinstonLogger } from '../../../src/entities/logging/winston-logger.js'; -import { AllExceptionsFilter } from '../../../src/exceptions/all-exceptions.filter.js'; -import { ValidationException } from '../../../src/exceptions/custom-exceptions/validation-exception.js'; -import { Cacher } from '../../../src/helpers/cache/cacher.js'; -import { DatabaseModule } from '../../../src/shared/database/database.module.js'; -import { DatabaseService } from '../../../src/shared/database/database.service.js'; -import { MockFactory } from '../../mock.factory.js'; -import { getTestData } from '../../utils/get-test-data.js'; -import { registerUserAndReturnUserInfo } from '../../utils/register-user-and-return-user-info.js'; -import { TestUtils } from '../../utils/test.utils.js'; -import { - createTestIBMDB2TablesWithComplexPFKeys, - createTestIBMDB2TablesWithSimplePFKeys, -} from '../../utils/test-utilities/create-test-ibmdb2-tables.js'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -const mockFactory = new MockFactory(); -let app: INestApplication; -let _testUtils: TestUtils; -const _testSearchedUserName = 'Vasia'; -const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - -let testTablesCompositeKeysData: TableCreationResult; -let testTablesSimpleKeysData: TableCreationResult; - -test.before(async () => { - const moduleFixture = await Test.createTestingModule({ - imports: [ApplicationModule, DatabaseModule], - providers: [DatabaseService, TestUtils], - }).compile(); - app = moduleFixture.createNestApplication() as any; - _testUtils = moduleFixture.get(TestUtils); - - app.use(cookieParser()); - app.useGlobalFilters(new AllExceptionsFilter(app.get(WinstonLogger))); - app.useGlobalPipes( - new ValidationPipe({ - exceptionFactory(validationErrors: ValidationError[] = []) { - return new ValidationException(validationErrors); - }, - }), - ); - await app.init(); - app.getHttpServer().listen(0); - - testTablesCompositeKeysData = await createTestIBMDB2TablesWithComplexPFKeys(connectionToTestDB); - testTablesSimpleKeysData = await createTestIBMDB2TablesWithSimplePFKeys(connectionToTestDB); -}); - -test.after(async () => { - try { - await Cacher.clearAllCache(); - await app.close(); - } catch (e) { - console.error('After tests error ' + e); - } -}); - -export type TableCreationResult = { - main_table: { - table_name: string; - column_names: string[]; - foreign_key_column_names: string[]; - binary_column_names: string[]; - primary_key_column_names: string[]; - }; - first_referenced_table: { - table_name: string; - column_names: string[]; - primary_key_column_names: string[]; - }; - second_referenced_table: { - table_name: string; - column_names: string[]; - primary_key_column_names: string[]; - foreign_key_column_names: string[]; - }; -}; - -// GET /connection/tables/:slug - -test.serial( - `GET /connection/tables/:slug - Should return list of table rows with referenced columns, when primary and foreign keys has composite structure`, - async (t) => { - try { - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const { main_table, first_referenced_table, second_referenced_table } = testTablesCompositeKeysData; - - const getMainTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${main_table.table_name}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const _getMainTableRowsRO = JSON.parse(getMainTableRowsResponse.text); - t.is(getMainTableRowsResponse.status, 200); - - const getFirstReferencedTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${first_referenced_table.table_name}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const getFirstReferencedTableRowsRO = JSON.parse(getFirstReferencedTableRowsResponse.text); - t.is(getFirstReferencedTableRowsResponse.status, 200); - - const firstReturnedRows = getFirstReferencedTableRowsRO.rows; - - for (const row of firstReturnedRows) { - t.is(typeof row.ORDER_ID, 'object'); - t.truthy(Object.hasOwn(row.ORDER_ID, 'ORDER_ID')); - t.truthy(row.ORDER_ID.ORDER_ID); - t.truthy(typeof row.ORDER_ID.ORDER_ID === 'number'); - t.is(typeof row.CUSTOMER_ID, 'object'); - t.truthy(Object.hasOwn(row.CUSTOMER_ID, 'CUSTOMER_ID')); - t.truthy(row.CUSTOMER_ID.CUSTOMER_ID); - t.truthy(typeof row.CUSTOMER_ID.CUSTOMER_ID === 'number'); - } - - const getSecondReferencedTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${second_referenced_table.table_name}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const getSecondReferencedTableRowsRO = JSON.parse(getSecondReferencedTableRowsResponse.text); - t.is(getSecondReferencedTableRowsResponse.status, 200); - const secondReturnedRows = getSecondReferencedTableRowsRO.rows; - for (const row of secondReturnedRows) { - t.is(typeof row.ORDER_ID, 'object'); - t.truthy(Object.hasOwn(row.ORDER_ID, 'ORDER_ID')); - t.truthy(row.ORDER_ID.ORDER_ID); - t.truthy(typeof row.ORDER_ID.ORDER_ID === 'number'); - t.is(typeof row.CUSTOMER_ID, 'object'); - t.truthy(Object.hasOwn(row.CUSTOMER_ID, 'CUSTOMER_ID')); - t.truthy(row.CUSTOMER_ID.CUSTOMER_ID); - t.truthy(typeof row.CUSTOMER_ID.CUSTOMER_ID === 'number'); - } - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `GET /connection/tables/:slug - Should return list of table rows with referenced columns, when primary and foreign keys has simple structure`, - async (t) => { - try { - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const { main_table, first_referenced_table, second_referenced_table } = testTablesSimpleKeysData; - - const getMainTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${main_table.table_name}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const _getMainTableRowsRO = JSON.parse(getMainTableRowsResponse.text); - t.is(getMainTableRowsResponse.status, 200); - - const getFirstReferencedTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${first_referenced_table.table_name}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const getFirstReferencedTableRowsRO = JSON.parse(getFirstReferencedTableRowsResponse.text); - t.is(getFirstReferencedTableRowsResponse.status, 200); - - const firstReturnedRows = getFirstReferencedTableRowsRO.rows; - - for (const element of firstReturnedRows) { - t.is(typeof element.ORDER_ID, 'object'); - t.truthy(Object.hasOwn(element.ORDER_ID, 'ORDER_ID')); - t.truthy(element.ORDER_ID.ORDER_ID); - t.truthy(typeof element.ORDER_ID.ORDER_ID === 'number'); - } - - const getSecondReferencedTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${second_referenced_table.table_name}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const getSecondReferencedTableRowsRO = JSON.parse(getSecondReferencedTableRowsResponse.text); - t.is(getSecondReferencedTableRowsResponse.status, 200); - - const secondReturnedRows = getSecondReferencedTableRowsRO.rows; - for (const element of secondReturnedRows) { - t.is(typeof element.ORDER_ID, 'object'); - t.truthy(Object.hasOwn(element.ORDER_ID, 'ORDER_ID')); - t.truthy(element.ORDER_ID.ORDER_ID); - t.truthy(typeof element.ORDER_ID.ORDER_ID === 'number'); - } - } catch (e) { - console.error(e); - throw e; - } - }, -); - -// GET /table/structure/:connectionId - -test.serial( - `GET /table/structure/:connectionId - Should return table structure for composite primary key table`, - async (t) => { - try { - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const { main_table } = testTablesCompositeKeysData; - - const getStructureResponse = await request(app.getHttpServer()) - .get(`/table/structure/${createConnectionRO.id}?tableName=${main_table.table_name}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const structureRO = JSON.parse(getStructureResponse.text); - t.is(getStructureResponse.status, 200); - t.truthy(structureRO.structure); - t.truthy(Array.isArray(structureRO.structure)); - t.truthy(structureRO.structure.length > 0); - - const columnNames = structureRO.structure.map((col: any) => col.column_name); - for (const expectedCol of main_table.column_names) { - t.truthy(columnNames.includes(expectedCol), `Structure should include column ${expectedCol}`); - } - - const orderIdCol = structureRO.structure.find((col: any) => col.column_name === 'ORDER_ID'); - const customerIdCol = structureRO.structure.find((col: any) => col.column_name === 'CUSTOMER_ID'); - t.truthy(orderIdCol); - t.truthy(customerIdCol); - - // Validate primaryColumns - t.truthy(structureRO.primaryColumns); - const primaryColumnNames = structureRO.primaryColumns.map((col: any) => col.column_name); - t.truthy(primaryColumnNames.includes('ORDER_ID')); - t.truthy(primaryColumnNames.includes('CUSTOMER_ID')); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `GET /table/structure/:connectionId - Should return structure for referenced table with foreign keys`, - async (t) => { - try { - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const { first_referenced_table } = testTablesCompositeKeysData; - - const getStructureResponse = await request(app.getHttpServer()) - .get(`/table/structure/${createConnectionRO.id}?tableName=${first_referenced_table.table_name}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(getStructureResponse.status, 200); - const structureRO = JSON.parse(getStructureResponse.text); - t.truthy(structureRO.structure); - t.truthy(Array.isArray(structureRO.structure)); - - const columnNames = structureRO.structure.map((col: any) => col.column_name); - t.truthy(columnNames.includes('ITEM_ID')); - t.truthy(columnNames.includes('ORDER_ID')); - t.truthy(columnNames.includes('CUSTOMER_ID')); - t.truthy(columnNames.includes('PRODUCT_NAME')); - t.truthy(columnNames.includes('QUANTITY')); - t.truthy(columnNames.includes('PRICE_PER_UNIT')); - - // Validate foreignKeys are present for referenced table - t.truthy(structureRO.foreignKeys); - t.truthy(structureRO.foreignKeys.length > 0); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -// GET /table/rows/:connectionId - Pagination tests - -test.serial(`GET /table/rows/:connectionId - Should return paginated rows for composite key table`, async (t) => { - try { - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const { main_table } = testTablesCompositeKeysData; - - const perPage = 10; - const getRowsPage1Response = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${main_table.table_name}&perPage=${perPage}&page=1`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(getRowsPage1Response.status, 200); - const page1RO = JSON.parse(getRowsPage1Response.text); - t.truthy(page1RO.rows); - t.is(page1RO.rows.length, perPage); - t.truthy(page1RO.pagination); - t.is(page1RO.pagination.currentPage, 1); - t.is(page1RO.pagination.perPage, perPage); - t.truthy(page1RO.pagination.total >= 42); - - const getRowsPage2Response = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${main_table.table_name}&perPage=${perPage}&page=2`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(getRowsPage2Response.status, 200); - const page2RO = JSON.parse(getRowsPage2Response.text); - t.truthy(page2RO.rows); - t.is(page2RO.rows.length, perPage); - t.is(page2RO.pagination.currentPage, 2); - - const page1OrderIds = page1RO.rows.map((r: any) => r.ORDER_ID); - const page2OrderIds = page2RO.rows.map((r: any) => r.ORDER_ID); - for (const id of page2OrderIds) { - t.falsy(page1OrderIds.includes(id), 'Page 2 rows should not overlap with page 1'); - } - } catch (e) { - console.error(e); - throw e; - } -}); - -// POST /table/row/:connectionId - Add row - -test.serial(`POST /table/row/:connectionId - Should add a new row to composite primary key table`, async (t) => { - try { - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const { main_table } = testTablesCompositeKeysData; - - const newRow = { - order_id: 9999, - customer_id: 9999, - order_date: '2025-01-15', - status: 'Pending', - total_amount: 150.5, - }; - - const addRowResponse = await request(app.getHttpServer()) - .post(`/table/row/${createConnectionRO.id}?tableName=${main_table.table_name}`) - .send(newRow) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(addRowResponse.status, 201); - const addRowRO = JSON.parse(addRowResponse.text); - t.truthy(addRowRO.row); - t.is(addRowRO.row.ORDER_ID, 9999); - t.is(addRowRO.row.CUSTOMER_ID, 9999); - t.is(addRowRO.row.STATUS, 'Pending'); - t.truthy(addRowRO.structure); - t.truthy(addRowRO.primaryColumns); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial( - `POST /table/row/:connectionId - Should add a new row to simple foreign key referenced table`, - async (t) => { - try { - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const { main_table, first_referenced_table } = testTablesSimpleKeysData; - - // First get an existing ORDER_ID - const getMainRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${main_table.table_name}&perPage=1`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const mainRowsRO = JSON.parse(getMainRowsResponse.text); - const existingOrderId = mainRowsRO.rows[0].ORDER_ID; - - const newOrderItem = { - order_id: existingOrderId, - product_name: 'Test Product', - quantity: 3, - price_per_unit: 25.0, - }; - - const addRowResponse = await request(app.getHttpServer()) - .post(`/table/row/${createConnectionRO.id}?tableName=${first_referenced_table.table_name}`) - .send(newOrderItem) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(addRowResponse.status, 201); - const addRowRO = JSON.parse(addRowResponse.text); - t.truthy(addRowRO.row); - t.truthy(addRowRO.row.ITEM_ID); - t.is(addRowRO.row.PRODUCT_NAME, 'Test Product'); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -// GET /table/row/:connectionId - Get single row - -test.serial(`GET /table/row/:connectionId - Should return a single row by composite primary key`, async (t) => { - try { - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const { main_table } = testTablesCompositeKeysData; - - const getRowResponse = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${main_table.table_name}&ORDER_ID=1&CUSTOMER_ID=101`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(getRowResponse.status, 200); - const getRowRO = JSON.parse(getRowResponse.text); - t.truthy(getRowRO.row); - t.is(getRowRO.row.ORDER_ID, 1); - t.is(getRowRO.row.CUSTOMER_ID, 101); - t.truthy(getRowRO.row.STATUS); - t.truthy(getRowRO.structure); - t.truthy(getRowRO.primaryColumns); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial( - `GET /table/row/:connectionId - Should return a single row by simple primary key from referenced table`, - async (t) => { - try { - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const { first_referenced_table } = testTablesSimpleKeysData; - - const getRowResponse = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${first_referenced_table.table_name}&ITEM_ID=1`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(getRowResponse.status, 200); - const getRowRO = JSON.parse(getRowResponse.text); - t.truthy(getRowRO.row); - t.truthy(getRowRO.row.ITEM_ID); - t.truthy(getRowRO.row.ORDER_ID); - t.truthy(getRowRO.structure); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -// PUT /table/row/:connectionId - Update row - -test.serial(`PUT /table/row/:connectionId - Should update a row in composite primary key table`, async (t) => { - try { - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const { main_table } = testTablesCompositeKeysData; - - const updatedValues = { - status: 'Delivered', - total_amount: 999.99, - }; - - const updateRowResponse = await request(app.getHttpServer()) - .put(`/table/row/${createConnectionRO.id}?tableName=${main_table.table_name}&ORDER_ID=1&CUSTOMER_ID=101`) - .send(updatedValues) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(updateRowResponse.status, 200); - const updateRowRO = JSON.parse(updateRowResponse.text); - t.truthy(updateRowRO.row); - t.is(updateRowRO.row.STATUS, 'Delivered'); - t.is(parseFloat(updateRowRO.row.TOTAL_AMOUNT), 999.99); - t.is(updateRowRO.row.ORDER_ID, 1); - t.is(updateRowRO.row.CUSTOMER_ID, 101); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial(`PUT /table/row/:connectionId - Should update a row in simple primary key table`, async (t) => { - try { - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const { main_table } = testTablesSimpleKeysData; - - const updatedValues = { - status: 'Cancelled', - total_amount: 555.55, - }; - - const updateRowResponse = await request(app.getHttpServer()) - .put(`/table/row/${createConnectionRO.id}?tableName=${main_table.table_name}&ORDER_ID=1`) - .send(updatedValues) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(updateRowResponse.status, 200); - const updateRowRO = JSON.parse(updateRowResponse.text); - t.truthy(updateRowRO.row); - t.is(updateRowRO.row.STATUS, 'Cancelled'); - t.is(parseFloat(updateRowRO.row.TOTAL_AMOUNT), 555.55); - } catch (e) { - console.error(e); - throw e; - } -}); - -// DELETE /table/row/:connectionId - Delete row - -test.serial(`DELETE /table/row/:connectionId - Should delete a row from composite primary key table`, async (t) => { - try { - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const { main_table } = testTablesCompositeKeysData; - - // Delete the row we added earlier (9999, 9999) - const deleteRowResponse = await request(app.getHttpServer()) - .delete(`/table/row/${createConnectionRO.id}?tableName=${main_table.table_name}&ORDER_ID=9999&CUSTOMER_ID=9999`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowResponse.status, 200); - const deleteRowRO = JSON.parse(deleteRowResponse.text); - t.truthy(deleteRowRO.row); - - // Verify the row is deleted - const getDeletedRowResponse = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${main_table.table_name}&ORDER_ID=9999&CUSTOMER_ID=9999`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(getDeletedRowResponse.status, 400); - } catch (e) { - console.error(e); - throw e; - } -}); - -// PUT /table/rows/delete/:connectionId - Bulk delete - -test.serial( - `PUT /table/rows/delete/:connectionId - Should bulk delete rows from composite primary key table`, - async (t) => { - try { - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const { main_table } = testTablesCompositeKeysData; - - // First add rows to delete - const rowsToAdd = [ - { order_id: 8881, customer_id: 8881, status: 'Pending', total_amount: 10.0 }, - { order_id: 8882, customer_id: 8882, status: 'Pending', total_amount: 20.0 }, - { order_id: 8883, customer_id: 8883, status: 'Pending', total_amount: 30.0 }, - ]; - - for (const row of rowsToAdd) { - const addResp = await request(app.getHttpServer()) - .post(`/table/row/${createConnectionRO.id}?tableName=${main_table.table_name}`) - .send(row) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(addResp.status, 201); - } - - const primaryKeysToDelete = [ - { ORDER_ID: 8881, CUSTOMER_ID: 8881 }, - { ORDER_ID: 8882, CUSTOMER_ID: 8882 }, - { ORDER_ID: 8883, CUSTOMER_ID: 8883 }, - ]; - - const bulkDeleteResponse = await request(app.getHttpServer()) - .put(`/table/rows/delete/${createConnectionRO.id}?tableName=${main_table.table_name}`) - .send(primaryKeysToDelete) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(bulkDeleteResponse.status, 200); - - // Verify rows are deleted - for (const pk of primaryKeysToDelete) { - const getResp = await request(app.getHttpServer()) - .get( - `/table/row/${createConnectionRO.id}?tableName=${main_table.table_name}&ORDER_ID=${pk.ORDER_ID}&CUSTOMER_ID=${pk.CUSTOMER_ID}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getResp.status, 400); - } - } catch (e) { - console.error(e); - throw e; - } - }, -); - -// PUT /table/rows/update/:connectionId - Bulk update - -test.serial( - `PUT /table/rows/update/:connectionId - Should bulk update rows in composite primary key table`, - async (t) => { - try { - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const { main_table } = testTablesCompositeKeysData; - - const bulkUpdateBody = { - primaryKeys: [ - { ORDER_ID: 2, CUSTOMER_ID: 102 }, - { ORDER_ID: 3, CUSTOMER_ID: 103 }, - ], - newValues: { - status: 'Cancelled', - }, - }; - - const bulkUpdateResponse = await request(app.getHttpServer()) - .put(`/table/rows/update/${createConnectionRO.id}?tableName=${main_table.table_name}`) - .send(bulkUpdateBody) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(bulkUpdateResponse.status, 200); - - // Verify rows are updated - const getRow1Response = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${main_table.table_name}&ORDER_ID=2&CUSTOMER_ID=102`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(getRow1Response.status, 200); - const row1RO = JSON.parse(getRow1Response.text); - t.is(row1RO.row.STATUS, 'Cancelled'); - - const getRow2Response = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${main_table.table_name}&ORDER_ID=3&CUSTOMER_ID=103`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(getRow2Response.status, 200); - const row2RO = JSON.parse(getRow2Response.text); - t.is(row2RO.row.STATUS, 'Cancelled'); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -// POST /table/rows/find/:connectionId - Rows with body filters - -test.serial(`POST /table/rows/find/:connectionId - Should return filtered rows for composite key table`, async (t) => { - try { - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const { main_table } = testTablesCompositeKeysData; - - const filterBody = { - filters: { - ORDER_ID: { eq: 1 }, - }, - }; - - const findRowsResponse = await request(app.getHttpServer()) - .post(`/table/rows/find/${createConnectionRO.id}?tableName=${main_table.table_name}`) - .send(filterBody) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(findRowsResponse.status, 200); - const findRowsRO = JSON.parse(findRowsResponse.text); - t.truthy(findRowsRO.rows); - t.is(findRowsRO.rows.length, 1); - t.is(findRowsRO.rows[0].ORDER_ID, 1); - t.is(findRowsRO.rows[0].CUSTOMER_ID, 101); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial( - `POST /table/rows/find/:connectionId - Should return rows filtered by status for composite key table`, - async (t) => { - try { - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const { main_table } = testTablesCompositeKeysData; - - const filterBody = { - filters: { - STATUS: { eq: 'Cancelled' }, - }, - }; - - const findRowsResponse = await request(app.getHttpServer()) - .post(`/table/rows/find/${createConnectionRO.id}?tableName=${main_table.table_name}`) - .send(filterBody) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(findRowsResponse.status, 200); - const findRowsRO = JSON.parse(findRowsResponse.text); - t.truthy(findRowsRO.rows); - for (const row of findRowsRO.rows) { - t.is(row.STATUS, 'Cancelled'); - } - } catch (e) { - console.error(e); - throw e; - } - }, -); - -// GET /connection/tables/:connectionId - List tables - -test.serial(`GET /connection/tables/:connectionId - Should list all complex test tables in connection`, async (t) => { - try { - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const getTablesResponse = await request(app.getHttpServer()) - .get(`/connection/tables/${createConnectionRO.id}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(getTablesResponse.status, 200); - const tablesRO = JSON.parse(getTablesResponse.text); - t.truthy(Array.isArray(tablesRO)); - - const tableNames = tablesRO.map((t: any) => t.table); - - const { main_table: compositeMain } = testTablesCompositeKeysData; - const { main_table: simpleMain } = testTablesSimpleKeysData; - - t.truthy(tableNames.includes(compositeMain.table_name), `Tables should include ${compositeMain.table_name}`); - t.truthy(tableNames.includes(simpleMain.table_name), `Tables should include ${simpleMain.table_name}`); - } catch (e) { - console.error(e); - throw e; - } -}); - -// GET /table/rows/:connectionId - Response structure validation - -test.serial( - `GET /table/rows/:connectionId - Should return correct response structure with primaryColumns and pagination for composite key table`, - async (t) => { - try { - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const { main_table } = testTablesCompositeKeysData; - - const getRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${main_table.table_name}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(getRowsResponse.status, 200); - const rowsRO = JSON.parse(getRowsResponse.text); - - // Validate response has required fields - t.truthy(rowsRO.rows); - t.truthy(rowsRO.primaryColumns); - t.truthy(rowsRO.pagination); - - // Validate primaryColumns includes both composite key columns - const primaryColumnNames = rowsRO.primaryColumns.map((col: any) => col.column_name); - t.truthy(primaryColumnNames.includes('ORDER_ID')); - t.truthy(primaryColumnNames.includes('CUSTOMER_ID')); - t.is(rowsRO.primaryColumns.length, 2); - - // Validate row data - t.truthy(rowsRO.rows.length > 0); - const firstRow = rowsRO.rows[0]; - t.truthy('ORDER_ID' in firstRow); - t.truthy('CUSTOMER_ID' in firstRow); - t.truthy('STATUS' in firstRow); - t.truthy('TOTAL_AMOUNT' in firstRow); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -// Cascade delete behavior - -test.serial( - `DELETE /table/row/:connectionId - Should cascade delete referenced rows when deleting from main composite key table`, - async (t) => { - try { - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const { main_table, first_referenced_table } = testTablesCompositeKeysData; - - // Add a new row to main table - const newMainRow = { - order_id: 7777, - customer_id: 7777, - status: 'Pending', - total_amount: 100.0, - }; - const addMainResp = await request(app.getHttpServer()) - .post(`/table/row/${createConnectionRO.id}?tableName=${main_table.table_name}`) - .send(newMainRow) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(addMainResp.status, 201); - - // Add a referenced row - const newReferencedRow = { - order_id: 7777, - customer_id: 7777, - product_name: 'Test Product', - quantity: 5, - price_per_unit: 20.0, - }; - const addRefResp = await request(app.getHttpServer()) - .post(`/table/row/${createConnectionRO.id}?tableName=${first_referenced_table.table_name}`) - .send(newReferencedRow) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(addRefResp.status, 201); - const addedRefRow = JSON.parse(addRefResp.text); - const refRowItemId = addedRefRow.row.ITEM_ID; - - // Delete the main row (should cascade) - const deleteResp = await request(app.getHttpServer()) - .delete(`/table/row/${createConnectionRO.id}?tableName=${main_table.table_name}&ORDER_ID=7777&CUSTOMER_ID=7777`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(deleteResp.status, 200); - - // Verify referenced row is also deleted (CASCADE) - const getRefResp = await request(app.getHttpServer()) - .get( - `/table/row/${createConnectionRO.id}?tableName=${first_referenced_table.table_name}&ITEM_ID=${refRowItemId}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getRefResp.status, 400); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -// Error cases - -test.serial(`GET /table/rows/:connectionId - Should return error when tableName is missing`, async (t) => { - try { - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const getRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(getRowsResponse.status, 400); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial( - `GET /table/row/:connectionId - Should return error when primary key is incomplete for composite key table`, - async (t) => { - try { - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const { main_table } = testTablesCompositeKeysData; - - // Only provide one part of composite key - const getRowResponse = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${main_table.table_name}&ORDER_ID=1`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - // Should fail because composite key requires both ORDER_ID and CUSTOMER_ID - t.truthy(getRowResponse.status >= 400); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `POST /table/row/:connectionId - Should return error when adding row with duplicate composite primary key`, - async (t) => { - try { - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const { main_table } = testTablesCompositeKeysData; - - // Try to add a row with existing composite key (1, 101) - const duplicateRow = { - order_id: 1, - customer_id: 101, - status: 'Duplicate', - total_amount: 0, - }; - - const addRowResponse = await request(app.getHttpServer()) - .post(`/table/row/${createConnectionRO.id}?tableName=${main_table.table_name}`) - .send(duplicateRow) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.truthy(addRowResponse.status >= 400); - } catch (e) { - console.error(e); - throw e; - } - }, -); diff --git a/backend/test/ava-tests/non-saas-tests/non-saas-table-ibmdb2-e2e.test.ts b/backend/test/ava-tests/non-saas-tests/non-saas-table-ibmdb2-e2e.test.ts deleted file mode 100644 index 3dcc81792..000000000 --- a/backend/test/ava-tests/non-saas-tests/non-saas-table-ibmdb2-e2e.test.ts +++ /dev/null @@ -1,3791 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -/* eslint-disable security/detect-object-injection */ - -import os from 'node:os'; -import { faker } from '@faker-js/faker'; -import { INestApplication, ValidationPipe } from '@nestjs/common'; -import { Test } from '@nestjs/testing'; -import test from 'ava'; -import { ValidationError } from 'class-validator'; -import cookieParser from 'cookie-parser'; -import fs from 'fs'; -import path, { join } from 'path'; -import request from 'supertest'; -import { fileURLToPath } from 'url'; -import { ApplicationModule } from '../../../src/app.module.js'; -import { WinstonLogger } from '../../../src/entities/logging/winston-logger.js'; -import { LogOperationTypeEnum } from '../../../src/enums/log-operation-type.enum.js'; -import { QueryOrderingEnum } from '../../../src/enums/query-ordering.enum.js'; -import { AllExceptionsFilter } from '../../../src/exceptions/all-exceptions.filter.js'; -import { ValidationException } from '../../../src/exceptions/custom-exceptions/validation-exception.js'; -import { Messages } from '../../../src/exceptions/text/messages.js'; -import { Cacher } from '../../../src/helpers/cache/cacher.js'; -import { Constants } from '../../../src/helpers/constants/constants.js'; -import { DatabaseModule } from '../../../src/shared/database/database.module.js'; -import { DatabaseService } from '../../../src/shared/database/database.service.js'; -import { MockFactory } from '../../mock.factory.js'; -import { createTestTable } from '../../utils/create-test-table.js'; -import { getTestData } from '../../utils/get-test-data.js'; -import { - createInitialTestUser, - registerUserAndReturnUserInfo, -} from '../../utils/register-user-and-return-user-info.js'; -import { setSaasEnvVariable } from '../../utils/set-saas-env-variable.js'; -import { TestUtils } from '../../utils/test.utils.js'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -const mockFactory = new MockFactory(); -let app: INestApplication; -let _testUtils: TestUtils; -const testSearchedUserName = 'Vasia'; -const testTables: Array = []; -let currentTest; - -test.before(async () => { - setSaasEnvVariable(); - const moduleFixture = await Test.createTestingModule({ - imports: [ApplicationModule, DatabaseModule], - providers: [DatabaseService, TestUtils], - }).compile(); - app = moduleFixture.createNestApplication(); - _testUtils = moduleFixture.get(TestUtils); - - app.use(cookieParser()); - app.useGlobalFilters(new AllExceptionsFilter(app.get(WinstonLogger))); - app.useGlobalPipes( - new ValidationPipe({ - exceptionFactory(validationErrors: ValidationError[] = []) { - return new ValidationException(validationErrors); - }, - }), - ); - await app.init(); - await createInitialTestUser(app); - app.getHttpServer().listen(0); -}); - -test.after(async () => { - try { - await Cacher.clearAllCache(); - await app.close(); - } catch (e) { - console.error('After tests error ' + e); - } -}); - -currentTest = 'GET /connection/tables/:slug'; - -test.serial(`${currentTest} should return list of tables in connection`, async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const getTablesResponse = await request(app.getHttpServer()) - .get(`/connection/tables/${createConnectionRO.id}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTablesResponse.status, 200); - const getTablesRO = JSON.parse(getTablesResponse.text); - - t.is(typeof getTablesRO, 'object'); - t.is(getTablesRO.length > 0, true); - - const testTableIndex = getTablesRO.findIndex((t) => t.table === testTableName); - - t.is(Object.hasOwn(getTablesRO[testTableIndex], 'table'), true); - t.is(Object.hasOwn(getTablesRO[testTableIndex], 'permissions'), true); - t.is(typeof getTablesRO[testTableIndex].permissions, 'object'); - t.is(Object.keys(getTablesRO[testTableIndex].permissions).length, 7); - t.is(getTablesRO[testTableIndex].table, testTableName); - t.is(getTablesRO[testTableIndex].permissions.visibility, true); - t.is(getTablesRO[testTableIndex].permissions.readonly, false); - t.is(getTablesRO[testTableIndex].permissions.add, true); - t.is(getTablesRO[testTableIndex].permissions.delete, true); - t.is(getTablesRO[testTableIndex].permissions.edit, true); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial(`${currentTest} should throw an error when connectionId not passed in request`, async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - createConnectionRO.id = ''; - const getTablesResponse = await request(app.getHttpServer()) - .get(`/connection/tables/${createConnectionRO.id}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTablesResponse.status, 404); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial(`${currentTest} should throw an error when connection id is incorrect`, async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - - t.is(createConnectionResponse.status, 201); - createConnectionRO.id = faker.string.uuid(); - const getTablesResponse = await request(app.getHttpServer()) - .get(`/connection/tables/${createConnectionRO.id}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTablesResponse.status, 400); - const { message } = JSON.parse(getTablesResponse.text); - t.is(message, Messages.CONNECTION_NOT_FOUND); - } catch (e) { - console.error(e); - throw e; - } -}); - -currentTest = 'GET /table/rows/:slug'; - -test.serial(`${currentTest} should return rows of selected table without search and without pagination`, async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testTableSecondColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, Constants.DEFAULT_PAGINATION.perPage); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(Object.hasOwn(getTableRowsRO.rows[0], 'ID'), true); - t.is(Object.hasOwn(getTableRowsRO.rows[1], testTableColumnName), true); - t.is(Object.hasOwn(getTableRowsRO.rows[10], testTableSecondColumnName), true); - t.is(Object.hasOwn(getTableRowsRO.rows[15], 'CREATED_AT'), true); - t.is(Object.hasOwn(getTableRowsRO.rows[19], 'UPDATED_AT'), true); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial(`${currentTest} should return rows of selected table with search and without pagination`, async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testTableSecondColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - ['ID'], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - undefined, - undefined, - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createTableSettingsResponse.status, 201); - - const searchedDescription = '25'; - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&search=${searchedDescription}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(getTableRowsResponse.status, 200); - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 1); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - t.is(getTableRowsRO.rows[0].ID, parseInt(searchedDescription, 10)); - t.is(Object.hasOwn(getTableRowsRO.rows[0], testTableColumnName), true); - t.is(Object.hasOwn(getTableRowsRO.rows[0], testTableSecondColumnName), true); - t.is(Object.hasOwn(getTableRowsRO.rows[0], 'CREATED_AT'), true); - t.is(Object.hasOwn(getTableRowsRO.rows[0], 'UPDATED_AT'), true); - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial(`${currentTest} should return page of all rows with pagination page=1, perPage=2`, async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - ['ID'], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - undefined, - undefined, - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=2`) - .set('Content-Type', 'application/json') - .set('Cookie', firstUserToken) - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(Object.hasOwn(getTableRowsRO.rows[0], 'ID'), true); - t.is(Object.hasOwn(getTableRowsRO.rows[1], testTableColumnName), true); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - t.is(getTableRowsRO.primaryColumns[0].column_name, 'ID'); - t.is(getTableRowsRO.primaryColumns[0].data_type, 'INTEGER'); - - t.is(getTableRowsRO.pagination.total, 42); - t.is(getTableRowsRO.pagination.lastPage, 21); - t.is(getTableRowsRO.pagination.perPage, 2); - t.is(getTableRowsRO.pagination.currentPage, 1); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial(`${currentTest} should return page of all rows with pagination page=3, perPage=2`, async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - ['ID'], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - undefined, - undefined, - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=3&perPage=2`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(Object.hasOwn(getTableRowsRO.rows[0], 'ID'), true); - t.is(Object.hasOwn(getTableRowsRO.rows[1], testTableColumnName), true); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - t.is(getTableRowsRO.primaryColumns[0].column_name, 'ID'); - t.is(getTableRowsRO.primaryColumns[0].data_type, 'INTEGER'); - - t.is(getTableRowsRO.pagination.total, 42); - t.is(getTableRowsRO.pagination.lastPage, 21); - t.is(getTableRowsRO.pagination.perPage, 2); - t.is(getTableRowsRO.pagination.currentPage, 3); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial( - `${currentTest} with search, with pagination, without sorting -should return all found rows with pagination page=1 perPage=2`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - undefined, - undefined, - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - t.is(getTableRowsRO.rows[0][testTableColumnName], testSearchedUserName); - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - t.is(getTableRowsRO.primaryColumns[0].column_name, 'ID'); - t.is(getTableRowsRO.primaryColumns[0].data_type, 'INTEGER'); - - //todo: rework pagination - // t.is(getTableRowsRO.pagination.total, 3); - // t.is(getTableRowsRO.pagination.lastPage, 2); - // t.is(getTableRowsRO.pagination.perPage, 2); - // t.is(getTableRowsRO.pagination.currentPage, 1); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination, without sorting -should return all found rows with pagination page=1 perPage=3`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - undefined, - undefined, - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - t.is(getTableRowsRO.rows[0][testTableColumnName], testSearchedUserName); - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - t.is(getTableRowsRO.primaryColumns[0].column_name, 'ID'); - t.is(getTableRowsRO.primaryColumns[0].data_type, 'INTEGER'); - - //todo: rework pagination - // t.is(getTableRowsRO.pagination.total, 3); - // t.is(getTableRowsRO.pagination.lastPage, 2); - // t.is(getTableRowsRO.pagination.perPage, 2); - // t.is(getTableRowsRO.pagination.currentPage, 1); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} without search and without pagination and with sorting -should return all found rows with sorting ids by DESC`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 42, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - t.is(getTableRowsResponse.status, 200); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 42); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 42); - t.is(getTableRowsRO.rows[1].ID, 41); - t.is(getTableRowsRO.rows[41].ID, 1); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} without search and without pagination and with sorting -should return all found rows with sorting ids by ASC`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 42, - QueryOrderingEnum.ASC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 42); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 1); - t.is(getTableRowsRO.rows[1].ID, 2); - t.is(getTableRowsRO.rows[41].ID, 42); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} without search and with pagination and with sorting -should return all found rows with sorting ports by DESC and with pagination page=1, perPage=2`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=2`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 42); - t.is(getTableRowsRO.rows[1].ID, 41); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} should return all found rows with sorting ports by ASC and with pagination page=1, perPage=2`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.ASC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=2`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 1); - t.is(getTableRowsRO.rows[1].ID, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} should return all found rows with sorting ports by DESC and with pagination page=2, perPage=3`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=2&perPage=3`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 3); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 39); - t.is(getTableRowsRO.rows[1].ID, 38); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination and with sorting -should return all found rows with search, pagination: page=1, perPage=2 and DESC sorting`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=2&search=${testSearchedUserName}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 38); - t.is(getTableRowsRO.rows[1].ID, 22); - t.is(getTableRowsRO.pagination.currentPage, 1); - t.is(getTableRowsRO.pagination.perPage, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination and with sorting -should return all found rows with search, pagination: page=2, perPage=2 and DESC sorting`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=2&perPage=2&search=${testSearchedUserName}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 1); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 1); - t.is(getTableRowsRO.pagination.currentPage, 2); - t.is(getTableRowsRO.pagination.perPage, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination and with sorting -should return all found rows with search, pagination: page=1, perPage=2 and ASC sorting`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.ASC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=2&search=${testSearchedUserName}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 1); - t.is(getTableRowsRO.rows[1].ID, 22); - t.is(getTableRowsRO.pagination.currentPage, 1); - t.is(getTableRowsRO.pagination.perPage, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination and with sorting -should return all found rows with search, pagination: page=2, perPage=2 and ASC sorting`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.ASC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=2&perPage=2&search=${testSearchedUserName}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 1); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 38); - t.is(getTableRowsRO.pagination.currentPage, 2); - t.is(getTableRowsRO.pagination.perPage, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination, with sorting and with filtering -should return all found rows with search, pagination: page=1, perPage=2 and DESC sorting and filtering`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = 'ID'; - const fieldvalue = '45'; - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2&f_${fieldname}__lt=${fieldvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - - t.is(getTableRowsRO.rows[0][testTableColumnName], testSearchedUserName); - t.is(getTableRowsRO.rows[0].ID, 38); - t.is(getTableRowsRO.rows[1][testTableColumnName], testSearchedUserName); - t.is(getTableRowsRO.rows[1].ID, 22); - - t.is(getTableRowsRO.pagination.currentPage, 1); - t.is(getTableRowsRO.pagination.perPage, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination, with sorting and with filtering -should return all found rows with search, pagination: page=1, perPage=10 and DESC sorting and filtering'`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = 'ID'; - const fieldvalue = '41'; - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=10&f_${fieldname}__lt=${fieldvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 3); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - - t.is(getTableRowsRO.rows[0][testTableColumnName], testSearchedUserName); - t.is(getTableRowsRO.rows[0].ID, 38); - t.is(getTableRowsRO.rows[1][testTableColumnName], testSearchedUserName); - t.is(getTableRowsRO.rows[1].ID, 22); - t.is(getTableRowsRO.rows[2][testTableColumnName], testSearchedUserName); - t.is(getTableRowsRO.rows[2].ID, 1); - - t.is(getTableRowsRO.pagination.currentPage, 1); - t.is(getTableRowsRO.pagination.perPage, 10); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination, with sorting and with filtering -should return all found rows with search, pagination: page=2, perPage=2 and DESC sorting and filtering`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = 'ID'; - const fieldvalue = '41'; - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&search=${testSearchedUserName}&page=2&perPage=2&f_${fieldname}__lt=${fieldvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 1); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - - t.is(getTableRowsRO.rows[0][testTableColumnName], testSearchedUserName); - t.is(getTableRowsRO.rows[0].ID, 1); - - t.is(getTableRowsRO.pagination.currentPage, 2); - t.is(getTableRowsRO.pagination.perPage, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination, with sorting and with filtering -should return all found rows with search, pagination: page=1, perPage=2 and DESC sorting and with multi filtering`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = 'ID'; - const fieldGtvalue = '25'; - const fieldLtvalue = '40'; - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2&f_${fieldname}__lt=${fieldLtvalue}&f_${fieldname}__gt=${fieldGtvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 1); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - - t.is(getTableRowsRO.rows[0].ID, 38); - t.is(getTableRowsRO.rows[0][testTableColumnName], testSearchedUserName); - - t.is(getTableRowsRO.pagination.currentPage, 1); - t.is(getTableRowsRO.pagination.perPage, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial(`${currentTest} should throw an exception when connection id is not passed in request`, async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = 'ID'; - const fieldGtvalue = '25'; - const fieldLtvalue = '40'; - createConnectionRO.id = ''; - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2&f_${fieldname}__lt=${fieldLtvalue}&f_${fieldname}__gt=${fieldGtvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 404); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial(`${currentTest} should throw an exception when connection id passed in request is incorrect`, async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = 'ID'; - const fieldGtvalue = '25'; - const fieldLtvalue = '40'; - - createConnectionRO.id = faker.string.uuid(); - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2&f_${fieldname}__lt=${fieldLtvalue}&f_${fieldname}__gt=${fieldGtvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 403); - - // const { message } = JSON.parse(getTableRowsResponse.text); - - // t.is(message, Messages.CONNECTION_NOT_FOUND); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial(`${currentTest} should throw an exception when table name passed in request is incorrect`, async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = 'ID'; - const fieldGtvalue = '25'; - const fieldLtvalue = '40'; - - const fakeTableName = `${faker.lorem.words(1)}_${faker.string.uuid()}`; - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${fakeTableName}&search=${testSearchedUserName}&page=1&perPage=2&f_${fieldname}__lt=${fieldLtvalue}&f_${fieldname}__gt=${fieldGtvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 400); - - const { message } = JSON.parse(getTableRowsResponse.text); - - t.is(message, Messages.TABLE_NOT_FOUND); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial( - `${currentTest} should return an array with searched fields when filtered name passed in request is incorrect`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = faker.lorem.words(1); - const fieldGtvalue = '25'; - const fieldLtvalue = '40'; - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2&f_${fieldname}__lt=${fieldLtvalue}&f_${fieldname}__gt=${fieldGtvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTablesRO = JSON.parse(getTableRowsResponse.text); - t.is(getTablesRO.rows.length, 2); - t.is(getTablesRO.rows[0][testTableColumnName], testSearchedUserName); - t.is(getTablesRO.rows[1][testTableColumnName], testSearchedUserName); - t.is(Object.hasOwn(getTablesRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTablesRO, 'pagination'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -currentTest = 'GET /table/structure/:slug'; -test.serial(`${currentTest} should return table structure`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const getTableStructure = await request(app.getHttpServer()) - .get(`/table/structure/${createConnectionRO.id}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableStructure.status, 200); - const getTableStructureRO = JSON.parse(getTableStructure.text); - - t.is(typeof getTableStructureRO, 'object'); - t.is(typeof getTableStructureRO.structure, 'object'); - t.is(getTableStructureRO.structure.length, 5); - - for (const element of getTableStructureRO.structure) { - t.is(Object.hasOwn(element, 'column_name'), true); - t.is(Object.hasOwn(element, 'column_default'), true); - t.is(Object.hasOwn(element, 'data_type'), true); - t.is(Object.hasOwn(element, 'isExcluded'), true); - t.is(Object.hasOwn(element, 'isSearched'), true); - } - - t.is(Object.hasOwn(getTableStructureRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableStructureRO, 'foreignKeys'), true); - - for (const element of getTableStructureRO.primaryColumns) { - t.is(Object.hasOwn(element, 'column_name'), true); - t.is(Object.hasOwn(element, 'data_type'), true); - } - - for (const element of getTableStructureRO.foreignKeys) { - t.is(Object.hasOwn(element, 'referenced_column_name'), true); - t.is(Object.hasOwn(element, 'referenced_table_name'), true); - t.is(Object.hasOwn(element, 'constraint_name'), true); - t.is(Object.hasOwn(element, 'column_name'), true); - } -}); - -test.serial(`${currentTest} should throw an exception whe connection id not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - createConnectionRO.id = ''; - const getTableStructure = await request(app.getHttpServer()) - .get(`/table/structure/${createConnectionRO.id}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableStructure.status, 404); -}); - -test.serial(`${currentTest} should throw an exception whe connection id passed in request id incorrect`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - createConnectionRO.id = faker.string.uuid(); - const getTableStructure = await request(app.getHttpServer()) - .get(`/table/structure/${createConnectionRO.id}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableStructure.status, 403); - const { message } = JSON.parse(getTableStructure.text); - t.is(message, Messages.DONT_HAVE_PERMISSIONS); -}); - -test.serial(`${currentTest}should throw an exception when tableName not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - const tableName = ''; - const getTableStructure = await request(app.getHttpServer()) - .get(`/table/structure/${createConnectionRO.id}?tableName=${tableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableStructure.status, 400); - const { message } = JSON.parse(getTableStructure.text); - t.is(message, Messages.TABLE_NAME_MISSING); -}); - -test.serial(`${currentTest} should throw an exception when tableName passed in request is incorrect`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - const tableName = faker.lorem.words(1); - const getTableStructure = await request(app.getHttpServer()) - .get(`/table/structure/${createConnectionRO.id}?tableName=${tableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableStructure.status, 400); - const { message } = JSON.parse(getTableStructure.text); - t.is(message, Messages.TABLE_NOT_FOUND); -}); - -currentTest = 'POST /table/row/:slug'; - -test.serial(`${currentTest} should add row in table and return result`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const addRowInTableResponse = await request(app.getHttpServer()) - .post(`/table/row/${createConnectionRO.id}?tableName=${testTableName}`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const addRowInTableRO = JSON.parse(addRowInTableResponse.text); - console.log('🚀 ~ test ~ addRowInTableRO:', addRowInTableRO); - t.is(addRowInTableResponse.status, 201); - - t.is(Object.hasOwn(addRowInTableRO, 'row'), true); - t.is(Object.hasOwn(addRowInTableRO, 'structure'), true); - t.is(Object.hasOwn(addRowInTableRO, 'foreignKeys'), true); - t.is(Object.hasOwn(addRowInTableRO, 'primaryColumns'), true); - t.is(Object.hasOwn(addRowInTableRO, 'readonly_fields'), true); - t.is(addRowInTableRO.row[testTableColumnName], row[testTableColumnName]); - t.is(addRowInTableRO.row[testTableSecondColumnName], row[testTableSecondColumnName]); - - //checking that the line was added - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 43); - t.is(rows[42][testTableColumnName], row[testTableColumnName]); - t.is(rows[42][testTableSecondColumnName], row[testTableSecondColumnName]); - t.is(rows[42].ID, rows[41].ID + 1); - - // check that rows adding was logged - - const getLogsResponse = await request(app.getHttpServer()) - .get(`/logs/${createConnectionRO.id}?page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(getLogsResponse.status, 200); - const getLogsRO = JSON.parse(getLogsResponse.text); - t.is(Object.hasOwn(getLogsRO, 'logs'), true); - t.is(Object.hasOwn(getLogsRO, 'pagination'), true); - t.is(getLogsRO.logs.length > 0, true); - const addRowLogIndex = getLogsRO.logs.findIndex((log) => log.operationType === 'addRow'); - t.is(Object.hasOwn(getLogsRO.logs[addRowLogIndex], 'affected_primary_key'), true); - t.is(typeof getLogsRO.logs[addRowLogIndex].affected_primary_key, 'object'); - t.is(Object.hasOwn(getLogsRO.logs[addRowLogIndex].affected_primary_key, 'ID'), true); - t.is(getLogsRO.logs[addRowLogIndex].affected_primary_key.ID, 43); -}); - -test.serial(`${currentTest} should throw an exception when connection id is not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - const fakeConnectionId = ''; - const addRowInTableResponse = await request(app.getHttpServer()) - .post(`/table/row/${fakeConnectionId}?tableName=${testTableName}`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(addRowInTableResponse.status, 404); - - //checking that the line wasn't added - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); -}); - -test.serial(`${currentTest} should throw an exception when table name is not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const addRowInTableResponse = await request(app.getHttpServer()) - .post(`/table/row/${createConnectionRO.id}?tableName=`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(addRowInTableResponse.status, 400); - const { message } = JSON.parse(addRowInTableResponse.text); - - t.is(message, Messages.TABLE_NAME_MISSING); - - //checking that the line wasn't added - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); -}); - -test.serial(`${currentTest} should throw an exception when row is not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const addRowInTableResponse = await request(app.getHttpServer()) - .post(`/table/row/${createConnectionRO.id}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(addRowInTableResponse.status, 400); - const { message } = JSON.parse(addRowInTableResponse.text); - - t.is(message, Messages.PARAMETER_MISSING); - - //checking that the line wasn't added - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); -}); - -test.serial(`${currentTest} should throw an exception when table name passed in request is incorrect`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const fakeTableName = `${faker.lorem.words(1)}_${faker.string.uuid()}`; - const addRowInTableResponse = await request(app.getHttpServer()) - .post(`/table/row/${createConnectionRO.id}?tableName=${fakeTableName}`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(addRowInTableResponse.status, 400); - const { message } = JSON.parse(addRowInTableResponse.text); - - t.is(message, Messages.TABLE_NOT_FOUND); - - //checking that the line wasn't added - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); -}); - -currentTest = 'PUT /table/row/:slug'; - -test.serial(`${currentTest} should update row in table and return result`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&ID=1`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const updateRowInTableRO = JSON.parse(updateRowInTableResponse.text); - - t.is(updateRowInTableResponse.status, 200); - t.is(Object.hasOwn(updateRowInTableRO, 'row'), true); - t.is(Object.hasOwn(updateRowInTableRO, 'structure'), true); - t.is(Object.hasOwn(updateRowInTableRO, 'foreignKeys'), true); - t.is(Object.hasOwn(updateRowInTableRO, 'primaryColumns'), true); - t.is(Object.hasOwn(updateRowInTableRO, 'readonly_fields'), true); - t.is(updateRowInTableRO.row[testTableColumnName], row[testTableColumnName]); - t.is(updateRowInTableRO.row[testTableSecondColumnName], row[testTableSecondColumnName]); - - //checking that the line was updated - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - const updateRowIndex = rows.map((row) => row.ID).indexOf(1); - t.is(rows.length, 42); - t.is(rows[updateRowIndex][testTableColumnName], row[testTableColumnName]); - t.is(rows[updateRowIndex][testTableSecondColumnName], row[testTableSecondColumnName]); -}); - -test.serial(`${currentTest} should throw an exception when connection id not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - createConnectionRO.id = ''; - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&ID=1`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(updateRowInTableResponse.status, 404); -}); - -test.serial(`${currentTest} should throw an exception when connection id passed in request is incorrect`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - - t.is(createConnectionResponse.status, 201); - - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - createConnectionRO.id = faker.string.uuid(); - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&ID=1`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(updateRowInTableResponse.status, 403); - const { message } = JSON.parse(updateRowInTableResponse.text); - t.is(message, Messages.DONT_HAVE_PERMISSIONS); -}); - -test.serial(`${currentTest} should throw an exception when tableName not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - createConnectionRO.id = faker.string.uuid(); - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${createConnectionRO.id}?tableName=&ID=1`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(updateRowInTableResponse.status, 400); - const { message } = JSON.parse(updateRowInTableResponse.text); - t.is(message, Messages.TABLE_NAME_MISSING); -}); - -test.serial(`${currentTest} should throw an exception when tableName passed in request is incorrect`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const fakeTableName = faker.string.uuid(); - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${createConnectionRO.id}?tableName=${fakeTableName}&ID=1`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(updateRowInTableResponse.status, 400); - const { message } = JSON.parse(updateRowInTableResponse.text); - t.is(message, Messages.TABLE_NOT_FOUND); -}); - -test.serial(`${currentTest} should throw an exception when primary key not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(updateRowInTableResponse.status, 400); - const { message } = JSON.parse(updateRowInTableResponse.text); - t.is(message, Messages.PRIMARY_KEY_INVALID); -}); - -test.serial( - `${currentTest} should throw an exception when primary key passed in request has incorrect field name`, - async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&IncorrectField=1`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(updateRowInTableResponse.status, 400); - const { message } = JSON.parse(updateRowInTableResponse.text); - t.is(message, Messages.PRIMARY_KEY_INVALID); - }, -); - -test.serial( - `${currentTest} should throw an exception when primary key passed in request has incorrect field value`, - async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&ID=100000000`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(updateRowInTableResponse.status, 400); - const { message } = JSON.parse(updateRowInTableResponse.text); - t.is(message, Messages.ROW_PRIMARY_KEY_NOT_FOUND); - }, -); - -currentTest = 'DELETE /table/row/:slug'; - -test.serial(`${currentTest} should delete row in table and return result`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForDeletion = 1; - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&ID=${idForDeletion}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowInTableResponse.status, 200); - const deleteRowInTableRO = JSON.parse(deleteRowInTableResponse.text); - - t.is(Object.hasOwn(deleteRowInTableRO, 'row'), true); - - //checking that the line was deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 41); - const deletedRowIndex = rows.map((row: Record) => row.ID).indexOf(idForDeletion); - t.is(deletedRowIndex < 0, true); -}); - -test.serial(`${currentTest} should throw an exception when connection id not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForDeletion = 1; - const connectionId = ''; - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${connectionId}?tableName=${testTableName}&ID=${idForDeletion}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowInTableResponse.status, 404); - - //checking that the line wasn't deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); - const deletedRowIndex = rows.map((row: Record) => row.ID).indexOf(idForDeletion); - t.is(deletedRowIndex < 0, false); -}); - -test.serial(`${currentTest} should throw an exception when connection id passed in request is incorrect`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForDeletion = 1; - const connectionId = faker.string.uuid(); - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${connectionId}?tableName=${testTableName}&ID=${idForDeletion}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowInTableResponse.status, 403); - const { message } = JSON.parse(deleteRowInTableResponse.text); - t.is(message, Messages.DONT_HAVE_PERMISSIONS); - - //checking that the line wasn't deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); - const deletedRowIndex = rows.map((row: Record) => row.ID).indexOf(idForDeletion); - t.is(deletedRowIndex < 0, false); -}); - -test.serial(`${currentTest} should throw an exception when tableName not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForDeletion = 1; - const fakeTableName = ''; - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${createConnectionRO.id}?tableName=${fakeTableName}&ID=${idForDeletion}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowInTableResponse.status, 400); - const { message } = JSON.parse(deleteRowInTableResponse.text); - t.is(message, Messages.TABLE_NAME_MISSING); - - //checking that the line wasn't deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); - const deletedRowIndex = rows.map((row: Record) => row.ID).indexOf(idForDeletion); - t.is(deletedRowIndex < 0, false); -}); - -test.serial(`${currentTest} should throw an exception when tableName passed in request is incorrect`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForDeletion = 1; - const fakeTableName = `${faker.lorem.words(1)}_${faker.string.uuid()}`; - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${createConnectionRO.id}?tableName=${fakeTableName}&ID=${idForDeletion}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowInTableResponse.status, 400); - const { message } = JSON.parse(deleteRowInTableResponse.text); - t.is(message, Messages.TABLE_NOT_FOUND); - - //checking that the line wasn't deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); - const deletedRowIndex = rows.map((row: Record) => row.ID).indexOf(idForDeletion); - t.is(deletedRowIndex < 0, false); -}); - -test.serial(`${currentTest} should throw an exception when primary key not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForDeletion = 1; - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowInTableResponse.status, 400); - const { message } = JSON.parse(deleteRowInTableResponse.text); - t.is(message, Messages.PRIMARY_KEY_INVALID); - - //checking that the line wasn't deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); - const deletedRowIndex = rows.map((row: Record) => row.ID).indexOf(idForDeletion); - t.is(deletedRowIndex < 0, false); -}); - -test.serial( - `${currentTest} should throw an exception when primary key passed in request has incorrect field name`, - async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForDeletion = 1; - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&fakePKey=1`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowInTableResponse.status, 400); - const { message } = JSON.parse(deleteRowInTableResponse.text); - t.is(message, Messages.PRIMARY_KEY_INVALID); - - //checking that the line wasn't deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); - const deletedRowIndex = rows.map((row: Record) => row.ID).indexOf(idForDeletion); - t.is(deletedRowIndex < 0, false); - }, -); - -test.serial( - `${currentTest} should throw an exception when primary key passed in request has incorrect field value`, - async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&ID=100000`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const deleteRowInTableRO = JSON.parse(deleteRowInTableResponse.text); - t.is(deleteRowInTableResponse.status, 400); - t.is(deleteRowInTableRO.message, Messages.ROW_PRIMARY_KEY_NOT_FOUND); - }, -); - -currentTest = 'GET /table/row/:slug'; - -test.serial(`${currentTest} found row`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForSearch = 1; - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&ID=${idForSearch}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 200); - const foundRowInTableRO = JSON.parse(foundRowInTableResponse.text); - t.is(Object.hasOwn(foundRowInTableRO, 'row'), true); - t.is(Object.hasOwn(foundRowInTableRO, 'structure'), true); - t.is(Object.hasOwn(foundRowInTableRO, 'foreignKeys'), true); - t.is(Object.hasOwn(foundRowInTableRO, 'primaryColumns'), true); - t.is(Object.hasOwn(foundRowInTableRO, 'readonly_fields'), true); - t.is(typeof foundRowInTableRO.row, 'object'); - t.is(typeof foundRowInTableRO.structure, 'object'); - t.is(typeof foundRowInTableRO.primaryColumns, 'object'); - t.is(typeof foundRowInTableRO.readonly_fields, 'object'); - t.is(typeof foundRowInTableRO.foreignKeys, 'object'); - t.is(foundRowInTableRO.row.ID, 1); - t.is(foundRowInTableRO.row[testTableColumnName], testSearchedUserName); - t.is(Object.keys(foundRowInTableRO.row).length, 5); -}); - -test.serial(`${currentTest} should throw an exception, when connection id is not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - const idForSearch = 1; - createConnectionRO.id = ''; - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&ID=${idForSearch}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 404); -}); - -test.serial( - `${currentTest} should throw an exception, when connection id passed in request is incorrect`, - async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForSearch = 1; - createConnectionRO.id = faker.string.uuid(); - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&ID=${idForSearch}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 403); - const { message } = JSON.parse(foundRowInTableResponse.text); - t.is(message, Messages.DONT_HAVE_PERMISSIONS); - }, -); - -test.serial(`${currentTest} should throw an exception, when tableName in not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForSearch = 1; - const fakeTableName = ''; - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${fakeTableName}&ID=${idForSearch}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 400); - const { message } = JSON.parse(foundRowInTableResponse.text); - t.is(message, Messages.TABLE_NAME_MISSING); -}); - -test.serial(`${currentTest} should throw an exception, when tableName passed in request is incorrect`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForSearch = 1; - const fakeTableName = `${faker.lorem.words(1)}_${faker.string.uuid()}`; - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${fakeTableName}&ID=${idForSearch}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 400); - const { message } = JSON.parse(foundRowInTableResponse.text); - t.is(message, Messages.TABLE_NOT_FOUND); -}); - -test.serial(`${currentTest} should throw an exception, when primary key is not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 400); - const { message } = JSON.parse(foundRowInTableResponse.text); - t.is(message, Messages.PRIMARY_KEY_INVALID); -}); - -test.serial( - `${currentTest} should throw an exception, when primary key passed in request has incorrect name`, - async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForSearch = 1; - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&fakeKeyName=${idForSearch}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 400); - const { message } = JSON.parse(foundRowInTableResponse.text); - t.is(message, Messages.PRIMARY_KEY_INVALID); - }, -); - -test.serial( - `${currentTest} should throw an exception, when primary key passed in request has incorrect value`, - async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForSearch = 1000000; - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&ID=${idForSearch}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 400); - const { message } = JSON.parse(foundRowInTableResponse.text); - t.is(message, Messages.ROW_PRIMARY_KEY_NOT_FOUND); - }, -); - -currentTest = 'PUT /table/rows/delete/:slug'; - -test.serial(`${currentTest} should delete row in table and return result`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - const primaryKeysForDeletion: Array> = [ - { - ID: 1, - }, - { - ID: 10, - }, - { - ID: 32, - }, - ]; - const deleteRowsInTableResponse = await request(app.getHttpServer()) - .put(`/table/rows/delete/${createConnectionRO.id}?tableName=${testTableName}`) - .send(primaryKeysForDeletion) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowsInTableResponse.status, 200); - const _deleteRowInTableRO = JSON.parse(deleteRowsInTableResponse.text); - - //checking that the line was deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - // check that lines was deleted - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, testEntitiesSeedsCount - primaryKeysForDeletion.length); - - for (const key of primaryKeysForDeletion) { - t.is( - rows.findIndex((row) => row.ID === key.id), - -1, - ); - } - - // check that table deletaion was logged - const tableLogsResponse = await request(app.getHttpServer()) - .get(`/logs/${createConnectionRO.id}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(tableLogsResponse.status, 200); - - const tableLogsRO = JSON.parse(tableLogsResponse.text); - t.is(tableLogsRO.logs.length, primaryKeysForDeletion.length + 1); - const onlyDeleteLogs = tableLogsRO.logs.filter((log) => log.operationType === LogOperationTypeEnum.deleteRow); - for (const key of primaryKeysForDeletion) { - t.is(onlyDeleteLogs.findIndex((log) => log.received_data.id === key.id) >= 0, true); - } -}); - -test.serial(`${currentTest} should test connection and return result`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const testConnectionResponse = await request(app.getHttpServer()) - .post('/connection/test/') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(testConnectionResponse.status, 201); - const { message } = JSON.parse(testConnectionResponse.text); - t.is(message, 'Successfully connected'); -}); - -currentTest = 'GET table/csv/:slug'; - -test.serial(`${currentTest} should return csv file with table data`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const getTableCsvResponse = await request(app.getHttpServer()) - .post(`/table/csv/export/${createConnectionRO.id}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'text/csv') - .set('Accept', 'text/csv'); - - if (getTableCsvResponse.status !== 201) { - console.log(getTableCsvResponse.text); - } - t.is(getTableCsvResponse.status, 201); - const fileName = `${testTableName}.csv`; - const downloadedFilePatch = join(os.tmpdir(), fileName); - - // eslint-disable-next-line security/detect-non-literal-fs-filename - fs.writeFileSync(downloadedFilePatch, getTableCsvResponse.body); - - // eslint-disable-next-line security/detect-non-literal-fs-filename - const isFileExists = fs.existsSync(downloadedFilePatch); - t.is(isFileExists, true); -}); - -test.serial( - `${currentTest} should return csv file with table data with search, with pagination, with sorting, -with search and pagination: page=1, perPage=2 and DESC sorting`, - async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableCsvResponse = await request(app.getHttpServer()) - .post( - `/table/csv/export/${createConnectionRO.id}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'text/csv') - .set('Accept', 'text/csv'); - - if (getTableCsvResponse.status !== 201) { - console.log(getTableCsvResponse.text); - } - t.is(getTableCsvResponse.status, 201); - const fileName = `${testTableName}.csv`; - const downloadedFilePatch = join(os.tmpdir(), fileName); - - // eslint-disable-next-line security/detect-non-literal-fs-filename - fs.writeFileSync(downloadedFilePatch, getTableCsvResponse.body); - - // eslint-disable-next-line security/detect-non-literal-fs-filename - const isFileExists = fs.existsSync(downloadedFilePatch); - t.is(isFileExists, true); - }, -); diff --git a/backend/test/ava-tests/non-saas-tests/non-saas-table-schema-ibmdb2-e2e.test.ts b/backend/test/ava-tests/non-saas-tests/non-saas-table-schema-ibmdb2-e2e.test.ts deleted file mode 100644 index 8cec2e550..000000000 --- a/backend/test/ava-tests/non-saas-tests/non-saas-table-schema-ibmdb2-e2e.test.ts +++ /dev/null @@ -1,330 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { faker } from '@faker-js/faker'; -import { INestApplication, ValidationPipe } from '@nestjs/common'; -import { Test } from '@nestjs/testing'; -import test from 'ava'; -import { ValidationError } from 'class-validator'; -import cookieParser from 'cookie-parser'; -import * as ibmdbNs from 'ibm_db'; - -const ibmdb = ibmdbNs.default as unknown as (options?: import('ibm_db').Options) => import('ibm_db').Database; - -import request from 'supertest'; -import { AICoreService } from '../../../src/ai-core/services/ai-core.service.js'; -import { ApplicationModule } from '../../../src/app.module.js'; -import { WinstonLogger } from '../../../src/entities/logging/winston-logger.js'; -import { - SchemaChangeStatusEnum, - SchemaChangeTypeEnum, -} from '../../../src/entities/table-schema/table-schema-change-enums.js'; -import { AllExceptionsFilter } from '../../../src/exceptions/all-exceptions.filter.js'; -import { ValidationException } from '../../../src/exceptions/custom-exceptions/validation-exception.js'; -import { Cacher } from '../../../src/helpers/cache/cacher.js'; -import { DatabaseModule } from '../../../src/shared/database/database.module.js'; -import { DatabaseService } from '../../../src/shared/database/database.service.js'; -import { MockFactory } from '../../mock.factory.js'; -import { getTestData } from '../../utils/get-test-data.js'; -import { - createInitialTestUser, - registerUserAndReturnUserInfo, -} from '../../utils/register-user-and-return-user-info.js'; -import { setSaasEnvVariable } from '../../utils/set-saas-env-variable.js'; -import { TestUtils } from '../../utils/test.utils.js'; - -interface ProposedChange { - forwardSql: string; - rollbackSql: string; - changeType: SchemaChangeTypeEnum; - targetTableName: string; - isReversible: boolean; - summary: string; - reasoning: string; -} - -let nextProposal: ProposedChange | null = null; - -function createProposalStream(proposal: ProposedChange) { - return { - *[Symbol.asyncIterator]() { - yield { - type: 'tool_call', - toolCall: { - id: faker.string.uuid(), - name: 'proposeSchemaChange', - arguments: { proposals: [proposal] }, - }, - responseId: faker.string.uuid(), - }; - }, - }; -} - -const mockAICoreService = { - streamChatWithToolsAndProvider: async () => { - if (!nextProposal) throw new Error('Test must set nextProposal.'); - return createProposalStream(nextProposal); - }, - complete: async () => 'mocked', - chat: async () => ({ content: 'mocked', responseId: faker.string.uuid() }), - streamChat: async () => ({ - *[Symbol.asyncIterator]() { - yield { type: 'text', content: 'mocked', responseId: faker.string.uuid() }; - }, - }), - chatWithTools: async () => ({ content: 'mocked', responseId: faker.string.uuid() }), - streamChatWithTools: async () => createProposalStream(nextProposal!), - chatWithToolsAndProvider: async () => ({ content: 'mocked', responseId: faker.string.uuid() }), - streamChatWithProvider: async () => ({ - *[Symbol.asyncIterator]() { - yield { type: 'text', content: 'mocked', responseId: faker.string.uuid() }; - }, - }), - completeWithProvider: async () => 'mocked', - chatWithProvider: async () => ({ content: 'mocked', responseId: faker.string.uuid() }), - continueAfterToolCall: async () => ({ content: 'mocked', responseId: faker.string.uuid() }), - continueStreamingAfterToolCall: async () => createProposalStream(nextProposal!), - getDefaultProvider: () => 'bedrock', - setDefaultProvider: () => {}, - getAvailableProviders: () => [], -}; - -const mockFactory = new MockFactory(); -let app: INestApplication; -let _testUtils: TestUtils; - -function buildConnStr(params: any): string { - return `DATABASE=${params.database};HOSTNAME=${params.host};UID=${params.username};PWD=${params.password};PORT=${params.port};PROTOCOL=TCPIP`; -} - -async function ensureSchema(params: any): Promise { - const db = ibmdb(); - await db.open(buildConnStr(params)); - try { - const exists = (await db.query( - `SELECT COUNT(*) AS C FROM SYSCAT.SCHEMATA WHERE SCHEMANAME = '${params.schema}'`, - )) as Array<{ C: number }>; - if (!exists[0] || !exists[0].C) { - await db.query(`CREATE SCHEMA ${params.schema}`); - } - } finally { - await db.close(); - } -} - -async function queryDb2(params: any, sql: string): Promise { - const db = ibmdb(); - await db.open(buildConnStr(params)); - try { - return (await db.query(sql)) as T[]; - } finally { - await db.close(); - } -} - -test.before(async () => { - setSaasEnvVariable(); - const moduleFixture = await Test.createTestingModule({ - imports: [ApplicationModule, DatabaseModule], - providers: [DatabaseService, TestUtils], - }) - .overrideProvider(AICoreService) - .useValue(mockAICoreService) - .compile(); - - _testUtils = moduleFixture.get(TestUtils); - app = moduleFixture.createNestApplication(); - app.use(cookieParser()); - app.useGlobalFilters(new AllExceptionsFilter(app.get(WinstonLogger))); - app.useGlobalPipes( - new ValidationPipe({ - exceptionFactory(validationErrors: ValidationError[] = []) { - return new ValidationException(validationErrors); - }, - }), - ); - await app.init(); - await createInitialTestUser(app); - app.getHttpServer().listen(0); - - await ensureSchema(getTestData(mockFactory).connectionToIbmDb2); -}); - -test.after(async () => { - try { - await Cacher.clearAllCache(); - await app.close(); - } catch (e) { - console.error('After tests error ' + e); - } -}); - -async function createConnection(token: string): Promise { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const resp = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', token) - .set('Content-Type', 'application/json'); - if (resp.status !== 201) { - throw new Error(`Failed to create connection: ${resp.status} ${resp.text}`); - } - return JSON.parse(resp.text).id; -} - -function randomTableName(prefix: string): string { - return `${prefix}_${faker.string.alphanumeric(6).toUpperCase()}`; -} - -function qualifyName(tableName: string): string { - const schema = getTestData(mockFactory).connectionToIbmDb2.schema; - return `${schema}.${tableName}`; -} - -async function tableExists(tableName: string): Promise { - const params = getTestData(mockFactory).connectionToIbmDb2; - const rows = await queryDb2<{ C: number }>( - params, - `SELECT COUNT(*) AS C FROM SYSCAT.TABLES WHERE TABSCHEMA = '${params.schema}' AND TABNAME = '${tableName}'`, - ); - return Number(rows[0]?.C ?? 0) > 0; -} - -async function columnExists(tableName: string, columnName: string): Promise { - const params = getTestData(mockFactory).connectionToIbmDb2; - const rows = await queryDb2<{ C: number }>( - params, - `SELECT COUNT(*) AS C FROM SYSCAT.COLUMNS WHERE TABSCHEMA = '${params.schema}' AND TABNAME = '${tableName}' AND COLNAME = '${columnName}'`, - ); - return Number(rows[0]?.C ?? 0) > 0; -} - -async function columnLength(tableName: string, columnName: string): Promise { - const params = getTestData(mockFactory).connectionToIbmDb2; - const rows = await queryDb2<{ LENGTH: number }>( - params, - `SELECT LENGTH FROM SYSCAT.COLUMNS WHERE TABSCHEMA = '${params.schema}' AND TABNAME = '${tableName}' AND COLNAME = '${columnName}'`, - ); - return rows[0]?.LENGTH ?? null; -} - -test.serial('DB2: generate → approve creates the table', async (t) => { - const { token } = await registerUserAndReturnUserInfo(app); - const connectionId = await createConnection(token); - const tableName = randomTableName('RA_T'); - - nextProposal = { - forwardSql: `CREATE TABLE ${qualifyName(tableName)} (ID BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, NAME VARCHAR(255))`, - rollbackSql: `DROP TABLE ${qualifyName(tableName)}`, - changeType: SchemaChangeTypeEnum.CREATE_TABLE, - targetTableName: tableName, - isReversible: true, - summary: 'db2 create', - reasoning: '', - }; - - const generateResp = await request(app.getHttpServer()) - .post(`/table-schema/${connectionId}/generate`) - .set('Cookie', token) - .send({ userPrompt: 'create table' }); - t.is(generateResp.status, 201); - const changeId = JSON.parse(generateResp.text).changes[0].id; - - const approveResp = await request(app.getHttpServer()) - .post(`/table-schema/change/${changeId}/approve`) - .set('Cookie', token) - .send({}); - t.is(approveResp.status, 200); - t.is(JSON.parse(approveResp.text).status, SchemaChangeStatusEnum.APPLIED); - - t.true(await tableExists(tableName)); -}); - -test.serial('DB2: ADD COLUMN approve adds the column; rollback removes it', async (t) => { - const { token } = await registerUserAndReturnUserInfo(app); - const connectionId = await createConnection(token); - const tableName = randomTableName('RA_ADDCOL'); - - const params = getTestData(mockFactory).connectionToIbmDb2; - await queryDb2( - params, - `CREATE TABLE ${qualifyName(tableName)} (ID BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY)`, - ); - - nextProposal = { - forwardSql: `ALTER TABLE ${qualifyName(tableName)} ADD COLUMN PHONE VARCHAR(255)`, - rollbackSql: `ALTER TABLE ${qualifyName(tableName)} DROP COLUMN PHONE`, - changeType: SchemaChangeTypeEnum.ADD_COLUMN, - targetTableName: tableName, - isReversible: true, - summary: 'add phone', - reasoning: '', - }; - - const generateResp = await request(app.getHttpServer()) - .post(`/table-schema/${connectionId}/generate`) - .set('Cookie', token) - .send({ userPrompt: 'add phone column' }); - t.is(generateResp.status, 201); - const changeId = JSON.parse(generateResp.text).changes[0].id; - - const approveResp = await request(app.getHttpServer()) - .post(`/table-schema/change/${changeId}/approve`) - .set('Cookie', token) - .send({}); - t.is(approveResp.status, 200); - t.true(await columnExists(tableName, 'PHONE')); - - const rollbackResp = await request(app.getHttpServer()) - .post(`/table-schema/change/${changeId}/rollback`) - .set('Cookie', token) - .send(); - t.is(rollbackResp.status, 200); - t.false(await columnExists(tableName, 'PHONE')); -}); - -test.serial('DB2: ALTER COLUMN SET DATA TYPE widens VARCHAR(32) → VARCHAR(255) preserving rows', async (t) => { - const { token } = await registerUserAndReturnUserInfo(app); - const connectionId = await createConnection(token); - const tableName = randomTableName('RA_ALT'); - - const params = getTestData(mockFactory).connectionToIbmDb2; - await queryDb2(params, `CREATE TABLE ${qualifyName(tableName)} (ID INTEGER PRIMARY KEY NOT NULL, NAME VARCHAR(32))`); - await queryDb2(params, `INSERT INTO ${qualifyName(tableName)} (ID, NAME) VALUES (1, 'alice')`); - await queryDb2(params, `INSERT INTO ${qualifyName(tableName)} (ID, NAME) VALUES (2, 'bob')`); - await queryDb2(params, `INSERT INTO ${qualifyName(tableName)} (ID, NAME) VALUES (3, 'carol')`); - - nextProposal = { - forwardSql: `ALTER TABLE ${qualifyName(tableName)} ALTER COLUMN NAME SET DATA TYPE VARCHAR(255)`, - rollbackSql: `ALTER TABLE ${qualifyName(tableName)} ALTER COLUMN NAME SET DATA TYPE VARCHAR(32)`, - changeType: SchemaChangeTypeEnum.ALTER_COLUMN, - targetTableName: tableName, - isReversible: true, - summary: 'widen name', - reasoning: '', - }; - - const generateResp = await request(app.getHttpServer()) - .post(`/table-schema/${connectionId}/generate`) - .set('Cookie', token) - .send({ userPrompt: 'widen name' }); - t.is(generateResp.status, 201); - const changeId = JSON.parse(generateResp.text).changes[0].id; - - const approveResp = await request(app.getHttpServer()) - .post(`/table-schema/change/${changeId}/approve`) - .set('Cookie', token) - .send({}); - t.is(approveResp.status, 200); - - const length = await columnLength(tableName, 'NAME'); - t.is(length, 255); - - const rows = await queryDb2<{ NAME: string; ID: number }>( - params, - `SELECT ID, NAME FROM ${qualifyName(tableName)} ORDER BY ID`, - ); - t.deepEqual( - rows.map((r) => r.NAME), - ['alice', 'bob', 'carol'], - ); -}); diff --git a/backend/test/ava-tests/saas-tests/table-ibmdb2-agent-e2e.test.ts b/backend/test/ava-tests/saas-tests/table-ibmdb2-agent-e2e.test.ts deleted file mode 100644 index cccb205d1..000000000 --- a/backend/test/ava-tests/saas-tests/table-ibmdb2-agent-e2e.test.ts +++ /dev/null @@ -1,2950 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -/* eslint-disable security/detect-object-injection */ -import { faker } from '@faker-js/faker'; -import { INestApplication, ValidationPipe } from '@nestjs/common'; -import { Test } from '@nestjs/testing'; -import test from 'ava'; -import { ValidationError } from 'class-validator'; -import cookieParser from 'cookie-parser'; -import fs from 'fs'; -import os from 'os'; -import path, { join } from 'path'; -import request from 'supertest'; -import { fileURLToPath } from 'url'; -import { ApplicationModule } from '../../../src/app.module.js'; -import { WinstonLogger } from '../../../src/entities/logging/winston-logger.js'; -import { LogOperationTypeEnum } from '../../../src/enums/log-operation-type.enum.js'; -import { QueryOrderingEnum } from '../../../src/enums/query-ordering.enum.js'; -import { AllExceptionsFilter } from '../../../src/exceptions/all-exceptions.filter.js'; -import { ValidationException } from '../../../src/exceptions/custom-exceptions/validation-exception.js'; -import { Messages } from '../../../src/exceptions/text/messages.js'; -import { Cacher } from '../../../src/helpers/cache/cacher.js'; -import { Constants } from '../../../src/helpers/constants/constants.js'; -import { DatabaseModule } from '../../../src/shared/database/database.module.js'; -import { DatabaseService } from '../../../src/shared/database/database.service.js'; -import { MockFactory } from '../../mock.factory.js'; -import { createTestTable } from '../../utils/create-test-table.js'; -import { getTestData } from '../../utils/get-test-data.js'; -import { registerUserAndReturnUserInfo } from '../../utils/register-user-and-return-user-info.js'; -import { TestUtils } from '../../utils/test.utils.js'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -const mockFactory = new MockFactory(); -let app: INestApplication; -let testUtils: TestUtils; -const testSearchedUserName = 'Vasia'; -const _testTables: Array = []; -let currentTest; -let connectionToTestDB: any; -let firstUserToken: string; -let createdConnectionId: string; -let testTableName: string; -let testTableColumnName: string; -let testTableSecondColumnName: string; -let testEntitiesSeedsCount: number; - -test.before(async () => { - const moduleFixture = await Test.createTestingModule({ - imports: [ApplicationModule, DatabaseModule], - providers: [DatabaseService, TestUtils], - }).compile(); - app = moduleFixture.createNestApplication(); - testUtils = moduleFixture.get(TestUtils); - - app.use(cookieParser()); - app.useGlobalFilters(new AllExceptionsFilter(app.get(WinstonLogger))); - app.useGlobalPipes( - new ValidationPipe({ - exceptionFactory(validationErrors: ValidationError[] = []) { - return new ValidationException(validationErrors); - }, - }), - ); - await app.init(); - app.getHttpServer().listen(0); - - firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - connectionToTestDB = getTestData(mockFactory).connectionToAgentIbmDB2; - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - createdConnectionId = createConnectionRO.id; - await testUtils.sleep(); - - // const connectionToIbmDb2 = getTestData(mockFactory).connectionToIbmDb2; - // const testTableCreationResult = await createTestTable(connectionToIbmDb2); - // testTableName = testTableCreationResult.testTableName; - // testTableColumnName = testTableCreationResult.testTableColumnName; - // testTableSecondColumnName = testTableCreationResult.testTableSecondColumnName; - // testEntitiesSeedsCount = testTableCreationResult.testEntitiesSeedsCount; -}); - -test.beforeEach(async () => { - const connectionToIbmDb2 = getTestData(mockFactory).connectionToIbmDb2; - const testTableCreationResult = await createTestTable(connectionToIbmDb2); - testTableName = testTableCreationResult.testTableName; - testTableColumnName = testTableCreationResult.testTableColumnName; - testTableSecondColumnName = testTableCreationResult.testTableSecondColumnName; - testEntitiesSeedsCount = testTableCreationResult.testEntitiesSeedsCount; -}); - -test.after(async () => { - try { - await Cacher.clearAllCache(); - await app.close(); - } catch (e) { - console.error('After tests error ' + e); - } -}); - -currentTest = 'GET /connection/tables/:slug'; - -test.serial(`${currentTest} should return list of tables in connection`, async (t) => { - try { - const getTablesResponse = await request(app.getHttpServer()) - .get(`/connection/tables/${createdConnectionId}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const getTablesRO = JSON.parse(getTablesResponse.text); - - t.is(getTablesResponse.status, 200); - t.is(typeof getTablesRO, 'object'); - t.is(getTablesRO.length > 0, true); - - const testTableIndex = getTablesRO.findIndex((t) => t.table === testTableName); - - t.is(Object.hasOwn(getTablesRO[testTableIndex], 'table'), true); - t.is(Object.hasOwn(getTablesRO[testTableIndex], 'permissions'), true); - t.is(typeof getTablesRO[testTableIndex].permissions, 'object'); - t.is(Object.keys(getTablesRO[testTableIndex].permissions).length, 7); - t.is(getTablesRO[testTableIndex].table, testTableName); - t.is(getTablesRO[testTableIndex].permissions.visibility, true); - t.is(getTablesRO[testTableIndex].permissions.readonly, false); - t.is(getTablesRO[testTableIndex].permissions.add, true); - t.is(getTablesRO[testTableIndex].permissions.delete, true); - t.is(getTablesRO[testTableIndex].permissions.edit, true); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial(`${currentTest} should throw an error when connectionId not passed in request`, async (t) => { - try { - const emptyConnectionId = ''; - const getTablesResponse = await request(app.getHttpServer()) - .get(`/connection/tables/${emptyConnectionId}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTablesResponse.status, 404); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial(`${currentTest} should throw an error when connection id is incorrect`, async (t) => { - try { - const fakeConnectionId = faker.string.uuid(); - const getTablesResponse = await request(app.getHttpServer()) - .get(`/connection/tables/${fakeConnectionId}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTablesResponse.status, 400); - const { message } = JSON.parse(getTablesResponse.text); - t.is(message, Messages.CONNECTION_NOT_FOUND); - } catch (e) { - console.error(e); - throw e; - } -}); - -currentTest = 'GET /table/rows/:slug'; - -test.serial(`${currentTest} should return rows of selected table without search and without pagination`, async (t) => { - try { - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, Constants.DEFAULT_PAGINATION.perPage); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(Object.hasOwn(getTableRowsRO.rows[0], 'ID'), true); - t.is(Object.hasOwn(getTableRowsRO.rows[1], testTableColumnName), true); - t.is(Object.hasOwn(getTableRowsRO.rows[10], testTableSecondColumnName), true); - t.is(Object.hasOwn(getTableRowsRO.rows[15], 'CREATED_AT'), true); - t.is(Object.hasOwn(getTableRowsRO.rows[19], 'UPDATED_AT'), true); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial(`${currentTest} should return rows of selected table with search and without pagination`, async (t) => { - try { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - ['ID'], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - undefined, - undefined, - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createTableSettingsResponse.status, 201); - - const searchedDescription = '25'; - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}&search=${searchedDescription}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(getTableRowsResponse.status, 200); - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 1); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - t.is(getTableRowsRO.rows[0].ID, parseInt(searchedDescription, 10)); - t.is(Object.hasOwn(getTableRowsRO.rows[0], testTableColumnName), true); - t.is(Object.hasOwn(getTableRowsRO.rows[0], testTableSecondColumnName), true); - t.is(Object.hasOwn(getTableRowsRO.rows[0], 'CREATED_AT'), true); - t.is(Object.hasOwn(getTableRowsRO.rows[0], 'UPDATED_AT'), true); - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial(`${currentTest} should return page of all rows with pagination page=1, perPage=2`, async (t) => { - try { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - ['ID'], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - undefined, - undefined, - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}&page=1&perPage=2`) - .set('Content-Type', 'application/json') - .set('Cookie', firstUserToken) - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(Object.hasOwn(getTableRowsRO.rows[0], 'ID'), true); - t.is(Object.hasOwn(getTableRowsRO.rows[1], testTableColumnName), true); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - t.is(getTableRowsRO.primaryColumns[0].column_name, 'ID'); - t.is(getTableRowsRO.primaryColumns[0].data_type, 'INTEGER'); - - t.is(getTableRowsRO.pagination.total, 42); - t.is(getTableRowsRO.pagination.lastPage, 21); - t.is(getTableRowsRO.pagination.perPage, 2); - t.is(getTableRowsRO.pagination.currentPage, 1); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial(`${currentTest} should return page of all rows with pagination page=3, perPage=2`, async (t) => { - try { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - ['ID'], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - undefined, - undefined, - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}&page=3&perPage=2`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(Object.hasOwn(getTableRowsRO.rows[0], 'ID'), true); - t.is(Object.hasOwn(getTableRowsRO.rows[1], testTableColumnName), true); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - t.is(getTableRowsRO.primaryColumns[0].column_name, 'ID'); - t.is(getTableRowsRO.primaryColumns[0].data_type, 'INTEGER'); - - t.is(getTableRowsRO.pagination.total, 42); - t.is(getTableRowsRO.pagination.lastPage, 21); - t.is(getTableRowsRO.pagination.perPage, 2); - t.is(getTableRowsRO.pagination.currentPage, 3); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial( - `${currentTest} with search, with pagination, without sorting -should return all found rows with pagination page=1 perPage=2`, - async (t) => { - try { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - undefined, - undefined, - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createdConnectionId}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - t.is(getTableRowsRO.rows[0][testTableColumnName], testSearchedUserName); - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - t.is(getTableRowsRO.primaryColumns[0].column_name, 'ID'); - t.is(getTableRowsRO.primaryColumns[0].data_type, 'INTEGER'); - - //todo: rework pagination - // t.is(getTableRowsRO.pagination.total, 3); - // t.is(getTableRowsRO.pagination.lastPage, 2); - // t.is(getTableRowsRO.pagination.perPage, 2); - // t.is(getTableRowsRO.pagination.currentPage, 1); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination, without sorting -should return all found rows with pagination page=1 perPage=3`, - async (t) => { - try { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - undefined, - undefined, - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createdConnectionId}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - t.is(getTableRowsRO.rows[0][testTableColumnName], testSearchedUserName); - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - t.is(getTableRowsRO.primaryColumns[0].column_name, 'ID'); - t.is(getTableRowsRO.primaryColumns[0].data_type, 'INTEGER'); - - //todo: rework pagination - // t.is(getTableRowsRO.pagination.total, 3); - // t.is(getTableRowsRO.pagination.lastPage, 2); - // t.is(getTableRowsRO.pagination.perPage, 2); - // t.is(getTableRowsRO.pagination.currentPage, 1); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} without search and without pagination and with sorting -should return all found rows with sorting ids by DESC`, - async (t) => { - try { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 42, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - t.is(getTableRowsResponse.status, 200); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 42); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 42); - t.is(getTableRowsRO.rows[1].ID, 41); - t.is(getTableRowsRO.rows[41].ID, 1); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} without search and without pagination and with sorting -should return all found rows with sorting ids by ASC`, - async (t) => { - try { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 42, - QueryOrderingEnum.ASC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 42); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 1); - t.is(getTableRowsRO.rows[1].ID, 2); - t.is(getTableRowsRO.rows[41].ID, 42); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} without search and with pagination and with sorting -should return all found rows with sorting ports by DESC and with pagination page=1, perPage=2`, - async (t) => { - try { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}&page=1&perPage=2`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 42); - t.is(getTableRowsRO.rows[1].ID, 41); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} should return all found rows with sorting ports by ASC and with pagination page=1, perPage=2`, - async (t) => { - try { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.ASC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}&page=1&perPage=2`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 1); - t.is(getTableRowsRO.rows[1].ID, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} should return all found rows with sorting ports by DESC and with pagination page=2, perPage=3`, - async (t) => { - try { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}&page=2&perPage=3`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 3); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 39); - t.is(getTableRowsRO.rows[1].ID, 38); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination and with sorting -should return all found rows with search, pagination: page=1, perPage=2 and DESC sorting`, - async (t) => { - try { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createdConnectionId}?tableName=${testTableName}&page=1&perPage=2&search=${testSearchedUserName}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 38); - t.is(getTableRowsRO.rows[1].ID, 22); - t.is(getTableRowsRO.pagination.currentPage, 1); - t.is(getTableRowsRO.pagination.perPage, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination and with sorting -should return all found rows with search, pagination: page=2, perPage=2 and DESC sorting`, - async (t) => { - try { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createdConnectionId}?tableName=${testTableName}&page=2&perPage=2&search=${testSearchedUserName}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 1); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 1); - t.is(getTableRowsRO.pagination.currentPage, 2); - t.is(getTableRowsRO.pagination.perPage, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination and with sorting -should return all found rows with search, pagination: page=1, perPage=2 and ASC sorting`, - async (t) => { - try { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.ASC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createdConnectionId}?tableName=${testTableName}&page=1&perPage=2&search=${testSearchedUserName}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 1); - t.is(getTableRowsRO.rows[1].ID, 22); - t.is(getTableRowsRO.pagination.currentPage, 1); - t.is(getTableRowsRO.pagination.perPage, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination and with sorting -should return all found rows with search, pagination: page=2, perPage=2 and ASC sorting`, - async (t) => { - try { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.ASC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createdConnectionId}?tableName=${testTableName}&page=2&perPage=2&search=${testSearchedUserName}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 1); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 38); - t.is(getTableRowsRO.pagination.currentPage, 2); - t.is(getTableRowsRO.pagination.perPage, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination, with sorting and with filtering -should return all found rows with search, pagination: page=1, perPage=2 and DESC sorting and filtering`, - async (t) => { - try { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = 'ID'; - const fieldvalue = '45'; - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createdConnectionId}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2&f_${fieldname}__lt=${fieldvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - - t.is(getTableRowsRO.rows[0][testTableColumnName], testSearchedUserName); - t.is(getTableRowsRO.rows[0].ID, 38); - t.is(getTableRowsRO.rows[1][testTableColumnName], testSearchedUserName); - t.is(getTableRowsRO.rows[1].ID, 22); - - t.is(getTableRowsRO.pagination.currentPage, 1); - t.is(getTableRowsRO.pagination.perPage, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination, with sorting and with filtering -should return all found rows with search, pagination: page=1, perPage=10 and DESC sorting and filtering'`, - async (t) => { - try { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = 'ID'; - const fieldvalue = '41'; - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createdConnectionId}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=10&f_${fieldname}__lt=${fieldvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 3); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - - t.is(getTableRowsRO.rows[0][testTableColumnName], testSearchedUserName); - t.is(getTableRowsRO.rows[0].ID, 38); - t.is(getTableRowsRO.rows[1][testTableColumnName], testSearchedUserName); - t.is(getTableRowsRO.rows[1].ID, 22); - t.is(getTableRowsRO.rows[2][testTableColumnName], testSearchedUserName); - t.is(getTableRowsRO.rows[2].ID, 1); - - t.is(getTableRowsRO.pagination.currentPage, 1); - t.is(getTableRowsRO.pagination.perPage, 10); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination, with sorting and with filtering -should return all found rows with search, pagination: page=2, perPage=2 and DESC sorting and filtering`, - async (t) => { - try { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = 'ID'; - const fieldvalue = '41'; - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createdConnectionId}?tableName=${testTableName}&search=${testSearchedUserName}&page=2&perPage=2&f_${fieldname}__lt=${fieldvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 1); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - - t.is(getTableRowsRO.rows[0][testTableColumnName], testSearchedUserName); - t.is(getTableRowsRO.rows[0].ID, 1); - - t.is(getTableRowsRO.pagination.currentPage, 2); - t.is(getTableRowsRO.pagination.perPage, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination, with sorting and with filtering -should return all found rows with search, pagination: page=1, perPage=2 and DESC sorting and with multi filtering`, - async (t) => { - try { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = 'ID'; - const fieldGtvalue = '25'; - const fieldLtvalue = '40'; - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createdConnectionId}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2&f_${fieldname}__lt=${fieldLtvalue}&f_${fieldname}__gt=${fieldGtvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 1); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - - t.is(getTableRowsRO.rows[0].ID, 38); - t.is(getTableRowsRO.rows[0][testTableColumnName], testSearchedUserName); - - t.is(getTableRowsRO.pagination.currentPage, 1); - t.is(getTableRowsRO.pagination.perPage, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial(`${currentTest} should throw an exception when connection id is not passed in request`, async (t) => { - try { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = 'ID'; - const fieldGtvalue = '25'; - const fieldLtvalue = '40'; - const emptyConnectionId = ''; - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${emptyConnectionId}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2&f_${fieldname}__lt=${fieldLtvalue}&f_${fieldname}__gt=${fieldGtvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 404); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial(`${currentTest} should throw an exception when connection id passed in request is incorrect`, async (t) => { - try { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = 'ID'; - const fieldGtvalue = '25'; - const fieldLtvalue = '40'; - - const fakeConnectionId = faker.string.uuid(); - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${fakeConnectionId}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2&f_${fieldname}__lt=${fieldLtvalue}&f_${fieldname}__gt=${fieldGtvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 403); - - const { message } = JSON.parse(getTableRowsResponse.text); - - t.is(message, Messages.DONT_HAVE_PERMISSIONS); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial(`${currentTest} should throw an exception when table name passed in request is incorrect`, async (t) => { - try { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = 'ID'; - const fieldGtvalue = '25'; - const fieldLtvalue = '40'; - - const fakeTableName = `${faker.lorem.words(1)}_${faker.string.uuid()}`; - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createdConnectionId}?tableName=${fakeTableName}&search=${testSearchedUserName}&page=1&perPage=2&f_${fieldname}__lt=${fieldLtvalue}&f_${fieldname}__gt=${fieldGtvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 400); - - const { message } = JSON.parse(getTableRowsResponse.text); - - t.is(message, Messages.TABLE_NOT_FOUND); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial( - `${currentTest} should return an array with searched fields when filtered name passed in request is incorrect`, - async (t) => { - try { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = faker.lorem.words(1); - const fieldGtvalue = '25'; - const fieldLtvalue = '40'; - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createdConnectionId}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2&f_${fieldname}__lt=${fieldLtvalue}&f_${fieldname}__gt=${fieldGtvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTablesRO = JSON.parse(getTableRowsResponse.text); - t.is(getTablesRO.rows.length, 2); - t.is(getTablesRO.rows[0][testTableColumnName], testSearchedUserName); - t.is(getTablesRO.rows[1][testTableColumnName], testSearchedUserName); - t.is(Object.hasOwn(getTablesRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTablesRO, 'pagination'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -currentTest = 'GET /table/structure/:slug'; -test.serial(`${currentTest} should return table structure`, async (t) => { - const getTableStructure = await request(app.getHttpServer()) - .get(`/table/structure/${createdConnectionId}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableStructure.status, 200); - const getTableStructureRO = JSON.parse(getTableStructure.text); - - t.is(typeof getTableStructureRO, 'object'); - t.is(typeof getTableStructureRO.structure, 'object'); - t.is(getTableStructureRO.structure.length, 5); - - for (const element of getTableStructureRO.structure) { - t.is(Object.hasOwn(element, 'column_name'), true); - t.is(Object.hasOwn(element, 'column_default'), true); - t.is(Object.hasOwn(element, 'data_type'), true); - t.is(Object.hasOwn(element, 'isExcluded'), true); - t.is(Object.hasOwn(element, 'isSearched'), true); - } - - t.is(Object.hasOwn(getTableStructureRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableStructureRO, 'foreignKeys'), true); - - for (const element of getTableStructureRO.primaryColumns) { - t.is(Object.hasOwn(element, 'column_name'), true); - t.is(Object.hasOwn(element, 'data_type'), true); - } - - for (const element of getTableStructureRO.foreignKeys) { - t.is(Object.hasOwn(element, 'referenced_column_name'), true); - t.is(Object.hasOwn(element, 'referenced_table_name'), true); - t.is(Object.hasOwn(element, 'constraint_name'), true); - t.is(Object.hasOwn(element, 'column_name'), true); - } -}); - -test.serial(`${currentTest} should throw an exception whe connection id not passed in request`, async (t) => { - const emptyConnectionId = ''; - const getTableStructure = await request(app.getHttpServer()) - .get(`/table/structure/${emptyConnectionId}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableStructure.status, 404); -}); - -test.serial(`${currentTest} should throw an exception whe connection id passed in request id incorrect`, async (t) => { - const fakeConnectionId = faker.string.uuid(); - const getTableStructure = await request(app.getHttpServer()) - .get(`/table/structure/${fakeConnectionId}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableStructure.status, 403); - const { message } = JSON.parse(getTableStructure.text); - t.is(message, Messages.DONT_HAVE_PERMISSIONS); -}); - -test.serial(`${currentTest}should throw an exception when tableName not passed in request`, async (t) => { - const tableName = ''; - const getTableStructure = await request(app.getHttpServer()) - .get(`/table/structure/${createdConnectionId}?tableName=${tableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableStructure.status, 400); - const { message } = JSON.parse(getTableStructure.text); - t.is(message, Messages.TABLE_NAME_MISSING); -}); - -test.serial(`${currentTest} should throw an exception when tableName passed in request is incorrect`, async (t) => { - const tableName = faker.lorem.words(1); - const getTableStructure = await request(app.getHttpServer()) - .get(`/table/structure/${createdConnectionId}?tableName=${tableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableStructure.status, 400); - const { message } = JSON.parse(getTableStructure.text); - t.is(message, Messages.TABLE_NOT_FOUND); -}); - -currentTest = 'POST /table/row/:slug'; - -test.serial(`${currentTest} should add row in table and return result`, async (t) => { - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const addRowInTableResponse = await request(app.getHttpServer()) - .post(`/table/row/${createdConnectionId}?tableName=${testTableName}`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const addRowInTableRO = JSON.parse(addRowInTableResponse.text); - console.log('🚀 ~ test ~ addRowInTableRO:', addRowInTableRO); - t.is(addRowInTableResponse.status, 201); - - t.is(Object.hasOwn(addRowInTableRO, 'row'), true); - t.is(Object.hasOwn(addRowInTableRO, 'structure'), true); - t.is(Object.hasOwn(addRowInTableRO, 'foreignKeys'), true); - t.is(Object.hasOwn(addRowInTableRO, 'primaryColumns'), true); - t.is(Object.hasOwn(addRowInTableRO, 'readonly_fields'), true); - t.is(addRowInTableRO.row[testTableColumnName], row[testTableColumnName]); - t.is(addRowInTableRO.row[testTableSecondColumnName], row[testTableSecondColumnName]); - - //checking that the line was added - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 43); - const addedRow = rows.find((r) => r.ID === 43); - t.truthy(addedRow, 'Added row with ID=43 should exist'); - t.is(addedRow[testTableColumnName], row[testTableColumnName]); - t.is(addedRow[testTableSecondColumnName], row[testTableSecondColumnName]); - - // check that rows adding was logged - - const getLogsResponse = await request(app.getHttpServer()) - .get(`/logs/${createdConnectionId}?page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(getLogsResponse.status, 200); - const getLogsRO = JSON.parse(getLogsResponse.text); - t.is(Object.hasOwn(getLogsRO, 'logs'), true); - t.is(Object.hasOwn(getLogsRO, 'pagination'), true); - t.is(getLogsRO.logs.length > 0, true); - const addRowLogIndex = getLogsRO.logs.findIndex((log) => log.operationType === 'addRow'); - t.is(Object.hasOwn(getLogsRO.logs[addRowLogIndex], 'affected_primary_key'), true); - t.is(typeof getLogsRO.logs[addRowLogIndex].affected_primary_key, 'object'); - t.is(Object.hasOwn(getLogsRO.logs[addRowLogIndex].affected_primary_key, 'ID'), true); - t.is(getLogsRO.logs[addRowLogIndex].affected_primary_key.ID, 43); -}); - -test.serial(`${currentTest} should throw an exception when connection id is not passed in request`, async (t) => { - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - const fakeConnectionId = ''; - const addRowInTableResponse = await request(app.getHttpServer()) - .post(`/table/row/${fakeConnectionId}?tableName=${testTableName}`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(addRowInTableResponse.status, 404); - - //checking that the line wasn't added - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); -}); - -test.serial(`${currentTest} should throw an exception when table name is not passed in request`, async (t) => { - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const addRowInTableResponse = await request(app.getHttpServer()) - .post(`/table/row/${createdConnectionId}?tableName=`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(addRowInTableResponse.status, 400); - const { message } = JSON.parse(addRowInTableResponse.text); - - t.is(message, Messages.TABLE_NAME_MISSING); - - //checking that the line wasn't added - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); -}); - -test.serial(`${currentTest} should throw an exception when row is not passed in request`, async (t) => { - const addRowInTableResponse = await request(app.getHttpServer()) - .post(`/table/row/${createdConnectionId}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(addRowInTableResponse.status, 400); - const { message } = JSON.parse(addRowInTableResponse.text); - - t.is(message, Messages.PARAMETER_MISSING); - - //checking that the line wasn't added - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); -}); - -test.serial(`${currentTest} should throw an exception when table name passed in request is incorrect`, async (t) => { - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const fakeTableName = `${faker.lorem.words(1)}_${faker.string.uuid()}`; - const addRowInTableResponse = await request(app.getHttpServer()) - .post(`/table/row/${createdConnectionId}?tableName=${fakeTableName}`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(addRowInTableResponse.status, 400); - const { message } = JSON.parse(addRowInTableResponse.text); - - t.is(message, Messages.TABLE_NOT_FOUND); - - //checking that the line wasn't added - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); -}); - -currentTest = 'PUT /table/row/:slug'; - -test.serial(`${currentTest} should update row in table and return result`, async (t) => { - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${createdConnectionId}?tableName=${testTableName}&ID=1`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const updateRowInTableRO = JSON.parse(updateRowInTableResponse.text); - - t.is(updateRowInTableResponse.status, 200); - t.is(Object.hasOwn(updateRowInTableRO, 'row'), true); - t.is(Object.hasOwn(updateRowInTableRO, 'structure'), true); - t.is(Object.hasOwn(updateRowInTableRO, 'foreignKeys'), true); - t.is(Object.hasOwn(updateRowInTableRO, 'primaryColumns'), true); - t.is(Object.hasOwn(updateRowInTableRO, 'readonly_fields'), true); - t.is(updateRowInTableRO.row[testTableColumnName], row[testTableColumnName]); - t.is(updateRowInTableRO.row[testTableSecondColumnName], row[testTableSecondColumnName]); - - //checking that the line was updated - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - const updateRowIndex = rows.map((row) => row.ID).indexOf(1); - t.is(rows.length, 42); - t.is(rows[updateRowIndex][testTableColumnName], row[testTableColumnName]); - t.is(rows[updateRowIndex][testTableSecondColumnName], row[testTableSecondColumnName]); -}); - -test.serial(`${currentTest} should throw an exception when connection id not passed in request`, async (t) => { - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const emptyConnectionId = ''; - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${emptyConnectionId}?tableName=${testTableName}&ID=1`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(updateRowInTableResponse.status, 404); -}); - -test.serial(`${currentTest} should throw an exception when connection id passed in request is incorrect`, async (t) => { - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const fakeConnectionId = faker.string.uuid(); - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${fakeConnectionId}?tableName=${testTableName}&ID=1`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(updateRowInTableResponse.status, 403); - const { message } = JSON.parse(updateRowInTableResponse.text); - t.is(message, Messages.DONT_HAVE_PERMISSIONS); -}); - -test.serial(`${currentTest} should throw an exception when tableName not passed in request`, async (t) => { - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const fakeConnectionId = faker.string.uuid(); - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${fakeConnectionId}?tableName=&ID=1`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(updateRowInTableResponse.status, 400); - const { message } = JSON.parse(updateRowInTableResponse.text); - t.is(message, Messages.TABLE_NAME_MISSING); -}); - -test.serial(`${currentTest} should throw an exception when tableName passed in request is incorrect`, async (t) => { - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const fakeTableName = faker.string.uuid(); - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${createdConnectionId}?tableName=${fakeTableName}&ID=1`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(updateRowInTableResponse.status, 400); - const { message } = JSON.parse(updateRowInTableResponse.text); - t.is(message, Messages.TABLE_NOT_FOUND); -}); - -test.serial(`${currentTest} should throw an exception when primary key not passed in request`, async (t) => { - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${createdConnectionId}?tableName=${testTableName}&`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(updateRowInTableResponse.status, 400); - const { message } = JSON.parse(updateRowInTableResponse.text); - t.is(message, Messages.PRIMARY_KEY_INVALID); -}); - -test.serial( - `${currentTest} should throw an exception when primary key passed in request has incorrect field name`, - async (t) => { - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${createdConnectionId}?tableName=${testTableName}&IncorrectField=1`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(updateRowInTableResponse.status, 400); - const { message } = JSON.parse(updateRowInTableResponse.text); - t.is(message, Messages.PRIMARY_KEY_INVALID); - }, -); - -test.serial( - `${currentTest} should throw an exception when primary key passed in request has incorrect field value`, - async (t) => { - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${createdConnectionId}?tableName=${testTableName}&ID=100000000`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const updateRowInTableRO = JSON.parse(updateRowInTableResponse.text); - t.is(updateRowInTableResponse.status, 500); - const { message } = updateRowInTableRO; - t.is(message, 'Failed to update row in table. No data returned from agent'); - }, -); - -currentTest = 'DELETE /table/row/:slug'; - -test.serial(`${currentTest} should delete row in table and return result`, async (t) => { - const idForDeletion = 1; - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${createdConnectionId}?tableName=${testTableName}&ID=${idForDeletion}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const deleteRowInTableRO = JSON.parse(deleteRowInTableResponse.text); - console.log('🚀 ~ test ~ deleteRowInTableRO:', deleteRowInTableRO); - - t.is(deleteRowInTableResponse.status, 200); - - t.is(Object.hasOwn(deleteRowInTableRO, 'row'), true); - - //checking that the line was deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 41); - const deletedRowIndex = rows.map((row: Record) => row.ID).indexOf(idForDeletion); - t.is(deletedRowIndex < 0, true); -}); - -test.serial(`${currentTest} should throw an exception when connection id not passed in request`, async (t) => { - const idForDeletion = 1; - const connectionId = ''; - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${connectionId}?tableName=${testTableName}&ID=${idForDeletion}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowInTableResponse.status, 404); - - //checking that the line wasn't deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); - const deletedRowIndex = rows.map((row: Record) => row.ID).indexOf(idForDeletion); - t.is(deletedRowIndex < 0, false); -}); - -test.serial(`${currentTest} should throw an exception when connection id passed in request is incorrect`, async (t) => { - const idForDeletion = 1; - const connectionId = faker.string.uuid(); - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${connectionId}?tableName=${testTableName}&ID=${idForDeletion}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowInTableResponse.status, 403); - const { message } = JSON.parse(deleteRowInTableResponse.text); - t.is(message, Messages.DONT_HAVE_PERMISSIONS); - - //checking that the line wasn't deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); - const deletedRowIndex = rows.map((row: Record) => row.ID).indexOf(idForDeletion); - t.is(deletedRowIndex < 0, false); -}); - -test.serial(`${currentTest} should throw an exception when tableName not passed in request`, async (t) => { - const idForDeletion = 1; - const fakeTableName = ''; - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${createdConnectionId}?tableName=${fakeTableName}&ID=${idForDeletion}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowInTableResponse.status, 400); - const { message } = JSON.parse(deleteRowInTableResponse.text); - t.is(message, Messages.TABLE_NAME_MISSING); - - //checking that the line wasn't deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); - const deletedRowIndex = rows.map((row: Record) => row.ID).indexOf(idForDeletion); - t.is(deletedRowIndex < 0, false); -}); - -test.serial(`${currentTest} should throw an exception when tableName passed in request is incorrect`, async (t) => { - const idForDeletion = 1; - const fakeTableName = `${faker.lorem.words(1)}_${faker.string.uuid()}`; - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${createdConnectionId}?tableName=${fakeTableName}&ID=${idForDeletion}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowInTableResponse.status, 400); - const { message } = JSON.parse(deleteRowInTableResponse.text); - t.is(message, Messages.TABLE_NOT_FOUND); - - //checking that the line wasn't deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); - const deletedRowIndex = rows.map((row: Record) => row.ID).indexOf(idForDeletion); - t.is(deletedRowIndex < 0, false); -}); - -test.serial(`${currentTest} should throw an exception when primary key not passed in request`, async (t) => { - const idForDeletion = 1; - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${createdConnectionId}?tableName=${testTableName}&`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowInTableResponse.status, 400); - const { message } = JSON.parse(deleteRowInTableResponse.text); - t.is(message, Messages.PRIMARY_KEY_INVALID); - - //checking that the line wasn't deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); - const deletedRowIndex = rows.map((row: Record) => row.ID).indexOf(idForDeletion); - t.is(deletedRowIndex < 0, false); -}); - -test.serial( - `${currentTest} should throw an exception when primary key passed in request has incorrect field name`, - async (t) => { - const idForDeletion = 1; - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${createdConnectionId}?tableName=${testTableName}&fakePKey=1`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowInTableResponse.status, 400); - const { message } = JSON.parse(deleteRowInTableResponse.text); - t.is(message, Messages.PRIMARY_KEY_INVALID); - - //checking that the line wasn't deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); - const deletedRowIndex = rows.map((row: Record) => row.ID).indexOf(idForDeletion); - t.is(deletedRowIndex < 0, false); - }, -); - -test.serial( - `${currentTest} should throw an exception when primary key passed in request has incorrect field value`, - async (t) => { - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${createdConnectionId}?tableName=${testTableName}&ID=100000`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const deleteRowInTableRO = JSON.parse(deleteRowInTableResponse.text); - t.is(deleteRowInTableResponse.status, 500); - t.is(deleteRowInTableRO.message, 'Failed to delete row from table. No data returned from agent'); - }, -); - -currentTest = 'GET /table/row/:slug'; - -test.serial(`${currentTest} found row`, async (t) => { - const idForSearch = 1; - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${createdConnectionId}?tableName=${testTableName}&ID=${idForSearch}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 200); - const foundRowInTableRO = JSON.parse(foundRowInTableResponse.text); - t.is(Object.hasOwn(foundRowInTableRO, 'row'), true); - t.is(Object.hasOwn(foundRowInTableRO, 'structure'), true); - t.is(Object.hasOwn(foundRowInTableRO, 'foreignKeys'), true); - t.is(Object.hasOwn(foundRowInTableRO, 'primaryColumns'), true); - t.is(Object.hasOwn(foundRowInTableRO, 'readonly_fields'), true); - t.is(typeof foundRowInTableRO.row, 'object'); - t.is(typeof foundRowInTableRO.structure, 'object'); - t.is(typeof foundRowInTableRO.primaryColumns, 'object'); - t.is(typeof foundRowInTableRO.readonly_fields, 'object'); - t.is(typeof foundRowInTableRO.foreignKeys, 'object'); - t.is(foundRowInTableRO.row.ID, 1); - t.is(foundRowInTableRO.row[testTableColumnName], testSearchedUserName); - t.is(Object.keys(foundRowInTableRO.row).length, 5); -}); - -test.serial(`${currentTest} should throw an exception, when connection id is not passed in request`, async (t) => { - const idForSearch = 1; - const emptyConnectionId = ''; - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${emptyConnectionId}?tableName=${testTableName}&ID=${idForSearch}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 404); -}); - -test.serial( - `${currentTest} should throw an exception, when connection id passed in request is incorrect`, - async (t) => { - const idForSearch = 1; - const fakeConnectionId = faker.string.uuid(); - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${fakeConnectionId}?tableName=${testTableName}&ID=${idForSearch}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 403); - const { message } = JSON.parse(foundRowInTableResponse.text); - t.is(message, Messages.DONT_HAVE_PERMISSIONS); - }, -); - -test.serial(`${currentTest} should throw an exception, when tableName in not passed in request`, async (t) => { - const idForSearch = 1; - const fakeTableName = ''; - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${createdConnectionId}?tableName=${fakeTableName}&ID=${idForSearch}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 400); - const { message } = JSON.parse(foundRowInTableResponse.text); - t.is(message, Messages.TABLE_NAME_MISSING); -}); - -test.serial(`${currentTest} should throw an exception, when tableName passed in request is incorrect`, async (t) => { - const idForSearch = 1; - const fakeTableName = `${faker.lorem.words(1)}_${faker.string.uuid()}`; - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${createdConnectionId}?tableName=${fakeTableName}&ID=${idForSearch}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 400); - const { message } = JSON.parse(foundRowInTableResponse.text); - t.is(message, Messages.TABLE_NOT_FOUND); -}); - -test.serial(`${currentTest} should throw an exception, when primary key is not passed in request`, async (t) => { - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${createdConnectionId}?tableName=${testTableName}&`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 400); - const { message } = JSON.parse(foundRowInTableResponse.text); - t.is(message, Messages.PRIMARY_KEY_INVALID); -}); - -test.serial( - `${currentTest} should throw an exception, when primary key passed in request has incorrect name`, - async (t) => { - const idForSearch = 1; - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${createdConnectionId}?tableName=${testTableName}&fakeKeyName=${idForSearch}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 400); - const { message } = JSON.parse(foundRowInTableResponse.text); - t.is(message, Messages.PRIMARY_KEY_INVALID); - }, -); - -test.serial( - `${currentTest} should throw an exception, when primary key passed in request has incorrect value`, - async (t) => { - const idForSearch = 1000000; - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${createdConnectionId}?tableName=${testTableName}&ID=${idForSearch}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 500); - const { message } = JSON.parse(foundRowInTableResponse.text); - t.is(message, 'Failed to get row by primary key. No data returned from agent'); - }, -); - -currentTest = 'PUT /table/rows/delete/:slug'; - -test.serial(`${currentTest} should delete row in table and return result`, async (t) => { - const primaryKeysForDeletion: Array> = [ - { - ID: 1, - }, - { - ID: 10, - }, - { - ID: 32, - }, - ]; - const deleteRowsInTableResponse = await request(app.getHttpServer()) - .put(`/table/rows/delete/${createdConnectionId}?tableName=${testTableName}`) - .send(primaryKeysForDeletion) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowsInTableResponse.status, 200); - const _deleteRowInTableRO = JSON.parse(deleteRowsInTableResponse.text); - - //checking that the line was deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - // check that lines was deleted - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, testEntitiesSeedsCount - primaryKeysForDeletion.length); - - for (const key of primaryKeysForDeletion) { - t.is( - rows.findIndex((row) => row.ID === key.id), - -1, - ); - } - - // check that table deletaion was logged - const tableLogsResponse = await request(app.getHttpServer()) - .get(`/logs/${createdConnectionId}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(tableLogsResponse.status, 200); - - const tableLogsRO = JSON.parse(tableLogsResponse.text); - const onlyDeleteLogs = tableLogsRO.logs.filter((log) => log.operationType === LogOperationTypeEnum.deleteRow); - t.true(onlyDeleteLogs.length >= primaryKeysForDeletion.length); - for (const key of primaryKeysForDeletion) { - t.is(onlyDeleteLogs.findIndex((log) => log.received_data.id === key.id) >= 0, true); - } -}); - -// currentTest = 'POST /connection/test/'; -// test.serial(`${currentTest} should test connection and return result`, async (t) => { -// const testConnectionResponse = await request(app.getHttpServer()) -// .post('/connection/test/') -// .send(connectionToTestDB) -// .set('Cookie', firstUserToken) -// .set('Content-Type', 'application/json') -// .set('Accept', 'application/json'); - -// t.is(testConnectionResponse.status, 201); -// const { message } = JSON.parse(testConnectionResponse.text); -// t.is(message, 'Successfully connected'); -// }); - -currentTest = 'GET table/csv/:slug'; - -test.serial(`${currentTest} should return csv file with table data`, async (t) => { - const getTableCsvResponse = await request(app.getHttpServer()) - .post(`/table/csv/export/${createdConnectionId}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'text/csv') - .set('Accept', 'text/csv'); - - if (getTableCsvResponse.status !== 201) { - console.log(getTableCsvResponse.text); - } - t.is(getTableCsvResponse.status, 201); - const fileName = `${testTableName}.csv`; - const downloadedFilePatch = join(os.tmpdir(), fileName); - - // eslint-disable-next-line security/detect-non-literal-fs-filename - fs.writeFileSync(downloadedFilePatch, getTableCsvResponse.body); - - // eslint-disable-next-line security/detect-non-literal-fs-filename - const isFileExists = fs.existsSync(downloadedFilePatch); - t.is(isFileExists, true); -}); - -test.serial( - `${currentTest} should return csv file with table data with search, with pagination, with sorting, -with search and pagination: page=1, perPage=2 and DESC sorting`, - async (t) => { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableCsvResponse = await request(app.getHttpServer()) - .post( - `/table/csv/export/${createdConnectionId}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'text/csv') - .set('Accept', 'text/csv'); - - if (getTableCsvResponse.status !== 201) { - console.log(getTableCsvResponse.text); - } - t.is(getTableCsvResponse.status, 201); - const fileName = `${testTableName}.csv`; - const downloadedFilePatch = join(os.tmpdir(), fileName); - - // eslint-disable-next-line security/detect-non-literal-fs-filename - fs.writeFileSync(downloadedFilePatch, getTableCsvResponse.body); - - // eslint-disable-next-line security/detect-non-literal-fs-filename - const isFileExists = fs.existsSync(downloadedFilePatch); - t.is(isFileExists, true); - }, -); - -currentTest = 'POST /table/csv/import/:slug'; -test.serial(`${currentTest} should import csv file with table data`, async (t) => { - const createTableSettingsDTO = mockFactory.generateTableSettings( - createdConnectionId, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createdConnectionId}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createdConnectionId}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableCsvResponse = await request(app.getHttpServer()) - .post( - `/table/csv/export/${createdConnectionId}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'text/csv') - .set('Accept', 'text/csv'); - - if (getTableCsvResponse.status !== 201) { - console.log(getTableCsvResponse.text); - } - t.is(getTableCsvResponse.status, 201); - const fileName = `${testTableName}.csv`; - const downloadedFilePatch = join(os.tmpdir(), fileName); - - // eslint-disable-next-line security/detect-non-literal-fs-filename - fs.writeFileSync(downloadedFilePatch, getTableCsvResponse.body); - // eslint-disable-next-line security/detect-non-literal-fs-filename - const isFileExists = fs.existsSync(downloadedFilePatch); - t.is(isFileExists, true); - - function deleteIdColumnsInCSVFile(filePatch: string) { - // eslint-disable-next-line security/detect-non-literal-fs-filename - const fileContent = fs.readFileSync(filePatch).toString(); - const rows = fileContent.split('\n'); - const idColumnIndex = rows[0].split(',').indexOf('ID'); - const newRows = rows.map((row) => { - const columns = row.split(','); - if (columns.length === 1) { - return row; - } - if (idColumnIndex >= 0) { - columns.splice(idColumnIndex, 1); - } - return columns.join(','); - }); - return newRows.join('\n'); - } - - const newFileContent = deleteIdColumnsInCSVFile(downloadedFilePatch); - // eslint-disable-next-line security/detect-non-literal-fs-filename - fs.writeFileSync(downloadedFilePatch, newFileContent); - - const importCsvResponse = await request(app.getHttpServer()) - .post(`/table/csv/import/${createdConnectionId}?tableName=${testTableName}`) - .attach('file', downloadedFilePatch) - .set('Cookie', firstUserToken) - .set('Accept', 'application/json'); - - t.is(importCsvResponse.status, 201); - //checking that the lines was added - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createdConnectionId}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - t.is(getTableRowsResponse.status, 200); - const addedRows = getTableRowsRO.rows.filter((row: Record) => row.ID > testEntitiesSeedsCount); - t.is(addedRows.length, 2); -}); diff --git a/backend/test/ava-tests/saas-tests/table-ibmdb2-e2e.test.ts b/backend/test/ava-tests/saas-tests/table-ibmdb2-e2e.test.ts deleted file mode 100644 index c984340cf..000000000 --- a/backend/test/ava-tests/saas-tests/table-ibmdb2-e2e.test.ts +++ /dev/null @@ -1,3967 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -/* eslint-disable security/detect-object-injection */ -import { faker } from '@faker-js/faker'; -import { INestApplication, ValidationPipe } from '@nestjs/common'; -import { Test } from '@nestjs/testing'; -import test from 'ava'; -import { ValidationError } from 'class-validator'; -import cookieParser from 'cookie-parser'; -import fs from 'fs'; -import os from 'os'; -import path, { join } from 'path'; -import request from 'supertest'; -import { fileURLToPath } from 'url'; -import { ApplicationModule } from '../../../src/app.module.js'; -import { WinstonLogger } from '../../../src/entities/logging/winston-logger.js'; -import { LogOperationTypeEnum } from '../../../src/enums/log-operation-type.enum.js'; -import { QueryOrderingEnum } from '../../../src/enums/query-ordering.enum.js'; -import { AllExceptionsFilter } from '../../../src/exceptions/all-exceptions.filter.js'; -import { ValidationException } from '../../../src/exceptions/custom-exceptions/validation-exception.js'; -import { Messages } from '../../../src/exceptions/text/messages.js'; -import { Cacher } from '../../../src/helpers/cache/cacher.js'; -import { Constants } from '../../../src/helpers/constants/constants.js'; -import { DatabaseModule } from '../../../src/shared/database/database.module.js'; -import { DatabaseService } from '../../../src/shared/database/database.service.js'; -import { MockFactory } from '../../mock.factory.js'; -import { createTestTable } from '../../utils/create-test-table.js'; -import { getTestData } from '../../utils/get-test-data.js'; -import { registerUserAndReturnUserInfo } from '../../utils/register-user-and-return-user-info.js'; -import { TestUtils } from '../../utils/test.utils.js'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -const mockFactory = new MockFactory(); -let app: INestApplication; -let _testUtils: TestUtils; -const testSearchedUserName = 'Vasia'; -const testTables: Array = []; -let currentTest; - -test.before(async () => { - const moduleFixture = await Test.createTestingModule({ - imports: [ApplicationModule, DatabaseModule], - providers: [DatabaseService, TestUtils], - }).compile(); - app = moduleFixture.createNestApplication(); - _testUtils = moduleFixture.get(TestUtils); - - app.use(cookieParser()); - app.useGlobalFilters(new AllExceptionsFilter(app.get(WinstonLogger))); - app.useGlobalPipes( - new ValidationPipe({ - exceptionFactory(validationErrors: ValidationError[] = []) { - return new ValidationException(validationErrors); - }, - }), - ); - await app.init(); - app.getHttpServer().listen(0); -}); - -test.after(async () => { - try { - await Cacher.clearAllCache(); - await app.close(); - } catch (e) { - console.error('After tests error ' + e); - } -}); - -currentTest = 'GET /connection/tables/:slug'; - -test.serial(`${currentTest} should return list of tables in connection`, async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const getTablesResponse = await request(app.getHttpServer()) - .get(`/connection/tables/${createConnectionRO.id}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTablesResponse.status, 200); - const getTablesRO = JSON.parse(getTablesResponse.text); - - t.is(typeof getTablesRO, 'object'); - t.is(getTablesRO.length > 0, true); - - const testTableIndex = getTablesRO.findIndex((t) => t.table === testTableName); - - t.is(Object.hasOwn(getTablesRO[testTableIndex], 'table'), true); - t.is(Object.hasOwn(getTablesRO[testTableIndex], 'permissions'), true); - t.is(typeof getTablesRO[testTableIndex].permissions, 'object'); - t.is(Object.keys(getTablesRO[testTableIndex].permissions).length, 7); - t.is(getTablesRO[testTableIndex].table, testTableName); - t.is(getTablesRO[testTableIndex].permissions.visibility, true); - t.is(getTablesRO[testTableIndex].permissions.readonly, false); - t.is(getTablesRO[testTableIndex].permissions.add, true); - t.is(getTablesRO[testTableIndex].permissions.delete, true); - t.is(getTablesRO[testTableIndex].permissions.edit, true); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial(`${currentTest} should throw an error when connectionId not passed in request`, async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - createConnectionRO.id = ''; - const getTablesResponse = await request(app.getHttpServer()) - .get(`/connection/tables/${createConnectionRO.id}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTablesResponse.status, 404); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial(`${currentTest} should throw an error when connection id is incorrect`, async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - - t.is(createConnectionResponse.status, 201); - createConnectionRO.id = faker.string.uuid(); - const getTablesResponse = await request(app.getHttpServer()) - .get(`/connection/tables/${createConnectionRO.id}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTablesResponse.status, 400); - const { message } = JSON.parse(getTablesResponse.text); - t.is(message, Messages.CONNECTION_NOT_FOUND); - } catch (e) { - console.error(e); - throw e; - } -}); - -currentTest = 'GET /table/rows/:slug'; - -test.serial(`${currentTest} should return rows of selected table without search and without pagination`, async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testTableSecondColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, Constants.DEFAULT_PAGINATION.perPage); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(Object.hasOwn(getTableRowsRO.rows[0], 'ID'), true); - t.is(Object.hasOwn(getTableRowsRO.rows[1], testTableColumnName), true); - t.is(Object.hasOwn(getTableRowsRO.rows[10], testTableSecondColumnName), true); - t.is(Object.hasOwn(getTableRowsRO.rows[15], 'CREATED_AT'), true); - t.is(Object.hasOwn(getTableRowsRO.rows[19], 'UPDATED_AT'), true); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial(`${currentTest} should return rows of selected table with search and without pagination`, async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testTableSecondColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - ['ID'], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - undefined, - undefined, - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createTableSettingsResponse.status, 201); - - const searchedDescription = '25'; - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&search=${searchedDescription}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(getTableRowsResponse.status, 200); - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 1); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - t.is(getTableRowsRO.rows[0].ID, parseInt(searchedDescription, 10)); - t.is(Object.hasOwn(getTableRowsRO.rows[0], testTableColumnName), true); - t.is(Object.hasOwn(getTableRowsRO.rows[0], testTableSecondColumnName), true); - t.is(Object.hasOwn(getTableRowsRO.rows[0], 'CREATED_AT'), true); - t.is(Object.hasOwn(getTableRowsRO.rows[0], 'UPDATED_AT'), true); - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial(`${currentTest} should return page of all rows with pagination page=1, perPage=2`, async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - ['ID'], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - undefined, - undefined, - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=2`) - .set('Content-Type', 'application/json') - .set('Cookie', firstUserToken) - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(Object.hasOwn(getTableRowsRO.rows[0], 'ID'), true); - t.is(Object.hasOwn(getTableRowsRO.rows[1], testTableColumnName), true); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - t.is(getTableRowsRO.primaryColumns[0].column_name, 'ID'); - t.is(getTableRowsRO.primaryColumns[0].data_type, 'INTEGER'); - - t.is(getTableRowsRO.pagination.total, 42); - t.is(getTableRowsRO.pagination.lastPage, 21); - t.is(getTableRowsRO.pagination.perPage, 2); - t.is(getTableRowsRO.pagination.currentPage, 1); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial(`${currentTest} should return page of all rows with pagination page=3, perPage=2`, async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - ['ID'], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - undefined, - undefined, - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=3&perPage=2`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(Object.hasOwn(getTableRowsRO.rows[0], 'ID'), true); - t.is(Object.hasOwn(getTableRowsRO.rows[1], testTableColumnName), true); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - t.is(getTableRowsRO.primaryColumns[0].column_name, 'ID'); - t.is(getTableRowsRO.primaryColumns[0].data_type, 'INTEGER'); - - t.is(getTableRowsRO.pagination.total, 42); - t.is(getTableRowsRO.pagination.lastPage, 21); - t.is(getTableRowsRO.pagination.perPage, 2); - t.is(getTableRowsRO.pagination.currentPage, 3); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial( - `${currentTest} with search, with pagination, without sorting -should return all found rows with pagination page=1 perPage=2`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - undefined, - undefined, - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - t.is(getTableRowsRO.rows[0][testTableColumnName], testSearchedUserName); - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - t.is(getTableRowsRO.primaryColumns[0].column_name, 'ID'); - t.is(getTableRowsRO.primaryColumns[0].data_type, 'INTEGER'); - - //todo: rework pagination - // t.is(getTableRowsRO.pagination.total, 3); - // t.is(getTableRowsRO.pagination.lastPage, 2); - // t.is(getTableRowsRO.pagination.perPage, 2); - // t.is(getTableRowsRO.pagination.currentPage, 1); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination, without sorting -should return all found rows with pagination page=1 perPage=3`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - undefined, - undefined, - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - t.is(getTableRowsRO.rows[0][testTableColumnName], testSearchedUserName); - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - t.is(getTableRowsRO.primaryColumns[0].column_name, 'ID'); - t.is(getTableRowsRO.primaryColumns[0].data_type, 'INTEGER'); - - //todo: rework pagination - // t.is(getTableRowsRO.pagination.total, 3); - // t.is(getTableRowsRO.pagination.lastPage, 2); - // t.is(getTableRowsRO.pagination.perPage, 2); - // t.is(getTableRowsRO.pagination.currentPage, 1); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} without search and without pagination and with sorting -should return all found rows with sorting ids by DESC`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 42, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - t.is(getTableRowsResponse.status, 200); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 42); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 42); - t.is(getTableRowsRO.rows[1].ID, 41); - t.is(getTableRowsRO.rows[41].ID, 1); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} without search and without pagination and with sorting -should return all found rows with sorting ids by ASC`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 42, - QueryOrderingEnum.ASC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 42); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 1); - t.is(getTableRowsRO.rows[1].ID, 2); - t.is(getTableRowsRO.rows[41].ID, 42); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} without search and with pagination and with sorting -should return all found rows with sorting ports by DESC and with pagination page=1, perPage=2`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=2`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 42); - t.is(getTableRowsRO.rows[1].ID, 41); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} should return all found rows with sorting ports by ASC and with pagination page=1, perPage=2`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.ASC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=2`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 1); - t.is(getTableRowsRO.rows[1].ID, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} should return all found rows with sorting ports by DESC and with pagination page=2, perPage=3`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=2&perPage=3`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 3); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 39); - t.is(getTableRowsRO.rows[1].ID, 38); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination and with sorting -should return all found rows with search, pagination: page=1, perPage=2 and DESC sorting`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=2&search=${testSearchedUserName}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 38); - t.is(getTableRowsRO.rows[1].ID, 22); - t.is(getTableRowsRO.pagination.currentPage, 1); - t.is(getTableRowsRO.pagination.perPage, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination and with sorting -should return all found rows with search, pagination: page=2, perPage=2 and DESC sorting`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=2&perPage=2&search=${testSearchedUserName}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 1); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 1); - t.is(getTableRowsRO.pagination.currentPage, 2); - t.is(getTableRowsRO.pagination.perPage, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination and with sorting -should return all found rows with search, pagination: page=1, perPage=2 and ASC sorting`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.ASC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=2&search=${testSearchedUserName}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 1); - t.is(getTableRowsRO.rows[1].ID, 22); - t.is(getTableRowsRO.pagination.currentPage, 1); - t.is(getTableRowsRO.pagination.perPage, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination and with sorting -should return all found rows with search, pagination: page=2, perPage=2 and ASC sorting`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.ASC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=2&perPage=2&search=${testSearchedUserName}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 1); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - t.is(getTableRowsRO.rows[0].ID, 38); - t.is(getTableRowsRO.pagination.currentPage, 2); - t.is(getTableRowsRO.pagination.perPage, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination, with sorting and with filtering -should return all found rows with search, pagination: page=1, perPage=2 and DESC sorting and filtering`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = 'ID'; - const fieldvalue = '45'; - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2&f_${fieldname}__lt=${fieldvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 2); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - - t.is(getTableRowsRO.rows[0][testTableColumnName], testSearchedUserName); - t.is(getTableRowsRO.rows[0].ID, 38); - t.is(getTableRowsRO.rows[1][testTableColumnName], testSearchedUserName); - t.is(getTableRowsRO.rows[1].ID, 22); - - t.is(getTableRowsRO.pagination.currentPage, 1); - t.is(getTableRowsRO.pagination.perPage, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination, with sorting and with filtering -should return all found rows with search, pagination: page=1, perPage=10 and DESC sorting and filtering'`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = 'ID'; - const fieldvalue = '41'; - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=10&f_${fieldname}__lt=${fieldvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 3); - t.is(Object.keys(getTableRowsRO.rows[1]).length, 5); - - t.is(getTableRowsRO.rows[0][testTableColumnName], testSearchedUserName); - t.is(getTableRowsRO.rows[0].ID, 38); - t.is(getTableRowsRO.rows[1][testTableColumnName], testSearchedUserName); - t.is(getTableRowsRO.rows[1].ID, 22); - t.is(getTableRowsRO.rows[2][testTableColumnName], testSearchedUserName); - t.is(getTableRowsRO.rows[2].ID, 1); - - t.is(getTableRowsRO.pagination.currentPage, 1); - t.is(getTableRowsRO.pagination.perPage, 10); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination, with sorting and with filtering -should return all found rows with search, pagination: page=2, perPage=2 and DESC sorting and filtering`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = 'ID'; - const fieldvalue = '41'; - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&search=${testSearchedUserName}&page=2&perPage=2&f_${fieldname}__lt=${fieldvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 1); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - - t.is(getTableRowsRO.rows[0][testTableColumnName], testSearchedUserName); - t.is(getTableRowsRO.rows[0].ID, 1); - - t.is(getTableRowsRO.pagination.currentPage, 2); - t.is(getTableRowsRO.pagination.perPage, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial( - `${currentTest} with search, with pagination, with sorting and with filtering -should return all found rows with search, pagination: page=1, perPage=2 and DESC sorting and with multi filtering`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = 'ID'; - const fieldGtvalue = '25'; - const fieldLtvalue = '40'; - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2&f_${fieldname}__lt=${fieldLtvalue}&f_${fieldname}__gt=${fieldGtvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(typeof getTableRowsRO, 'object'); - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - t.is(getTableRowsRO.rows.length, 1); - t.is(Object.keys(getTableRowsRO.rows[0]).length, 5); - - t.is(getTableRowsRO.rows[0].ID, 38); - t.is(getTableRowsRO.rows[0][testTableColumnName], testSearchedUserName); - - t.is(getTableRowsRO.pagination.currentPage, 1); - t.is(getTableRowsRO.pagination.perPage, 2); - - t.is(typeof getTableRowsRO.primaryColumns, 'object'); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'column_name'), true); - t.is(Object.hasOwn(getTableRowsRO.primaryColumns[0], 'data_type'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -test.serial(`${currentTest} should throw an exception when connection id is not passed in request`, async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = 'ID'; - const fieldGtvalue = '25'; - const fieldLtvalue = '40'; - createConnectionRO.id = ''; - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2&f_${fieldname}__lt=${fieldLtvalue}&f_${fieldname}__gt=${fieldGtvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 404); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial(`${currentTest} should throw an exception when connection id passed in request is incorrect`, async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = 'ID'; - const fieldGtvalue = '25'; - const fieldLtvalue = '40'; - - createConnectionRO.id = faker.string.uuid(); - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2&f_${fieldname}__lt=${fieldLtvalue}&f_${fieldname}__gt=${fieldGtvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 403); - - const { message } = JSON.parse(getTableRowsResponse.text); - - t.is(message, Messages.DONT_HAVE_PERMISSIONS); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial(`${currentTest} should throw an exception when table name passed in request is incorrect`, async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = 'ID'; - const fieldGtvalue = '25'; - const fieldLtvalue = '40'; - - const fakeTableName = `${faker.lorem.words(1)}_${faker.string.uuid()}`; - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${fakeTableName}&search=${testSearchedUserName}&page=1&perPage=2&f_${fieldname}__lt=${fieldLtvalue}&f_${fieldname}__gt=${fieldGtvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 400); - - const { message } = JSON.parse(getTableRowsResponse.text); - - t.is(message, Messages.TABLE_NOT_FOUND); - } catch (e) { - console.error(e); - throw e; - } -}); - -test.serial( - `${currentTest} should return an array with searched fields when filtered name passed in request is incorrect`, - async (t) => { - try { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName } = await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const fieldname = faker.lorem.words(1); - const fieldGtvalue = '25'; - const fieldLtvalue = '40'; - - const getTableRowsResponse = await request(app.getHttpServer()) - .get( - `/table/rows/${createConnectionRO.id}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2&f_${fieldname}__lt=${fieldLtvalue}&f_${fieldname}__gt=${fieldGtvalue}`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTablesRO = JSON.parse(getTableRowsResponse.text); - t.is(getTablesRO.rows.length, 2); - t.is(getTablesRO.rows[0][testTableColumnName], testSearchedUserName); - t.is(getTablesRO.rows[1][testTableColumnName], testSearchedUserName); - t.is(Object.hasOwn(getTablesRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTablesRO, 'pagination'), true); - } catch (e) { - console.error(e); - throw e; - } - }, -); - -currentTest = 'GET /table/structure/:slug'; -test.serial(`${currentTest} should return table structure`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const getTableStructure = await request(app.getHttpServer()) - .get(`/table/structure/${createConnectionRO.id}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableStructure.status, 200); - const getTableStructureRO = JSON.parse(getTableStructure.text); - - t.is(typeof getTableStructureRO, 'object'); - t.is(typeof getTableStructureRO.structure, 'object'); - t.is(getTableStructureRO.structure.length, 5); - - for (const element of getTableStructureRO.structure) { - t.is(Object.hasOwn(element, 'column_name'), true); - t.is(Object.hasOwn(element, 'column_default'), true); - t.is(Object.hasOwn(element, 'data_type'), true); - t.is(Object.hasOwn(element, 'isExcluded'), true); - t.is(Object.hasOwn(element, 'isSearched'), true); - } - - t.is(Object.hasOwn(getTableStructureRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableStructureRO, 'foreignKeys'), true); - - for (const element of getTableStructureRO.primaryColumns) { - t.is(Object.hasOwn(element, 'column_name'), true); - t.is(Object.hasOwn(element, 'data_type'), true); - } - - for (const element of getTableStructureRO.foreignKeys) { - t.is(Object.hasOwn(element, 'referenced_column_name'), true); - t.is(Object.hasOwn(element, 'referenced_table_name'), true); - t.is(Object.hasOwn(element, 'constraint_name'), true); - t.is(Object.hasOwn(element, 'column_name'), true); - } -}); - -test.serial(`${currentTest} should throw an exception whe connection id not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - createConnectionRO.id = ''; - const getTableStructure = await request(app.getHttpServer()) - .get(`/table/structure/${createConnectionRO.id}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableStructure.status, 404); -}); - -test.serial(`${currentTest} should throw an exception whe connection id passed in request id incorrect`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - createConnectionRO.id = faker.string.uuid(); - const getTableStructure = await request(app.getHttpServer()) - .get(`/table/structure/${createConnectionRO.id}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableStructure.status, 403); - const { message } = JSON.parse(getTableStructure.text); - t.is(message, Messages.DONT_HAVE_PERMISSIONS); -}); - -test.serial(`${currentTest}should throw an exception when tableName not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - const tableName = ''; - const getTableStructure = await request(app.getHttpServer()) - .get(`/table/structure/${createConnectionRO.id}?tableName=${tableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableStructure.status, 400); - const { message } = JSON.parse(getTableStructure.text); - t.is(message, Messages.TABLE_NAME_MISSING); -}); - -test.serial(`${currentTest} should throw an exception when tableName passed in request is incorrect`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - const tableName = faker.lorem.words(1); - const getTableStructure = await request(app.getHttpServer()) - .get(`/table/structure/${createConnectionRO.id}?tableName=${tableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableStructure.status, 400); - const { message } = JSON.parse(getTableStructure.text); - t.is(message, Messages.TABLE_NOT_FOUND); -}); - -currentTest = 'POST /table/row/:slug'; - -test.serial(`${currentTest} should add row in table and return result`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const addRowInTableResponse = await request(app.getHttpServer()) - .post(`/table/row/${createConnectionRO.id}?tableName=${testTableName}`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const addRowInTableRO = JSON.parse(addRowInTableResponse.text); - t.is(addRowInTableResponse.status, 201); - - t.is(Object.hasOwn(addRowInTableRO, 'row'), true); - t.is(Object.hasOwn(addRowInTableRO, 'structure'), true); - t.is(Object.hasOwn(addRowInTableRO, 'foreignKeys'), true); - t.is(Object.hasOwn(addRowInTableRO, 'primaryColumns'), true); - t.is(Object.hasOwn(addRowInTableRO, 'readonly_fields'), true); - t.is(addRowInTableRO.row[testTableColumnName], row[testTableColumnName]); - t.is(addRowInTableRO.row[testTableSecondColumnName], row[testTableSecondColumnName]); - - //checking that the line was added - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 43); - t.is(rows[42][testTableColumnName], row[testTableColumnName]); - t.is(rows[42][testTableSecondColumnName], row[testTableSecondColumnName]); - t.is(rows[42].ID, rows[41].ID + 1); - - // check that rows adding was logged - - const getLogsResponse = await request(app.getHttpServer()) - .get(`/logs/${createConnectionRO.id}?page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(getLogsResponse.status, 200); - const getLogsRO = JSON.parse(getLogsResponse.text); - t.is(Object.hasOwn(getLogsRO, 'logs'), true); - t.is(Object.hasOwn(getLogsRO, 'pagination'), true); - t.is(getLogsRO.logs.length > 0, true); - const addRowLogIndex = getLogsRO.logs.findIndex((log) => log.operationType === 'addRow'); - t.is(Object.hasOwn(getLogsRO.logs[addRowLogIndex], 'affected_primary_key'), true); - t.is(typeof getLogsRO.logs[addRowLogIndex].affected_primary_key, 'object'); - t.is(Object.hasOwn(getLogsRO.logs[addRowLogIndex].affected_primary_key, 'ID'), true); - t.is(getLogsRO.logs[addRowLogIndex].affected_primary_key.ID, 43); -}); - -test.serial(`${currentTest} should throw an exception when connection id is not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - const fakeConnectionId = ''; - const addRowInTableResponse = await request(app.getHttpServer()) - .post(`/table/row/${fakeConnectionId}?tableName=${testTableName}`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(addRowInTableResponse.status, 404); - - //checking that the line wasn't added - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); -}); - -test.serial(`${currentTest} should throw an exception when table name is not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const addRowInTableResponse = await request(app.getHttpServer()) - .post(`/table/row/${createConnectionRO.id}?tableName=`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(addRowInTableResponse.status, 400); - const { message } = JSON.parse(addRowInTableResponse.text); - - t.is(message, Messages.TABLE_NAME_MISSING); - - //checking that the line wasn't added - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); -}); - -test.serial(`${currentTest} should throw an exception when row is not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const addRowInTableResponse = await request(app.getHttpServer()) - .post(`/table/row/${createConnectionRO.id}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(addRowInTableResponse.status, 400); - const { message } = JSON.parse(addRowInTableResponse.text); - - t.is(message, Messages.PARAMETER_MISSING); - - //checking that the line wasn't added - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); -}); - -test.serial(`${currentTest} should throw an exception when table name passed in request is incorrect`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const fakeTableName = `${faker.lorem.words(1)}_${faker.string.uuid()}`; - const addRowInTableResponse = await request(app.getHttpServer()) - .post(`/table/row/${createConnectionRO.id}?tableName=${fakeTableName}`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(addRowInTableResponse.status, 400); - const { message } = JSON.parse(addRowInTableResponse.text); - - t.is(message, Messages.TABLE_NOT_FOUND); - - //checking that the line wasn't added - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); -}); - -currentTest = 'PUT /table/row/:slug'; - -test.serial(`${currentTest} should update row in table and return result`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&ID=1`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const updateRowInTableRO = JSON.parse(updateRowInTableResponse.text); - - t.is(updateRowInTableResponse.status, 200); - t.is(Object.hasOwn(updateRowInTableRO, 'row'), true); - t.is(Object.hasOwn(updateRowInTableRO, 'structure'), true); - t.is(Object.hasOwn(updateRowInTableRO, 'foreignKeys'), true); - t.is(Object.hasOwn(updateRowInTableRO, 'primaryColumns'), true); - t.is(Object.hasOwn(updateRowInTableRO, 'readonly_fields'), true); - t.is(updateRowInTableRO.row[testTableColumnName], row[testTableColumnName]); - t.is(updateRowInTableRO.row[testTableSecondColumnName], row[testTableSecondColumnName]); - - //checking that the line was updated - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - const updateRowIndex = rows.map((row) => row.ID).indexOf(1); - t.is(rows.length, 42); - t.is(rows[updateRowIndex][testTableColumnName], row[testTableColumnName]); - t.is(rows[updateRowIndex][testTableSecondColumnName], row[testTableSecondColumnName]); -}); - -test.serial(`${currentTest} should throw an exception when connection id not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - createConnectionRO.id = ''; - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&ID=1`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(updateRowInTableResponse.status, 404); -}); - -test.serial(`${currentTest} should throw an exception when connection id passed in request is incorrect`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - - t.is(createConnectionResponse.status, 201); - - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - createConnectionRO.id = faker.string.uuid(); - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&ID=1`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(updateRowInTableResponse.status, 403); - const { message } = JSON.parse(updateRowInTableResponse.text); - t.is(message, Messages.DONT_HAVE_PERMISSIONS); -}); - -test.serial(`${currentTest} should throw an exception when tableName not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - createConnectionRO.id = faker.string.uuid(); - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${createConnectionRO.id}?tableName=&ID=1`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(updateRowInTableResponse.status, 400); - const { message } = JSON.parse(updateRowInTableResponse.text); - t.is(message, Messages.TABLE_NAME_MISSING); -}); - -test.serial(`${currentTest} should throw an exception when tableName passed in request is incorrect`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const fakeTableName = faker.string.uuid(); - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${createConnectionRO.id}?tableName=${fakeTableName}&ID=1`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(updateRowInTableResponse.status, 400); - const { message } = JSON.parse(updateRowInTableResponse.text); - t.is(message, Messages.TABLE_NOT_FOUND); -}); - -test.serial(`${currentTest} should throw an exception when primary key not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(updateRowInTableResponse.status, 400); - const { message } = JSON.parse(updateRowInTableResponse.text); - t.is(message, Messages.PRIMARY_KEY_INVALID); -}); - -test.serial( - `${currentTest} should throw an exception when primary key passed in request has incorrect field name`, - async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&IncorrectField=1`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(updateRowInTableResponse.status, 400); - const { message } = JSON.parse(updateRowInTableResponse.text); - t.is(message, Messages.PRIMARY_KEY_INVALID); - }, -); - -test.serial( - `${currentTest} should throw an exception when primary key passed in request has incorrect field value`, - async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const row = { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }; - - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&ID=100000000`) - .send(JSON.stringify(row)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(updateRowInTableResponse.status, 400); - const { message } = JSON.parse(updateRowInTableResponse.text); - t.is(message, Messages.ROW_PRIMARY_KEY_NOT_FOUND); - }, -); - -currentTest = 'PUT /table/rows/update/:connectionId'; - -test.serial(`${currentTest} should update multiple rows and return result`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const fakeName = faker.person.firstName(); - const fakeMail = faker.internet.email(); - - const requestData = { - primaryKeys: [{ ID: 1 }, { ID: 2 }], - newValues: { - [testTableColumnName]: fakeName, - [testTableSecondColumnName]: fakeMail, - }, - }; - - const updateRowInTableResponse = await request(app.getHttpServer()) - .put(`/table/rows/update/${createConnectionRO.id}?tableName=${testTableName}`) - .send(JSON.stringify(requestData)) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const updateRowInTableRO = JSON.parse(updateRowInTableResponse.text); - - t.is(updateRowInTableResponse.status, 200); - t.is(updateRowInTableRO.success, true); - - // check that the rows were updated - const firstRowResponse = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&ID=1`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const firstRow = JSON.parse(firstRowResponse.text); - t.is(firstRowResponse.status, 200); - t.is(firstRow.row[testTableColumnName], fakeName); - t.is(firstRow.row[testTableSecondColumnName], fakeMail); - - const secondRowResponse = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&ID=2`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const secondRow = JSON.parse(secondRowResponse.text); - t.is(secondRowResponse.status, 200); - t.is(secondRow.row[testTableColumnName], fakeName); - t.is(secondRow.row[testTableSecondColumnName], fakeMail); -}); - -currentTest = 'DELETE /table/row/:slug'; - -test.serial(`${currentTest} should delete row in table and return result`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForDeletion = 1; - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&ID=${idForDeletion}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowInTableResponse.status, 200); - const deleteRowInTableRO = JSON.parse(deleteRowInTableResponse.text); - - t.is(Object.hasOwn(deleteRowInTableRO, 'row'), true); - - //checking that the line was deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 41); - const deletedRowIndex = rows.map((row: Record) => row.ID).indexOf(idForDeletion); - t.is(deletedRowIndex < 0, true); -}); - -test.serial(`${currentTest} should throw an exception when connection id not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForDeletion = 1; - const connectionId = ''; - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${connectionId}?tableName=${testTableName}&ID=${idForDeletion}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowInTableResponse.status, 404); - - //checking that the line wasn't deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); - const deletedRowIndex = rows.map((row: Record) => row.ID).indexOf(idForDeletion); - t.is(deletedRowIndex < 0, false); -}); - -test.serial(`${currentTest} should throw an exception when connection id passed in request is incorrect`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForDeletion = 1; - const connectionId = faker.string.uuid(); - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${connectionId}?tableName=${testTableName}&ID=${idForDeletion}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowInTableResponse.status, 403); - const { message } = JSON.parse(deleteRowInTableResponse.text); - t.is(message, Messages.DONT_HAVE_PERMISSIONS); - - //checking that the line wasn't deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); - const deletedRowIndex = rows.map((row: Record) => row.ID).indexOf(idForDeletion); - t.is(deletedRowIndex < 0, false); -}); - -test.serial(`${currentTest} should throw an exception when tableName not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForDeletion = 1; - const fakeTableName = ''; - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${createConnectionRO.id}?tableName=${fakeTableName}&ID=${idForDeletion}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowInTableResponse.status, 400); - const { message } = JSON.parse(deleteRowInTableResponse.text); - t.is(message, Messages.TABLE_NAME_MISSING); - - //checking that the line wasn't deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); - const deletedRowIndex = rows.map((row: Record) => row.ID).indexOf(idForDeletion); - t.is(deletedRowIndex < 0, false); -}); - -test.serial(`${currentTest} should throw an exception when tableName passed in request is incorrect`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForDeletion = 1; - const fakeTableName = `${faker.lorem.words(1)}_${faker.string.uuid()}`; - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${createConnectionRO.id}?tableName=${fakeTableName}&ID=${idForDeletion}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowInTableResponse.status, 400); - const { message } = JSON.parse(deleteRowInTableResponse.text); - t.is(message, Messages.TABLE_NOT_FOUND); - - //checking that the line wasn't deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); - const deletedRowIndex = rows.map((row: Record) => row.ID).indexOf(idForDeletion); - t.is(deletedRowIndex < 0, false); -}); - -test.serial(`${currentTest} should throw an exception when primary key not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForDeletion = 1; - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowInTableResponse.status, 400); - const { message } = JSON.parse(deleteRowInTableResponse.text); - t.is(message, Messages.PRIMARY_KEY_INVALID); - - //checking that the line wasn't deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); - const deletedRowIndex = rows.map((row: Record) => row.ID).indexOf(idForDeletion); - t.is(deletedRowIndex < 0, false); -}); - -test.serial( - `${currentTest} should throw an exception when primary key passed in request has incorrect field name`, - async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForDeletion = 1; - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&fakePKey=1`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowInTableResponse.status, 400); - const { message } = JSON.parse(deleteRowInTableResponse.text); - t.is(message, Messages.PRIMARY_KEY_INVALID); - - //checking that the line wasn't deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, 42); - const deletedRowIndex = rows.map((row: Record) => row.ID).indexOf(idForDeletion); - t.is(deletedRowIndex < 0, false); - }, -); - -test.serial( - `${currentTest} should throw an exception when primary key passed in request has incorrect field value`, - async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const deleteRowInTableResponse = await request(app.getHttpServer()) - .delete(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&ID=100000`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const deleteRowInTableRO = JSON.parse(deleteRowInTableResponse.text); - t.is(deleteRowInTableResponse.status, 400); - t.is(deleteRowInTableRO.message, Messages.ROW_PRIMARY_KEY_NOT_FOUND); - }, -); - -currentTest = 'GET /table/row/:slug'; - -test.serial(`${currentTest} found row`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForSearch = 1; - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&ID=${idForSearch}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 200); - const foundRowInTableRO = JSON.parse(foundRowInTableResponse.text); - t.is(Object.hasOwn(foundRowInTableRO, 'row'), true); - t.is(Object.hasOwn(foundRowInTableRO, 'structure'), true); - t.is(Object.hasOwn(foundRowInTableRO, 'foreignKeys'), true); - t.is(Object.hasOwn(foundRowInTableRO, 'primaryColumns'), true); - t.is(Object.hasOwn(foundRowInTableRO, 'readonly_fields'), true); - t.is(typeof foundRowInTableRO.row, 'object'); - t.is(typeof foundRowInTableRO.structure, 'object'); - t.is(typeof foundRowInTableRO.primaryColumns, 'object'); - t.is(typeof foundRowInTableRO.readonly_fields, 'object'); - t.is(typeof foundRowInTableRO.foreignKeys, 'object'); - t.is(foundRowInTableRO.row.ID, 1); - t.is(foundRowInTableRO.row[testTableColumnName], testSearchedUserName); - t.is(Object.keys(foundRowInTableRO.row).length, 5); -}); - -test.serial(`${currentTest} should throw an exception, when connection id is not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - const idForSearch = 1; - createConnectionRO.id = ''; - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&ID=${idForSearch}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 404); -}); - -test.serial( - `${currentTest} should throw an exception, when connection id passed in request is incorrect`, - async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForSearch = 1; - createConnectionRO.id = faker.string.uuid(); - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&ID=${idForSearch}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 403); - const { message } = JSON.parse(foundRowInTableResponse.text); - t.is(message, Messages.DONT_HAVE_PERMISSIONS); - }, -); - -test.serial(`${currentTest} should throw an exception, when tableName in not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForSearch = 1; - const fakeTableName = ''; - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${fakeTableName}&ID=${idForSearch}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 400); - const { message } = JSON.parse(foundRowInTableResponse.text); - t.is(message, Messages.TABLE_NAME_MISSING); -}); - -test.serial(`${currentTest} should throw an exception, when tableName passed in request is incorrect`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForSearch = 1; - const fakeTableName = `${faker.lorem.words(1)}_${faker.string.uuid()}`; - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${fakeTableName}&ID=${idForSearch}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 400); - const { message } = JSON.parse(foundRowInTableResponse.text); - t.is(message, Messages.TABLE_NOT_FOUND); -}); - -test.serial(`${currentTest} should throw an exception, when primary key is not passed in request`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 400); - const { message } = JSON.parse(foundRowInTableResponse.text); - t.is(message, Messages.PRIMARY_KEY_INVALID); -}); - -test.serial( - `${currentTest} should throw an exception, when primary key passed in request has incorrect name`, - async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForSearch = 1; - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&fakeKeyName=${idForSearch}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 400); - const { message } = JSON.parse(foundRowInTableResponse.text); - t.is(message, Messages.PRIMARY_KEY_INVALID); - }, -); - -test.serial( - `${currentTest} should throw an exception, when primary key passed in request has incorrect value`, - async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const idForSearch = 1000000; - const foundRowInTableResponse = await request(app.getHttpServer()) - .get(`/table/row/${createConnectionRO.id}?tableName=${testTableName}&ID=${idForSearch}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(foundRowInTableResponse.status, 400); - const { message } = JSON.parse(foundRowInTableResponse.text); - t.is(message, Messages.ROW_PRIMARY_KEY_NOT_FOUND); - }, -); - -currentTest = 'PUT /table/rows/delete/:slug'; - -test.serial(`${currentTest} should delete row in table and return result`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - testTables.push(testTableName); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - const primaryKeysForDeletion: Array> = [ - { - ID: 1, - }, - { - ID: 10, - }, - { - ID: 32, - }, - ]; - const deleteRowsInTableResponse = await request(app.getHttpServer()) - .put(`/table/rows/delete/${createConnectionRO.id}?tableName=${testTableName}`) - .send(primaryKeysForDeletion) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(deleteRowsInTableResponse.status, 200); - const _deleteRowInTableRO = JSON.parse(deleteRowsInTableResponse.text); - - //checking that the line was deleted - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(getTableRowsResponse.status, 200); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - - t.is(Object.hasOwn(getTableRowsRO, 'rows'), true); - t.is(Object.hasOwn(getTableRowsRO, 'primaryColumns'), true); - t.is(Object.hasOwn(getTableRowsRO, 'pagination'), true); - // check that lines was deleted - - const { rows, primaryColumns, pagination } = getTableRowsRO; - - t.is(rows.length, testEntitiesSeedsCount - primaryKeysForDeletion.length); - - for (const key of primaryKeysForDeletion) { - t.is( - rows.findIndex((row) => row.ID === key.id), - -1, - ); - } - - // check that table deletaion was logged - const tableLogsResponse = await request(app.getHttpServer()) - .get(`/logs/${createConnectionRO.id}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(tableLogsResponse.status, 200); - - const tableLogsRO = JSON.parse(tableLogsResponse.text); - t.is(tableLogsRO.logs.length, primaryKeysForDeletion.length + 1); - const onlyDeleteLogs = tableLogsRO.logs.filter((log) => log.operationType === LogOperationTypeEnum.deleteRow); - for (const key of primaryKeysForDeletion) { - t.is(onlyDeleteLogs.findIndex((log) => log.received_data.id === key.id) >= 0, true); - } -}); - -test.serial(`${currentTest} should test connection and return result`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const testConnectionResponse = await request(app.getHttpServer()) - .post('/connection/test/') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(testConnectionResponse.status, 201); - const { message } = JSON.parse(testConnectionResponse.text); - t.is(message, 'Successfully connected'); -}); - -currentTest = 'GET table/csv/:slug'; - -test.serial(`${currentTest} should return csv file with table data`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const getTableCsvResponse = await request(app.getHttpServer()) - .post(`/table/csv/export/${createConnectionRO.id}?tableName=${testTableName}`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'text/csv') - .set('Accept', 'text/csv'); - - if (getTableCsvResponse.status !== 201) { - console.log(getTableCsvResponse.text); - } - t.is(getTableCsvResponse.status, 201); - const fileName = `${testTableName}.csv`; - const downloadedFilePatch = join(os.tmpdir(), fileName); - - // eslint-disable-next-line security/detect-non-literal-fs-filename - fs.writeFileSync(downloadedFilePatch, getTableCsvResponse.body); - - // eslint-disable-next-line security/detect-non-literal-fs-filename - const isFileExists = fs.existsSync(downloadedFilePatch); - t.is(isFileExists, true); -}); - -test.serial( - `${currentTest} should return csv file with table data with search, with pagination, with sorting, -with search and pagination: page=1, perPage=2 and DESC sorting`, - async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableCsvResponse = await request(app.getHttpServer()) - .post( - `/table/csv/export/${createConnectionRO.id}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'text/csv') - .set('Accept', 'text/csv'); - - if (getTableCsvResponse.status !== 201) { - console.log(getTableCsvResponse.text); - } - t.is(getTableCsvResponse.status, 201); - const fileName = `${testTableName}.csv`; - const downloadedFilePatch = join(os.tmpdir(), fileName); - - // eslint-disable-next-line security/detect-non-literal-fs-filename - fs.writeFileSync(downloadedFilePatch, getTableCsvResponse.body); - - // eslint-disable-next-line security/detect-non-literal-fs-filename - const isFileExists = fs.existsSync(downloadedFilePatch); - t.is(isFileExists, true); - }, -); - -currentTest = 'POST /table/csv/import/:slug'; -test.serial(`${currentTest} should import csv file with table data`, async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const firstUserToken = (await registerUserAndReturnUserInfo(app)).token; - - const { testTableName, testTableColumnName, testEntitiesSeedsCount, testTableSecondColumnName } = - await createTestTable(connectionToTestDB); - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - - const createTableSettingsDTO = mockFactory.generateTableSettings( - createConnectionRO.id, - testTableName, - [testTableColumnName], - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - const createPersonalTableSettingsDTO = mockFactory.generatePersonalTableSettingsDto( - undefined, - 3, - QueryOrderingEnum.DESC, - 'ID', - ); - - const createPersonalTableSettingsResponse = await request(app.getHttpServer()) - .put(`/settings/personal/${createConnectionRO.id}`) - .query({ tableName: testTableName }) - .send(createPersonalTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - t.is(createPersonalTableSettingsResponse.status, 200); - - const createTableSettingsResponse = await request(app.getHttpServer()) - .post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`) - .send(createTableSettingsDTO) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - t.is(createTableSettingsResponse.status, 201); - - const getTableCsvResponse = await request(app.getHttpServer()) - .post( - `/table/csv/export/${createConnectionRO.id}?tableName=${testTableName}&search=${testSearchedUserName}&page=1&perPage=2`, - ) - .set('Cookie', firstUserToken) - .set('Content-Type', 'text/csv') - .set('Accept', 'text/csv'); - - if (getTableCsvResponse.status !== 201) { - console.log(getTableCsvResponse.text); - } - t.is(getTableCsvResponse.status, 201); - const fileName = `${testTableName}.csv`; - const downloadedFilePatch = join(os.tmpdir(), fileName); - - // eslint-disable-next-line security/detect-non-literal-fs-filename - fs.writeFileSync(downloadedFilePatch, getTableCsvResponse.body); - // eslint-disable-next-line security/detect-non-literal-fs-filename - const isFileExists = fs.existsSync(downloadedFilePatch); - t.is(isFileExists, true); - - function deleteIdColumnsInCSVFile(filePatch: string) { - // eslint-disable-next-line security/detect-non-literal-fs-filename - const fileContent = fs.readFileSync(filePatch).toString(); - const rows = fileContent.split('\n'); - const idColumnIndex = rows[0].split(',').indexOf('ID'); - const newRows = rows.map((row) => { - const columns = row.split(','); - if (columns.length === 1) { - return row; - } - if (idColumnIndex >= 0) { - columns.splice(idColumnIndex, 1); - } - return columns.join(','); - }); - return newRows.join('\n'); - } - - const newFileContent = deleteIdColumnsInCSVFile(downloadedFilePatch); - // eslint-disable-next-line security/detect-non-literal-fs-filename - fs.writeFileSync(downloadedFilePatch, newFileContent); - - const importCsvResponse = await request(app.getHttpServer()) - .post(`/table/csv/import/${createConnectionRO.id}?tableName=${testTableName}`) - .attach('file', downloadedFilePatch) - .set('Cookie', firstUserToken) - .set('Accept', 'application/json'); - - t.is(importCsvResponse.status, 201); - //checking that the lines was added - - const getTableRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=50`) - .set('Cookie', firstUserToken) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - - const getTableRowsRO = JSON.parse(getTableRowsResponse.text); - t.is(getTableRowsResponse.status, 200); - const addedRows = getTableRowsRO.rows.filter((row: Record) => row.ID > testEntitiesSeedsCount); - t.is(addedRows.length, 2); -}); diff --git a/backend/test/ava-tests/saas-tests/table-widgets-e2e.test.ts b/backend/test/ava-tests/saas-tests/table-widgets-e2e.test.ts index 83d69a334..4656aa5fb 100644 --- a/backend/test/ava-tests/saas-tests/table-widgets-e2e.test.ts +++ b/backend/test/ava-tests/saas-tests/table-widgets-e2e.test.ts @@ -7,10 +7,6 @@ import { Test } from '@nestjs/testing'; import test from 'ava'; import { ValidationError } from 'class-validator'; import cookieParser from 'cookie-parser'; -import * as ibmdbNs from 'ibm_db'; - -const ibmdb = ibmdbNs.default as unknown as (options?: import('ibm_db').Options) => import('ibm_db').Database; - import JSON5 from 'json5'; import { MongoClient } from 'mongodb'; import request from 'supertest'; @@ -27,7 +23,6 @@ import { DatabaseService } from '../../../src/shared/database/database.service.j import { MockFactory } from '../../mock.factory.js'; import { compareTableWidgetsArrays } from '../../utils/compare-table-widgets-arrays.js'; import { createTestTable } from '../../utils/create-test-table.js'; -import { getRandomTestTableName } from '../../utils/get-random-test-table-name.js'; import { getTestData } from '../../utils/get-test-data.js'; import { getTestKnex } from '../../utils/get-test-knex.js'; import { registerUserAndReturnUserInfo } from '../../utils/register-user-and-return-user-info.js'; @@ -1226,173 +1221,6 @@ test.serial( }, ); -test.serial( - `${currentTest} should return created table widgets for IBMDB2 database and return rows with attached foreign entities info`, - async (t) => { - const connectionToTestDB = getTestData(mockFactory).connectionToIbmDb2; - const { token } = await registerUserAndReturnUserInfo(app); - const firstTableData = await createTestTable(connectionToTestDB); - const connectionParamsCopy = { - ...connectionToTestDB, - }; - if (connectionToTestDB.type === 'mysql') { - connectionParamsCopy.type = 'mysql2'; - } - - const connStr = `DATABASE=${connectionToTestDB.database};HOSTNAME=${connectionToTestDB.host};UID=${connectionToTestDB.username};PWD=${connectionToTestDB.password};PORT=${connectionToTestDB.port};PROTOCOL=TCPIP`; - const ibmDatabase = ibmdb(); - await ibmDatabase.open(connStr); - - const referencedByTableTableName = getRandomTestTableName().toUpperCase(); - const referencedColumnName = 'REFERENCED_ON_ID'; - - const queryCheckSchemaExists = `SELECT COUNT(*) FROM SYSCAT.SCHEMATA WHERE SCHEMANAME = '${connectionToTestDB.schema}'`; - const schemaExists = await ibmDatabase.query(queryCheckSchemaExists); - - if (!schemaExists.length || !schemaExists[0]['1']) { - const queryCreateSchema = `CREATE SCHEMA ${connectionToTestDB.schema}`; - try { - await ibmDatabase.query(queryCreateSchema); - } catch (error) { - console.error(`Error while creating schema: ${error}`); - console.info(`Query: ${queryCreateSchema}`); - } - } - - const queryCheckTableExists = `SELECT COUNT(*) FROM SYSCAT.TABLES WHERE TABNAME = '${referencedByTableTableName}' AND TABSCHEMA = '${connectionToTestDB.schema}'`; - const tableExists = await ibmDatabase.query(queryCheckTableExists); - - if (tableExists.length && tableExists[0]['1']) { - await ibmDatabase.query(`DROP TABLE ${connectionToTestDB.schema}.${referencedByTableTableName}`); - } - - const testColumnName = `product_description`; - const query = ` - CREATE TABLE ${connectionToTestDB.schema}.${referencedByTableTableName} ( - id INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1), - ${referencedColumnName} INTEGER, - ${testColumnName} VARCHAR(255), - created_at TIMESTAMP DEFAULT CURRENT TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT TIMESTAMP, - PRIMARY KEY (id) - )`; - - try { - await ibmDatabase.query(query); - } catch (error) { - console.error(`Error while creating table: ${error}`); - console.info(`Query: ${query}`); - } - - for (let index = 0; index < 42; index++) { - const insertQuery = `INSERT INTO ${ - connectionToTestDB.schema - }.${referencedByTableTableName} (${referencedColumnName}, ${testColumnName}, created_at, updated_at) VALUES (${faker.number.int({ min: 1, max: 42 })}, '${faker.lorem.words(1).replace(/["']/g, '')}', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)`; - - await ibmDatabase.query(insertQuery); - } - - const foreignKeyWidgetsDTO: CreateOrUpdateTableWidgetsDto = { - widgets: [ - { - widget_type: WidgetTypeEnum.Foreign_key, - widget_params: JSON.stringify({ - referenced_column_name: 'ID', - referenced_table_name: firstTableData.testTableName, - constraint_name: 'manually_created_constraint', - column_name: referencedColumnName, - }), - field_name: referencedColumnName, - description: 'User ID as foreign key', - name: 'User ID', - widget_options: JSON.stringify({}), - }, - ], - }; - - const createConnectionResponse = await request(app.getHttpServer()) - .post('/connection') - .send(connectionToTestDB) - .set('Cookie', token) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json'); - const createConnectionRO = JSON.parse(createConnectionResponse.text); - t.is(createConnectionResponse.status, 201); - const connectionId = createConnectionRO.id; - - const findTablesResponse = await request(app.getHttpServer()) - .get(`/connection/tables/${connectionId}`) - .set('Content-Type', 'application/json') - .set('Cookie', token) - .set('Accept', 'application/json'); - const _findTablesRO = JSON.parse(findTablesResponse.text); - t.is(findTablesResponse.status, 200); - - const createTableWidgetResponse = await request(app.getHttpServer()) - .post(`/widget/${connectionId}?tableName=${referencedByTableTableName}`) - .send(foreignKeyWidgetsDTO) - .set('Content-Type', 'application/json') - .set('Cookie', token) - .set('Accept', 'application/json'); - - const _createTableWidgetRO = JSON.parse(createTableWidgetResponse.text); - t.is(createTableWidgetResponse.status, 201); - - const getTableWidgets = await request(app.getHttpServer()) - .get(`/widgets/${connectionId}?tableName=${referencedByTableTableName}`) - .set('Content-Type', 'application/json') - .set('Cookie', token) - .set('Accept', 'application/json'); - t.is(getTableWidgets.status, 200); - const getTableWidgetsRO = JSON.parse(getTableWidgets.text); - t.is(typeof getTableWidgetsRO, 'object'); - t.is(getTableWidgetsRO.length, 1); - - t.is(getTableWidgetsRO[0].widget_type, foreignKeyWidgetsDTO.widgets[0].widget_type); - - const getTableStructureResponse = await request(app.getHttpServer()) - .get(`/table/structure/${connectionId}?tableName=${referencedByTableTableName}`) - .set('Content-Type', 'application/json') - .set('Cookie', token) - .set('Accept', 'application/json'); - - const getTableStructureRO = JSON.parse(getTableStructureResponse.text); - t.is(getTableStructureResponse.status, 200); - t.is(Object.hasOwn(getTableStructureRO, 'table_widgets'), true); - t.is(getTableStructureRO.table_widgets.length, 1); - t.is(getTableStructureRO.table_widgets[0].field_name, foreignKeyWidgetsDTO.widgets[0].field_name); - t.is(getTableStructureRO.table_widgets[0].widget_type, foreignKeyWidgetsDTO.widgets[0].widget_type); - t.is(Object.hasOwn(getTableStructureRO, 'foreignKeys'), true); - t.is(getTableStructureRO.foreignKeys.length, 1); - t.is(getTableStructureRO.foreignKeys[0].column_name, foreignKeyWidgetsDTO.widgets[0].field_name); - t.is(getTableStructureRO.foreignKeys[0].referenced_table_name, firstTableData.testTableName); - const widgetParams = JSON5.parse(getTableStructureRO.table_widgets[0].widget_params); - t.is(widgetParams.referenced_table_name, firstTableData.testTableName); - t.is(widgetParams.referenced_column_name, 'ID'); - t.is(widgetParams.constraint_name, 'manually_created_constraint'); - t.is(widgetParams.column_name, referencedColumnName); - t.is(Object.hasOwn(getTableStructureRO.foreignKeys[0], 'autocomplete_columns'), true); - t.is(getTableStructureRO.foreignKeys[0].autocomplete_columns.length, 5); - - // check table rows received with foreign keys from widget - - const getRowsResponse = await request(app.getHttpServer()) - .get(`/table/rows/${connectionId}?tableName=${referencedByTableTableName}`) - .set('Content-Type', 'application/json') - .set('Cookie', token) - .set('Accept', 'application/json'); - const getRowsRO = JSON.parse(getRowsResponse.text); - t.is(getRowsResponse.status, 200); - - t.is(typeof getRowsRO.rows[0], 'object'); - for (const row of getRowsRO.rows) { - t.is(Object.hasOwn(row, 'ID'), true); - t.is(Object.hasOwn(row, referencedColumnName), true); - t.is(Object.hasOwn(row[referencedColumnName], 'ID'), true); - } - }, -); - // Table widgets for mongodb database test.serial( `${currentTest} should return created table widgets as foreign keys, when database is mongodb`, diff --git a/backend/test/mock.factory.ts b/backend/test/mock.factory.ts index ecc3deb3b..9b55cd6f4 100644 --- a/backend/test/mock.factory.ts +++ b/backend/test/mock.factory.ts @@ -278,20 +278,6 @@ export class MockFactory { return dto; } - generateConnectionToTestDbIbmDb2() { - const dto = new CreateConnectionDto() as any; - dto.title = 'Test connection to cli db ibm db2'; - dto.type = ConnectionTypesEnum.ibmdb2; - dto.host = 'test-ibm-db2-e2e-testing'; - dto.port = 50000; - dto.username = 'db2inst1'; - dto.password = 'password'; - dto.database = 'testdb'; - dto.schema = 'SCHEMA_NAME'; - dto.ssh = false; - return dto; - } - generateConnectionToTestElasticsearchInDocker() { const dto = new CreateConnectionDto() as any; dto.title = 'Test connection to Elasticsearch in Docker'; @@ -387,13 +373,6 @@ export class MockFactory { return dto; } - generateConnectionToTestDbIbmDb2Agent() { - const dto = new CreateConnectionDto() as any; - dto.title = 'Test connection to agent db'; - dto.type = ConnectionTypesEnum.agent_ibmdb2; - return dto; - } - generateUpdateConnectionDto() { const dto = new CreateConnectionDto() as any; dto.title = 'Updated Test Connection'; diff --git a/backend/test/utils/create-test-table.ts b/backend/test/utils/create-test-table.ts index daa9a6965..a0535f51a 100644 --- a/backend/test/utils/create-test-table.ts +++ b/backend/test/utils/create-test-table.ts @@ -7,10 +7,6 @@ import { Client } from '@elastic/elasticsearch'; import { faker } from '@faker-js/faker'; import { ConnectionTypesEnum } from '@rocketadmin/shared-code/dist/src/shared/enums/connection-types-enum.js'; import * as cassandra from 'cassandra-driver'; -import * as ibmdbNs from 'ibm_db'; - -const ibmdb = ibmdbNs.default as unknown as (options?: import('ibm_db').Options) => import('ibm_db').Database; - import { MongoClient } from 'mongodb'; import { createClient } from 'redis'; import { v4 as uuidv4 } from 'uuid'; @@ -24,10 +20,6 @@ export async function createTestTable( withJsonField = false, withWidgetsData = false, ): Promise { - if (connectionParams.type === ConnectionTypesEnum.ibmdb2) { - return createTestTableIbmDb2(connectionParams, testEntitiesSeedsCount, testSearchedUserName); - } - if (connectionParams.type === ConnectionTypesEnum.mongodb) { return createTestMongoTable(connectionParams, testEntitiesSeedsCount, testSearchedUserName); } @@ -212,87 +204,6 @@ async function createTestElasticsearchTable( }; } -async function createTestTableIbmDb2( - connectionParams: any, - testEntitiesSeedsCount = 42, - testSearchedUserName = 'Vasia', -): Promise { - const testTableName = getRandomTestTableName().toUpperCase(); - const testTableColumnName = `${faker.lorem.words(1)}_${faker.lorem.words(1)}`.replace(/[-@]/g, '').toUpperCase(); - const testTableSecondColumnName = `${faker.lorem.words(1)}_${faker.lorem.words(1)}` - .replace(/[-@]/g, '') - .toUpperCase(); - const connStr = `DATABASE=${connectionParams.database};HOSTNAME=${connectionParams.host};UID=${connectionParams.username};PWD=${connectionParams.password};PORT=${connectionParams.port};PROTOCOL=TCPIP`; - - const ibmDatabase = ibmdb(); - await ibmDatabase.open(connStr); - const queryCheckSchemaExists = `SELECT COUNT(*) FROM SYSCAT.SCHEMATA WHERE SCHEMANAME = '${connectionParams.schema}'`; - const schemaExists = await ibmDatabase.query(queryCheckSchemaExists); - - if (!schemaExists.length || !schemaExists[0]['1']) { - const queryCreateSchema = `CREATE SCHEMA ${connectionParams.schema}`; - try { - await ibmDatabase.query(queryCreateSchema); - } catch (error) { - console.error(`Error while creating schema: ${error}`); - console.info(`Query: ${queryCreateSchema}`); - } - } - - const queryCheckTableExists = `SELECT COUNT(*) FROM SYSCAT.TABLES WHERE TABNAME = '${testTableName}' AND TABSCHEMA = '${connectionParams.schema}'`; - const tableExists = await ibmDatabase.query(queryCheckTableExists); - - if (tableExists.length && tableExists[0]['1']) { - await ibmDatabase.query(`DROP TABLE ${connectionParams.schema}.${testTableName}`); - } - - const query = ` - CREATE TABLE ${connectionParams.schema}.${testTableName} ( - id INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1), - ${testTableColumnName} VARCHAR(255), - ${testTableSecondColumnName} VARCHAR(255), - created_at TIMESTAMP DEFAULT CURRENT TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT TIMESTAMP, - PRIMARY KEY (id) -)`; - - try { - await ibmDatabase.query(query); - } catch (error) { - console.error(`Error while creating table: ${error}`); - console.info(`Query: ${query}`); - } - - const valueTuples: Array = []; - for (let i = 0; i < testEntitiesSeedsCount; i++) { - if (i === 0 || i === testEntitiesSeedsCount - 21 || i === testEntitiesSeedsCount - 5) { - valueTuples.push( - `('${testSearchedUserName}', '${faker.internet.email().replace(/["']/g, '')}', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)`, - ); - } else { - valueTuples.push( - `('${faker.person.firstName().replace(/["']/g, '')}', '${faker.internet.email().replace(/["']/g, '')}', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)`, - ); - } - } - if (valueTuples.length > 0) { - const batchSize = 100; - for (let start = 0; start < valueTuples.length; start += batchSize) { - const chunk = valueTuples.slice(start, start + batchSize); - await ibmDatabase.query( - `INSERT INTO ${connectionParams.schema}.${testTableName} (${testTableColumnName}, ${testTableSecondColumnName}, created_at, updated_at) VALUES ${chunk.join(', ')}`, - ); - } - } - - return { - testTableName: testTableName, - testTableColumnName: testTableColumnName, - testTableSecondColumnName: testTableSecondColumnName, - testEntitiesSeedsCount: testEntitiesSeedsCount, - }; -} - async function createTestMongoTable( connectionParams, testEntitiesSeedsCount, diff --git a/backend/test/utils/get-test-data.ts b/backend/test/utils/get-test-data.ts index ba62f6884..4673a56de 100644 --- a/backend/test/utils/get-test-data.ts +++ b/backend/test/utils/get-test-data.ts @@ -22,8 +22,6 @@ export function getTestData(mockFactory: MockFactory) { const oracleAgentConnection = mockFactory.generateConnectionToTestDbOracleAgent(); const mysqlAgentConnection = mockFactory.generateConnectionToTestDbMysqlAgent(); const mssqlAgentConnection = mockFactory.generateConnectionToTestDbMssqlAgent(); - const connectionToIbmDb2 = mockFactory.generateConnectionToTestDbIbmDb2(); - const connectionToAgentIbmDB2 = mockFactory.generateConnectionToTestDbIbmDb2Agent(); const mongoDbConnection = mockFactory.generateConnectionToTestMongoDBInDocker(); const mongoDbAgentConnection = mockFactory.generateConnectionToTestMongoDBAgent(); const dynamoDBConnection = mockFactory.generateConnectionToTestDynamoDBInDocker(); @@ -56,8 +54,6 @@ export function getTestData(mockFactory: MockFactory) { oracleAgentConnection, mysqlAgentConnection, mssqlAgentConnection, - connectionToIbmDb2, - connectionToAgentIbmDB2, mongoDbConnection, mongoDbAgentConnection, dynamoDBConnection, diff --git a/backend/test/utils/test-utilities/create-test-ibmdb2-tables.ts b/backend/test/utils/test-utilities/create-test-ibmdb2-tables.ts deleted file mode 100644 index 2c52dfd15..000000000 --- a/backend/test/utils/test-utilities/create-test-ibmdb2-tables.ts +++ /dev/null @@ -1,573 +0,0 @@ -import * as ibmdbNs from 'ibm_db'; - -const ibmdb = ibmdbNs.default as unknown as (options?: import('ibm_db').Options) => import('ibm_db').Database; - -import { TableCreationResult } from '../../ava-tests/complex-table-tests/complex-ibmdb2-table-e2e.test.js'; - -export const createTestIBMDB2TablesWithComplexPFKeys = async (connectionParams: any): Promise => { - const mainTableName = 'ORDERS_COMPLEX'; - const firstReferencedTableName = 'ORDER_ITEMS_COMPLEX'; - const referencedOnTableName = 'SHIPMENTS_COMPLEX'; - - // Create main_table - // await knex.schema.createTable(mainTableName, (table) => { - // table.integer('order_id').notNullable(); - // table.integer('customer_id').notNullable(); - // table.date('order_date'); - // table.string('status', 20); - // table.decimal('total_amount', 10, 2); - // table.primary(['order_id', 'customer_id']); - // }); - - // // Create first_referenced_table - // const firstReferencedTableQuery = knex.schema.createTable(firstReferencedTableName, (table) => { - // table.integer('order_id').notNullable(); - // table.integer('customer_id').notNullable(); - // table.increments('item_id').primary(); - // table.string('product_name', 100); - // table.integer('quantity'); - // table.decimal('price_per_unit', 10, 2); - // table - // .foreign(['order_id', 'customer_id']) - // .references(['order_id', 'customer_id']) - // .inTable(mainTableName) - // .onDelete('CASCADE'); - // }); - // await firstReferencedTableQuery; - - // // Create second_referenced_table - // await knex.schema.createTable(referencedOnTableName, (table) => { - // table.increments('shipment_id').primary(); - // table.integer('order_id'); - // table.integer('customer_id'); - // table.date('shipped_date'); - // table.string('carrier', 50); - // table.string('tracking_number', 100); - // table - // .foreign(['order_id', 'customer_id']) - // .references(['order_id', 'customer_id']) - // .inTable(mainTableName) - // .onDelete('SET NULL'); - // }); - - const connStr = `DATABASE=${connectionParams.database};HOSTNAME=${connectionParams.host};UID=${connectionParams.username};PWD=${connectionParams.password};PORT=${connectionParams.port};PROTOCOL=TCPIP`; - - const ibmDatabase = ibmdb(); - await ibmDatabase.open(connStr); - const queryCheckSchemaExists = `SELECT COUNT(*) FROM SYSCAT.SCHEMATA WHERE SCHEMANAME = '${connectionParams.schema}'`; - const schemaExists = await ibmDatabase.query(queryCheckSchemaExists); - - if (!schemaExists.length || !schemaExists[0]['1']) { - const queryCreateSchema = `CREATE SCHEMA ${connectionParams.schema}`; - try { - await ibmDatabase.query(queryCreateSchema); - } catch (error) { - console.error(`Error while creating schema: ${error}`); - console.info(`Query: ${queryCreateSchema}`); - } - } - - const queryCheckFirstTableExists = `SELECT COUNT(*) FROM SYSCAT.TABLES WHERE TABNAME = '${mainTableName}' AND TABSCHEMA = '${connectionParams.schema}'`; - const queryCheckSecondTableExists = `SELECT COUNT(*) FROM SYSCAT.TABLES WHERE TABNAME = '${firstReferencedTableName}' AND TABSCHEMA = '${connectionParams.schema}'`; - const queryCheckThirdTableExists = `SELECT COUNT(*) FROM SYSCAT.TABLES WHERE TABNAME = '${referencedOnTableName}' AND TABSCHEMA = '${connectionParams.schema}'`; - - const firstTableExists = await ibmDatabase.query(queryCheckFirstTableExists); - const secondTableExists = await ibmDatabase.query(queryCheckSecondTableExists); - const thirdTableExists = await ibmDatabase.query(queryCheckThirdTableExists); - - if (thirdTableExists.length && thirdTableExists[0]['1']) { - await ibmDatabase.query(`DROP TABLE ${connectionParams.schema}.${thirdTableExists}`); - } - if (secondTableExists.length && secondTableExists[0]['1']) { - await ibmDatabase.query(`DROP TABLE ${connectionParams.schema}.${firstReferencedTableName}`); - } - if (firstTableExists.length && firstTableExists[0]['1']) { - await ibmDatabase.query(`DROP TABLE ${connectionParams.schema}.${mainTableName}`); - } - - const queryCreateMainTable = ` - CREATE TABLE ${connectionParams.schema}.${mainTableName} ( - order_id INT NOT NULL, - customer_id INT NOT NULL, - order_date DATE, - status VARCHAR(20), - total_amount DECIMAL(10, 2), - PRIMARY KEY (order_id, customer_id) - ) - `; - - const queryCreateFirstReferencedTable = ` - CREATE TABLE ${connectionParams.schema}.${firstReferencedTableName} ( - order_id INT NOT NULL, - customer_id INT NOT NULL, - item_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, - product_name VARCHAR(100), - quantity INT, - price_per_unit DECIMAL(10, 2), - FOREIGN KEY (order_id, customer_id) REFERENCES ${connectionParams.schema}.${mainTableName}(order_id, customer_id) ON DELETE CASCADE - ) - `; - - const queryCreateSecondReferencedTable = ` - CREATE TABLE ${connectionParams.schema}.${referencedOnTableName} ( - shipment_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, - order_id INT, - customer_id INT, - shipped_date DATE, - carrier VARCHAR(50), - tracking_number VARCHAR(100), - FOREIGN KEY (order_id, customer_id) REFERENCES ${connectionParams.schema}.${mainTableName}(order_id, customer_id) ON DELETE SET NULL - ) - `; - - try { - await ibmDatabase.query(queryCreateMainTable); - await ibmDatabase.query(queryCreateFirstReferencedTable); - await ibmDatabase.query(queryCreateSecondReferencedTable); - } catch (error) { - console.error(`Error while creating tables: ${error}`); - console.info(`Queries: - ${queryCreateMainTable} - ${queryCreateFirstReferencedTable} - ${queryCreateSecondReferencedTable} - `); - } - - // populate tables with test data - - const insertMainTableData = ` - INSERT INTO ${connectionParams.schema}.${mainTableName} (order_id, customer_id, order_date, status, total_amount) VALUES - (1, 101, '2023-01-15', 'Shipped', 250.75), - (2, 102, '2023-01-16', 'Processing', 150.50), - (3, 103, '2023-01-17', 'Delivered', 300.00), - (4, 104, '2023-01-18', 'Pending', 425.30), - (5, 105, '2023-01-19', 'Shipped', 189.99), - (6, 106, '2023-01-20', 'Cancelled', 75.25), - (7, 107, '2023-01-21', 'Processing', 550.00), - (8, 108, '2023-01-22', 'Delivered', 399.50), - (9, 109, '2023-01-23', 'Shipped', 275.80), - (10, 110, '2023-01-24', 'Processing', 680.45), - (11, 111, '2023-01-25', 'Shipped', 320.15), - (12, 112, '2023-01-26', 'Delivered', 445.90), - (13, 113, '2023-01-27', 'Pending', 199.99), - (14, 114, '2023-01-28', 'Processing', 525.30), - (15, 115, '2023-01-29', 'Shipped', 289.75), - (16, 116, '2023-01-30', 'Cancelled', 95.50), - (17, 117, '2023-01-31', 'Delivered', 610.20), - (18, 118, '2023-02-01', 'Processing', 375.85), - (19, 119, '2023-02-02', 'Shipped', 455.60), - (20, 120, '2023-02-03', 'Pending', 225.40), - (21, 121, '2023-02-04', 'Delivered', 505.95), - (22, 122, '2023-02-05', 'Processing', 340.25), - (23, 123, '2023-02-06', 'Shipped', 420.80), - (24, 124, '2023-02-07', 'Cancelled', 125.00), - (25, 125, '2023-02-08', 'Delivered', 590.45), - (26, 126, '2023-02-09', 'Processing', 310.70), - (27, 127, '2023-02-10', 'Shipped', 475.30), - (28, 128, '2023-02-11', 'Pending', 265.85), - (29, 129, '2023-02-12', 'Delivered', 535.20), - (30, 130, '2023-02-13', 'Processing', 395.65), - (31, 131, '2023-02-14', 'Shipped', 485.90), - (32, 132, '2023-02-15', 'Cancelled', 155.25), - (33, 133, '2023-02-16', 'Delivered', 625.40), - (34, 134, '2023-02-17', 'Processing', 355.75), - (35, 135, '2023-02-18', 'Shipped', 495.20), - (36, 136, '2023-02-19', 'Pending', 285.95), - (37, 137, '2023-02-20', 'Delivered', 565.30), - (38, 138, '2023-02-21', 'Processing', 415.85), - (39, 139, '2023-02-22', 'Shipped', 515.60), - (40, 140, '2023-02-23', 'Cancelled', 185.40), - (41, 141, '2023-02-24', 'Delivered', 655.75), - (42, 142, '2023-02-25', 'Processing', 435.90) - `; - - const insertFirstReferencedTableData = ` - INSERT INTO ${connectionParams.schema}.${firstReferencedTableName} (order_id, customer_id, product_name, quantity, price_per_unit) VALUES - (1, 101, 'Product A', 2, 50.00), - (2, 102, 'Product B', 3, 30.25), - (3, 103, 'Product C', 4, 75.00), - (4, 104, 'Product D', 5, 85.06), - (5, 105, 'Product E', 2, 94.99), - (6, 106, 'Product F', 1, 75.25), - (7, 107, 'Product G', 3, 183.33), - (8, 108, 'Product H', 6, 66.58), - (9, 109, 'Product I', 4, 68.95), - (10, 110, 'Product J', 7, 97.21), - (11, 111, 'Product K', 2, 160.07), - (12, 112, 'Product L', 5, 89.18), - (13, 113, 'Product M', 3, 66.66), - (14, 114, 'Product N', 4, 131.32), - (15, 115, 'Product O', 2, 144.87), - (16, 116, 'Product P', 1, 95.50), - (17, 117, 'Product Q', 6, 101.70), - (18, 118, 'Product R', 3, 125.28), - (19, 119, 'Product S', 5, 91.12), - (20, 120, 'Product T', 2, 112.70), - (21, 121, 'Product U', 4, 126.48), - (22, 122, 'Product V', 3, 113.41), - (23, 123, 'Product W', 5, 84.16), - (24, 124, 'Product X', 1, 125.00), - (25, 125, 'Product Y', 6, 98.40), - (26, 126, 'Product Z', 2, 155.35), - (27, 127, 'Product AA', 4, 118.82), - (28, 128, 'Product AB', 3, 88.61), - (29, 129, 'Product AC', 5, 107.04), - (30, 130, 'Product AD', 2, 197.82), - (31, 131, 'Product AE', 4, 121.47), - (32, 132, 'Product AF', 1, 155.25), - (33, 133, 'Product AG', 6, 104.23), - (34, 134, 'Product AH', 3, 118.58), - (35, 135, 'Product AI', 5, 99.04), - (36, 136, 'Product AJ', 2, 142.97), - (37, 137, 'Product AK', 4, 141.32), - (38, 138, 'Product AL', 3, 138.61), - (39, 139, 'Product AM', 5, 103.12), - (40, 140, 'Product AN', 1, 185.40), - (41, 141, 'Product AO', 6, 109.29), - (42, 142, 'Product AP', 2, 217.95) - `; - - const insertSecondReferencedTableData = ` - INSERT INTO ${connectionParams.schema}.${referencedOnTableName} (order_id, customer_id, shipped_date, carrier, tracking_number) VALUES - (1, 101, '2023-01-18', 'Carrier X', 'TRACK12345'), - (3, 103, '2023-01-20', 'Carrier Y', 'TRACK67890'), - (5, 105, '2023-01-22', 'Carrier X', 'TRACK11111'), - (8, 108, '2023-01-25', 'Carrier Z', 'TRACK22222'), - (9, 109, '2023-01-26', 'Carrier Y', 'TRACK33333'), - (11, 111, '2023-01-28', 'Carrier X', 'TRACK44444'), - (12, 112, '2023-01-29', 'Carrier Z', 'TRACK55555'), - (15, 115, '2023-02-01', 'Carrier Y', 'TRACK66666'), - (17, 117, '2023-02-03', 'Carrier X', 'TRACK77777'), - (19, 119, '2023-02-05', 'Carrier Z', 'TRACK88888'), - (21, 121, '2023-02-07', 'Carrier Y', 'TRACK99999'), - (23, 123, '2023-02-09', 'Carrier X', 'TRACK10101'), - (25, 125, '2023-02-11', 'Carrier Z', 'TRACK20202'), - (27, 127, '2023-02-13', 'Carrier Y', 'TRACK30303'), - (29, 129, '2023-02-15', 'Carrier X', 'TRACK40404'), - (31, 131, '2023-02-17', 'Carrier Z', 'TRACK50505'), - (33, 133, '2023-02-19', 'Carrier Y', 'TRACK60606'), - (35, 135, '2023-02-21', 'Carrier X', 'TRACK70707'), - (37, 137, '2023-02-23', 'Carrier Z', 'TRACK80808'), - (39, 139, '2023-02-25', 'Carrier Y', 'TRACK90909'), - (41, 141, '2023-02-27', 'Carrier X', 'TRACK11011'), - (1, 101, '2023-01-19', 'Carrier Y', 'TRACK11121'), - (3, 103, '2023-01-21', 'Carrier Z', 'TRACK11131'), - (5, 105, '2023-01-23', 'Carrier X', 'TRACK11141'), - (8, 108, '2023-01-26', 'Carrier Y', 'TRACK11151'), - (9, 109, '2023-01-27', 'Carrier Z', 'TRACK11161'), - (11, 111, '2023-01-29', 'Carrier Y', 'TRACK11171'), - (12, 112, '2023-01-30', 'Carrier X', 'TRACK11181'), - (15, 115, '2023-02-02', 'Carrier Z', 'TRACK11191'), - (17, 117, '2023-02-04', 'Carrier Y', 'TRACK11201'), - (19, 119, '2023-02-06', 'Carrier X', 'TRACK11211'), - (21, 121, '2023-02-08', 'Carrier Z', 'TRACK11221'), - (23, 123, '2023-02-10', 'Carrier Y', 'TRACK11231'), - (25, 125, '2023-02-12', 'Carrier X', 'TRACK11241'), - (27, 127, '2023-02-14', 'Carrier Z', 'TRACK11251'), - (29, 129, '2023-02-16', 'Carrier Y', 'TRACK11261'), - (31, 131, '2023-02-18', 'Carrier X', 'TRACK11271'), - (33, 133, '2023-02-20', 'Carrier Z', 'TRACK11281'), - (35, 135, '2023-02-22', 'Carrier Y', 'TRACK11291'), - (37, 137, '2023-02-24', 'Carrier X', 'TRACK11301'), - (39, 139, '2023-02-26', 'Carrier Z', 'TRACK11311'), - (41, 141, '2023-02-28', 'Carrier Y', 'TRACK11321') - `; - - try { - await ibmDatabase.query(insertMainTableData); - await ibmDatabase.query(insertFirstReferencedTableData); - await ibmDatabase.query(insertSecondReferencedTableData); - } catch (error) { - console.error(`Error while inserting data: ${error}`); - console.info(`Insert Queries: - ${insertMainTableData} - ${insertFirstReferencedTableData} - ${insertSecondReferencedTableData} - `); - } - - await ibmDatabase.close(); - - return { - first_referenced_table: { - table_name: firstReferencedTableName, - column_names: ['ORDER_ID', 'CUSTOMER_ID', 'ITEM_ID', 'PRODUCT_NAME', 'QUANTITY', 'PRICE_PER_UNIT'], - primary_key_column_names: ['ITEM_ID'], - }, - main_table: { - table_name: mainTableName, - column_names: ['ORDER_ID', 'CUSTOMER_ID', 'ORDER_DATE', 'STATUS', 'TOTAL_AMOUNT'], - foreign_key_column_names: [], - binary_column_names: [], - primary_key_column_names: ['ORDER_ID', 'CUSTOMER_ID'], - }, - second_referenced_table: { - table_name: referencedOnTableName, - column_names: ['SHIPMENT_ID', 'ORDER_ID', 'CUSTOMER_ID', 'SHIPPED_DATE', 'CARRIER', 'TRACKING_NUMBER'], - primary_key_column_names: ['SHIPMENT_ID'], - foreign_key_column_names: ['ORDER_ID', 'CUSTOMER_ID'], - }, - }; -}; - -export const createTestIBMDB2TablesWithSimplePFKeys = async (connectionParams: any): Promise => { - const mainTableName = 'ORDERS_SIMPLE'; - const firstReferencedTableName = 'ORDER_ITEMS_SIMPLE'; - const referencedOnTableName = 'SHIPMENTS_SIMPLE'; - - const connStr = `DATABASE=${connectionParams.database};HOSTNAME=${connectionParams.host};UID=${connectionParams.username};PWD=${connectionParams.password};PORT=${connectionParams.port};PROTOCOL=TCPIP`; - - const ibmDatabase = ibmdb(); - await ibmDatabase.open(connStr); - const queryCheckSchemaExists = `SELECT COUNT(*) FROM SYSCAT.SCHEMATA WHERE SCHEMANAME = '${connectionParams.schema}'`; - const schemaExists = await ibmDatabase.query(queryCheckSchemaExists); - - if (!schemaExists.length || !schemaExists[0]['1']) { - const queryCreateSchema = `CREATE SCHEMA ${connectionParams.schema}`; - try { - await ibmDatabase.query(queryCreateSchema); - } catch (error) { - console.error(`Error while creating schema: ${error}`); - console.info(`Query: ${queryCreateSchema}`); - } - } - - const queryCheckFirstTableExists = `SELECT COUNT(*) FROM SYSCAT.TABLES WHERE TABNAME = '${mainTableName}' AND TABSCHEMA = '${connectionParams.schema}'`; - const queryCheckSecondTableExists = `SELECT COUNT(*) FROM SYSCAT.TABLES WHERE TABNAME = '${firstReferencedTableName}' AND TABSCHEMA = '${connectionParams.schema}'`; - const queryCheckThirdTableExists = `SELECT COUNT(*) FROM SYSCAT.TABLES WHERE TABNAME = '${referencedOnTableName}' AND TABSCHEMA = '${connectionParams.schema}'`; - - const firstTableExists = await ibmDatabase.query(queryCheckFirstTableExists); - const secondTableExists = await ibmDatabase.query(queryCheckSecondTableExists); - const thirdTableExists = await ibmDatabase.query(queryCheckThirdTableExists); - - if (thirdTableExists.length && thirdTableExists[0]['1']) { - await ibmDatabase.query(`DROP TABLE ${connectionParams.schema}.${referencedOnTableName}`); - } - if (secondTableExists.length && secondTableExists[0]['1']) { - await ibmDatabase.query(`DROP TABLE ${connectionParams.schema}.${firstReferencedTableName}`); - } - if (firstTableExists.length && firstTableExists[0]['1']) { - await ibmDatabase.query(`DROP TABLE ${connectionParams.schema}.${mainTableName}`); - } - - const queryCreateMainTable = ` - CREATE TABLE ${connectionParams.schema}.${mainTableName} ( - order_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, - customer_id INT NOT NULL, - order_date DATE, - status VARCHAR(20), - total_amount DECIMAL(10, 2) - ) - `; - - const queryCreateFirstReferencedTable = ` - CREATE TABLE ${connectionParams.schema}.${firstReferencedTableName} ( - item_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, - order_id INT NOT NULL, - product_name VARCHAR(100), - quantity INT, - price_per_unit DECIMAL(10, 2), - FOREIGN KEY (order_id) REFERENCES ${connectionParams.schema}.${mainTableName}(order_id) ON DELETE CASCADE - ) - `; - - const queryCreateSecondReferencedTable = ` - CREATE TABLE ${connectionParams.schema}.${referencedOnTableName} ( - shipment_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, - order_id INT, - shipped_date DATE, - carrier VARCHAR(50), - tracking_number VARCHAR(100), - FOREIGN KEY (order_id) REFERENCES ${connectionParams.schema}.${mainTableName}(order_id) ON DELETE SET NULL - ) - `; - - try { - await ibmDatabase.query(queryCreateMainTable); - await ibmDatabase.query(queryCreateFirstReferencedTable); - await ibmDatabase.query(queryCreateSecondReferencedTable); - } catch (error) { - console.error(`Error while creating tables: ${error}`); - console.info(`Queries: - ${queryCreateMainTable} - ${queryCreateFirstReferencedTable} - ${queryCreateSecondReferencedTable} - `); - } - - // populate tables with test data - - const insertMainTableData = ` - INSERT INTO ${connectionParams.schema}.${mainTableName} (customer_id, order_date, status, total_amount) VALUES - (101, '2023-01-15', 'Shipped', 250.75), - (102, '2023-01-16', 'Processing', 150.50), - (103, '2023-01-17', 'Delivered', 300.00), - (104, '2023-01-18', 'Pending', 425.30), - (105, '2023-01-19', 'Shipped', 189.99), - (106, '2023-01-20', 'Cancelled', 75.25), - (107, '2023-01-21', 'Processing', 550.00), - (108, '2023-01-22', 'Delivered', 399.50), - (109, '2023-01-23', 'Shipped', 275.80), - (110, '2023-01-24', 'Processing', 680.45), - (111, '2023-01-25', 'Shipped', 320.15), - (112, '2023-01-26', 'Delivered', 445.90), - (113, '2023-01-27', 'Pending', 199.99), - (114, '2023-01-28', 'Processing', 525.30), - (115, '2023-01-29', 'Shipped', 289.75), - (116, '2023-01-30', 'Cancelled', 95.50), - (117, '2023-01-31', 'Delivered', 610.20), - (118, '2023-02-01', 'Processing', 375.85), - (119, '2023-02-02', 'Shipped', 455.60), - (120, '2023-02-03', 'Pending', 225.40), - (121, '2023-02-04', 'Delivered', 505.95), - (122, '2023-02-05', 'Processing', 340.25), - (123, '2023-02-06', 'Shipped', 420.80), - (124, '2023-02-07', 'Cancelled', 125.00), - (125, '2023-02-08', 'Delivered', 590.45), - (126, '2023-02-09', 'Processing', 310.70), - (127, '2023-02-10', 'Shipped', 475.30), - (128, '2023-02-11', 'Pending', 265.85), - (129, '2023-02-12', 'Delivered', 535.20), - (130, '2023-02-13', 'Processing', 395.65), - (131, '2023-02-14', 'Shipped', 485.90), - (132, '2023-02-15', 'Cancelled', 155.25), - (133, '2023-02-16', 'Delivered', 625.40), - (134, '2023-02-17', 'Processing', 355.75), - (135, '2023-02-18', 'Shipped', 495.20), - (136, '2023-02-19', 'Pending', 285.95), - (137, '2023-02-20', 'Delivered', 565.30), - (138, '2023-02-21', 'Processing', 415.85), - (139, '2023-02-22', 'Shipped', 515.60), - (140, '2023-02-23', 'Cancelled', 185.40), - (141, '2023-02-24', 'Delivered', 655.75), - (142, '2023-02-25', 'Processing', 435.90) - `; - - const insertFirstReferencedTableData = ` - INSERT INTO ${connectionParams.schema}.${firstReferencedTableName} (order_id, product_name, quantity, price_per_unit) VALUES - (1, 'Product A', 2, 50.00), - (2, 'Product B', 3, 30.25), - (3, 'Product C', 4, 75.00), - (4, 'Product D', 5, 85.06), - (5, 'Product E', 2, 94.99), - (6, 'Product F', 1, 75.25), - (7, 'Product G', 3, 183.33), - (8, 'Product H', 6, 66.58), - (9, 'Product I', 4, 68.95), - (10, 'Product J', 7, 97.21), - (11, 'Product K', 2, 160.07), - (12, 'Product L', 5, 89.18), - (13, 'Product M', 3, 66.66), - (14, 'Product N', 4, 131.32), - (15, 'Product O', 2, 144.87), - (16, 'Product P', 1, 95.50), - (17, 'Product Q', 6, 101.70), - (18, 'Product R', 3, 125.28), - (19, 'Product S', 5, 91.12), - (20, 'Product T', 2, 112.70), - (21, 'Product U', 4, 126.48), - (22, 'Product V', 3, 113.41), - (23, 'Product W', 5, 84.16), - (24, 'Product X', 1, 125.00), - (25, 'Product Y', 6, 98.40), - (26, 'Product Z', 2, 155.35), - (27, 'Product AA', 4, 118.82), - (28, 'Product AB', 3, 88.61), - (29, 'Product AC', 5, 107.04), - (30, 'Product AD', 2, 197.82), - (31, 'Product AE', 4, 121.47), - (32, 'Product AF', 1, 155.25), - (33, 'Product AG', 6, 104.23), - (34, 'Product AH', 3, 118.58), - (35, 'Product AI', 5, 99.04), - (36, 'Product AJ', 2, 142.97), - (37, 'Product AK', 4, 141.32), - (38, 'Product AL', 3, 138.61), - (39, 'Product AM', 5, 103.12), - (40, 'Product AN', 1, 185.40), - (41, 'Product AO', 6, 109.29), - (42, 'Product AP', 2, 217.95) - `; - - const insertSecondReferencedTableData = ` - INSERT INTO ${connectionParams.schema}.${referencedOnTableName} (order_id, shipped_date, carrier, tracking_number) VALUES - (1, '2023-01-18', 'Carrier X', 'TRACK12345'), - (3, '2023-01-20', 'Carrier Y', 'TRACK67890'), - (5, '2023-01-22', 'Carrier X', 'TRACK11111'), - (8, '2023-01-25', 'Carrier Z', 'TRACK22222'), - (9, '2023-01-26', 'Carrier Y', 'TRACK33333'), - (11, '2023-01-28', 'Carrier X', 'TRACK44444'), - (12, '2023-01-29', 'Carrier Z', 'TRACK55555'), - (15, '2023-02-01', 'Carrier Y', 'TRACK66666'), - (17, '2023-02-03', 'Carrier X', 'TRACK77777'), - (19, '2023-02-05', 'Carrier Z', 'TRACK88888'), - (21, '2023-02-07', 'Carrier Y', 'TRACK99999'), - (23, '2023-02-09', 'Carrier X', 'TRACK10101'), - (25, '2023-02-11', 'Carrier Z', 'TRACK20202'), - (27, '2023-02-13', 'Carrier Y', 'TRACK30303'), - (29, '2023-02-15', 'Carrier X', 'TRACK40404'), - (31, '2023-02-17', 'Carrier Z', 'TRACK50505'), - (33, '2023-02-19', 'Carrier Y', 'TRACK60606'), - (35, '2023-02-21', 'Carrier X', 'TRACK70707'), - (37, '2023-02-23', 'Carrier Z', 'TRACK80808'), - (39, '2023-02-25', 'Carrier Y', 'TRACK90909'), - (41, '2023-02-27', 'Carrier X', 'TRACK11011'), - (1, '2023-01-19', 'Carrier Y', 'TRACK11121'), - (3, '2023-01-21', 'Carrier Z', 'TRACK11131'), - (5, '2023-01-23', 'Carrier X', 'TRACK11141'), - (8, '2023-01-26', 'Carrier Y', 'TRACK11151'), - (9, '2023-01-27', 'Carrier Z', 'TRACK11161'), - (11, '2023-01-29', 'Carrier Y', 'TRACK11171'), - (12, '2023-01-30', 'Carrier X', 'TRACK11181'), - (15, '2023-02-02', 'Carrier Z', 'TRACK11191'), - (17, '2023-02-04', 'Carrier Y', 'TRACK11201'), - (19, '2023-02-06', 'Carrier X', 'TRACK11211'), - (21, '2023-02-08', 'Carrier Z', 'TRACK11221'), - (23, '2023-02-10', 'Carrier Y', 'TRACK11231'), - (25, '2023-02-12', 'Carrier X', 'TRACK11241'), - (27, '2023-02-14', 'Carrier Z', 'TRACK11251'), - (29, '2023-02-16', 'Carrier Y', 'TRACK11261'), - (31, '2023-02-18', 'Carrier X', 'TRACK11271'), - (33, '2023-02-20', 'Carrier Z', 'TRACK11281'), - (35, '2023-02-22', 'Carrier Y', 'TRACK11291'), - (37, '2023-02-24', 'Carrier X', 'TRACK11301'), - (39, '2023-02-26', 'Carrier Z', 'TRACK11311'), - (41, '2023-02-28', 'Carrier Y', 'TRACK11321') - `; - - try { - await ibmDatabase.query(insertMainTableData); - await ibmDatabase.query(insertFirstReferencedTableData); - await ibmDatabase.query(insertSecondReferencedTableData); - } catch (error) { - console.error(`Error while inserting data: ${error}`); - console.info(`Insert Queries: - ${insertMainTableData} - ${insertFirstReferencedTableData} - ${insertSecondReferencedTableData} - `); - } - - await ibmDatabase.close(); - - return { - main_table: { - table_name: mainTableName, - column_names: ['ORDER_ID', 'CUSTOMER_ID', 'ORDER_DATE', 'STATUS', 'TOTAL_AMOUNT'], - foreign_key_column_names: [], - binary_column_names: [], - primary_key_column_names: ['ORDER_ID'], - }, - first_referenced_table: { - table_name: firstReferencedTableName, - column_names: ['ITEM_ID', 'ORDER_ID', 'PRODUCT_NAME', 'QUANTITY', 'PRICE_PER_UNIT'], - primary_key_column_names: ['ITEM_ID'], - }, - second_referenced_table: { - table_name: referencedOnTableName, - column_names: ['SHIPMENT_ID', 'ORDER_ID', 'SHIPPED_DATE', 'CARRIER', 'TRACKING_NUMBER'], - primary_key_column_names: ['SHIPMENT_ID'], - foreign_key_column_names: ['ORDER_ID'], - }, - }; -}; diff --git a/docker-compose.yml b/docker-compose.yml index b864ed6f9..3734cb82b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,7 +16,6 @@ services: - testPg-e2e-testing - mssql-e2e-testing - test-oracle-e2e-testing - - test-ibm-db2-e2e-testing - test-mongo-e2e-testing - test-dynamodb-e2e-testing - test-elasticsearch-e2e-testing @@ -30,7 +29,6 @@ services: - testPg-e2e-testing - mssql-e2e-testing - test-oracle-e2e-testing - - test-ibm-db2-e2e-testing - test-mongo-e2e-testing - test-dynamodb-e2e-testing - test-elasticsearch-e2e-testing @@ -135,29 +133,6 @@ services: tmpfs: - /var/lib/postgresql - test-ibm-db2-e2e-testing: - image: icr.io/db2_community/db2 - restart: always - privileged: true - environment: - - LICENSE=accept - - DB2INSTANCE=db2inst1 - - DB2INST1_PASSWORD=password - - DBNAME=testdb - - BLU=false - - ENABLE_ORACLE_COMPATIBILITY=false - - UPDATEAVAIL=NO - - TO_CREATE_SAMPLEDB=true - - REPODB=false - - IS_OSXFS=false - - PERSISTENT_HOME=true - - HADR_ENABLED=false - - ETCD_ENDPOINT= - - ETCD_USERNAME= - - ETCD_PASSWORD= - ports: - - 50000:50000 - test-mongo-e2e-testing: image: mongo restart: always @@ -352,26 +327,6 @@ services: - APPLICATION_CONFIG_FILE_NAME=.mongodb_test_agent_config.txt command: ["pnpm", "start:dev"] - rocketadmin-agent_ibmdb2: - build: - context: . - dockerfile: ./rocketadmin-agent/Dockerfile - ports: - - 8308:8308 - volumes: - - ./rocketadmin-agent/dist:/app/dist - - ./rocketadmin-agent/src:/app/src - - ./rocketadmin-agent/wait-for-db2.sh:/app/wait-for-db2.sh - - ./rocketadmin-agent/wait-for-db2.js:/app/wait-for-db2.js - links: - - autoadmin-ws-server - depends_on: - - autoadmin-ws-server - environment: - - REMOTE_WEBSOCKET_ADDRESS=ws://autoadmin-ws-server:8009 - - APPLICATION_CONFIG_FILE_NAME=.ibmdb2_test_agent_config.txt - command: ["node", "/app/wait-for-db2.js"] - rocketadmin-agent_oracle: build: context: . diff --git a/frontend/CLAUDE.md b/frontend/CLAUDE.md index 70fe660c1..af0f8fe2c 100644 --- a/frontend/CLAUDE.md +++ b/frontend/CLAUDE.md @@ -153,7 +153,6 @@ The application supports multiple database types: - Cassandra - OracleDB - MSSQL -- IBM DB2 Database configurations are defined in `src/app/consts/databases.ts`. diff --git a/frontend/src/app/app.component.ts b/frontend/src/app/app.component.ts index dbc770560..2a43177a4 100644 --- a/frontend/src/app/app.component.ts +++ b/frontend/src/app/app.component.ts @@ -127,10 +127,6 @@ export class AppComponent { 'dynamodb', this.domSanitizer.bypassSecurityTrustResourceUrl('/assets/icons/db-logos/dynamodb_logo.svg'), ); - this.matIconRegistry.addSvgIcon( - 'ibmdb2', - this.domSanitizer.bypassSecurityTrustResourceUrl('/assets/icons/db-logos/db2_logo.svg'), - ); this.matIconRegistry.addSvgIcon( 'cassandra', this.domSanitizer.bypassSecurityTrustResourceUrl('/assets/icons/db-logos/сassandra_logo.svg'), diff --git a/frontend/src/app/components/connect-db/connect-db.component.ts b/frontend/src/app/components/connect-db/connect-db.component.ts index c6c7a53c0..0e50feec0 100644 --- a/frontend/src/app/components/connect-db/connect-db.component.ts +++ b/frontend/src/app/components/connect-db/connect-db.component.ts @@ -39,7 +39,6 @@ import { DbConnectionIpAccessDialogComponent } from './db-connection-ip-access-d import { BaseCredentialsFormComponent } from './db-credentials-forms/base-credentials-form/base-credentials-form.component'; import { CassandraCredentialsFormComponent } from './db-credentials-forms/cassandra-credentials-form/cassandra-credentials-form.component'; import { ClickhouseCredentialsFormComponent } from './db-credentials-forms/clickhouse-credentials-form/clickhouse-credentials-form.component'; -import { Db2CredentialsFormComponent } from './db-credentials-forms/db2-credentials-form/db2-credentials-form.component'; import { DynamodbCredentialsFormComponent } from './db-credentials-forms/dynamodb-credentials-form/dynamodb-credentials-form.component'; import { ElasticCredentialsFormComponent } from './db-credentials-forms/elastic-credentials-form/elastic-credentials-form.component'; import { MongodbCredentialsFormComponent } from './db-credentials-forms/mongodb-credentials-form/mongodb-credentials-form.component'; @@ -106,7 +105,6 @@ export class ConnectDBComponent implements OnInit { [DBtype.Redis]: RedisCredentialsFormComponent, [DBtype.Elasticsearch]: ElasticCredentialsFormComponent, [DBtype.ClickHouse]: ClickhouseCredentialsFormComponent, - [DBtype.DB2]: Db2CredentialsFormComponent, }; public supportedOrderedDatabases = supportedOrderedDatabases; @@ -122,7 +120,6 @@ export class ConnectDBComponent implements OnInit { [DBtype.Redis]: '6379', [DBtype.Elasticsearch]: '9200', [DBtype.ClickHouse]: '8443', - [DBtype.DB2]: '50000', }; // public isDemo: boolean = false; @@ -502,7 +499,7 @@ export class ConnectDBComponent implements OnInit { this.db.ssl = true; } - setTimeout(() => this.connectionString = '', 300); + setTimeout(() => (this.connectionString = ''), 300); } catch (_e) { // Validation directive handles error display } diff --git a/frontend/src/app/components/connect-db/db-credentials-forms/db2-credentials-form/db2-credentials-form.component.css b/frontend/src/app/components/connect-db/db-credentials-forms/db2-credentials-form/db2-credentials-form.component.css deleted file mode 100644 index 6f4923742..000000000 --- a/frontend/src/app/components/connect-db/db-credentials-forms/db2-credentials-form/db2-credentials-form.component.css +++ /dev/null @@ -1,14 +0,0 @@ -.connectForm__hostname, -.connectForm__port { - padding-bottom: 20px; -} - -@media (width <= 600px) { - .connectForm__hostname { - padding-bottom: 44px; - } - - .connectForm__port { - padding-bottom: 0; - } -} diff --git a/frontend/src/app/components/connect-db/db-credentials-forms/db2-credentials-form/db2-credentials-form.component.html b/frontend/src/app/components/connect-db/db-credentials-forms/db2-credentials-form/db2-credentials-form.component.html deleted file mode 100644 index 4566ea997..000000000 --- a/frontend/src/app/components/connect-db/db-credentials-forms/db2-credentials-form/db2-credentials-form.component.html +++ /dev/null @@ -1,210 +0,0 @@ - - Hostname - - - E.g. my-test-connection.cvfuxe8nltiq.us-east-2.rds.amazonaws.com
- Connections from internal IPs (e.g. localhost) are not supported -
- - - To connect a database to an internal IP, use something like Pinggy - (here's a guide), - or to connect through an agent - - Hostname is invalid -
- - - Port - - Port should not be empty - - - - Username - - Username should not be empty - - - - Password - - To keep password the same keep this field blank - Password needed due to hostname/port change - - - - - Database Name - - Name should not be empty - - - - Schema - - Name should not be empty - - - - - - Advanced settings - - - -
- - - - - Use SSH tunnel - - - - Private SSH key - - Private SSH key should not be empty - - - - SSH host - - SSH host should not be empty - - - - SSH port - - SSH port should not be empty - - - - SSH username - - SSH username should not be empty - - - - Check SSL certificate - - - - SSL certificate - - SSL certificate should not be empty - -
-
\ No newline at end of file diff --git a/frontend/src/app/components/connect-db/db-credentials-forms/db2-credentials-form/db2-credentials-form.component.spec.ts b/frontend/src/app/components/connect-db/db-credentials-forms/db2-credentials-form/db2-credentials-form.component.spec.ts deleted file mode 100644 index 2d15eefeb..000000000 --- a/frontend/src/app/components/connect-db/db-credentials-forms/db2-credentials-form/db2-credentials-form.component.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { provideHttpClient } from '@angular/common/http'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { FormsModule } from '@angular/forms'; -import { MatCheckboxModule } from '@angular/material/checkbox'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { Angulartics2Module } from 'angulartics2'; -import { Db2CredentialsFormComponent } from './db2-credentials-form.component'; - -describe('Db2CredentialsFormComponent', () => { - let component: Db2CredentialsFormComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - FormsModule, - MatCheckboxModule, - Db2CredentialsFormComponent, - BrowserAnimationsModule, - Angulartics2Module.forRoot(), - ], - providers: [provideHttpClient()], - }).compileComponents(); - - fixture = TestBed.createComponent(Db2CredentialsFormComponent); - component = fixture.componentInstance; - - component.connection = { - id: '12345678', - } as any; - - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/frontend/src/app/components/connect-db/db-credentials-forms/db2-credentials-form/db2-credentials-form.component.stories.ts b/frontend/src/app/components/connect-db/db-credentials-forms/db2-credentials-form/db2-credentials-form.component.stories.ts deleted file mode 100644 index 5d8c54d85..000000000 --- a/frontend/src/app/components/connect-db/db-credentials-forms/db2-credentials-form/db2-credentials-form.component.stories.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/angular'; -import { Db2CredentialsFormComponent } from './db2-credentials-form.component'; - -const mockConnection = { - id: null, - database: 'test_db', - title: 'Test IBM DB2 Connection', - host: 'localhost', - port: '50000', - sid: null, - type: 'ibmdb2', - username: 'admin', - password: '', - ssh: false, - ssl: false, - cert: '', - masterEncryption: false, - azure_encryption: false, - connectionType: 'direct', - schema: '', -}; - -const meta: Meta = { - title: 'DB Credentials/IBM DB2', - component: Db2CredentialsFormComponent, - args: { - connection: mockConnection as any, - readonly: false, - submitting: false, - masterKey: '', - accessLevel: 'edit', - }, -}; - -export default meta; -type Story = StoryObj; - -export const Default: Story = {}; - -export const Readonly: Story = { - args: { - readonly: true, - }, -}; - -export const Submitting: Story = { - args: { - submitting: true, - }, -}; diff --git a/frontend/src/app/components/connect-db/db-credentials-forms/db2-credentials-form/db2-credentials-form.component.ts b/frontend/src/app/components/connect-db/db-credentials-forms/db2-credentials-form/db2-credentials-form.component.ts deleted file mode 100644 index 3bc6cb0e9..000000000 --- a/frontend/src/app/components/connect-db/db-credentials-forms/db2-credentials-form/db2-credentials-form.component.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { NgIf } from '@angular/common'; -import { Component } from '@angular/core'; -import { FormsModule } from '@angular/forms'; -import { MatCheckboxModule } from '@angular/material/checkbox'; -import { MatExpansionModule } from '@angular/material/expansion'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatInputModule } from '@angular/material/input'; -import { Angulartics2Module } from 'angulartics2'; -import posthog from 'posthog-js'; -import { HostnameValidationDirective } from 'src/app/directives/hostnameValidator.directive'; -import { MasterEncryptionPasswordComponent } from '../../master-encryption-password/master-encryption-password.component'; -import { BaseCredentialsFormComponent } from '../base-credentials-form/base-credentials-form.component'; - -@Component({ - selector: 'app-db2-credentials-form', - templateUrl: './db2-credentials-form.component.html', - styleUrls: ['../base-credentials-form/base-credentials-form.component.css', './db2-credentials-form.component.css'], - imports: [ - NgIf, - FormsModule, - MatFormFieldModule, - MatInputModule, - MatCheckboxModule, - MatExpansionModule, - HostnameValidationDirective, - MasterEncryptionPasswordComponent, - Angulartics2Module, - ], -}) -export class Db2CredentialsFormComponent extends BaseCredentialsFormComponent { - protected posthog = posthog; -} diff --git a/frontend/src/app/components/connections-list/own-connections/own-connections.component.ts b/frontend/src/app/components/connections-list/own-connections/own-connections.component.ts index 3cafdc687..598e86fd7 100644 --- a/frontend/src/app/components/connections-list/own-connections/own-connections.component.ts +++ b/frontend/src/app/components/connections-list/own-connections/own-connections.component.ts @@ -121,7 +121,6 @@ export class OwnConnectionsComponent implements OnInit, OnChanges { type === DBtype.MySQL || type === DBtype.Oracle || type === DBtype.MSSQL || - type === DBtype.DB2 || type === DBtype.ClickHouse ); } diff --git a/frontend/src/app/components/upgrade/upgrade.component.ts b/frontend/src/app/components/upgrade/upgrade.component.ts index 87e5abe21..80a47824d 100644 --- a/frontend/src/app/components/upgrade/upgrade.component.ts +++ b/frontend/src/app/components/upgrade/upgrade.component.ts @@ -76,12 +76,6 @@ export class UpgradeComponent implements OnInit { team: '∞', enterprise: '∞', }, - { - title: 'IBM DB2', - free: 3, - team: '∞', - enterprise: '∞', - }, { title: 'Oracle', free: 1, diff --git a/frontend/src/app/consts/databases.ts b/frontend/src/app/consts/databases.ts index be1896b3f..9a1772132 100644 --- a/frontend/src/app/consts/databases.ts +++ b/frontend/src/app/consts/databases.ts @@ -9,7 +9,6 @@ export const supportedOrderedDatabases = [ 'redis', 'elasticsearch', 'clickhouse', - 'ibmdb2', ]; export const supportedDatabasesTitles = { @@ -23,5 +22,4 @@ export const supportedDatabasesTitles = { redis: 'Redis', elasticsearch: 'Elasticsearch (OpenSearch)', clickhouse: 'ClickHouse', - ibmdb2: 'IBM DB2', }; diff --git a/frontend/src/app/models/connection.ts b/frontend/src/app/models/connection.ts index 87e4104a1..a413ee3a3 100644 --- a/frontend/src/app/models/connection.ts +++ b/frontend/src/app/models/connection.ts @@ -11,7 +11,6 @@ export enum DBtype { Redis = 'redis', Elasticsearch = 'elasticsearch', ClickHouse = 'clickhouse', - DB2 = 'ibmdb2', } export enum ConnectionType { diff --git a/frontend/src/app/validators/connection-string.validator.ts b/frontend/src/app/validators/connection-string.validator.ts index b1eb6ecbc..d2aeec84c 100644 --- a/frontend/src/app/validators/connection-string.validator.ts +++ b/frontend/src/app/validators/connection-string.validator.ts @@ -30,8 +30,6 @@ const schemeToDbType: Record = { rediss: DBtype.Redis, elasticsearch: DBtype.Elasticsearch, clickhouse: DBtype.ClickHouse, - ibmdb2: DBtype.DB2, - db2: DBtype.DB2, }; const defaultPorts: Record = { @@ -45,7 +43,6 @@ const defaultPorts: Record = { [DBtype.Redis]: '6379', [DBtype.Elasticsearch]: '9200', [DBtype.ClickHouse]: '8443', - [DBtype.DB2]: '50000', }; export function parseConnectionString(connectionString: string): ParsedConnectionString { diff --git a/frontend/src/assets/icons/db-logos/db2_logo.svg b/frontend/src/assets/icons/db-logos/db2_logo.svg deleted file mode 100644 index 27df40743..000000000 --- a/frontend/src/assets/icons/db-logos/db2_logo.svg +++ /dev/null @@ -1,937 +0,0 @@ - - - -image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/justfile b/justfile index 93cd40763..138c8805f 100644 --- a/justfile +++ b/justfile @@ -1,7 +1,7 @@ # CI default runs only the Postgres + MySQL (and DB-agnostic) suites — the -# other database engines (Oracle, MSSQL, Mongo, IBM DB2, Cassandra, Redis, +# other database engines (Oracle, MSSQL, Mongo, Cassandra, Redis, # DynamoDB, ClickHouse, Elasticsearch) are excluded so their heavy containers # aren't needed. Pass an explicit glob to run a different subset locally, e.g. # just test 'test/ava-tests/non-saas-tests/*mongo*.test.ts' -test args='test/ava-tests/non-saas-tests/!(*oracle*|*ibmdb2*|*cassandra*|*elasticsearch*|*mssql*|*mongo*|*redis*|*dynamodb*|*clickhouse*).test.ts': +test args='test/ava-tests/non-saas-tests/!(*oracle*|*cassandra*|*elasticsearch*|*mssql*|*mongo*|*redis*|*dynamodb*|*clickhouse*).test.ts': EXTRA_ARGS="{{args}}" docker compose -f docker-compose.tst.yml up --abort-on-container-exit --force-recreate --build --attach=backend --no-log-prefix diff --git a/package.json b/package.json index 368a53caf..b05dd0553 100644 --- a/package.json +++ b/package.json @@ -38,18 +38,10 @@ "fast-xml-builder@=1.1.5": ">=1.1.6", "brace-expansion@>=5.0.0 <5.0.6": ">=5.0.6" }, - "packageExtensions": { - "ibm_db": { - "dependencies": { - "node-gyp": "^11.5.0" - } - } - }, "onlyBuiltDependencies": [ "argon2", "bcrypt", "cpu-features", - "ibm_db", "oracledb", "ssh2" ] diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e46ada084..08c2f3609 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,8 +22,6 @@ overrides: fast-xml-builder@=1.1.5: '>=1.1.6' brace-expansion@>=5.0.0 <5.0.6: '>=5.0.6' -packageExtensionsChecksum: sha256-qM/gPCDCAwbN43hScuRM/oThrQiWcAMxRCqJ3FQdbM0= - importers: .: @@ -282,9 +280,6 @@ importers: '@types/express': specifier: ^5.0.6 version: 5.0.6 - '@types/ibm_db': - specifier: ^3.2.0 - version: 3.2.0 '@types/json2csv': specifier: ^5.0.7 version: 5.0.7 @@ -473,10 +468,6 @@ importers: typescript: specifier: ^6.0.3 version: 6.0.3 - optionalDependencies: - ibm_db: - specifier: 4.0.1 - version: 4.0.1 packages: @@ -1297,10 +1288,6 @@ packages: '@types/node': optional: true - '@isaacs/cliui@8.0.2': - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} - '@isaacs/fs-minipass@4.0.1': resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} engines: {node: '>=18.0.0'} @@ -1509,14 +1496,6 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@npmcli/agent@3.0.0': - resolution: {integrity: sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q==} - engines: {node: ^18.17.0 || >=20.5.0} - - '@npmcli/fs@4.0.0': - resolution: {integrity: sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q==} - engines: {node: ^18.17.0 || >=20.5.0} - '@nuxt/opencollective@0.4.1': resolution: {integrity: sha512-GXD3wy50qYbxCJ652bDrDzgMr3NFEkIS374+IgFQKkCvk9yiYcLvX2XDYr7UyQxf4wK0e+yqDYRubZ0DtOxnmQ==} engines: {node: ^14.18.0 || >=16.10.0, npm: '>=5.10.0'} @@ -1970,10 +1949,6 @@ packages: resolution: {integrity: sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==} engines: {node: '>=10'} - '@pkgjs/parseargs@0.11.0': - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} - '@prisma/instrumentation@7.6.0': resolution: {integrity: sha512-ZPW2gRiwpPzEfgeZgaekhqXrbW+Y2RJKHVqUmlhZhKzRNCcvR6DykzylDrynpArKKRQtLxoZy36fK7U0p3pdgQ==} peerDependencies: @@ -2387,9 +2362,6 @@ packages: '@types/http-errors@2.0.5': resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} - '@types/ibm_db@3.2.0': - resolution: {integrity: sha512-Sfw54KJi93RMQh5rHgF3LQIKwm24iQbbU/mB+GQQNAYYHMb5ulKkemzSNl+65jEmd51eF2xcK0QKksdwU5ZJ4w==} - '@types/inquirer@9.0.9': resolution: {integrity: sha512-/mWx5136gts2Z2e5izdoRCo46lPp5TMs9R15GTSsgg/XnZyxDWVqoVU3R9lWnccKpqwsJLvRoxbCjoJtZB7DSw==} @@ -2777,9 +2749,6 @@ packages: bindings@1.5.0: resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} - bl@1.2.3: - resolution: {integrity: sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==} - bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -2799,9 +2768,6 @@ packages: brace-expansion@1.1.14: resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} - brace-expansion@2.1.0: - resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} - brace-expansion@5.0.6: resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} engines: {node: 18 || 20 || >=22} @@ -2819,18 +2785,9 @@ packages: resolution: {integrity: sha512-YCEo7KjMlbNlyHhz7zAZNDpIpQbd+wOEHJYezv0nMYTn4x31eIUM2yomNNubclAt63dObUzKHWsBLJ9QcZNSnQ==} engines: {node: '>=20.19.0'} - buffer-alloc-unsafe@1.1.0: - resolution: {integrity: sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==} - - buffer-alloc@1.2.0: - resolution: {integrity: sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==} - buffer-equal-constant-time@1.0.1: resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} - buffer-fill@1.0.0: - resolution: {integrity: sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==} - buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -2856,10 +2813,6 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} - cacache@19.0.1: - resolution: {integrity: sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ==} - engines: {node: ^18.17.0 || >=20.5.0} - call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -2914,9 +2867,6 @@ packages: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} - chownr@1.1.4: - resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} - chownr@3.0.0: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} @@ -3274,9 +3224,6 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} @@ -3296,9 +3243,6 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - enabled@2.0.0: resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==} @@ -3309,24 +3253,14 @@ packages: encoding@0.1.13: resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} - end-of-stream@1.4.5: - resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} - enhanced-resolve@5.20.1: resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} engines: {node: '>=10.13.0'} - env-paths@2.2.1: - resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} - engines: {node: '>=6'} - environment@1.1.0: resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} engines: {node: '>=18'} - err-code@2.0.3: - resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} - error-ex@1.3.4: resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} @@ -3418,9 +3352,6 @@ packages: resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==} engines: {node: ^18.19.0 || >=20.5.0} - exponential-backoff@3.1.3: - resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} - express@5.2.1: resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} @@ -3532,10 +3463,6 @@ packages: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} - foreground-child@3.3.1: - resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} - engines: {node: '>=14'} - fork-ts-checker-webpack-plugin@9.1.0: resolution: {integrity: sha512-mpafl89VFPJmhnJ1ssH+8wmM2b50n+Rew5x42NeI2U78aRWgtkEtGmctp7iT16UjquJTjorEmIfESj3DxdW84Q==} engines: {node: '>=14.21.3'} @@ -3567,21 +3494,10 @@ packages: resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} engines: {node: '>= 0.8'} - fs-constants@1.0.0: - resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - fs-extra@10.1.0: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} - fs-extra@11.3.4: - resolution: {integrity: sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==} - engines: {node: '>=14.14'} - - fs-minipass@3.0.3: - resolution: {integrity: sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - fs-monkey@1.1.0: resolution: {integrity: sha512-QMUezzXWII9EV5aTFXW1UBVUO77wYPpjqIF8/AviUCThNeSYZykpoTixUeaNNBwmCev0AMDWMAni+f8Hxb1IFw==} @@ -3632,11 +3548,6 @@ packages: glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - glob@10.5.0: - resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - hasBin: true - glob@13.0.6: resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} engines: {node: 18 || 20 || >=22} @@ -3683,9 +3594,6 @@ packages: resolution: {integrity: sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==} engines: {node: '>=14'} - http-cache-semantics@4.2.0: - resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} - http-errors@2.0.1: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} @@ -3715,10 +3623,6 @@ packages: resolution: {integrity: sha512-nXHJZYtNrfsi1UQbyRqm3Gou431elgLjKl//CYlnBGt5aTWdRPH1PiS2T/p/n8Q8LnqYqzQJik3Q7mkwvLokeg==} engines: {node: '>= 12'} - ibm_db@4.0.1: - resolution: {integrity: sha512-0fO1fyaDm3jqaydObwKZw1aUNh6SbfHKxtrSfadWHoFsrnmBhQfp1oMFm6cWJSRNjE9pHyQw7zUNteuLRObwSg==} - engines: {node: '>=6.0'} - iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} @@ -3749,10 +3653,6 @@ packages: resolution: {integrity: sha512-pYkiyXVL2Mf3pozdlDGV6NAObxQx13Ae8knZk1UJRJ6uRW/ZRmTGHlQYtrsSl7ubuE5F8CD1z+s1n4RHNuTtuA==} engines: {node: '>=18'} - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - indent-string@5.0.0: resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} engines: {node: '>=12'} @@ -3891,17 +3791,10 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - isexe@3.1.5: - resolution: {integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==} - engines: {node: '>=18'} - iterare@1.2.1: resolution: {integrity: sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==} engines: {node: '>=6'} - jackspeak@3.4.3: - resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - jest-worker@27.5.1: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} @@ -4125,9 +4018,6 @@ packages: long@5.3.2: resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} - lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.5.0: resolution: {integrity: sha512-5YgH9UJd7wVb9hIouI2adWpgqrrICkt070Dnj8EUY1+B4B2P9eRLPAkAAo6NICA7CEhOIeBHl46u9zSNpNu7zA==} engines: {node: 20 || >=22} @@ -4146,10 +4036,6 @@ packages: make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - make-fetch-happen@14.0.3: - resolution: {integrity: sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ==} - engines: {node: ^18.17.0 || >=20.5.0} - matcher@6.0.0: resolution: {integrity: sha512-TzDerdcNtI79w7Av4GT57bLdElPA/VAkjqdMZv8yhuc8geU2z0ljW9anXbX/55aHEMTpYypZb1lxsA/46r9oOQ==} engines: {node: '>=20'} @@ -4239,37 +4125,9 @@ packages: minimatch@3.1.5: resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - minimatch@9.0.9: - resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} - engines: {node: '>=16 || 14 >=14.17'} - minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - minipass-collect@2.0.1: - resolution: {integrity: sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==} - engines: {node: '>=16 || 14 >=14.17'} - - minipass-fetch@4.0.1: - resolution: {integrity: sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ==} - engines: {node: ^18.17.0 || >=20.5.0} - - minipass-flush@1.0.7: - resolution: {integrity: sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==} - engines: {node: '>= 8'} - - minipass-pipeline@1.2.4: - resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} - engines: {node: '>=8'} - - minipass-sized@1.0.3: - resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} - engines: {node: '>=8'} - - minipass@3.3.6: - resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} - engines: {node: '>=8'} - minipass@7.1.3: resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} @@ -4278,10 +4136,6 @@ packages: resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} engines: {node: '>= 18'} - mkdirp@0.5.6: - resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} - hasBin: true - mnemonist@0.38.3: resolution: {integrity: sha512-2K9QYubXx/NAjv4VLq1d1Ly8pWNC5L3BrixtdkyTegXWJIqY+zLNDhhX/A+ZwWt70tB1S8H4BE8FLYEFyNoOBw==} @@ -4379,9 +4233,6 @@ packages: node-abort-controller@3.1.1: resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} - node-addon-api@7.1.1: - resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - node-addon-api@8.7.0: resolution: {integrity: sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==} engines: {node: ^18 || ^20 || >= 21} @@ -4402,11 +4253,6 @@ packages: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true - node-gyp@11.5.0: - resolution: {integrity: sha512-ra7Kvlhxn5V9Slyus0ygMa2h+UqExPqUIkfk7Pc8QTLT956JLSy51uWFwHtIYy0vI8cB4BDhc/S03+880My/LQ==} - engines: {node: ^18.17.0 || >=20.5.0} - hasBin: true - node-releases@2.0.37: resolution: {integrity: sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==} @@ -4585,10 +4431,6 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} - path-scurry@2.0.2: resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} @@ -4700,10 +4542,6 @@ packages: resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} engines: {node: '>=18'} - proc-log@5.0.0: - resolution: {integrity: sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==} - engines: {node: ^18.17.0 || >=20.5.0} - process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -4711,10 +4549,6 @@ packages: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} - promise-retry@2.0.1: - resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} - engines: {node: '>=10'} - propagate@2.0.1: resolution: {integrity: sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==} engines: {node: '>= 8'} @@ -4727,9 +4561,6 @@ packages: resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} engines: {node: '>=10'} - pump@1.0.3: - resolution: {integrity: sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==} - punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -4827,10 +4658,6 @@ packages: resolution: {integrity: sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==} engines: {node: '>=10'} - retry@0.12.0: - resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} - engines: {node: '>= 4'} - reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -4986,10 +4813,6 @@ packages: resolution: {integrity: sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==} engines: {node: '>= 18'} - socks-proxy-agent@8.0.5: - resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} - engines: {node: '>= 14'} - socks@2.8.7: resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} @@ -5034,10 +4857,6 @@ packages: resolution: {integrity: sha512-wPldCk3asibAjQ/kziWQQt1Wh3PgDFpC0XpwclzKcdT1vql6KeYxf5LIt4nlFkUeR8WuphYMKqUA56X4rjbfgQ==} engines: {node: '>=10.16.0'} - ssri@12.0.0: - resolution: {integrity: sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==} - engines: {node: ^18.17.0 || >=20.5.0} - stack-trace@0.0.10: resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} @@ -5071,10 +4890,6 @@ packages: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} - string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} - string-width@7.2.0: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} @@ -5155,20 +4970,10 @@ packages: resolution: {integrity: sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==} engines: {node: '>=6'} - tar-fs@1.16.6: - resolution: {integrity: sha512-JkOgFt3FxM/2v2CNpAVHqMW2QASjc/Hxo7IGfNd3MHaDYSW/sBFiS7YVmmhmr8x6vwN1VFQDQGdT2MWpmIuVKA==} - - tar-stream@1.6.2: - resolution: {integrity: sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==} - engines: {node: '>= 0.8.0'} - tar@7.5.13: resolution: {integrity: sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng==} engines: {node: '>=18'} - targz@1.0.1: - resolution: {integrity: sha512-6q4tP9U55mZnRuMTBqnqc3nwYQY3kv+QthCFZuMk+Tn1qYUnMPmL/JZ/mzgXINzFpSqfU+242IFmFU9VPvqaQw==} - tarn@3.0.2: resolution: {integrity: sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==} engines: {node: '>=8.0.0'} @@ -5413,14 +5218,6 @@ packages: resolution: {integrity: sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==} engines: {node: '>=20'} - unique-filename@4.0.0: - resolution: {integrity: sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ==} - engines: {node: ^18.17.0 || >=20.5.0} - - unique-slug@5.0.0: - resolution: {integrity: sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg==} - engines: {node: ^18.17.0 || >=20.5.0} - universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -5520,11 +5317,6 @@ packages: engines: {node: '>= 8'} hasBin: true - which@5.0.0: - resolution: {integrity: sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==} - engines: {node: ^18.17.0 || >=20.5.0} - hasBin: true - winston-transport@4.9.0: resolution: {integrity: sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==} engines: {node: '>= 12.0.0'} @@ -5541,14 +5333,6 @@ packages: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - - wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} - wrap-ansi@9.0.2: resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} engines: {node: '>=18'} @@ -5591,9 +5375,6 @@ packages: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - yallist@5.0.0: resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} engines: {node: '>=18'} @@ -7004,16 +6785,6 @@ snapshots: optionalDependencies: '@types/node': 24.12.2 - '@isaacs/cliui@8.0.2': - dependencies: - string-width: 5.1.2 - string-width-cjs: string-width@4.2.3 - strip-ansi: 7.2.0 - strip-ansi-cjs: strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: wrap-ansi@7.0.0 - optional: true - '@isaacs/fs-minipass@4.0.1': dependencies: minipass: 7.1.3 @@ -7266,22 +7037,6 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 - '@npmcli/agent@3.0.0': - dependencies: - agent-base: 7.1.4 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 - lru-cache: 10.4.3 - socks-proxy-agent: 8.0.5 - transitivePeerDependencies: - - supports-color - optional: true - - '@npmcli/fs@4.0.0': - dependencies: - semver: 7.7.4 - optional: true - '@nuxt/opencollective@0.4.1': dependencies: consola: 3.4.2 @@ -7685,9 +7440,6 @@ snapshots: '@phc/format@1.0.0': {} - '@pkgjs/parseargs@0.11.0': - optional: true - '@prisma/instrumentation@7.6.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 @@ -8230,8 +7982,6 @@ snapshots: '@types/http-errors@2.0.5': {} - '@types/ibm_db@3.2.0': {} - '@types/inquirer@9.0.9': dependencies: '@types/through': 0.0.33 @@ -8703,12 +8453,6 @@ snapshots: dependencies: file-uri-to-path: 1.0.0 - bl@1.2.3: - dependencies: - readable-stream: 2.3.8 - safe-buffer: 5.2.1 - optional: true - bl@4.1.0: dependencies: buffer: 5.7.1 @@ -8745,11 +8489,6 @@ snapshots: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@2.1.0: - dependencies: - balanced-match: 1.0.2 - optional: true - brace-expansion@5.0.6: dependencies: balanced-match: 4.0.4 @@ -8768,20 +8507,8 @@ snapshots: bson@7.2.0: {} - buffer-alloc-unsafe@1.1.0: - optional: true - - buffer-alloc@1.2.0: - dependencies: - buffer-alloc-unsafe: 1.1.0 - buffer-fill: 1.0.0 - optional: true - buffer-equal-constant-time@1.0.1: {} - buffer-fill@1.0.0: - optional: true - buffer-from@1.1.2: {} buffer@5.7.1: @@ -8807,22 +8534,6 @@ snapshots: bytes@3.1.2: {} - cacache@19.0.1: - dependencies: - '@npmcli/fs': 4.0.0 - fs-minipass: 3.0.3 - glob: 10.5.0 - lru-cache: 10.4.3 - minipass: 7.1.3 - minipass-collect: 2.0.1 - minipass-flush: 1.0.7 - minipass-pipeline: 1.2.4 - p-map: 7.0.4 - ssri: 12.0.0 - tar: 7.5.13 - unique-filename: 4.0.0 - optional: true - call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -8875,9 +8586,6 @@ snapshots: dependencies: readdirp: 4.1.2 - chownr@1.1.4: - optional: true - chownr@3.0.0: {} chrome-trace-event@1.0.4: {} @@ -9192,9 +8900,6 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - eastasianwidth@0.2.0: - optional: true - ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer: 5.2.1 @@ -9209,9 +8914,6 @@ snapshots: emoji-regex@8.0.0: {} - emoji-regex@9.2.2: - optional: true - enabled@2.0.0: {} encodeurl@2.0.0: {} @@ -9221,24 +8923,13 @@ snapshots: iconv-lite: 0.6.3 optional: true - end-of-stream@1.4.5: - dependencies: - once: 1.4.0 - optional: true - enhanced-resolve@5.20.1: dependencies: graceful-fs: 4.2.11 tapable: 2.3.2 - env-paths@2.2.1: - optional: true - environment@1.1.0: {} - err-code@2.0.3: - optional: true - error-ex@1.3.4: dependencies: is-arrayish: 0.2.1 @@ -9314,9 +9005,6 @@ snapshots: strip-final-newline: 4.0.0 yoctocolors: 2.1.2 - exponential-backoff@3.1.3: - optional: true - express@5.2.1: dependencies: accepts: 2.0.0 @@ -9462,12 +9150,6 @@ snapshots: dependencies: is-callable: 1.2.7 - foreground-child@3.3.1: - dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 - optional: true - fork-ts-checker-webpack-plugin@9.1.0(typescript@5.9.3)(webpack@5.106.0): dependencies: '@babel/code-frame': 7.29.0 @@ -9509,27 +9191,12 @@ snapshots: fresh@2.0.0: {} - fs-constants@1.0.0: - optional: true - fs-extra@10.1.0: dependencies: graceful-fs: 4.2.11 jsonfile: 6.2.0 universalify: 2.0.1 - fs-extra@11.3.4: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.2.0 - universalify: 2.0.1 - optional: true - - fs-minipass@3.0.3: - dependencies: - minipass: 7.1.3 - optional: true - fs-monkey@1.1.0: {} function-bind@1.1.2: {} @@ -9581,16 +9248,6 @@ snapshots: glob-to-regexp@0.4.1: {} - glob@10.5.0: - dependencies: - foreground-child: 3.3.1 - jackspeak: 3.4.3 - minimatch: 9.0.9 - minipass: 7.1.3 - package-json-from-dist: 1.0.1 - path-scurry: 1.11.1 - optional: true - glob@13.0.6: dependencies: minimatch: 10.2.5 @@ -9637,9 +9294,6 @@ snapshots: hpagent@1.2.0: {} - http-cache-semantics@4.2.0: - optional: true - http-errors@2.0.1: dependencies: depd: 2.0.0 @@ -9677,22 +9331,6 @@ snapshots: dependencies: diacritics: 1.3.0 - ibm_db@4.0.1: - dependencies: - adm-zip: 0.5.17 - axios: 1.16.1 - big-integer: 1.6.52 - bindings: 1.5.0 - fs-extra: 11.3.4 - lodash: 4.18.1 - node-addon-api: 7.1.1 - node-gyp: 11.5.0 - targz: 1.0.1 - transitivePeerDependencies: - - debug - - supports-color - optional: true - iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 @@ -9727,9 +9365,6 @@ snapshots: cjs-module-lexer: 2.2.0 module-details-from-path: 1.0.4 - imurmurhash@0.1.4: - optional: true - indent-string@5.0.0: {} inherits@2.0.4: {} @@ -9825,18 +9460,8 @@ snapshots: isexe@2.0.0: {} - isexe@3.1.5: - optional: true - iterare@1.2.1: {} - jackspeak@3.4.3: - dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 - optional: true - jest-worker@27.5.1: dependencies: '@types/node': 24.12.2 @@ -10064,9 +9689,6 @@ snapshots: long@5.3.2: {} - lru-cache@10.4.3: - optional: true - lru-cache@11.5.0: {} lru.min@1.1.4: {} @@ -10079,23 +9701,6 @@ snapshots: make-error@1.3.6: {} - make-fetch-happen@14.0.3: - dependencies: - '@npmcli/agent': 3.0.0 - cacache: 19.0.1 - http-cache-semantics: 4.2.0 - minipass: 7.1.3 - minipass-fetch: 4.0.1 - minipass-flush: 1.0.7 - minipass-pipeline: 1.2.4 - negotiator: 1.0.0 - proc-log: 5.0.0 - promise-retry: 2.0.1 - ssri: 12.0.0 - transitivePeerDependencies: - - supports-color - optional: true - matcher@6.0.0: dependencies: escape-string-regexp: 5.0.0 @@ -10165,58 +9770,14 @@ snapshots: dependencies: brace-expansion: 1.1.14 - minimatch@9.0.9: - dependencies: - brace-expansion: 2.1.0 - optional: true - minimist@1.2.8: {} - minipass-collect@2.0.1: - dependencies: - minipass: 7.1.3 - optional: true - - minipass-fetch@4.0.1: - dependencies: - minipass: 7.1.3 - minipass-sized: 1.0.3 - minizlib: 3.1.0 - optionalDependencies: - encoding: 0.1.13 - optional: true - - minipass-flush@1.0.7: - dependencies: - minipass: 3.3.6 - optional: true - - minipass-pipeline@1.2.4: - dependencies: - minipass: 3.3.6 - optional: true - - minipass-sized@1.0.3: - dependencies: - minipass: 3.3.6 - optional: true - - minipass@3.3.6: - dependencies: - yallist: 4.0.0 - optional: true - minipass@7.1.3: {} minizlib@3.1.0: dependencies: minipass: 7.1.3 - mkdirp@0.5.6: - dependencies: - minimist: 1.2.8 - optional: true - mnemonist@0.38.3: dependencies: obliterator: 1.6.1 @@ -10292,9 +9853,6 @@ snapshots: node-abort-controller@3.1.1: {} - node-addon-api@7.1.1: - optional: true - node-addon-api@8.7.0: {} node-emoji@1.11.0: @@ -10309,22 +9867,6 @@ snapshots: node-gyp-build@4.8.4: {} - node-gyp@11.5.0: - dependencies: - env-paths: 2.2.1 - exponential-backoff: 3.1.3 - graceful-fs: 4.2.11 - make-fetch-happen: 14.0.3 - nopt: 8.1.0 - proc-log: 5.0.0 - semver: 7.7.4 - tar: 7.5.13 - tinyglobby: 0.2.16 - which: 5.0.0 - transitivePeerDependencies: - - supports-color - optional: true - node-releases@2.0.37: {} node-sql-parser@5.4.0: @@ -10539,12 +10081,6 @@ snapshots: path-parse@1.0.7: {} - path-scurry@1.11.1: - dependencies: - lru-cache: 10.4.3 - minipass: 7.1.3 - optional: true - path-scurry@2.0.2: dependencies: lru-cache: 11.5.0 @@ -10634,19 +10170,10 @@ snapshots: dependencies: parse-ms: 4.0.0 - proc-log@5.0.0: - optional: true - process-nextick-args@2.0.1: {} process@0.11.10: {} - promise-retry@2.0.1: - dependencies: - err-code: 2.0.3 - retry: 0.12.0 - optional: true - propagate@2.0.1: {} proxy-addr@2.0.7: @@ -10656,12 +10183,6 @@ snapshots: proxy-from-env@2.1.0: {} - pump@1.0.3: - dependencies: - end-of-stream: 1.4.5 - once: 1.4.0 - optional: true - punycode@2.3.1: {} qrcode@1.5.4: @@ -10770,9 +10291,6 @@ snapshots: ret@0.5.0: {} - retry@0.12.0: - optional: true - reusify@1.1.0: {} rfdc@1.4.1: {} @@ -10952,15 +10470,6 @@ snapshots: smol-toml@1.6.1: {} - socks-proxy-agent@8.0.5: - dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - socks: 2.8.7 - transitivePeerDependencies: - - supports-color - optional: true - socks@2.8.7: dependencies: ip-address: 10.2.0 @@ -11000,11 +10509,6 @@ snapshots: cpu-features: 0.0.10 nan: 2.26.2 - ssri@12.0.0: - dependencies: - minipass: 7.1.3 - optional: true - stack-trace@0.0.10: {} stack-utils@2.0.6: @@ -11029,13 +10533,6 @@ snapshots: is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - string-width@5.1.2: - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.2.0 - optional: true - string-width@7.2.0: dependencies: emoji-regex: 10.6.0 @@ -11127,25 +10624,6 @@ snapshots: tapable@2.3.2: {} - tar-fs@1.16.6: - dependencies: - chownr: 1.1.4 - mkdirp: 0.5.6 - pump: 1.0.3 - tar-stream: 1.6.2 - optional: true - - tar-stream@1.6.2: - dependencies: - bl: 1.2.3 - buffer-alloc: 1.2.0 - end-of-stream: 1.4.5 - fs-constants: 1.0.0 - readable-stream: 2.3.8 - to-buffer: 1.2.2 - xtend: 4.0.2 - optional: true - tar@7.5.13: dependencies: '@isaacs/fs-minipass': 4.0.1 @@ -11154,11 +10632,6 @@ snapshots: minizlib: 3.1.0 yallist: 5.0.0 - targz@1.0.1: - dependencies: - tar-fs: 1.16.6 - optional: true - tarn@3.0.2: {} tedious@19.2.1(@azure/core-client@1.10.1): @@ -11359,16 +10832,6 @@ snapshots: unicorn-magic@0.4.0: {} - unique-filename@4.0.0: - dependencies: - unique-slug: 5.0.0 - optional: true - - unique-slug@5.0.0: - dependencies: - imurmurhash: 0.1.4 - optional: true - universalify@2.0.1: {} unpipe@1.0.0: {} @@ -11483,11 +10946,6 @@ snapshots: dependencies: isexe: 2.0.0 - which@5.0.0: - dependencies: - isexe: 3.1.5 - optional: true - winston-transport@4.9.0: dependencies: logform: 2.7.0 @@ -11516,20 +10974,6 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 - wrap-ansi@7.0.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - optional: true - - wrap-ansi@8.1.0: - dependencies: - ansi-styles: 6.2.3 - string-width: 5.1.2 - strip-ansi: 7.2.0 - optional: true - wrap-ansi@9.0.2: dependencies: ansi-styles: 6.2.3 @@ -11556,9 +11000,6 @@ snapshots: y18n@5.0.8: {} - yallist@4.0.0: - optional: true - yallist@5.0.0: {} yaml@2.8.3: {} diff --git a/rocketadmin-agent/.ibmdb2_test_agent_config.txt b/rocketadmin-agent/.ibmdb2_test_agent_config.txt deleted file mode 100644 index a44d34e84..000000000 --- a/rocketadmin-agent/.ibmdb2_test_agent_config.txt +++ /dev/null @@ -1,23 +0,0 @@ -{ - "encrypted": false, - "hash": null, - "credentials": { - "app_port": 3000, - "azure_encryption": false, - "cert": null, - "database": "testdb", - "host": "test-ibm-db2-e2e-testing", - "password": "password", - "port": 50000, - "schema": "SCHEMA_NAME", - "sid": "null", - "ssl": false, - "token": "IBMDB2-TEST-AGENT-TOKEN", - "type": "ibmdb2", - "username": "db2inst1", - "application_save_option": true, - "config_encryption_option": false, - "encryption_password": null, - "saving_logs_option": false - } -} diff --git a/rocketadmin-agent/Dockerfile b/rocketadmin-agent/Dockerfile index 6610206f2..771c3413c 100644 --- a/rocketadmin-agent/Dockerfile +++ b/rocketadmin-agent/Dockerfile @@ -15,7 +15,6 @@ COPY ./rocketadmin-agent/.oracle_test_agent_config.txt /app/rocketadmin-agent/ COPY ./rocketadmin-agent/.postgres_test_agent_config.txt /app/rocketadmin-agent/ COPY ./rocketadmin-agent/.mysql_test_agent_config.txt /app/rocketadmin-agent/ COPY ./rocketadmin-agent/.mssql_test_agent_config.txt /app/rocketadmin-agent/ -COPY ./rocketadmin-agent/.ibmdb2_test_agent_config.txt /app/rocketadmin-agent/ COPY ./rocketadmin-agent/.mongodb_test_agent_config.txt /app/rocketadmin-agent/ COPY ./rocketadmin-agent/.cassandra_test_agent_config.txt /app/rocketadmin-agent/ COPY ./rocketadmin-agent/.redis_test_agent_config.txt /app/rocketadmin-agent/ @@ -24,6 +23,5 @@ COPY shared-code /app/shared-code COPY ./rocketadmin-agent/ssl-cert.txt /app/rocketadmin-agent/ RUN cd shared-code && ../node_modules/.bin/tsc RUN cd rocketadmin-agent && pnpm run build -COPY ./rocketadmin-agent/wait-for-db2.js /app/ WORKDIR /app/rocketadmin-agent CMD [ "node", "dist/main.js"] diff --git a/rocketadmin-agent/src/helpers/cli/interactive-prompts.ts b/rocketadmin-agent/src/helpers/cli/interactive-prompts.ts index 22822e442..ceff17592 100644 --- a/rocketadmin-agent/src/helpers/cli/interactive-prompts.ts +++ b/rocketadmin-agent/src/helpers/cli/interactive-prompts.ts @@ -1,427 +1,423 @@ -import inquirer from 'inquirer'; -import chalk from 'chalk'; import { ConnectionTypesEnum } from '@rocketadmin/shared-code/dist/src/shared/enums/connection-types-enum.js'; +import chalk from 'chalk'; +import inquirer from 'inquirer'; import { ICLIConnectionCredentials } from '../../interfaces/interfaces.js'; const DATABASE_CHOICES = [ - { name: 'PostgreSQL', value: ConnectionTypesEnum.postgres }, - { name: 'MySQL', value: ConnectionTypesEnum.mysql }, - { name: 'Oracle Database', value: ConnectionTypesEnum.oracledb }, - { name: 'Microsoft SQL Server', value: ConnectionTypesEnum.mssql }, - { name: 'MongoDB', value: ConnectionTypesEnum.mongodb }, - { name: 'IBM Db2', value: ConnectionTypesEnum.ibmdb2 }, - { name: 'Redis', value: ConnectionTypesEnum.redis }, - { name: 'ClickHouse', value: ConnectionTypesEnum.clickhouse }, + { name: 'PostgreSQL', value: ConnectionTypesEnum.postgres }, + { name: 'MySQL', value: ConnectionTypesEnum.mysql }, + { name: 'Oracle Database', value: ConnectionTypesEnum.oracledb }, + { name: 'Microsoft SQL Server', value: ConnectionTypesEnum.mssql }, + { name: 'MongoDB', value: ConnectionTypesEnum.mongodb }, + { name: 'Redis', value: ConnectionTypesEnum.redis }, + { name: 'ClickHouse', value: ConnectionTypesEnum.clickhouse }, ]; const DEFAULT_PORTS: Record = { - [ConnectionTypesEnum.postgres]: 5432, - [ConnectionTypesEnum.mysql]: 3306, - [ConnectionTypesEnum.oracledb]: 1521, - [ConnectionTypesEnum.mssql]: 1433, - [ConnectionTypesEnum.mongodb]: 27017, - [ConnectionTypesEnum.ibmdb2]: 50000, - [ConnectionTypesEnum.redis]: 6379, - [ConnectionTypesEnum.clickhouse]: 8123, + [ConnectionTypesEnum.postgres]: 5432, + [ConnectionTypesEnum.mysql]: 3306, + [ConnectionTypesEnum.oracledb]: 1521, + [ConnectionTypesEnum.mssql]: 1433, + [ConnectionTypesEnum.mongodb]: 27017, + [ConnectionTypesEnum.redis]: 6379, + [ConnectionTypesEnum.clickhouse]: 8123, }; export class InteractivePrompts { - static displayWelcome(): void { - console.log(''); - console.log(chalk.cyan('╔════════════════════════════════════════════════════════════════╗')); - console.log( - chalk.cyan('║') + - chalk.white.bold(' RocketAdmin Agent Configuration Wizard ') + - chalk.cyan('║'), - ); - console.log(chalk.cyan('╚════════════════════════════════════════════════════════════════╝')); - console.log(''); - console.log(chalk.gray('This wizard will help you configure your database connection.')); - console.log(chalk.gray('You can quit at any time by pressing Ctrl+C.')); - console.log(''); - } - - static async askConnectionToken(): Promise { - const { token } = await inquirer.prompt([ - { - type: 'input', - name: 'token', - message: chalk.cyan('Enter your connection token from RocketAdmin:'), - validate: (input: string) => { - if (!input || input.trim().length === 0) { - return chalk.red('Connection token is required'); - } - return true; - }, - }, - ]); - return token.trim(); - } - - static async askConnectionType(): Promise { - const { type } = await inquirer.prompt([ - { - type: 'rawlist', - name: 'type', - message: chalk.cyan('Select your database type:'), - choices: DATABASE_CHOICES, - }, - ]); - console.log(chalk.green(`✓ Selected: ${DATABASE_CHOICES.find((c) => c.value === type)?.name}`)); - return type; - } - - static async askConnectionHost(): Promise { - const { host } = await inquirer.prompt([ - { - type: 'input', - name: 'host', - message: chalk.cyan('Enter database host:'), - default: 'localhost', - validate: (input: string) => { - if (!input || input.trim().length === 0) { - return chalk.red('Host is required'); - } - return true; - }, - }, - ]); - return host.trim(); - } - - static async askConnectionPort(dbType: ConnectionTypesEnum): Promise { - // eslint-disable-next-line security/detect-object-injection - const defaultPort = DEFAULT_PORTS[dbType] || 5432; - const { port } = await inquirer.prompt([ - { - type: 'number', - name: 'port', - message: chalk.cyan('Enter database port:'), - default: defaultPort, - validate: (input: number) => { - if (Number.isNaN(input) || input < 1 || input > 65535) { - return chalk.red('Port must be a number between 1 and 65535'); - } - return true; - }, - }, - ]); - return port; - } - - static async askConnectionUserName(): Promise { - const { username } = await inquirer.prompt([ - { - type: 'input', - name: 'username', - message: chalk.cyan('Enter database username:'), - validate: (input: string) => { - if (!input || input.trim().length === 0) { - return chalk.red('Username is required'); - } - return true; - }, - }, - ]); - return username.trim(); - } - - static async askConnectionPassword(message?: string): Promise { - const { password } = await inquirer.prompt([ - { - type: 'password', - name: 'password', - message: message || chalk.cyan('Enter database password:'), - mask: '*', - validate: (input: string) => { - if (!input || input.trim().length === 0) { - return chalk.red('Password is required'); - } - return true; - }, - }, - ]); - return password.trim(); - } - - static async askConnectionDatabase(): Promise { - const { database } = await inquirer.prompt([ - { - type: 'input', - name: 'database', - message: chalk.cyan('Enter database name:'), - validate: (input: string) => { - if (!input || input.trim().length === 0) { - return chalk.red('Database name is required'); - } - return true; - }, - }, - ]); - return database.trim(); - } - - static async askConnectionSchema(): Promise { - const { schema } = await inquirer.prompt([ - { - type: 'input', - name: 'schema', - message: chalk.cyan('Enter schema name (optional, press Enter to skip):'), - }, - ]); - return schema.trim() || null; - } - - static async askConnectionSid(): Promise { - const { sid } = await inquirer.prompt([ - { - type: 'input', - name: 'sid', - message: chalk.cyan('Enter Oracle SID (optional, press Enter to skip):'), - }, - ]); - return sid.trim() || null; - } - - static async askConnectionAzureEncryption(): Promise { - const { azureEncryption } = await inquirer.prompt([ - { - type: 'confirm', - name: 'azureEncryption', - message: chalk.cyan('Enable Azure encryption?'), - default: false, - }, - ]); - return azureEncryption; - } - - static async askConnectionSslOption(): Promise { - const { ssl } = await inquirer.prompt([ - { - type: 'confirm', - name: 'ssl', - message: chalk.cyan('Enable SSL connection?'), - default: false, - }, - ]); - if (ssl) { - console.log( - chalk.yellow('⚠ Make sure to place your SSL certificate as "cert.pem" in the application directory'), - ); - } - return ssl; - } - - static async askConnectionDataCenter(): Promise { - const { dataCenter } = await inquirer.prompt([ - { - type: 'input', - name: 'dataCenter', - message: chalk.cyan('Enter Cassandra data center (optional, press Enter to skip):'), - }, - ]); - return dataCenter.trim() || null; - } - - static async askConnectionAuthSource(): Promise { - const { authSource } = await inquirer.prompt([ - { - type: 'input', - name: 'authSource', - message: chalk.cyan('Enter MongoDB auth source (optional, press Enter to skip):'), - default: 'admin', - }, - ]); - return authSource.trim() || null; - } - - static async askApplicationSaveConfig(): Promise { - const { save } = await inquirer.prompt([ - { - type: 'confirm', - name: 'save', - message: chalk.cyan('Save configuration to file for future use?'), - default: true, - }, - ]); - return save; - } - - static async askApplicationEncryptConfigOption(): Promise { - const { encrypt } = await inquirer.prompt([ - { - type: 'confirm', - name: 'encrypt', - message: chalk.cyan('Encrypt the saved configuration with a password?'), - default: true, - }, - ]); - return encrypt; - } - - static async askApplicationEncryptionPassword(): Promise { - const { password } = await inquirer.prompt([ - { - type: 'password', - name: 'password', - message: chalk.cyan('Enter encryption password:'), - mask: '*', - validate: (input: string) => { - if (!input || input.length < 4) { - return chalk.red('Password must be at least 4 characters'); - } - return true; - }, - }, - ]); - - const { confirmPassword: _confirmPassword } = await inquirer.prompt([ - { - type: 'password', - name: 'confirmPassword', - message: chalk.cyan('Confirm encryption password:'), - mask: '*', - validate: (input: string) => { - // eslint-disable-next-line security/detect-possible-timing-attacks - if (input !== password) { - return chalk.red('Passwords do not match'); - } - return true; - }, - }, - ]); - - return password; - } - - static async askApplicationSaveLogsOption(): Promise { - const { saveLogs } = await inquirer.prompt([ - { - type: 'confirm', - name: 'saveLogs', - message: chalk.cyan('Save application logs to file?'), - default: false, - }, - ]); - return saveLogs; - } - - static async askDecryptionPassword(): Promise { - const { password } = await inquirer.prompt([ - { - type: 'password', - name: 'password', - message: chalk.cyan('Enter your encryption password to decrypt configuration:'), - mask: '*', - validate: (input: string) => { - if (!input || input.length === 0) { - return chalk.red('Password is required'); - } - return true; - }, - }, - ]); - return password; - } - - static async runInteractiveSetup(): Promise { - InteractivePrompts.displayWelcome(); - - const credentials: ICLIConnectionCredentials = { - app_port: 3000, - azure_encryption: false, - cert: null, - database: null, - host: null, - password: null, - port: null, - schema: null, - sid: null, - ssl: false, - token: null, - type: null, - username: null, - application_save_option: false, - config_encryption_option: false, - encryption_password: null, - saving_logs_option: false, - dataCenter: null, - authSource: null, - }; - - credentials.token = await InteractivePrompts.askConnectionToken(); - credentials.type = await InteractivePrompts.askConnectionType(); - credentials.host = await InteractivePrompts.askConnectionHost(); - credentials.port = await InteractivePrompts.askConnectionPort(credentials.type as ConnectionTypesEnum); - - if (credentials.type !== ConnectionTypesEnum.redis) { - credentials.username = await InteractivePrompts.askConnectionUserName(); - } - credentials.password = await InteractivePrompts.askConnectionPassword(); - - if (credentials.type !== ConnectionTypesEnum.redis) { - credentials.database = await InteractivePrompts.askConnectionDatabase(); - credentials.schema = await InteractivePrompts.askConnectionSchema(); - } - - if (credentials.type === ConnectionTypesEnum.oracledb) { - credentials.sid = await InteractivePrompts.askConnectionSid(); - } - if (credentials.type === ConnectionTypesEnum.mssql) { - credentials.azure_encryption = await InteractivePrompts.askConnectionAzureEncryption(); - } - if (credentials.type === ConnectionTypesEnum.cassandra) { - credentials.dataCenter = await InteractivePrompts.askConnectionDataCenter(); - } - if (credentials.type === ConnectionTypesEnum.mongodb) { - credentials.authSource = await InteractivePrompts.askConnectionAuthSource(); - } - - credentials.ssl = await InteractivePrompts.askConnectionSslOption(); - - console.log(''); - console.log(chalk.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); - console.log(chalk.white.bold(' Configuration Storage Options')); - console.log(chalk.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); - console.log(''); - - credentials.application_save_option = await InteractivePrompts.askApplicationSaveConfig(); - - if (credentials.application_save_option) { - credentials.config_encryption_option = await InteractivePrompts.askApplicationEncryptConfigOption(); - if (credentials.config_encryption_option) { - credentials.encryption_password = await InteractivePrompts.askApplicationEncryptionPassword(); - } - } - - credentials.saving_logs_option = await InteractivePrompts.askApplicationSaveLogsOption(); - - console.log(''); - console.log(chalk.green('✓ Configuration complete!')); - console.log(''); - - return credentials; - } - - static displayConfigSummary(config: ICLIConnectionCredentials): void { - console.log(''); - console.log(chalk.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); - console.log(chalk.white.bold(' Connection Configuration')); - console.log(chalk.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); - console.log(` ${chalk.gray('Database Type:')} ${chalk.white(config.type)}`); - console.log(` ${chalk.gray('Host:')} ${chalk.white(config.host)}`); - console.log(` ${chalk.gray('Port:')} ${chalk.white(config.port)}`); - if (config.username) { - console.log(` ${chalk.gray('Username:')} ${chalk.white('[set]')}`); - } - if (config.database) { - console.log(` ${chalk.gray('Database:')} ${chalk.white(config.database)}`); - } - if (config.schema) { - console.log(` ${chalk.gray('Schema:')} ${chalk.white(config.schema)}`); - } - console.log(` ${chalk.gray('SSL:')} ${chalk.white(config.ssl ? 'Enabled' : 'Disabled')}`); - console.log(chalk.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); - console.log(''); - } + static displayWelcome(): void { + console.log(''); + console.log(chalk.cyan('╔════════════════════════════════════════════════════════════════╗')); + console.log( + chalk.cyan('║') + + chalk.white.bold(' RocketAdmin Agent Configuration Wizard ') + + chalk.cyan('║'), + ); + console.log(chalk.cyan('╚════════════════════════════════════════════════════════════════╝')); + console.log(''); + console.log(chalk.gray('This wizard will help you configure your database connection.')); + console.log(chalk.gray('You can quit at any time by pressing Ctrl+C.')); + console.log(''); + } + + static async askConnectionToken(): Promise { + const { token } = await inquirer.prompt([ + { + type: 'input', + name: 'token', + message: chalk.cyan('Enter your connection token from RocketAdmin:'), + validate: (input: string) => { + if (!input || input.trim().length === 0) { + return chalk.red('Connection token is required'); + } + return true; + }, + }, + ]); + return token.trim(); + } + + static async askConnectionType(): Promise { + const { type } = await inquirer.prompt([ + { + type: 'rawlist', + name: 'type', + message: chalk.cyan('Select your database type:'), + choices: DATABASE_CHOICES, + }, + ]); + console.log(chalk.green(`✓ Selected: ${DATABASE_CHOICES.find((c) => c.value === type)?.name}`)); + return type; + } + + static async askConnectionHost(): Promise { + const { host } = await inquirer.prompt([ + { + type: 'input', + name: 'host', + message: chalk.cyan('Enter database host:'), + default: 'localhost', + validate: (input: string) => { + if (!input || input.trim().length === 0) { + return chalk.red('Host is required'); + } + return true; + }, + }, + ]); + return host.trim(); + } + + static async askConnectionPort(dbType: ConnectionTypesEnum): Promise { + // eslint-disable-next-line security/detect-object-injection + const defaultPort = DEFAULT_PORTS[dbType] || 5432; + const { port } = await inquirer.prompt([ + { + type: 'number', + name: 'port', + message: chalk.cyan('Enter database port:'), + default: defaultPort, + validate: (input: number) => { + if (Number.isNaN(input) || input < 1 || input > 65535) { + return chalk.red('Port must be a number between 1 and 65535'); + } + return true; + }, + }, + ]); + return port; + } + + static async askConnectionUserName(): Promise { + const { username } = await inquirer.prompt([ + { + type: 'input', + name: 'username', + message: chalk.cyan('Enter database username:'), + validate: (input: string) => { + if (!input || input.trim().length === 0) { + return chalk.red('Username is required'); + } + return true; + }, + }, + ]); + return username.trim(); + } + + static async askConnectionPassword(message?: string): Promise { + const { password } = await inquirer.prompt([ + { + type: 'password', + name: 'password', + message: message || chalk.cyan('Enter database password:'), + mask: '*', + validate: (input: string) => { + if (!input || input.trim().length === 0) { + return chalk.red('Password is required'); + } + return true; + }, + }, + ]); + return password.trim(); + } + + static async askConnectionDatabase(): Promise { + const { database } = await inquirer.prompt([ + { + type: 'input', + name: 'database', + message: chalk.cyan('Enter database name:'), + validate: (input: string) => { + if (!input || input.trim().length === 0) { + return chalk.red('Database name is required'); + } + return true; + }, + }, + ]); + return database.trim(); + } + + static async askConnectionSchema(): Promise { + const { schema } = await inquirer.prompt([ + { + type: 'input', + name: 'schema', + message: chalk.cyan('Enter schema name (optional, press Enter to skip):'), + }, + ]); + return schema.trim() || null; + } + + static async askConnectionSid(): Promise { + const { sid } = await inquirer.prompt([ + { + type: 'input', + name: 'sid', + message: chalk.cyan('Enter Oracle SID (optional, press Enter to skip):'), + }, + ]); + return sid.trim() || null; + } + + static async askConnectionAzureEncryption(): Promise { + const { azureEncryption } = await inquirer.prompt([ + { + type: 'confirm', + name: 'azureEncryption', + message: chalk.cyan('Enable Azure encryption?'), + default: false, + }, + ]); + return azureEncryption; + } + + static async askConnectionSslOption(): Promise { + const { ssl } = await inquirer.prompt([ + { + type: 'confirm', + name: 'ssl', + message: chalk.cyan('Enable SSL connection?'), + default: false, + }, + ]); + if (ssl) { + console.log(chalk.yellow('⚠ Make sure to place your SSL certificate as "cert.pem" in the application directory')); + } + return ssl; + } + + static async askConnectionDataCenter(): Promise { + const { dataCenter } = await inquirer.prompt([ + { + type: 'input', + name: 'dataCenter', + message: chalk.cyan('Enter Cassandra data center (optional, press Enter to skip):'), + }, + ]); + return dataCenter.trim() || null; + } + + static async askConnectionAuthSource(): Promise { + const { authSource } = await inquirer.prompt([ + { + type: 'input', + name: 'authSource', + message: chalk.cyan('Enter MongoDB auth source (optional, press Enter to skip):'), + default: 'admin', + }, + ]); + return authSource.trim() || null; + } + + static async askApplicationSaveConfig(): Promise { + const { save } = await inquirer.prompt([ + { + type: 'confirm', + name: 'save', + message: chalk.cyan('Save configuration to file for future use?'), + default: true, + }, + ]); + return save; + } + + static async askApplicationEncryptConfigOption(): Promise { + const { encrypt } = await inquirer.prompt([ + { + type: 'confirm', + name: 'encrypt', + message: chalk.cyan('Encrypt the saved configuration with a password?'), + default: true, + }, + ]); + return encrypt; + } + + static async askApplicationEncryptionPassword(): Promise { + const { password } = await inquirer.prompt([ + { + type: 'password', + name: 'password', + message: chalk.cyan('Enter encryption password:'), + mask: '*', + validate: (input: string) => { + if (!input || input.length < 4) { + return chalk.red('Password must be at least 4 characters'); + } + return true; + }, + }, + ]); + + const { confirmPassword: _confirmPassword } = await inquirer.prompt([ + { + type: 'password', + name: 'confirmPassword', + message: chalk.cyan('Confirm encryption password:'), + mask: '*', + validate: (input: string) => { + // eslint-disable-next-line security/detect-possible-timing-attacks + if (input !== password) { + return chalk.red('Passwords do not match'); + } + return true; + }, + }, + ]); + + return password; + } + + static async askApplicationSaveLogsOption(): Promise { + const { saveLogs } = await inquirer.prompt([ + { + type: 'confirm', + name: 'saveLogs', + message: chalk.cyan('Save application logs to file?'), + default: false, + }, + ]); + return saveLogs; + } + + static async askDecryptionPassword(): Promise { + const { password } = await inquirer.prompt([ + { + type: 'password', + name: 'password', + message: chalk.cyan('Enter your encryption password to decrypt configuration:'), + mask: '*', + validate: (input: string) => { + if (!input || input.length === 0) { + return chalk.red('Password is required'); + } + return true; + }, + }, + ]); + return password; + } + + static async runInteractiveSetup(): Promise { + InteractivePrompts.displayWelcome(); + + const credentials: ICLIConnectionCredentials = { + app_port: 3000, + azure_encryption: false, + cert: null, + database: null, + host: null, + password: null, + port: null, + schema: null, + sid: null, + ssl: false, + token: null, + type: null, + username: null, + application_save_option: false, + config_encryption_option: false, + encryption_password: null, + saving_logs_option: false, + dataCenter: null, + authSource: null, + }; + + credentials.token = await InteractivePrompts.askConnectionToken(); + credentials.type = await InteractivePrompts.askConnectionType(); + credentials.host = await InteractivePrompts.askConnectionHost(); + credentials.port = await InteractivePrompts.askConnectionPort(credentials.type as ConnectionTypesEnum); + + if (credentials.type !== ConnectionTypesEnum.redis) { + credentials.username = await InteractivePrompts.askConnectionUserName(); + } + credentials.password = await InteractivePrompts.askConnectionPassword(); + + if (credentials.type !== ConnectionTypesEnum.redis) { + credentials.database = await InteractivePrompts.askConnectionDatabase(); + credentials.schema = await InteractivePrompts.askConnectionSchema(); + } + + if (credentials.type === ConnectionTypesEnum.oracledb) { + credentials.sid = await InteractivePrompts.askConnectionSid(); + } + if (credentials.type === ConnectionTypesEnum.mssql) { + credentials.azure_encryption = await InteractivePrompts.askConnectionAzureEncryption(); + } + if (credentials.type === ConnectionTypesEnum.cassandra) { + credentials.dataCenter = await InteractivePrompts.askConnectionDataCenter(); + } + if (credentials.type === ConnectionTypesEnum.mongodb) { + credentials.authSource = await InteractivePrompts.askConnectionAuthSource(); + } + + credentials.ssl = await InteractivePrompts.askConnectionSslOption(); + + console.log(''); + console.log(chalk.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(chalk.white.bold(' Configuration Storage Options')); + console.log(chalk.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(''); + + credentials.application_save_option = await InteractivePrompts.askApplicationSaveConfig(); + + if (credentials.application_save_option) { + credentials.config_encryption_option = await InteractivePrompts.askApplicationEncryptConfigOption(); + if (credentials.config_encryption_option) { + credentials.encryption_password = await InteractivePrompts.askApplicationEncryptionPassword(); + } + } + + credentials.saving_logs_option = await InteractivePrompts.askApplicationSaveLogsOption(); + + console.log(''); + console.log(chalk.green('✓ Configuration complete!')); + console.log(''); + + return credentials; + } + + static displayConfigSummary(config: ICLIConnectionCredentials): void { + console.log(''); + console.log(chalk.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(chalk.white.bold(' Connection Configuration')); + console.log(chalk.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(` ${chalk.gray('Database Type:')} ${chalk.white(config.type)}`); + console.log(` ${chalk.gray('Host:')} ${chalk.white(config.host)}`); + console.log(` ${chalk.gray('Port:')} ${chalk.white(config.port)}`); + if (config.username) { + console.log(` ${chalk.gray('Username:')} ${chalk.white('[set]')}`); + } + if (config.database) { + console.log(` ${chalk.gray('Database:')} ${chalk.white(config.database)}`); + } + if (config.schema) { + console.log(` ${chalk.gray('Schema:')} ${chalk.white(config.schema)}`); + } + console.log(` ${chalk.gray('SSL:')} ${chalk.white(config.ssl ? 'Enabled' : 'Disabled')}`); + console.log(chalk.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(''); + } } diff --git a/rocketadmin-agent/src/main.ts b/rocketadmin-agent/src/main.ts index 226343c7b..554b14ae9 100644 --- a/rocketadmin-agent/src/main.ts +++ b/rocketadmin-agent/src/main.ts @@ -1,206 +1,206 @@ #!/usr/bin/env node import 'dotenv/config'; -import { Command } from 'commander'; +import { ConnectionTypesEnum } from '@rocketadmin/shared-code/dist/src/shared/enums/connection-types-enum.js'; import chalk from 'chalk'; +import { Command } from 'commander'; +import { readFileSync } from 'fs'; import ora from 'ora'; -import { ConnectionTypesEnum } from '@rocketadmin/shared-code/dist/src/shared/enums/connection-types-enum.js'; +import { dirname, join } from 'path'; +import { fileURLToPath } from 'url'; import { checkConnection } from './helpers/check-connection.js'; -import { Constants } from './helpers/constants/constants.js'; import { InteractivePrompts } from './helpers/cli/interactive-prompts.js'; +import { Constants } from './helpers/constants/constants.js'; import { mkDirIfNotExistsUtil } from './helpers/write-file-util.js'; import { ICLIConnectionCredentials } from './interfaces/interfaces.js'; import { Config } from './shared/config/config.js'; import { createWebSocketClient } from './websocket/websocket-client.js'; -import { readFileSync } from 'fs'; -import { fileURLToPath } from 'url'; -import { dirname, join } from 'path'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); let version = '0.0.1'; try { - const packageJson = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8')); - version = packageJson.version; + const packageJson = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8')); + version = packageJson.version; } catch {} const program = new Command(); program - .name('rocketadmin-agent') - .description('RocketAdmin Agent - Connect your database to RocketAdmin through a secure agent') - .version(version) - .option('-t, --token ', 'Connection token from RocketAdmin') - .option('--type ', 'Database type (postgres, mysql, oracledb, mssql, mongodb, ibmdb2, redis, clickhouse)') - .option('-H, --host ', 'Database host') - .option('-p, --port ', 'Database port', parseInt) - .option('-u, --username ', 'Database username') - .option('-P, --password ', 'Database password') - .option('-d, --database ', 'Database name') - .option('-s, --schema ', 'Database schema') - .option('--sid ', 'Oracle SID') - .option('--ssl', 'Enable SSL connection', false) - .option('--azure-encryption', 'Enable Azure encryption (MSSQL)', false) - .option('--data-center ', 'Cassandra data center') - .option('--auth-source ', 'MongoDB auth source') - .option('--ws-url ', 'WebSocket server URL (overrides REMOTE_WEBSOCKET_ADDRESS env)') - .option('--save-config', 'Save configuration to file', false) - .option('--encrypt-config', 'Encrypt saved configuration', false) - .option('--encryption-password ', 'Password for config encryption') - .option('--save-logs', 'Save logs to file', false) - .option('-i, --interactive', 'Run interactive configuration wizard', false); + .name('rocketadmin-agent') + .description('RocketAdmin Agent - Connect your database to RocketAdmin through a secure agent') + .version(version) + .option('-t, --token ', 'Connection token from RocketAdmin') + .option('--type ', 'Database type (postgres, mysql, oracledb, mssql, mongodb, redis, clickhouse)') + .option('-H, --host ', 'Database host') + .option('-p, --port ', 'Database port', parseInt) + .option('-u, --username ', 'Database username') + .option('-P, --password ', 'Database password') + .option('-d, --database ', 'Database name') + .option('-s, --schema ', 'Database schema') + .option('--sid ', 'Oracle SID') + .option('--ssl', 'Enable SSL connection', false) + .option('--azure-encryption', 'Enable Azure encryption (MSSQL)', false) + .option('--data-center ', 'Cassandra data center') + .option('--auth-source ', 'MongoDB auth source') + .option('--ws-url ', 'WebSocket server URL (overrides REMOTE_WEBSOCKET_ADDRESS env)') + .option('--save-config', 'Save configuration to file', false) + .option('--encrypt-config', 'Encrypt saved configuration', false) + .option('--encryption-password ', 'Password for config encryption') + .option('--save-logs', 'Save logs to file', false) + .option('-i, --interactive', 'Run interactive configuration wizard', false); async function testDatabaseConnection(connection: ICLIConnectionCredentials, maxRetries: number = 6): Promise { - const spinner = ora({ - text: 'Testing database connection...', - color: 'cyan', - }).start(); - - const testResult = await checkConnection(connection); - if (testResult.result) { - spinner.succeed(chalk.green('Database connection successful')); - return true; - } - - spinner.warn(chalk.yellow('Initial connection failed, retrying...')); - - for (let attempt = 1; attempt <= maxRetries; attempt++) { - const delay = 2000 + attempt * 2000; - console.log(chalk.gray(` Retry ${attempt}/${maxRetries} in ${delay / 1000}s...`)); - - await new Promise((resolve) => setTimeout(resolve, delay)); - - const retryResult = await checkConnection(connection); - if (retryResult.result) { - console.log(chalk.green(`✓ Database connection successful on retry ${attempt}`)); - return true; - } - } - - console.error(chalk.red('✗ Database connection failed after all retries')); - console.error(chalk.red(' Please check your credentials and network connection')); - return false; + const spinner = ora({ + text: 'Testing database connection...', + color: 'cyan', + }).start(); + + const testResult = await checkConnection(connection); + if (testResult.result) { + spinner.succeed(chalk.green('Database connection successful')); + return true; + } + + spinner.warn(chalk.yellow('Initial connection failed, retrying...')); + + for (let attempt = 1; attempt <= maxRetries; attempt++) { + const delay = 2000 + attempt * 2000; + console.log(chalk.gray(` Retry ${attempt}/${maxRetries} in ${delay / 1000}s...`)); + + await new Promise((resolve) => setTimeout(resolve, delay)); + + const retryResult = await checkConnection(connection); + if (retryResult.result) { + console.log(chalk.green(`✓ Database connection successful on retry ${attempt}`)); + return true; + } + } + + console.error(chalk.red('✗ Database connection failed after all retries')); + console.error(chalk.red(' Please check your credentials and network connection')); + return false; } function buildCredentialsFromOptions(options: Record): ICLIConnectionCredentials | null { - if (!options.token || !options.type || !options.host || !options.port) { - return null; - } - - const validTypes = Object.values(ConnectionTypesEnum); - if (!validTypes.includes(options.type as ConnectionTypesEnum)) { - console.error(chalk.red(`Invalid database type: ${options.type}`)); - console.error(chalk.gray(`Valid types: ${validTypes.join(', ')}`)); - process.exit(1); - } - - return { - token: options.token, - type: options.type, - host: options.host, - port: options.port, - username: options.username || null, - password: options.password || null, - database: options.database || null, - schema: options.schema || null, - sid: options.sid || null, - ssl: options.ssl || false, - cert: null, - app_port: 3000, - azure_encryption: options.azureEncryption || false, - application_save_option: options.saveConfig || false, - config_encryption_option: options.encryptConfig || false, - encryption_password: options.encryptionPassword || null, - saving_logs_option: options.saveLogs || false, - dataCenter: options.dataCenter || null, - authSource: options.authSource || null, - }; + if (!options.token || !options.type || !options.host || !options.port) { + return null; + } + + const validTypes = Object.values(ConnectionTypesEnum); + if (!validTypes.includes(options.type as ConnectionTypesEnum)) { + console.error(chalk.red(`Invalid database type: ${options.type}`)); + console.error(chalk.gray(`Valid types: ${validTypes.join(', ')}`)); + process.exit(1); + } + + return { + token: options.token, + type: options.type, + host: options.host, + port: options.port, + username: options.username || null, + password: options.password || null, + database: options.database || null, + schema: options.schema || null, + sid: options.sid || null, + ssl: options.ssl || false, + cert: null, + app_port: 3000, + azure_encryption: options.azureEncryption || false, + application_save_option: options.saveConfig || false, + config_encryption_option: options.encryptConfig || false, + encryption_password: options.encryptionPassword || null, + saving_logs_option: options.saveLogs || false, + dataCenter: options.dataCenter || null, + authSource: options.authSource || null, + }; } async function startAgent(config: ICLIConnectionCredentials, wsUrl?: string): Promise { - console.log(''); - console.log(chalk.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); - console.log(chalk.white.bold(' RocketAdmin Agent Starting')); - console.log(chalk.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); - console.log(''); + console.log(''); + console.log(chalk.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(chalk.white.bold(' RocketAdmin Agent Starting')); + console.log(chalk.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')); + console.log(''); - InteractivePrompts.displayConfigSummary(config); + InteractivePrompts.displayConfigSummary(config); - const connected = await testDatabaseConnection(config); - if (!connected) { - process.exit(1); - } + const connected = await testDatabaseConnection(config); + if (!connected) { + process.exit(1); + } - if (config.saving_logs_option) { - await mkDirIfNotExistsUtil(Constants.DEFAULT_LOGS_DIRNAME); - console.log(chalk.gray('→ Logs will be saved to', Constants.DEFAULT_LOGS_DIRNAME)); - } + if (config.saving_logs_option) { + await mkDirIfNotExistsUtil(Constants.DEFAULT_LOGS_DIRNAME); + console.log(chalk.gray('→ Logs will be saved to', Constants.DEFAULT_LOGS_DIRNAME)); + } - const client = createWebSocketClient(config, wsUrl); - client.connect(); + const client = createWebSocketClient(config, wsUrl); + client.connect(); - console.log(''); - console.log(chalk.green('Agent is running. Press Ctrl+C to stop.')); + console.log(''); + console.log(chalk.green('Agent is running. Press Ctrl+C to stop.')); } function getWebSocketUrl(cliOption?: string): string { - const defaultUrl = 'wss://ws.rocketadmin.com:443/'; - const wsUrl = cliOption || process.env.REMOTE_WEBSOCKET_ADDRESS || defaultUrl; - console.log(chalk.gray(`→ WebSocket URL: ${wsUrl}`)); - console.log(chalk.gray(` (env REMOTE_WEBSOCKET_ADDRESS: ${process.env.REMOTE_WEBSOCKET_ADDRESS || 'not set'})`)); - return wsUrl; + const defaultUrl = 'wss://ws.rocketadmin.com:443/'; + const wsUrl = cliOption || process.env.REMOTE_WEBSOCKET_ADDRESS || defaultUrl; + console.log(chalk.gray(`→ WebSocket URL: ${wsUrl}`)); + console.log(chalk.gray(` (env REMOTE_WEBSOCKET_ADDRESS: ${process.env.REMOTE_WEBSOCKET_ADDRESS || 'not set'})`)); + return wsUrl; } async function main(): Promise { - program.parse(); - const options = program.opts(); - const wsUrl = getWebSocketUrl(options.wsUrl); - - try { - const envConfig = Config.readConnectionConfigFromEnv(); - if (envConfig) { - console.log(chalk.green('→ Configuration loaded from environment variables')); - await Config.setConnectionConfig(envConfig); - await startAgent(envConfig, wsUrl); - return; - } - - const cliConfig = buildCredentialsFromOptions(options); - if (cliConfig && !options.interactive) { - console.log(chalk.green('→ Configuration loaded from command line arguments')); - await Config.setConnectionConfig(cliConfig, cliConfig.application_save_option); - await startAgent(cliConfig, wsUrl); - return; - } - - const savedConfig = await Config.readConfigFromFile(); - if (savedConfig && !options.interactive) { - console.log(chalk.green('→ Configuration loaded from saved file')); - await Config.setConnectionConfig(savedConfig); - await startAgent(savedConfig, wsUrl); - return; - } - - console.log(chalk.gray('No existing configuration found. Starting interactive setup...')); - const interactiveConfig = await InteractivePrompts.runInteractiveSetup(); - - if (interactiveConfig.saving_logs_option) { - await mkDirIfNotExistsUtil(Constants.DEFAULT_LOGS_DIRNAME); - } - - await Config.setConnectionConfig(interactiveConfig, true); - await startAgent(interactiveConfig, wsUrl); - } catch (error) { - if ((error as NodeJS.ErrnoException).code === 'ERR_USE_AFTER_CLOSE') { - console.log(chalk.yellow('\nSetup cancelled.')); - process.exit(0); - } - console.error(chalk.red('Failed to start agent:'), error); - process.exit(1); - } + program.parse(); + const options = program.opts(); + const wsUrl = getWebSocketUrl(options.wsUrl); + + try { + const envConfig = Config.readConnectionConfigFromEnv(); + if (envConfig) { + console.log(chalk.green('→ Configuration loaded from environment variables')); + await Config.setConnectionConfig(envConfig); + await startAgent(envConfig, wsUrl); + return; + } + + const cliConfig = buildCredentialsFromOptions(options); + if (cliConfig && !options.interactive) { + console.log(chalk.green('→ Configuration loaded from command line arguments')); + await Config.setConnectionConfig(cliConfig, cliConfig.application_save_option); + await startAgent(cliConfig, wsUrl); + return; + } + + const savedConfig = await Config.readConfigFromFile(); + if (savedConfig && !options.interactive) { + console.log(chalk.green('→ Configuration loaded from saved file')); + await Config.setConnectionConfig(savedConfig); + await startAgent(savedConfig, wsUrl); + return; + } + + console.log(chalk.gray('No existing configuration found. Starting interactive setup...')); + const interactiveConfig = await InteractivePrompts.runInteractiveSetup(); + + if (interactiveConfig.saving_logs_option) { + await mkDirIfNotExistsUtil(Constants.DEFAULT_LOGS_DIRNAME); + } + + await Config.setConnectionConfig(interactiveConfig, true); + await startAgent(interactiveConfig, wsUrl); + } catch (error) { + if ((error as NodeJS.ErrnoException).code === 'ERR_USE_AFTER_CLOSE') { + console.log(chalk.yellow('\nSetup cancelled.')); + process.exit(0); + } + console.error(chalk.red('Failed to start agent:'), error); + process.exit(1); + } } main().catch((error) => { - console.error(chalk.red('Unexpected error:'), error); - process.exit(1); + console.error(chalk.red('Unexpected error:'), error); + process.exit(1); }); diff --git a/rocketadmin-agent/wait-for-db2.js b/rocketadmin-agent/wait-for-db2.js deleted file mode 100644 index 5ae61454a..000000000 --- a/rocketadmin-agent/wait-for-db2.js +++ /dev/null @@ -1,75 +0,0 @@ -/* eslint-disable @typescript-eslint/no-require-imports */ -const waitOn = require('wait-on'); -const { exec } = require('child_process'); -const { Pool } = require('ibm_db'); - -const opts = { - resources: ['tcp:test-ibm-db2-e2e-testing:50000'], - delay: 1000, - interval: 1000, - timeout: 60000, - tcpTimeout: 1000, - window: 1000, -}; - -async function testConnectionToDB2() { - let connStr = `DATABASE=testdb;HOSTNAME=test-ibm-db2-e2e-testing;UID=db2inst1;PWD=password;PORT=50000;PROTOCOL=TCPIP`; - const connectionPool = new Pool(); - try { - const databaseConnection = await connectionPool.open(connStr); - const query = `SELECT 1 FROM sysibm.sysdummy1`; - const testResult = await databaseConnection.query(query); - await databaseConnection.close(); - if (testResult?.[0] && testResult[0]['1'] === 1) { - return true; - } - } catch (error) { - console.error('Error connecting to DB2:', error); - return false; - } -} - -function checkDB2() { - waitOn(opts, async (err) => { - if (err) { - console.error('Error waiting for DB2:', err); - setTimeout(checkDB2, 5000); - } else { - console.log('DB2 is available'); - const isConnected = await testConnectionToDB2(); - if (isConnected) { - console.log('Successfully connected to DB2'); - console.log('Waiting for 35 seconds to make sure everything is ready...'); - setTimeout(() => { - console.log('Probably DB2 is ready. Starting the application...'); - const child = exec('pnpm start:dev', (err, stdout, stderr) => { - if (err) { - console.error('Error starting the application:', err); - process.exit(1); - } - console.log('Application stdout:', stdout); - console.error('Application stderr:', stderr); - console.log('Application started'); - }); - - child.stdout.on('data', (data) => { - console.log(`stdout: ${data}`); - }); - - child.stderr.on('data', (data) => { - console.error(`stderr: ${data}`); - }); - - child.on('close', (code) => { - console.log(`child process exited with code ${code}`); - }); - }, 35000); - } else { - console.error('Failed to connect to DB2'); - setTimeout(checkDB2, 5000); - } - } - }); -} - -checkDB2(); diff --git a/rocketadmin-agent/wait-for-db2.sh b/rocketadmin-agent/wait-for-db2.sh deleted file mode 100755 index 51a496dbc..000000000 --- a/rocketadmin-agent/wait-for-db2.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -until nc -z test-ibm-db2-e2e-testing 50000; do - echo "$(date) - AGENT waiting for DB2..." - sleep 1 -done - -echo "DB2 is up and running. Waiting for 35 seconds to make sure everything is ready..." -sleep 35 - -echo "Probably DB2 is ready. Starting the application..." -exec pnpm start:dev diff --git a/shared-code/package.json b/shared-code/package.json index 62f1c355d..67670bbc5 100644 --- a/shared-code/package.json +++ b/shared-code/package.json @@ -29,9 +29,6 @@ "tedious": "^19.2.1", "tunnel-ssh": "5.2.0" }, - "optionalDependencies": { - "ibm_db": "4.0.1" - }, "devDependencies": { "@types/oracledb": "^6.10.4", "@types/pg-copy-streams": "^1.2.5", diff --git a/shared-code/src/caching/caching-constants.ts b/shared-code/src/caching/caching-constants.ts index 599fe36f4..4456ac10d 100644 --- a/shared-code/src/caching/caching-constants.ts +++ b/shared-code/src/caching/caching-constants.ts @@ -1,7 +1,6 @@ +import { Client } from 'cassandra-driver'; import { Knex } from 'knex'; -import { Database } from 'ibm_db'; import { MongoClientDB } from '../data-access-layer/data-access-objects/data-access-object-mongodb.js'; -import { Client } from 'cassandra-driver'; export const CACHING_CONSTANTS = { DEFAULT_CONNECTION_CACHE_OPTIONS: { max: 150, @@ -13,16 +12,6 @@ export const CACHING_CONSTANTS = { }, }, - DEFAULT_IMDB_DB2_CACHE_OPTIONS: { - max: 150, - ttl: 1000 * 60 * 60, - updateAgeOnGet: false, - updateAgeOnHas: false, - dispose: async (db: Database) => { - await db.close(); - }, - }, - DEFAULT_CASSANDRA_CLIENT_CACHE_OPTIONS: { max: 150, ttl: 1000 * 60 * 60, diff --git a/shared-code/src/caching/lru-storage.ts b/shared-code/src/caching/lru-storage.ts index 522f460d6..08086dc83 100644 --- a/shared-code/src/caching/lru-storage.ts +++ b/shared-code/src/caching/lru-storage.ts @@ -1,6 +1,5 @@ /** biome-ignore-all lint/complexity/noStaticOnlyClass: */ import { Client } from 'cassandra-driver'; -import { Database } from 'ibm_db'; import { Knex } from 'knex'; import { LRUCache } from 'lru-cache'; import { MongoClientDB } from '../data-access-layer/data-access-objects/data-access-object-mongodb.js'; @@ -12,9 +11,9 @@ import { ForeignKeyDS } from '../data-access-layer/shared/data-structures/foreig import { PrimaryKeyDS } from '../data-access-layer/shared/data-structures/primary-key.ds.js'; import { TableStructureDS } from '../data-access-layer/shared/data-structures/table-structure.ds.js'; import { CACHING_CONSTANTS } from './caching-constants.js'; + const knexCache = new LRUCache(CACHING_CONSTANTS.DEFAULT_CONNECTION_CACHE_OPTIONS); const tunnelCache = new LRUCache(CACHING_CONSTANTS.DEFAULT_TUNNEL_CACHE_OPTIONS); -const imdbDb2Cache = new LRUCache(CACHING_CONSTANTS.DEFAULT_IMDB_DB2_CACHE_OPTIONS); const mongoDbCache = new LRUCache(CACHING_CONSTANTS.DEFAULT_MONGO_DB_CACHE_OPTIONS); const cassandraClientCache = new LRUCache(CACHING_CONSTANTS.DEFAULT_CASSANDRA_CLIENT_CACHE_OPTIONS); const tableStructureCache = new LRUCache(CACHING_CONSTANTS.DEFAULT_TABLE_STRUCTURE_ELEMENTS_CACHE_OPTIONS); @@ -70,19 +69,6 @@ export class LRUStorage { mongoDbCache.delete(LRUStorage.getConnectionIdentifier(connection)); } - public static getImdbDb2Cache(connection: ConnectionParams): Database | null { - const cachedDb = imdbDb2Cache.get(LRUStorage.getConnectionIdentifier(connection)) as Database; - return cachedDb ? cachedDb : null; - } - - public static delImdbDb2Cache(connection: ConnectionParams): void { - imdbDb2Cache.delete(LRUStorage.getConnectionIdentifier(connection)); - } - - public static setImdbDb2Cache(connection: ConnectionParams, newDb: Database): void { - imdbDb2Cache.set(LRUStorage.getConnectionIdentifier(connection), newDb); - } - public static getCachedKnex(connectionConfig: ConnectionParams): Knex | null { const cachedKnex = knexCache.get(LRUStorage.getConnectionIdentifier(connectionConfig)) as Knex; return cachedKnex ? cachedKnex : null; diff --git a/shared-code/src/data-access-layer/data-access-objects/basic-data-access-object.ts b/shared-code/src/data-access-layer/data-access-objects/basic-data-access-object.ts index 84e3b6741..b97a439be 100644 --- a/shared-code/src/data-access-layer/data-access-objects/basic-data-access-object.ts +++ b/shared-code/src/data-access-layer/data-access-objects/basic-data-access-object.ts @@ -106,11 +106,6 @@ export class BasicDataAccessObject { 'TIMESTAMP', 'TIMESTAMP WITH TIME ZONE', 'TIMESTAMP WITH LOCAL TIME ZONE', - - // IBM Db2 - 'DATE', - 'TIME', - 'TIMESTAMP', ]; return dateTimeDataTypes.includes(columnTypeName.toUpperCase()); } diff --git a/shared-code/src/data-access-layer/data-access-objects/data-access-object-ibmdb2.ts b/shared-code/src/data-access-layer/data-access-objects/data-access-object-ibmdb2.ts deleted file mode 100644 index 2b44d0e06..000000000 --- a/shared-code/src/data-access-layer/data-access-objects/data-access-object-ibmdb2.ts +++ /dev/null @@ -1,836 +0,0 @@ -import { Readable, Stream } from 'node:stream'; -import * as csv from 'csv'; -import getPort from 'get-port'; -import { Database, Pool, SQLParam } from 'ibm_db'; -import { nanoid } from 'nanoid'; -import { LRUStorage } from '../../caching/lru-storage.js'; -import { DAO_CONSTANTS } from '../../helpers/data-access-objects-constants.js'; -import { ERROR_MESSAGES } from '../../helpers/errors/error-messages.js'; -import { getTunnel } from '../../helpers/get-ssh-tunnel.js'; -import { tableSettingsFieldValidator } from '../../helpers/validation/table-settings-validator.js'; -import { FilterCriteriaEnum } from '../../shared/enums/filter-criteria.enum.js'; -import { IDataAccessObject } from '../../shared/interfaces/data-access-object.interface.js'; -import { MulterFile } from '../../types/multer-file.js'; -import { AutocompleteFieldsDS } from '../shared/data-structures/autocomplete-fields.ds.js'; -import { ConnectionParams } from '../shared/data-structures/connections-params.ds.js'; -import { FilteringFieldsDS } from '../shared/data-structures/filtering-fields.ds.js'; -import { ForeignKeyDS } from '../shared/data-structures/foreign-key.ds.js'; -import { FoundRowsDS } from '../shared/data-structures/found-rows.ds.js'; -import { PrimaryKeyDS } from '../shared/data-structures/primary-key.ds.js'; -import { ReferencedTableNamesAndColumnsDS } from '../shared/data-structures/referenced-table-names-columns.ds.js'; -import { RowsPaginationDS } from '../shared/data-structures/rows-pagination.ds.js'; -import { TableDS } from '../shared/data-structures/table.ds.js'; -import { TableSettingsDS } from '../shared/data-structures/table-settings.ds.js'; -import { TableStructureDS } from '../shared/data-structures/table-structure.ds.js'; -import { TestConnectionResultDS } from '../shared/data-structures/test-result-connection.ds.js'; -import { ValidateTableSettingsDS } from '../shared/data-structures/validate-table-settings.ds.js'; -import { BasicDataAccessObject } from './basic-data-access-object.js'; - -interface IbmDb2Row { - COLUMN_NAME: string; - DATA_TYPE: string; - CONSTRAINT_NAME?: string; - REFERENCED_TABLE_NAME?: string; - REFERENCED_COLUMN_NAME?: string; - IS_NULLABLE?: string; - COLUMN_DEFAULT?: string; - CHARACTER_MAXIMUM_LENGTH?: number; - TABLE_NAME?: string; - TABLE_TYPE?: string; - REFERENCING_TABLE_NAME?: string; - REFERENCING_COLUMN_NAME?: string; -} - -export class DataAccessObjectIbmDb2 extends BasicDataAccessObject implements IDataAccessObject { - public async addRowInTable( - tableName: string, - row: Record, - ): Promise> { - this.validateNamesAndThrowError([tableName, this.connection.schema, ...Object.keys(row)]); - const connectionToDb = await this.getConnectionToDatabase(); - const [tableStructure, primaryColumns] = await Promise.all([ - this.getTableStructure(tableName), - this.getTablePrimaryColumns(tableName), - ]); - - const jsonColumnNames = tableStructure - .filter((structEl) => structEl.data_type.toLowerCase() === 'json') - .map((structEl) => structEl.column_name); - - for (const key in row) { - if (jsonColumnNames.includes(key)) { - // eslint-disable-next-line security/detect-object-injection - row[key] = JSON.stringify(row[key]); - } - } - - const columns = Object.keys(row).join(', '); - const placeholders = Object.keys(row) - .map(() => '?') - .join(', '); - const values = Object.values(row) as SQLParam[]; - const query = ` - INSERT INTO ${this.connection.schema.toUpperCase()}.${tableName.toUpperCase()} (${columns}) - VALUES (${placeholders}) - `; - await connectionToDb.query(query, values); - - if (primaryColumns?.length > 0) { - const primaryKey = primaryColumns.map((column) => column.column_name); - const selectQuery = ` - SELECT ${primaryKey.join(', ')} - FROM ${this.connection.schema.toUpperCase()}.${tableName.toUpperCase()} - WHERE ${Object.keys(row) - .map((key) => `${key} = ?`) - .join(' AND ')} - `; - const result = await connectionToDb.query(selectQuery, Object.values(row) as SQLParam[]); - return result[0] as Record; - } - return row; - } - - public async deleteRowInTable( - tableName: string, - primaryKey: Record, - ): Promise> { - this.validateNamesAndThrowError([tableName, this.connection.schema, ...Object.keys(primaryKey)]); - const connectionToDb = await this.getConnectionToDatabase(); - const whereClause = Object.keys(primaryKey) - .map((key) => `${key} = ?`) - .join(' AND '); - const query = ` - DELETE FROM ${this.connection.schema.toUpperCase()}.${tableName.toUpperCase()} - WHERE ${whereClause} - `; - const params = Object.values(primaryKey) as SQLParam[]; - await connectionToDb.query(query, params); - return primaryKey; - } - - public async getIdentityColumns( - tableName: string, - referencedFieldName: string, - identityColumnName: string, - fieldValues: (string | number)[], - ): Promise>> { - const schemaName = this.connection.schema.toUpperCase(); - const namesToValidate = [tableName, referencedFieldName, schemaName]; - if (identityColumnName) { - namesToValidate.push(identityColumnName); - } - this.validateNamesAndThrowError(namesToValidate); - const connectionToDb = await this.getConnectionToDatabase(); - const columnsToSelect = identityColumnName ? `${referencedFieldName}, ${identityColumnName}` : referencedFieldName; - const placeholders = fieldValues.map(() => '?').join(', '); - const query = ` - SELECT ${columnsToSelect} - FROM ${schemaName}.${tableName.toUpperCase()} - WHERE ${referencedFieldName} IN (${placeholders}) - `; - const result = await connectionToDb.query(query, [...fieldValues] as SQLParam[]); - return result as Record[]; - } - - public async getRowByPrimaryKey( - tableName: string, - primaryKey: Record, - settings: TableSettingsDS, - ): Promise> { - this.validateNamesAndThrowError([tableName, this.connection.schema, ...Object.keys(primaryKey)]); - const connectionToDb = await this.getConnectionToDatabase(); - const whereClause = Object.keys(primaryKey) - .map((key) => `${key} = ?`) - .join(' AND '); - let selectFields = '*'; - if (settings) { - const tableStructure = await this.getTableStructure(tableName); - const availableFields = this.findAvailableFields(settings, tableStructure); - selectFields = availableFields.join(', '); - } - const query = ` - SELECT ${selectFields} - FROM ${this.connection.schema.toUpperCase()}.${tableName.toUpperCase()} - WHERE ${whereClause} - `; - const params = Object.values(primaryKey) as SQLParam[]; - const result = await connectionToDb.query(query, params); - return result[0] as Record; - } - - public async bulkGetRowsFromTableByPrimaryKeys( - tableName: string, - primaryKeys: Array>, - settings: TableSettingsDS, - ): Promise>> { - this.validateNamesAndThrowError([tableName, this.connection.schema, ...primaryKeys.flatMap(Object.keys)]); - - const connectionToDb = await this.getConnectionToDatabase(); - const schemaName = this.connection.schema.toUpperCase(); - tableName = tableName.toUpperCase(); - - let selectFields = '*'; - if (settings) { - const tableStructure = await this.getTableStructure(tableName); - const availableFields = this.findAvailableFields(settings, tableStructure); - selectFields = availableFields.join(', '); - } - - const whereClauses = primaryKeys - .map((primaryKey) => { - const conditions = Object.entries(primaryKey) - .map(([key, _value]) => `${key} = ?`) - .join(' AND '); - return `(${conditions})`; - }) - .join(' OR '); - - const flatPrimaryKeysValues = primaryKeys.flatMap(Object.values) as SQLParam[]; - - const query = ` - SELECT ${selectFields} - FROM ${schemaName}.${tableName} - WHERE ${whereClauses} - `; - - const results = await connectionToDb.query(query, flatPrimaryKeysValues); - return results as Record[]; - } - - public async getRowsFromTable( - tableName: string, - settings: TableSettingsDS, - page: number, - perPage: number, - searchedFieldValue: string, - filteringFields: FilteringFieldsDS[], - autocompleteFields: AutocompleteFieldsDS, - tableStructure: TableStructureDS[] | null, - ): Promise { - const connectionSchema = this.connection.schema.toUpperCase(); - tableName = tableName.toUpperCase(); - this.validateNamesAndThrowError([tableName, connectionSchema]); - - if (!page || page <= 0) { - page = DAO_CONSTANTS.DEFAULT_PAGINATION.page; - const { list_per_page } = settings; - if (list_per_page && list_per_page > 0 && (!perPage || perPage <= 0)) { - perPage = list_per_page; - } else { - perPage = DAO_CONSTANTS.DEFAULT_PAGINATION.perPage; - } - } - const connectionToDb = await this.getConnectionToDatabase(); - - const { large_dataset, rowsCount } = await this.getRowsCount(tableName, this.connection.schema); - if (!tableStructure) { - tableStructure = await this.getTableStructure(tableName); - } - const availableFields = this.findAvailableFields(settings, tableStructure); - - const lastPage = Math.ceil(rowsCount / perPage); - let rowsRO: FoundRowsDS; - - const queryParams: SQLParam[] = []; - - if (autocompleteFields?.value && autocompleteFields.fields.length > 0) { - const validatedAutocompleteFields = autocompleteFields.fields.filter((field) => availableFields.includes(field)); - if (validatedAutocompleteFields.length === 0) { - throw new Error('Invalid autocomplete fields provided'); - } - this.validateNamesAndThrowError(validatedAutocompleteFields); - const fields = validatedAutocompleteFields.join(', '); - const autocompleteConditions = validatedAutocompleteFields.map((field) => `${field} LIKE ?`).join(' OR '); - const autocompleteQuery = `SELECT ${fields} FROM ${connectionSchema}.${tableName} WHERE ${autocompleteConditions} FETCH FIRST ${DAO_CONSTANTS.AUTOCOMPLETE_ROW_LIMIT} ROWS ONLY`; - const autocompleteParams = validatedAutocompleteFields.map(() => `${autocompleteFields.value}%`); - const rows = await connectionToDb.query(autocompleteQuery, autocompleteParams); - - rowsRO = { - data: rows as Record[], - pagination: {} as RowsPaginationDS, - large_dataset: large_dataset, - }; - return rowsRO; - } - - let searchQuery = ''; - if (searchedFieldValue) { - const searchFields = settings.search_fields?.length > 0 ? settings.search_fields : availableFields; - const validatedSearchFields = searchFields.filter((field) => availableFields.includes(field)); - this.validateNamesAndThrowError(validatedSearchFields); - if (rowsCount <= 1000) { - const searchConditions = validatedSearchFields - .map((field) => { - queryParams.push(`%${searchedFieldValue.toLowerCase()}%`); - return `LOWER(CAST(${field} AS VARCHAR(255))) LIKE ?`; - }) - .join(' OR '); - searchQuery = ` WHERE (${searchConditions})`; - } else { - const searchConditions = validatedSearchFields - .map((field) => { - queryParams.push(`${searchedFieldValue.toLowerCase()}%`); - return `LOWER(CAST(${field} AS VARCHAR(255))) LIKE ?`; - }) - .join(' OR '); - searchQuery = ` WHERE (${searchConditions})`; - } - } - - let filterQuery = ''; - if (filteringFields && filteringFields.length > 0) { - const invalidFields = filteringFields.filter((f) => !availableFields.includes(f.field)); - if (invalidFields.length > 0) { - throw new Error(`Invalid filter fields: ${invalidFields.map((f) => f.field).join(', ')}`); - } - this.validateNamesAndThrowError(filteringFields.map((f) => f.field)); - - const filterConditions = filteringFields - .map((filterObject) => { - switch (filterObject.criteria) { - case FilterCriteriaEnum.eq: - queryParams.push(filterObject.value as SQLParam); - return `${filterObject.field} = ?`; - case FilterCriteriaEnum.startswith: - queryParams.push(`${filterObject.value}%`); - return `${filterObject.field} LIKE ?`; - case FilterCriteriaEnum.endswith: - queryParams.push(`%${filterObject.value}`); - return `${filterObject.field} LIKE ?`; - case FilterCriteriaEnum.gt: - queryParams.push(filterObject.value as SQLParam); - return `${filterObject.field} > ?`; - case FilterCriteriaEnum.lt: - queryParams.push(filterObject.value as SQLParam); - return `${filterObject.field} < ?`; - case FilterCriteriaEnum.lte: - queryParams.push(filterObject.value as SQLParam); - return `${filterObject.field} <= ?`; - case FilterCriteriaEnum.gte: - queryParams.push(filterObject.value as SQLParam); - return `${filterObject.field} >= ?`; - case FilterCriteriaEnum.contains: - queryParams.push(`%${filterObject.value}%`); - return `${filterObject.field} LIKE ?`; - case FilterCriteriaEnum.icontains: - queryParams.push(`%${filterObject.value}%`); - return `${filterObject.field} NOT LIKE ?`; - case FilterCriteriaEnum.empty: - return `(${filterObject.field} IS NULL)`; - case FilterCriteriaEnum.in: { - const inValues = Array.isArray(filterObject.value) - ? filterObject.value - : String(filterObject.value) - .split(',') - .map((v) => v.trim()); - const placeholders = inValues.map(() => '?').join(', '); - queryParams.push(...(inValues as SQLParam[])); - return `${filterObject.field} IN (${placeholders})`; - } - case FilterCriteriaEnum.between: { - const betweenValues = Array.isArray(filterObject.value) - ? filterObject.value - : String(filterObject.value) - .split(',') - .map((v) => v.trim()); - queryParams.push(betweenValues[0] as SQLParam, betweenValues[1] as SQLParam); - return `${filterObject.field} BETWEEN ? AND ?`; - } - } - }) - .join(' AND '); - filterQuery = searchQuery ? ` AND (${filterConditions})` : ` WHERE (${filterConditions})`; - } - - let orderQuery = ''; - if (settings.ordering_field && settings.ordering) { - if (!availableFields.includes(settings.ordering_field)) { - throw new Error(`Invalid ordering field: ${settings.ordering_field}`); - } - this.validateNamesAndThrowError([settings.ordering_field]); - const orderDirection = settings.ordering.toUpperCase() === 'DESC' ? 'DESC' : 'ASC'; - orderQuery = ` ORDER BY ${settings.ordering_field} ${orderDirection}`; - } - const paginationQuery = ` OFFSET ${(page - 1) * perPage} ROWS FETCH NEXT ${perPage} ROWS ONLY`; - - const rowsQuery = `SELECT ${availableFields.join( - ',', - )} FROM ${connectionSchema}.${tableName}${searchQuery}${filterQuery}${orderQuery}${paginationQuery}`; - - const rows = await connectionToDb.query(rowsQuery, queryParams); - - rowsRO = { - data: rows as Record[], - pagination: { - total: rowsCount, - lastPage: lastPage, - perPage: perPage, - currentPage: page, - }, - large_dataset: large_dataset, - }; - return rowsRO; - } - - public async getTableForeignKeys(tableName: string): Promise { - const cachedForeignKeys = LRUStorage.getTableForeignKeysCache(this.connection, tableName); - if (cachedForeignKeys) { - return cachedForeignKeys; - } - const connectionToDb = await this.getConnectionToDatabase(); - const query = ` - SELECT - ref.constname AS constraint_name, - col.colname AS column_name, - pk.tabname AS referenced_table_name, - pk.colname AS referenced_column_name -FROM - syscat.references ref - JOIN - syscat.keycoluse col - ON - ref.constname = col.constname AND - ref.tabschema = col.tabschema - JOIN - syscat.keycoluse pk - ON - ref.refkeyname = pk.constname AND - ref.reftabschema = pk.tabschema AND - col.colseq = pk.colseq -WHERE - ref.tabname = ? AND - ref.tabschema = ? -ORDER BY - ref.constname, col.colseq - `; - const foreignKeys = await connectionToDb.query(query, [ - tableName.toUpperCase(), - this.connection.schema.toUpperCase(), - ]); - - const resultKeys = (foreignKeys as unknown as IbmDb2Row[]).map((foreignKey) => { - return { - column_name: foreignKey.COLUMN_NAME, - constraint_name: foreignKey.CONSTRAINT_NAME, - referenced_table_name: foreignKey.REFERENCED_TABLE_NAME, - referenced_column_name: foreignKey.REFERENCED_COLUMN_NAME, - }; - }); - LRUStorage.setTableForeignKeysCache(this.connection, tableName, resultKeys); - return resultKeys; - } - - public async getTablePrimaryColumns(tableName: string): Promise { - const cachedPrimaryColumns = LRUStorage.getTablePrimaryKeysCache(this.connection, tableName); - if (cachedPrimaryColumns) { - return cachedPrimaryColumns; - } - const connectionToDb = await this.getConnectionToDatabase(); - const query = ` - SELECT colname AS column_name, typename AS data_type - FROM syscat.columns - WHERE tabname = ? - AND tabschema = ? - AND keyseq IS NOT NULL - `; - const primaryKeys = await connectionToDb.query(query, [ - tableName.toUpperCase(), - this.connection.schema.toUpperCase(), - ]); - - const resultKeys = (primaryKeys as unknown as IbmDb2Row[]).map((primaryKey) => { - return { - column_name: primaryKey.COLUMN_NAME, - data_type: primaryKey.DATA_TYPE as string, - }; - }); - LRUStorage.setTablePrimaryKeysCache(this.connection, tableName, resultKeys); - return resultKeys; - } - - public async getTablesFromDB(): Promise { - const connectionToDb = await this.getConnectionToDatabase(); - const query = ` - SELECT tabname AS table_name, type AS table_type - FROM syscat.tables - WHERE tabschema = ? - AND type IN ('T', 'V') - `; - const tables = await connectionToDb.query(query, [this.connection.schema.toUpperCase()]); - - return (tables as unknown as IbmDb2Row[]).map((table) => { - return { - tableName: table.TABLE_NAME, - isView: table.TABLE_TYPE === 'V', - }; - }); - } - - public async getTableStructure(tableName: string): Promise { - const connectionToDb = await this.getConnectionToDatabase(); - const query = ` - SELECT colname AS column_name, - typename AS data_type, - length AS character_maximum_length, - scale AS numeric_scale, - keyseq AS ordinal_position, - nulls AS is_nullable, - default AS column_default - FROM syscat.columns - WHERE tabname = ? - AND tabschema = ? - `; - const tableStructure = await connectionToDb.query(query, [ - tableName.toUpperCase(), - this.connection.schema.toUpperCase(), - ]); - - return (tableStructure as unknown as IbmDb2Row[]).map((column) => { - return { - allow_null: column.IS_NULLABLE === 'Y', - column_default: column.COLUMN_DEFAULT, - column_name: column.COLUMN_NAME, - data_type: column.DATA_TYPE, - character_maximum_length: column.CHARACTER_MAXIMUM_LENGTH, - data_type_params: null, - udt_name: null, - extra: null, - }; - }); - } - - public async getTableStructureWithoutCache(tableName: string): Promise { - return this.getTableStructure(tableName); - } - - public async testConnect(): Promise { - if (!this.connection.id) { - this.connection.id = nanoid(6); - } - const connectionToDb = await this.getConnectionToDatabase(); - const query = ` - SELECT 1 FROM sysibm.sysdummy1 - `; - try { - const testResult = await connectionToDb.query(query); - if (testResult?.[0] && testResult[0]['1'] === 1) { - return { - result: true, - message: 'Successfully connected', - }; - } - } catch (error) { - return { - result: false, - message: error.message, - }; - } finally { - LRUStorage.delImdbDb2Cache(this.connection); - } - return { - result: false, - message: 'Unknown error', - }; - } - - public async updateRowInTable( - tableName: string, - row: Record, - primaryKey: Record, - ): Promise> { - this.validateNamesAndThrowError([ - tableName, - this.connection.schema, - ...Object.keys(row), - ...Object.keys(primaryKey), - ]); - const connectionToDb = await this.getConnectionToDatabase(); - - const setClause = Object.keys(row) - .map((key) => `${key} = ?`) - .join(', '); - const whereClause = Object.keys(primaryKey) - .map((key) => `${key} = ?`) - .join(' AND '); - - const query = ` - UPDATE ${this.connection.schema.toUpperCase()}.${tableName.toUpperCase()} - SET ${setClause} - WHERE ${whereClause} - `; - const params = [...Object.values(row), ...Object.values(primaryKey)] as SQLParam[]; - await connectionToDb.query(query, params); - - const selectQuery = ` - SELECT * - FROM ${this.connection.schema.toUpperCase()}.${tableName.toUpperCase()} - WHERE ${whereClause} - `; - const result = await connectionToDb.query(selectQuery, Object.values(primaryKey) as SQLParam[]); - return result[0] as Record; - } - - public async bulkUpdateRowsInTable( - tableName: string, - newValues: Record, - primaryKeys: Array>, - ): Promise>> { - await Promise.allSettled(primaryKeys.map((key) => this.updateRowInTable(tableName, newValues, key))); - return primaryKeys; - } - - public async bulkDeleteRowsInTable(tableName: string, primaryKeys: Array>): Promise { - await Promise.allSettled(primaryKeys.map((key) => this.deleteRowInTable(tableName, key))); - return primaryKeys.length; - } - - public async validateSettings(settings: ValidateTableSettingsDS, tableName: string): Promise { - const [tableStructure, primaryColumns] = await Promise.all([ - this.getTableStructure(tableName), - this.getTablePrimaryColumns(tableName), - ]); - return tableSettingsFieldValidator(tableStructure, primaryColumns, settings); - } - - public async getReferencedTableNamesAndColumns(tableName: string): Promise { - const primaryColumns = await this.getTablePrimaryColumns(tableName); - const connectionToDb = await this.getConnectionToDatabase(); - const results: Array = []; - for (const primaryColumn of primaryColumns) { - const query = ` - SELECT - ref.tabname AS referencing_table_name, - col.colname AS referencing_column_name - FROM - syscat.references ref - JOIN - syscat.keycoluse col - ON - ref.constname = col.constname AND - ref.tabschema = col.tabschema - WHERE - ref.reftabname = ? AND - ref.reftabschema = ? AND - ref.refkeyname IN ( - SELECT constname - FROM syscat.keycoluse - WHERE tabschema = ? AND - tabname = ? AND - colname = ? - ) - `; - const foreignKeys = await connectionToDb.query(query, [ - tableName.toUpperCase(), - this.connection.schema.toUpperCase(), - this.connection.schema.toUpperCase(), - tableName.toUpperCase(), - primaryColumn.column_name.toUpperCase(), - ]); - results.push({ - referenced_on_column_name: primaryColumn.column_name, - referenced_by: (foreignKeys as unknown as IbmDb2Row[]).map((foreignKey) => { - return { - table_name: foreignKey.REFERENCING_TABLE_NAME, - column_name: foreignKey.REFERENCING_COLUMN_NAME, - }; - }), - }); - } - return results; - } - - public async isView(tableName: string): Promise { - const connectionToDb = await this.getConnectionToDatabase(); - const query = ` - SELECT TYPE AS table_type - FROM SYSCAT.TABLES - WHERE TABSCHEMA = ? AND TABNAME = ? - `; - const tableData = await connectionToDb.query(query, [ - this.connection.schema.toUpperCase(), - tableName.toUpperCase(), - ]); - return (tableData[0] as unknown as IbmDb2Row).TABLE_TYPE === 'V'; - } - - public async getTableRowsStream( - tableName: string, - settings: TableSettingsDS, - page: number, - perPage: number, - searchedFieldValue: string, - filteringFields: FilteringFieldsDS[], - ): Promise>> { - const { large_dataset } = await this.getRowsCount(tableName, this.connection.schema); - if (large_dataset) { - throw new Error(ERROR_MESSAGES.DATA_IS_TO_LARGE); - } - const rowsResult = await this.getRowsFromTable( - tableName, - settings, - page, - perPage, - searchedFieldValue, - filteringFields, - null, - null, - ); - return rowsResult.data as unknown as Stream & AsyncIterable>; - } - - public async getRowsCount( - tableName: string, - tableSchema: string, - ): Promise<{ rowsCount: number; large_dataset: boolean }> { - const connectionToDb = await this.getConnectionToDatabase(); - const fastCount = await this.getFastRowsCount(tableName, tableSchema); - if (fastCount >= DAO_CONSTANTS.LARGE_DATASET_ROW_LIMIT) { - return { rowsCount: fastCount, large_dataset: true }; - } - const countQuery = ` - SELECT COUNT(*) - FROM ${tableSchema}.${tableName} - `; - const countResult = await connectionToDb.query(countQuery); - const rowsCount = parseInt(countResult[0]['1'], 10); - return { rowsCount: rowsCount, large_dataset: false }; - } - - public async getFastRowsCount(tableName: string, tableSchema: string): Promise { - const connectionToDb = await this.getConnectionToDatabase(); - const fastCountQuery = ` - SELECT CARD - FROM SYSIBM.SYSTABLES - WHERE NAME = ? - AND CREATOR = ? - `; - const fastCountParams = [tableName, tableSchema]; - const fastCountQueryResult = await connectionToDb.query(fastCountQuery, fastCountParams); - const fastCount = (fastCountQueryResult[0] as Record).CARD; - return fastCount; - } - - public async importCSVInTable(file: MulterFile, tableName: string): Promise { - const stream = new Readable(); - stream.push(file.buffer); - stream.push(null); - - const parser = stream.pipe(csv.parse({ columns: true })); - const results: Record[] = []; - for await (const record of parser) { - results.push(record as Record); - } - await Promise.allSettled( - results.map(async (row) => { - return await this.addRowInTable(tableName, row); - }), - ); - } - - public async executeRawQuery(query: string): Promise>> { - const connectionToDb = await this.getConnectionToDatabase(); - const result = await connectionToDb.query(query); - return result as Record[]; - } - - public async getSchemaHash(): Promise { - const cachedHash = LRUStorage.getSchemaHashCache(this.connection); - if (cachedHash) { - return cachedHash; - } - - const connectionToDb = await this.getConnectionToDatabase(); - const schema = this.connection.schema?.toUpperCase() ?? this.connection.username.toUpperCase(); - - const query = ` - SELECT - COALESCE(table_count, 0) || '|' || - COALESCE(column_count, 0) || '|' || - COALESCE(index_count, 0) || '|' || - COALESCE(column_checksum, 0) AS SCHEMA_HASH - FROM ( - SELECT - (SELECT COUNT(*) FROM SYSCAT.TABLES WHERE TABSCHEMA = ? AND TYPE = 'T') AS table_count, - (SELECT COUNT(*) FROM SYSCAT.COLUMNS WHERE TABSCHEMA = ?) AS column_count, - (SELECT COUNT(*) FROM SYSCAT.INDEXES WHERE TABSCHEMA = ?) AS index_count, - (SELECT COALESCE(SUM(COLNO + LENGTH(COLNAME) + LENGTH(TYPENAME)), 0) - FROM SYSCAT.COLUMNS WHERE TABSCHEMA = ?) AS column_checksum - FROM SYSIBM.SYSDUMMY1 - ) - `; - - const result = await connectionToDb.query(query, [schema, schema, schema, schema]); - const hash = (result as Array>)?.[0]?.SCHEMA_HASH || ''; - - LRUStorage.validateSchemaHashAndInvalidate(this.connection, hash as string); - - return hash as string; - } - - private getConnectionToDatabase(): Promise { - if (this.connection.ssh) { - return this.createTunneledConnection(this.connection); - } - return this.getUsualConnection(); - } - - private async getUsualConnection(withCache = true): Promise { - const cachedDatabase = LRUStorage.getImdbDb2Cache(this.connection); - if (withCache && cachedDatabase && cachedDatabase.connected) { - return cachedDatabase; - } - let connStr = `DATABASE=${this.connection.database};HOSTNAME=${this.connection.host};UID=${this.connection.username};PWD=${this.connection.password};PORT=${this.connection.port};PROTOCOL=TCPIP`; - if (this.connection.ssl) { - connStr += ';SECURITY=SSL'; - if (this.connection.cert) { - connStr += `;SSLServerCertificate=${this.connection.cert}`; - } - } - const connectionPool = new Pool(); - const databaseConnection = await connectionPool.open(connStr); - LRUStorage.setImdbDb2Cache(this.connection, databaseConnection); - return databaseConnection; - } - - private createTunneledConnection(connection: ConnectionParams): Promise { - const connectionCopy = { ...connection }; - return new Promise(async (resolve, reject) => { - const cachedTnl = LRUStorage.getTunnelCache(connectionCopy); - if (cachedTnl?.database && cachedTnl.server && cachedTnl.client && cachedTnl.database.connected) { - resolve(cachedTnl.database); - return; - } - const freePort = await getPort(); - try { - const [server, client] = await getTunnel(connectionCopy, freePort); - connection.host = '127.0.0.1'; - connection.port = freePort; - const database = await this.getUsualConnection(false); - const tnlCachedObj = { - server: server, - client: client, - database: database, - }; - LRUStorage.setTunnelCache(connectionCopy, tnlCachedObj); - resolve(tnlCachedObj.database); - - client.on('error', (e) => { - LRUStorage.delTunnelCache(connectionCopy); - reject(e); - return; - }); - - server.on('error', (e) => { - LRUStorage.delTunnelCache(connectionCopy); - reject(e); - return; - }); - return; - } catch (error) { - LRUStorage.delTunnelCache(connectionCopy); - reject(error); - return; - } - }); - } -} diff --git a/shared-code/src/data-access-layer/shared/create-data-access-object.ts b/shared-code/src/data-access-layer/shared/create-data-access-object.ts index 99bee6bdb..344255492 100644 --- a/shared-code/src/data-access-layer/shared/create-data-access-object.ts +++ b/shared-code/src/data-access-layer/shared/create-data-access-object.ts @@ -1,10 +1,12 @@ import { ERROR_MESSAGES } from '../../helpers/errors/error-messages.js'; +import { ConnectionTypesEnum } from '../../shared/enums/connection-types-enum.js'; +import { IDataAccessObject } from '../../shared/interfaces/data-access-object.interface.js'; +import { IDataAccessObjectAgent } from '../../shared/interfaces/data-access-object-agent.interface.js'; import { DataAccessObjectAgent } from '../data-access-objects/data-access-object-agent.js'; import { DataAccessObjectCassandra } from '../data-access-objects/data-access-object-cassandra.js'; import { DataAccessObjectClickHouse } from '../data-access-objects/data-access-object-clickhouse.js'; import { DataAccessObjectDynamoDB } from '../data-access-objects/data-access-object-dynamodb.js'; import { DataAccessObjectElasticsearch } from '../data-access-objects/data-access-object-elasticsearch.js'; -import { DataAccessObjectIbmDb2 } from '../data-access-objects/data-access-object-ibmdb2.js'; import { DataAccessObjectMongo } from '../data-access-objects/data-access-object-mongodb.js'; import { DataAccessObjectMssql } from '../data-access-objects/data-access-object-mssql.js'; import { DataAccessObjectMysql } from '../data-access-objects/data-access-object-mysql.js'; @@ -12,9 +14,6 @@ import { DataAccessObjectOracle } from '../data-access-objects/data-access-objec import { DataAccessObjectPostgres } from '../data-access-objects/data-access-object-postgres.js'; import { DataAccessObjectRedis } from '../data-access-objects/data-access-object-redis.js'; import { ConnectionAgentParams, ConnectionParams } from './data-structures/connections-params.ds.js'; -import { ConnectionTypesEnum } from '../../shared/enums/connection-types-enum.js'; -import { IDataAccessObjectAgent } from '../../shared/interfaces/data-access-object-agent.interface.js'; -import { IDataAccessObject } from '../../shared/interfaces/data-access-object.interface.js'; interface IUnknownConnectionParams { [key: string]: any; @@ -27,7 +26,6 @@ export function getDataAccessObject( ConnectionTypesEnum.agent_mysql, ConnectionTypesEnum.agent_oracledb, ConnectionTypesEnum.agent_postgres, - ConnectionTypesEnum.agent_ibmdb2, ConnectionTypesEnum.agent_mongodb, ConnectionTypesEnum.agent_cassandra, ConnectionTypesEnum.agent_redis, @@ -56,10 +54,6 @@ export function getDataAccessObject( const connectionParamsOracle = buildConnectionParams(connectionParams); return new DataAccessObjectOracle(connectionParamsOracle); } - case ConnectionTypesEnum.ibmdb2: { - const connectionParamsToIbmDB2 = buildConnectionParams(connectionParams); - return new DataAccessObjectIbmDb2(connectionParamsToIbmDB2); - } case ConnectionTypesEnum.mongodb: { const connectionParamsMongo = buildConnectionParams(connectionParams); return new DataAccessObjectMongo(connectionParamsMongo); @@ -121,7 +115,6 @@ function buildConnectionParams(connectionParams: IUnknownConnectionParams): Conn case ConnectionTypesEnum.mysql: case ConnectionTypesEnum.mssql: case ConnectionTypesEnum.oracledb: - case ConnectionTypesEnum.ibmdb2: case ConnectionTypesEnum.mongodb: case ConnectionTypesEnum.cassandra: case ConnectionTypesEnum.clickhouse: diff --git a/shared-code/src/data-access-layer/shared/data-structures/connections-params.ds.ts b/shared-code/src/data-access-layer/shared/data-structures/connections-params.ds.ts index 476abe7f8..c6d45121e 100644 --- a/shared-code/src/data-access-layer/shared/data-structures/connections-params.ds.ts +++ b/shared-code/src/data-access-layer/shared/data-structures/connections-params.ds.ts @@ -8,7 +8,6 @@ export class ConnectionParams { | 'oracledb' | 'mysql2' | 'mssql' - | 'ibmdb2' | 'mongodb' | 'dynamodb' | 'elasticsearch' diff --git a/shared-code/src/shared/enums/connection-types-enum.ts b/shared-code/src/shared/enums/connection-types-enum.ts index fc74c8f37..1acacdfdb 100644 --- a/shared-code/src/shared/enums/connection-types-enum.ts +++ b/shared-code/src/shared/enums/connection-types-enum.ts @@ -4,7 +4,6 @@ export enum ConnectionTypesEnum { mysql2 = 'mysql2', oracledb = 'oracledb', mssql = 'mssql', - ibmdb2 = 'ibmdb2', mongodb = 'mongodb', dynamodb = 'dynamodb', elasticsearch = 'elasticsearch', @@ -15,7 +14,6 @@ export enum ConnectionTypesEnum { agent_mysql = 'agent_mysql', agent_oracledb = 'agent_oracledb', agent_mssql = 'agent_mssql', - agent_ibmdb2 = 'agent_ibmdb2', agent_mongodb = 'agent_mongodb', agent_cassandra = 'agent_cassandra', agent_redis = 'agent_redis', @@ -28,7 +26,6 @@ export enum ConnectionTypeTestEnum { mysql2 = 'mysql2', oracledb = 'oracledb', mssql = 'mssql', - ibmdb2 = 'ibmdb2', mongodb = 'mongodb', dynamodb = 'dynamodb', elasticsearch = 'elasticsearch', @@ -39,7 +36,6 @@ export enum ConnectionTypeTestEnum { agent_mysql = 'agent_mysql', agent_oracledb = 'agent_oracledb', agent_mssql = 'agent_mssql', - agent_ibmdb2 = 'agent_ibmdb2', agent_mongodb = 'agent_mongodb', agent_elasticsearch = 'agent_elasticsearch', agent_cassandra = 'agent_cassandra',