diff --git a/shared-code/package.json b/shared-code/package.json index 6090a5fb3..b704ad118 100644 --- a/shared-code/package.json +++ b/shared-code/package.json @@ -37,7 +37,7 @@ "tunnel-ssh": "5.2.0" }, "optionalDependencies": { - "ibm_db": "3.3.0" + "ibm_db": "3.3.4" }, "devDependencies": { "@types/oracledb": "^6.10.1", 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 index 183c58106..b40141d29 100644 --- 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 @@ -1,6 +1,6 @@ import * as csv from 'csv'; import getPort from 'get-port'; -import { Database, Pool } from 'ibm_db'; +import { Database, Pool, SQLParam } from 'ibm_db'; import { nanoid } from 'nanoid'; import { Readable, Stream } from 'node:stream'; import { LRUStorage } from '../../caching/lru-storage.js'; @@ -15,6 +15,7 @@ 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 { TableSettingsDS } from '../shared/data-structures/table-settings.ds.js'; import { TableStructureDS } from '../shared/data-structures/table-structure.ds.js'; import { TableDS } from '../shared/data-structures/table.ds.js'; @@ -24,6 +25,21 @@ import { FilterCriteriaEnum } from '../../shared/enums/filter-criteria.enum.js'; import { IDataAccessObject } from '../../shared/interfaces/data-access-object.interface.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, @@ -51,7 +67,7 @@ export class DataAccessObjectIbmDb2 extends BasicDataAccessObject implements IDa const placeholders = Object.keys(row) .map(() => '?') .join(', '); - const values = Object.values(row); + const values = Object.values(row) as SQLParam[]; const query = ` INSERT INTO ${this.connection.schema.toUpperCase()}.${tableName.toUpperCase()} (${columns}) VALUES (${placeholders}) @@ -67,8 +83,8 @@ export class DataAccessObjectIbmDb2 extends BasicDataAccessObject implements IDa .map((key) => `${key} = ?`) .join(' AND ')} `; - const result = await connectionToDb.query(selectQuery, Object.values(row)); - return result[0]; + const result = await connectionToDb.query(selectQuery, Object.values(row) as SQLParam[]); + return result[0] as Record; } return row; } @@ -86,7 +102,7 @@ export class DataAccessObjectIbmDb2 extends BasicDataAccessObject implements IDa DELETE FROM ${this.connection.schema.toUpperCase()}.${tableName.toUpperCase()} WHERE ${whereClause} `; - const params = Object.values(primaryKey); + const params = Object.values(primaryKey) as SQLParam[]; await connectionToDb.query(query, params); return primaryKey; } @@ -111,8 +127,8 @@ export class DataAccessObjectIbmDb2 extends BasicDataAccessObject implements IDa FROM ${schemaName}.${tableName.toUpperCase()} WHERE ${referencedFieldName} IN (${placeholders}) `; - const result = connectionToDb.query(query, [...fieldValues]); - return result; + const result = await connectionToDb.query(query, [...fieldValues] as SQLParam[]); + return result as Record[]; } public async getRowByPrimaryKey( @@ -136,9 +152,9 @@ export class DataAccessObjectIbmDb2 extends BasicDataAccessObject implements IDa FROM ${this.connection.schema.toUpperCase()}.${tableName.toUpperCase()} WHERE ${whereClause} `; - const params = Object.values(primaryKey); + const params = Object.values(primaryKey) as SQLParam[]; const result = await connectionToDb.query(query, params); - return result[0]; + return result[0] as Record; } public async bulkGetRowsFromTableByPrimaryKeys( @@ -168,7 +184,7 @@ export class DataAccessObjectIbmDb2 extends BasicDataAccessObject implements IDa }) .join(' OR '); - const flatPrimaryKeysValues = primaryKeys.flatMap(Object.values); + const flatPrimaryKeysValues = primaryKeys.flatMap(Object.values) as SQLParam[]; const query = ` SELECT ${selectFields} @@ -177,7 +193,7 @@ export class DataAccessObjectIbmDb2 extends BasicDataAccessObject implements IDa `; const results = await connectionToDb.query(query, flatPrimaryKeysValues); - return results; + return results as Record[]; } public async getRowsFromTable( @@ -214,7 +230,7 @@ export class DataAccessObjectIbmDb2 extends BasicDataAccessObject implements IDa const lastPage = Math.ceil(rowsCount / perPage); let rowsRO: FoundRowsDS; - const queryParams: unknown[] = []; + const queryParams: SQLParam[] = []; if (autocompleteFields?.value && autocompleteFields.fields.length > 0) { const validatedAutocompleteFields = autocompleteFields.fields.filter((field) => availableFields.includes(field)); @@ -229,8 +245,8 @@ export class DataAccessObjectIbmDb2 extends BasicDataAccessObject implements IDa const rows = await connectionToDb.query(autocompleteQuery, autocompleteParams); rowsRO = { - data: rows, - pagination: {} as any, + data: rows as Record[], + pagination: {} as RowsPaginationDS, large_dataset: large_dataset, }; return rowsRO; @@ -272,7 +288,7 @@ export class DataAccessObjectIbmDb2 extends BasicDataAccessObject implements IDa .map((filterObject) => { switch (filterObject.criteria) { case FilterCriteriaEnum.eq: - queryParams.push(filterObject.value); + queryParams.push(filterObject.value as SQLParam); return `${filterObject.field} = ?`; case FilterCriteriaEnum.startswith: queryParams.push(`${filterObject.value}%`); @@ -281,16 +297,16 @@ export class DataAccessObjectIbmDb2 extends BasicDataAccessObject implements IDa queryParams.push(`%${filterObject.value}`); return `${filterObject.field} LIKE ?`; case FilterCriteriaEnum.gt: - queryParams.push(filterObject.value); + queryParams.push(filterObject.value as SQLParam); return `${filterObject.field} > ?`; case FilterCriteriaEnum.lt: - queryParams.push(filterObject.value); + queryParams.push(filterObject.value as SQLParam); return `${filterObject.field} < ?`; case FilterCriteriaEnum.lte: - queryParams.push(filterObject.value); + queryParams.push(filterObject.value as SQLParam); return `${filterObject.field} <= ?`; case FilterCriteriaEnum.gte: - queryParams.push(filterObject.value); + queryParams.push(filterObject.value as SQLParam); return `${filterObject.field} >= ?`; case FilterCriteriaEnum.contains: queryParams.push(`%${filterObject.value}%`); @@ -324,13 +340,13 @@ export class DataAccessObjectIbmDb2 extends BasicDataAccessObject implements IDa const rows = await connectionToDb.query(rowsQuery, queryParams); rowsRO = { - data: rows, + data: rows as Record[], pagination: { total: rowsCount, lastPage: lastPage, perPage: perPage, currentPage: page, - } as any, + }, large_dataset: large_dataset, }; return rowsRO; @@ -372,7 +388,7 @@ ORDER BY this.connection.schema.toUpperCase(), ]); - const resultKeys = foreignKeys.map((foreignKey: any) => { + const resultKeys = (foreignKeys as unknown as IbmDb2Row[]).map((foreignKey) => { return { column_name: foreignKey.COLUMN_NAME, constraint_name: foreignKey.CONSTRAINT_NAME, @@ -402,7 +418,7 @@ ORDER BY this.connection.schema.toUpperCase(), ]); - const resultKeys = primaryKeys.map((primaryKey: any) => { + const resultKeys = (primaryKeys as unknown as IbmDb2Row[]).map((primaryKey) => { return { column_name: primaryKey.COLUMN_NAME, data_type: primaryKey.DATA_TYPE as string, @@ -422,7 +438,7 @@ ORDER BY `; const tables = await connectionToDb.query(query, [this.connection.schema.toUpperCase()]); - return tables.map((table: any) => { + return (tables as unknown as IbmDb2Row[]).map((table) => { return { tableName: table.TABLE_NAME, isView: table.TABLE_TYPE === 'V', @@ -449,7 +465,7 @@ ORDER BY this.connection.schema.toUpperCase(), ]); - return tableStructure.map((column: any) => { + return (tableStructure as unknown as IbmDb2Row[]).map((column) => { return { allow_null: column.IS_NULLABLE === 'Y', column_default: column.COLUMN_DEFAULT, @@ -518,7 +534,7 @@ ORDER BY SET ${setClause} WHERE ${whereClause} `; - const params = [...Object.values(row), ...Object.values(primaryKey)]; + const params = [...Object.values(row), ...Object.values(primaryKey)] as SQLParam[]; await connectionToDb.query(query, params); const selectQuery = ` @@ -526,8 +542,8 @@ ORDER BY FROM ${this.connection.schema.toUpperCase()}.${tableName.toUpperCase()} WHERE ${whereClause} `; - const result = await connectionToDb.query(selectQuery, Object.values(primaryKey)); - return result[0]; + const result = await connectionToDb.query(selectQuery, Object.values(primaryKey) as SQLParam[]); + return result[0] as Record; } public async bulkUpdateRowsInTable( @@ -588,7 +604,7 @@ ORDER BY ]); results.push({ referenced_on_column_name: primaryColumn.column_name, - referenced_by: foreignKeys.map((foreignKey: any) => { + referenced_by: (foreignKeys as unknown as IbmDb2Row[]).map((foreignKey) => { return { table_name: foreignKey.REFERENCING_TABLE_NAME, column_name: foreignKey.REFERENCING_COLUMN_NAME, @@ -610,7 +626,7 @@ ORDER BY this.connection.schema.toUpperCase(), tableName.toUpperCase(), ]); - return tableData[0].TABLE_TYPE === 'V'; + return (tableData[0] as unknown as IbmDb2Row).TABLE_TYPE === 'V'; } public async getTableRowsStream( @@ -620,12 +636,12 @@ ORDER BY perPage: number, searchedFieldValue: string, filteringFields: FilteringFieldsDS[], - ): Promise> { + ): 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( + const rowsResult = await this.getRowsFromTable( tableName, settings, page, @@ -634,8 +650,8 @@ ORDER BY filteringFields, null, null, - )) as any; - return rowsResult.data; + ); + return rowsResult.data as unknown as Stream & AsyncIterable>; } public async getRowsCount( @@ -666,7 +682,7 @@ ORDER BY `; const fastCountParams = [tableName, tableSchema]; const fastCountQueryResult = await connectionToDb.query(fastCountQuery, fastCountParams); - const fastCount = fastCountQueryResult[0].CARD; + const fastCount = (fastCountQueryResult[0] as Record).CARD; return fastCount; } @@ -676,9 +692,9 @@ ORDER BY stream.push(null); const parser = stream.pipe(csv.parse({ columns: true })); - const results: any[] = []; + const results: Record[] = []; for await (const record of parser) { - results.push(record); + results.push(record as Record); } await Promise.allSettled( results.map(async (row) => { @@ -690,10 +706,10 @@ ORDER BY public async executeRawQuery(query: string): Promise>> { const connectionToDb = await this.getConnectionToDatabase(); const result = await connectionToDb.query(query); - return result; + return result as Record[]; } - private async getConnectionToDatabase(): Promise { + private getConnectionToDatabase(): Promise { if (this.connection.ssh) { return this.createTunneledConnection(this.connection); } @@ -718,9 +734,9 @@ ORDER BY return databaseConnection; } - private async createTunneledConnection(connection: ConnectionParams): Promise { + private createTunneledConnection(connection: ConnectionParams): Promise { const connectionCopy = { ...connection }; - return new Promise(async (resolve, reject): Promise => { + return new Promise(async (resolve, reject) => { const cachedTnl = LRUStorage.getTunnelCache(connectionCopy); if (cachedTnl?.database && cachedTnl.server && cachedTnl.client && cachedTnl.database.connected) { resolve(cachedTnl.database); diff --git a/yarn.lock b/yarn.lock index 10069501e..95498f2e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3970,7 +3970,7 @@ __metadata: cassandra-driver: ^4.8.0 csv: ^6.4.1 get-port: ^7.1.0 - ibm_db: 3.3.0 + ibm_db: 3.3.4 jsonwebtoken: ^9.0.3 knex: ^3.1.0 lru-cache: ^11.2.6 @@ -6115,7 +6115,7 @@ __metadata: languageName: node linkType: hard -"axios@npm:^1.13.2, axios@npm:^1.13.5, axios@npm:^1.7.4": +"axios@npm:^1.12.0, axios@npm:^1.13.2, axios@npm:^1.13.5": version: 1.13.5 resolution: "axios@npm:1.13.5" dependencies: @@ -8483,20 +8483,20 @@ __metadata: languageName: node linkType: hard -"ibm_db@npm:3.3.0": - version: 3.3.0 - resolution: "ibm_db@npm:3.3.0" +"ibm_db@npm:3.3.4": + version: 3.3.4 + resolution: "ibm_db@npm:3.3.4" dependencies: adm-zip: ^0.5.16 - axios: ^1.7.4 + axios: ^1.12.0 big-integer: ^1.6.51 bindings: ^1.5.0 fs-extra: ^11.1.1 lodash: ^4.17.21 - nan: ^2.22.0 + nan: ^2.23.0 q: ^1.5.1 targz: ^1.0.1 - checksum: 7a266c6bd5bbc9ba3d3fd83c82e7b207f704be72a80ceeed1b8f22fc05ebeb65e6baada7e6ca9710c773f48cb2a1a53ddc7a593eacf7b0d5b5f376696007bc5b + checksum: 3ac61a91a91770a269705db7e4bc2a165641b8586f7ea0f5a64e435a2dae2dac24ddb188c351faff05fc3062569cec8e7d5c707746e07d2331e4ccd4a960a187 languageName: node linkType: hard @@ -9984,7 +9984,7 @@ __metadata: languageName: node linkType: hard -"nan@npm:^2.19.0, nan@npm:^2.22.0, nan@npm:^2.23.0": +"nan@npm:^2.19.0, nan@npm:^2.23.0": version: 2.24.0 resolution: "nan@npm:2.24.0" dependencies: