cube-msfabric-driver
Version:
Cube.js MS Fabric Database Driver using msnodesqlv8
177 lines (176 loc) • 7.02 kB
JavaScript
;
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;