Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion shared-code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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';
Expand All @@ -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,
Expand Down Expand Up @@ -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})
Expand All @@ -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<string, unknown>;
}
return row;
}
Expand All @@ -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;
}
Expand All @@ -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<string, unknown>[];
}

public async getRowByPrimaryKey(
Expand All @@ -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<string, unknown>;
}

public async bulkGetRowsFromTableByPrimaryKeys(
Expand Down Expand Up @@ -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}
Expand All @@ -177,7 +193,7 @@ export class DataAccessObjectIbmDb2 extends BasicDataAccessObject implements IDa
`;

const results = await connectionToDb.query(query, flatPrimaryKeysValues);
return results;
return results as Record<string, unknown>[];
}

public async getRowsFromTable(
Expand Down Expand Up @@ -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));
Expand All @@ -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<string, unknown>[],
pagination: {} as RowsPaginationDS,
large_dataset: large_dataset,
};
return rowsRO;
Expand Down Expand Up @@ -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}%`);
Expand All @@ -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}%`);
Expand Down Expand Up @@ -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<string, unknown>[],
pagination: {
total: rowsCount,
lastPage: lastPage,
perPage: perPage,
currentPage: page,
} as any,
},
large_dataset: large_dataset,
};
return rowsRO;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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',
Expand All @@ -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,
Expand Down Expand Up @@ -518,16 +534,16 @@ 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 = `
SELECT *
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<string, unknown>;
}

public async bulkUpdateRowsInTable(
Expand Down Expand Up @@ -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,
Expand All @@ -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(
Expand All @@ -620,12 +636,12 @@ ORDER BY
perPage: number,
searchedFieldValue: string,
filteringFields: FilteringFieldsDS[],
): Promise<Stream & AsyncIterable<any>> {
): Promise<Stream & AsyncIterable<Record<string, unknown>>> {
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,
Expand All @@ -634,8 +650,8 @@ ORDER BY
filteringFields,
null,
null,
)) as any;
return rowsResult.data;
);
return rowsResult.data as unknown as Stream & AsyncIterable<Record<string, unknown>>;
}

public async getRowsCount(
Expand Down Expand Up @@ -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<string, number>).CARD;
return fastCount;
}

Expand All @@ -676,9 +692,9 @@ ORDER BY
stream.push(null);

const parser = stream.pipe(csv.parse({ columns: true }));
const results: any[] = [];
const results: Record<string, unknown>[] = [];
for await (const record of parser) {
results.push(record);
results.push(record as Record<string, unknown>);
}
await Promise.allSettled(
results.map(async (row) => {
Expand All @@ -690,10 +706,10 @@ ORDER BY
public async executeRawQuery(query: string): Promise<Array<Record<string, unknown>>> {
const connectionToDb = await this.getConnectionToDatabase();
const result = await connectionToDb.query(query);
return result;
return result as Record<string, unknown>[];
}

private async getConnectionToDatabase(): Promise<Database> {
private getConnectionToDatabase(): Promise<Database> {
if (this.connection.ssh) {
return this.createTunneledConnection(this.connection);
}
Expand All @@ -718,9 +734,9 @@ ORDER BY
return databaseConnection;
}

private async createTunneledConnection(connection: ConnectionParams): Promise<Database> {
private createTunneledConnection(connection: ConnectionParams): Promise<Database> {
const connectionCopy = { ...connection };
return new Promise<Database>(async (resolve, reject): Promise<Database> => {
return new Promise<Database>(async (resolve, reject) => {
const cachedTnl = LRUStorage.getTunnelCache(connectionCopy);
if (cachedTnl?.database && cachedTnl.server && cachedTnl.client && cachedTnl.database.connected) {
resolve(cachedTnl.database);
Expand Down
18 changes: 9 additions & 9 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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:
Expand Down
Loading