UNPKG

snowflake-promise

Version:

A Promise-based, TypeScript-friendly helper for the Snowflake SDK

312 lines (301 loc) 9.42 kB
// src/lib/promisify-or-not.ts import { promisify } from "util"; function promisifyOrNot(original) { const promisified = promisify(original); return function(...args) { const lastArg = args.at(-1); if (typeof lastArg === "function") { return original.apply(this, args); } return promisified.apply(this, args); }; } // src/lib/promisify-statement.ts function promisifyStatement(stmt) { if (stmt && Object.prototype.hasOwnProperty.call(stmt, "__isPromisified")) { return stmt; } return new Proxy(stmt, { get(target, prop, receiver) { if (prop === "__isPromisified") { return true; } const originalValue = Reflect.get(target, prop, receiver); if (typeof originalValue === "function") { switch (prop) { // Methods with a traditional callback case "cancel": return promisifyOrNot( originalValue ).bind(target); default: return originalValue.bind(target); } } return originalValue; } }); } // src/lib/promisify-options-callback-function.ts function promisifyOptionsCallbackFunction(target, fn) { return function(options) { if (options && typeof options.complete === "function") { return fn.call(target, options); } let rowsResolve; let rowsReject; const resultsPromise = new Promise((resolve, reject) => { rowsResolve = resolve; rowsReject = reject; }); const newOptions = { ...options }; newOptions.complete = (err, stmt, rows) => { if (err) { rowsReject(err); } else { rowsResolve(rows); } }; const statement = fn.call(target, newOptions); return { statement: promisifyStatement(statement), resultsPromise }; }; } // src/lib/promisify-connection.ts function promisifyConnection(conn) { if (conn && Object.prototype.hasOwnProperty.call(conn, "__isPromisified")) { return conn; } const proxy = new Proxy(conn, { get(target, prop, receiver) { if (prop === "__isPromisified") { return true; } const originalValue = Reflect.get(target, prop, receiver); if (typeof originalValue === "function") { switch (prop) { // Methods that take an options object containing a `complete` property // These methods return RowStatement objects that are wrapped with // promisifyStatement. `getResultsFromQueryId` is not promisified due to // its use case, which would be hard to handle and isn’t needed when using // this Promise proxy. case "execute": case "fetchResult": return promisifyOptionsCallbackFunction(target, originalValue); // Methods with a traditional callback case "connect": case "connectAsync": case "destroy": return promisifyOrNot(originalValue).bind(target); default: return originalValue.bind(target); } } return originalValue; } }); return proxy; } // src/legacy-compatibility/snowflake.ts import SDK from "snowflake-sdk"; // src/legacy-compatibility/statement.ts import { strict as assert } from "assert"; // src/legacy-compatibility/types/SnowflakeError.ts var SnowflakeError = class extends Error { constructor(message) { super(message); } }; // src/legacy-compatibility/types/StatementNotExecutedError.ts var StatementNotExecutedError = class extends SnowflakeError { constructor() { super("Statement not executed yet - call the execute() method"); } }; // src/legacy-compatibility/statement.ts var Statement = class { connection; executePromise; stmt; rows; executeOptions; logSql; constructor(connection, executeOptions, logSql) { this.connection = promisifyConnection(connection); this.executeOptions = executeOptions; this.logSql = logSql; } execute() { if (this.executePromise) { throw new StatementAlreadyExecutedError(); } const startTime = Date.now(); const { statement, resultsPromise } = this.connection.execute(this.executeOptions); this.stmt = statement; this.executePromise = resultsPromise.then((rows) => { if (this.logSql) { const elapsed = Date.now() - startTime; this.log(elapsed); } this.rows = rows; }); return this.executePromise; } async cancel() { await this.stmt?.cancel(); } getRows() { if (!this.executePromise) { throw new StatementNotExecutedError(); } return this.executePromise.then(() => this.rows); } streamRows(options = {}) { if (!this.executePromise) { throw new StatementNotExecutedError(); } assert(this.stmt, "Statement must be executed before streaming rows"); return this.stmt.streamRows(options); } getSqlText() { if (!this.executePromise) { throw new StatementNotExecutedError(); } assert(this.stmt, "Statement must be executed before getting SQL text"); return this.stmt.getSqlText(); } getStatus() { if (!this.executePromise) { throw new StatementNotExecutedError(); } assert(this.stmt, "Statement must be executed before getting status"); return this.stmt.getStatus(); } getColumns() { if (!this.executePromise) { throw new StatementNotExecutedError(); } assert(this.stmt, "Statement must be executed before getting columns"); return this.stmt.getColumns(); } getColumn(columnIdentifier) { if (!this.executePromise) { throw new StatementNotExecutedError(); } assert(this.stmt, "Statement must be executed before getting column"); return this.stmt.getColumn(columnIdentifier); } getNumRows() { if (!this.executePromise) { throw new StatementNotExecutedError(); } assert(this.stmt, "Statement must be executed before getting number of rows"); return this.stmt.getNumRows(); } getNumUpdatedRows() { if (!this.executePromise) { throw new StatementNotExecutedError(); } assert(this.stmt, "Statement must be executed before getting number of updated rows"); return this.stmt.getNumUpdatedRows(); } getSessionState() { if (!this.executePromise) { throw new StatementNotExecutedError(); } assert(this.stmt, "Statement must be executed before getting session state"); return this.stmt.getSessionState(); } getRequestId() { if (!this.executePromise) { throw new StatementNotExecutedError(); } assert(this.stmt, "Statement must be executed before getting request ID"); return this.stmt.getRequestId(); } getStatementId() { if (!this.executePromise) { throw new StatementNotExecutedError(); } assert(this.stmt, "Statement must be executed before getting statement ID"); return this.stmt.getQueryId(); } log(elapsedTime) { let logMessage = "Executed"; const state = this.getSessionState(); if (state) { logMessage += ` (${state.getCurrentDatabase()}.${state.getCurrentSchema()})`; } logMessage += `: ${this.getSqlText()}`; if (logMessage[logMessage.length - 1] !== ";") { logMessage += ";"; } if (this.executeOptions.binds) { logMessage += ` with binds: ${JSON.stringify(this.executeOptions.binds)};`; } logMessage += ` Elapsed time: ${elapsedTime}ms`; this.logSql?.(logMessage); } }; // src/legacy-compatibility/types/LoggingOptions.ts function toSdkLogLevel(logLevel) { return logLevel.toUpperCase(); } // src/legacy-compatibility/snowflake.ts var Snowflake = class { logSql; connection; constructor(connectionOptions, loggingOptions = {}, configureOptions) { if (loggingOptions && loggingOptions.logLevel) { SDK.configure({ logLevel: toSdkLogLevel(loggingOptions.logLevel) }); } this.logSql = (loggingOptions && loggingOptions.logSql) ?? void 0; if (typeof configureOptions === "boolean") { console.warn( "[snowflake-promise] the insecureConnect boolean argument is deprecated; please remove it or use the ocspFailOpen configure option" ); } else if (typeof configureOptions === "object") { SDK.configure(configureOptions); } this.connection = promisifyConnection(SDK.createConnection(connectionOptions)); } get id() { return this.connection.getId(); } async connect() { await this.connection.connect(); } async connectAsync() { await this.connection.connectAsync(); } async destroy() { await this.connection.destroy(); } createStatement(options) { return new Statement(this.connection, options, this.logSql); } /** A convenience function to execute a SQL statement and return the resulting rows. */ // eslint-disable-next-line @typescript-eslint/no-explicit-any async execute(sqlText, binds) { const { resultsPromise } = this.connection.execute({ sqlText, binds }); const rows = await resultsPromise; return rows; } }; // src/legacy-compatibility/types/StatementAlreadyExecutedError.ts var StatementAlreadyExecutedError = class extends SnowflakeError { constructor() { super("Statement already executed - it cannot be executed again"); } }; export { Snowflake, SnowflakeError, Statement, StatementAlreadyExecutedError, StatementNotExecutedError, promisifyConnection }; //# sourceMappingURL=index.js.map