UNPKG

cube-msfabric-driver

Version:

Cube.js MS Fabric Database Driver using msnodesqlv8

177 lines (176 loc) 7.02 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MSFabricDriver = void 0; const base_driver_1 = require("@cubejs-backend/base-driver"); const sql = __importStar(require("msnodesqlv8")); const MSFabricQuery_1 = require("./MSFabricQuery"); class MSFabricDriver extends base_driver_1.BaseDriver { constructor({ connectionString, maxPoolSize = 8, acquireTimeout = 30000, }) { super(); this.pool = null; this.connectionString = connectionString; this.maxPoolSize = maxPoolSize; this.acquireTimeout = acquireTimeout; } static dialectClass() { return MSFabricQuery_1.MSFabricQuery; } async testConnection() { try { await this.query("SELECT 1 as test"); console.log("Connection test successful"); } catch (error) { throw new Error(`Connection test failed: ${error instanceof Error ? error.message : String(error)}`); } } async getConnection() { if (!this.pool) { try { const connection = await new Promise((resolve, reject) => { sql.open(this.connectionString, (err, conn) => { if (err) reject(err); else resolve(conn); }); }); // Create adapter object that implements SqlPool interface this.pool = { query(sql, paramsOrCallback, callback) { if (typeof paramsOrCallback === "function") { connection.query(sql, paramsOrCallback); } else { connection.query(sql, paramsOrCallback, callback); } }, close: async () => { return new Promise((resolve) => { connection.close(() => resolve()); }); }, }; } catch (error) { throw new Error(`Failed to create connection pool: ${error instanceof Error ? error.message : String(error)}`); } } return this.pool; } async query(query, values = []) { const pool = await this.getConnection(); try { const result = await new Promise((resolve, reject) => { const callback = (err, rows) => { if (err) reject(err); else resolve(rows); }; if (values.length > 0) { pool.query(query, values, callback); } else { pool.query(query, callback); } }); // check if column data is type of date, convert it to iso string, use by moment.js - temporary solution // const transform = result.map((row: T) => { // const transformedRow: any = {}; // for (const key in row) { // if (Object.prototype.hasOwnProperty.call(row, key)) { // const value = row[key]; // if (value instanceof Date) { // transformedRow[key] = value.toISOString(); // } else { // transformedRow[key] = value; // } // } // } // return transformedRow; // }); // return transform; return result; } catch (error) { throw new Error(`Query failed: ${error instanceof Error ? error.message : String(error)}`); } } async release() { if (this.pool) { try { await this.pool.close(); this.pool = null; } catch (error) { throw new Error(`Failed to close connection pool: ${error instanceof Error ? error.message : String(error)}`); } } } async tablesSchema() { const schema = {}; try { const tables = await this.query(` SELECT TABLE_CATALOG AS [database], TABLE_NAME AS tableName, CAST(0 as bit) as isTemporary FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' `); for (const table of tables) { if (!schema[table.database]) { schema[table.database] = {}; } // Use parameterized query for security const columns = await this.query(`SELECT COLUMN_NAME as name, DATA_TYPE as type, CASE WHEN DATA_TYPE IN ('datetime', 'datetime2', 'smalldatetime', 'datetimeoffset', 'date', 'time') THEN 'timestamp' ELSE UPPER(DATA_TYPE) END as normalizedType, IS_NULLABLE as isNullable FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_CATALOG = ? AND TABLE_NAME = ? ORDER BY ORDINAL_POSITION`, [table.database, table.tableName]); schema[table.database][table.tableName] = columns.map((column) => ({ name: column.name, type: column.normalizedType.toLowerCase(), isNullable: column.isNullable === "YES", })); } return schema; } catch (error) { throw new Error(`Failed to get schema: ${error instanceof Error ? error.message : String(error)}`); } } } exports.MSFabricDriver = MSFabricDriver;