UNPKG

snowflake-promise

Version:

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

1 lines 23.9 kB
{"version":3,"sources":["../src/index.ts","../src/lib/promisify-or-not.ts","../src/lib/promisify-statement.ts","../src/lib/promisify-options-callback-function.ts","../src/lib/promisify-connection.ts","../src/legacy-compatibility/snowflake.ts","../src/legacy-compatibility/statement.ts","../src/legacy-compatibility/types/SnowflakeError.ts","../src/legacy-compatibility/types/StatementNotExecutedError.ts","../src/legacy-compatibility/types/LoggingOptions.ts","../src/legacy-compatibility/types/StatementAlreadyExecutedError.ts"],"sourcesContent":["// Our main entry point\n/* v8 ignore next */\nexport { promisifyConnection } from \"./lib/promisify-connection.js\";\n\n// Legacy entry points\n/* v8 ignore next */\nexport * from \"./legacy-compatibility/index.js\";\n\n// Types to export\nexport type { PromisifiedConnection } from \"./types/promisified-connection.ts\";\nexport type { PromisifiedRowStatement } from \"./types/promisified-row-statement.ts\";\n","import { promisify } from \"node:util\";\n\ntype Callback<ResultType> = (error: Error | null, result: ResultType) => void;\n\n/**\n * Given a function that takes a callback as its last argument, return a wrapper that\n * can be called using either a Promise or a callback.\n *\n * @param fn The function to promisify.\n * @returns A function that can be called using either a Promise or a callback.\n */\nexport function promisifyOrNot<Args extends unknown[], ResultType>(\n original: (...args: [...Args, Callback<ResultType>]) => unknown,\n) {\n const promisified = promisify(original) as (...args: Args) => Promise<ResultType>;\n\n return function (this: unknown, ...args: [...Args] | [...Args, Callback<ResultType>]) {\n const lastArg = args.at(-1);\n\n if (typeof lastArg === \"function\") {\n return original.apply(this, args as [...Args, Callback<ResultType>]);\n }\n\n return promisified.apply(this, args as Args);\n };\n}\n","import type { RowStatement } from \"snowflake-sdk\";\nimport type { PromisifiedRowStatement } from \"../types/promisified-row-statement.ts\";\nimport { promisifyOrNot } from \"./promisify-or-not.ts\";\n\n// Define a type for the callback function expected by promisifyOrNot\ntype PromisifyCallback<T> = (error: Error | null, result: T) => void;\n\n/**\n * Given a Snowflake RowStatement object or FileAndStageBindStatement (which is a subclass of RowStatement),\n * returns a proxy with promisified methods.\n *\n * To support compatibility with the callback-based API, we continue to support\n * calling these methods using callbacks. But if a callback is not provided, a\n * Promise is returned.\n *\n * @param stmt - The Snowflake Statement object to promisify.\n * @returns A proxy with promisified methods that matches the PromisifiedRowStatement interface.\n */\nexport function promisifyStatement<T extends RowStatement>(\n stmt: T,\n): T & PromisifiedRowStatement {\n // If the Statement is already promisified, return it as-is\n if (stmt && Object.prototype.hasOwnProperty.call(stmt, \"__isPromisified\")) {\n return stmt as T & PromisifiedRowStatement;\n }\n\n return new Proxy(stmt, {\n get(target, prop, receiver) {\n // Return true for the __isPromisified property\n if (prop === \"__isPromisified\") {\n return true;\n }\n\n const originalValue = Reflect.get(target, prop, receiver);\n\n if (typeof originalValue === \"function\") {\n switch (prop) {\n // Methods with a traditional callback\n case \"cancel\":\n // Type assertion to match the expected signature for promisifyOrNot\n return promisifyOrNot(\n originalValue as (\n ...args: [...unknown[], PromisifyCallback<void>]\n ) => unknown,\n ).bind(target);\n\n default:\n return originalValue.bind(target);\n }\n }\n\n // For everything else, return the original value\n return originalValue;\n },\n }) as T & PromisifiedRowStatement;\n}\n","import type { Connection, RowStatement, StatementOption } from \"snowflake-sdk\";\nimport { promisifyStatement } from \"./promisify-statement.ts\";\n\n/**\n * Promisifies Snowflake SDK functions that use the StatementCallback pattern.\n *\n * In Snowflake's SDK, methods like execute and fetchResult use a non-standard\n * callback pattern where the callback is provided in the `complete` property of an\n * options object, rather than as the last argument.\n *\n * This utility wrapper enables these methods to work with either:\n * 1. Traditional callbacks (by passing a function to options.complete)\n * 2. Promises (by not providing a callback)\n *\n * When using the Promise approach, it returns a Promise that resolves to an object\n * with:\n * - statement: The promisified Snowflake Statement object (available immediately)\n * - resultsPromise: A Promise that resolves with the query results when completed\n *\n * This approach allows you to both:\n * - Access the Statement object immediately (for cancellation or other operations)\n * - Await the resultsPromise to get the actual query results\n *\n * @param target The Snowflake connection object containing the function\n * @param fn The Snowflake function to promisify (e.g., execute, fetchResult)\n * @returns A function supporting both callback and Promise patterns\n */\nexport function promisifyOptionsCallbackFunction<RowType, T extends RowStatement>(\n target: Connection,\n fn: (options: StatementOption) => T,\n) {\n return function (\n options: StatementOption,\n ): T | { statement: T; resultsPromise: Promise<RowType[] | undefined> } {\n // If options includes a `complete` callback, call the original function\n if (options && typeof options.complete === \"function\") {\n return fn.call(target, options);\n }\n\n // Otherwise, handle the Promise pattern\n let rowsResolve: (value: RowType[] | undefined) => void;\n let rowsReject: (reason: Error) => void;\n const resultsPromise = new Promise<RowType[] | undefined>((resolve, reject) => {\n rowsResolve = resolve;\n rowsReject = reject;\n });\n\n // Create a new options object with a `complete` callback to capture row results\n const newOptions: StatementOption = { ...options };\n\n newOptions.complete = (err, stmt, rows) => {\n if (err) {\n rowsReject(err);\n } else {\n rowsResolve(rows as RowType[] | undefined);\n }\n };\n\n // Call the original function and wrap the returned statement in a Promise\n const statement = fn.call(target, newOptions);\n\n return {\n statement: promisifyStatement<T>(statement),\n resultsPromise,\n };\n };\n}\n","import type { Connection } from \"snowflake-sdk\";\nimport { promisifyOptionsCallbackFunction } from \"./promisify-options-callback-function.ts\";\nimport { promisifyOrNot } from \"./promisify-or-not.ts\";\nimport type { PromisifiedConnection } from \"../types/promisified-connection.ts\";\n\n/**\n * Given a Snowflake Connection object, returns a proxy with promisified methods.\n *\n * Snowflake's SDK is partially promisified, but key methods such as `execute` are\n * not. We promisify these methods to make them easier to use with async/await.\n *\n * To support compatibility with the callback-based API, we continue to support\n * calling these methods using callbacks. But if a callback is not provided, a\n * Promise is returned.\n *\n * @param conn - The Snowflake Connection object to promisify.\n * @returns A proxy with promisified methods.\n */\nexport function promisifyConnection(conn: Connection) {\n // If the Connection is already promisified, return it as-is\n if (conn && Object.prototype.hasOwnProperty.call(conn, \"__isPromisified\")) {\n return conn as PromisifiedConnection;\n }\n\n const proxy = new Proxy(conn, {\n get(target, prop, receiver) {\n // Return true for the __isPromisified property\n if (prop === \"__isPromisified\") {\n return true;\n }\n\n const originalValue = Reflect.get(target, prop, receiver);\n\n if (typeof originalValue === \"function\") {\n switch (prop) {\n // Methods that take an options object containing a `complete` property\n // These methods return RowStatement objects that are wrapped with\n // promisifyStatement. `getResultsFromQueryId` is not promisified due to\n // its use case, which would be hard to handle and isn’t needed when using\n // this Promise proxy.\n case \"execute\":\n case \"fetchResult\":\n return promisifyOptionsCallbackFunction(target, originalValue);\n\n // Methods with a traditional callback\n case \"connect\":\n case \"connectAsync\":\n case \"destroy\":\n return promisifyOrNot(originalValue).bind(target);\n\n default:\n return originalValue.bind(target);\n }\n }\n\n // For everything else, return the original value\n return originalValue;\n },\n });\n\n return proxy as PromisifiedConnection;\n}\n","import SDK from \"snowflake-sdk\";\nimport { promisifyConnection } from \"../lib/promisify-connection.ts\";\nimport type { PromisifiedConnection } from \"../types/promisified-connection.ts\";\nimport { Statement } from \"./statement.ts\";\nimport type { ConfigureOptions } from \"./types/ConfigureOptions.ts\";\nimport type { ConnectionOptions } from \"./types/ConnectionOptions.ts\";\nimport type { ExecuteOptions } from \"./types/ExecuteOptions.ts\";\nimport { toSdkLogLevel, type LoggingOptions } from \"./types/LoggingOptions.ts\";\n\n/**\n * @deprecated Use the standard Snowflake SDK. First get a connection and then call\n * promisifyConnection() to augment the connection with Promise-based methods.\n */\nexport class Snowflake {\n private readonly logSql?: (sqlText: string) => void;\n private readonly connection: PromisifiedConnection;\n\n constructor(\n connectionOptions: ConnectionOptions,\n loggingOptions: LoggingOptions = {},\n configureOptions?: ConfigureOptions | boolean,\n ) {\n if (loggingOptions && loggingOptions.logLevel) {\n SDK.configure({ logLevel: toSdkLogLevel(loggingOptions.logLevel) });\n }\n this.logSql = (loggingOptions && loggingOptions.logSql) ?? undefined;\n // For backward compatibility, configureOptions is allowed to be a boolean, but\n // it’s ignored. The new default settings accomplish the same thing as the old\n // `insecureConnect` boolean.\n if (typeof configureOptions === \"boolean\") {\n console.warn(\n \"[snowflake-promise] the insecureConnect boolean argument is deprecated; \" +\n \"please remove it or use the ocspFailOpen configure option\",\n );\n } else if (typeof configureOptions === \"object\") {\n SDK.configure(configureOptions);\n }\n this.connection = promisifyConnection(SDK.createConnection(connectionOptions));\n }\n\n get id(): string {\n return this.connection.getId();\n }\n\n async connect() {\n await this.connection.connect();\n }\n\n async connectAsync() {\n await this.connection.connectAsync();\n }\n\n async destroy() {\n await this.connection.destroy();\n }\n\n createStatement(options: ExecuteOptions) {\n return new Statement(this.connection, options, this.logSql);\n }\n\n /** A convenience function to execute a SQL statement and return the resulting rows. */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async execute(sqlText: string, binds?: any[]) {\n const { resultsPromise } = this.connection.execute({ sqlText, binds });\n const rows = await resultsPromise;\n return rows;\n }\n}\n","import { strict as assert } from \"node:assert\";\nimport type { Readable } from \"node:stream\";\nimport type { Connection, RowStatement } from \"snowflake-sdk\";\nimport { promisifyConnection } from \"../lib/promisify-connection.ts\";\nimport type { PromisifiedConnection } from \"../types/promisified-connection.ts\";\nimport { StatementAlreadyExecutedError } from \"./index.ts\";\nimport type { ExecuteOptions } from \"./types/ExecuteOptions.ts\";\nimport { StatementNotExecutedError } from \"./types/StatementNotExecutedError.ts\";\nimport type { StreamRowsOptions } from \"./types/StreamRowsOptions.ts\";\n\n/**\n * @deprecated Use the standard Snowflake SDK. First get a connection and then call\n * promisifyConnection() to augment the connection with Promise-based methods. If you\n * have a Statement instance, you can call promisifyStatement() to augment it with\n * Promise-based methods.\n */\nexport class Statement {\n private readonly connection: PromisifiedConnection;\n private executePromise?: Promise<void>;\n private stmt?: RowStatement;\n private rows?: unknown[];\n private readonly executeOptions: ExecuteOptions;\n private readonly logSql: ((sqlText: string) => void) | undefined;\n\n constructor(\n connection: Connection,\n executeOptions: ExecuteOptions,\n logSql?: (sqlText: string) => void,\n ) {\n this.connection = promisifyConnection(connection);\n this.executeOptions = executeOptions;\n this.logSql = logSql;\n }\n\n execute() {\n if (this.executePromise) {\n throw new StatementAlreadyExecutedError();\n }\n\n const startTime = Date.now();\n\n const { statement, resultsPromise } = this.connection.execute(this.executeOptions);\n\n this.stmt = statement;\n\n this.executePromise = resultsPromise.then((rows) => {\n if (this.logSql) {\n const elapsed = Date.now() - startTime;\n this.log(elapsed);\n }\n this.rows = rows;\n });\n\n return this.executePromise;\n }\n\n async cancel() {\n await this.stmt?.cancel();\n }\n\n getRows() {\n if (!this.executePromise) {\n throw new StatementNotExecutedError();\n }\n return this.executePromise.then(() => this.rows);\n }\n\n streamRows(options: StreamRowsOptions = {}): Readable {\n if (!this.executePromise) {\n throw new StatementNotExecutedError();\n }\n assert(this.stmt, \"Statement must be executed before streaming rows\");\n return this.stmt.streamRows(options);\n }\n\n getSqlText(): string {\n if (!this.executePromise) {\n throw new StatementNotExecutedError();\n }\n assert(this.stmt, \"Statement must be executed before getting SQL text\");\n return this.stmt.getSqlText();\n }\n\n getStatus(): string {\n if (!this.executePromise) {\n throw new StatementNotExecutedError();\n }\n assert(this.stmt, \"Statement must be executed before getting status\");\n return this.stmt.getStatus();\n }\n\n getColumns(): object[] {\n if (!this.executePromise) {\n throw new StatementNotExecutedError();\n }\n assert(this.stmt, \"Statement must be executed before getting columns\");\n return this.stmt.getColumns();\n }\n\n getColumn(columnIdentifier: string | number) {\n if (!this.executePromise) {\n throw new StatementNotExecutedError();\n }\n assert(this.stmt, \"Statement must be executed before getting column\");\n return this.stmt.getColumn(columnIdentifier);\n }\n\n getNumRows() {\n if (!this.executePromise) {\n throw new StatementNotExecutedError();\n }\n assert(this.stmt, \"Statement must be executed before getting number of rows\");\n return this.stmt.getNumRows();\n }\n\n getNumUpdatedRows() {\n if (!this.executePromise) {\n throw new StatementNotExecutedError();\n }\n assert(this.stmt, \"Statement must be executed before getting number of updated rows\");\n return this.stmt.getNumUpdatedRows();\n }\n\n getSessionState() {\n if (!this.executePromise) {\n throw new StatementNotExecutedError();\n }\n assert(this.stmt, \"Statement must be executed before getting session state\");\n return this.stmt.getSessionState();\n }\n\n getRequestId() {\n if (!this.executePromise) {\n throw new StatementNotExecutedError();\n }\n assert(this.stmt, \"Statement must be executed before getting request ID\");\n return this.stmt.getRequestId();\n }\n\n getStatementId() {\n if (!this.executePromise) {\n throw new StatementNotExecutedError();\n }\n assert(this.stmt, \"Statement must be executed before getting statement ID\");\n // Note: getStatementId() was deprecated by Snowflake in favor of getQueryId().\n // They return the same value, but we should use the newer method.\n return this.stmt.getQueryId();\n }\n\n private log(elapsedTime: number) {\n let logMessage = \"Executed\";\n\n const state = this.getSessionState();\n if (state) {\n // @ts-expect-error: state.getCurrentDatabase and getCurrentSchema do exist\n logMessage += ` (${state.getCurrentDatabase()}.${state.getCurrentSchema()})`;\n }\n\n logMessage += `: ${this.getSqlText()}`;\n if (logMessage[logMessage.length - 1] !== \";\") {\n logMessage += \";\";\n }\n\n if (this.executeOptions.binds) {\n logMessage += ` with binds: ${JSON.stringify(this.executeOptions.binds)};`;\n }\n\n logMessage += ` Elapsed time: ${elapsedTime}ms`;\n\n this.logSql?.(logMessage);\n }\n}\n","export class SnowflakeError extends Error {\n constructor(message: string) {\n super(message);\n }\n}\n","import { SnowflakeError } from \"./SnowflakeError.ts\";\n\nexport class StatementNotExecutedError extends SnowflakeError {\n constructor() {\n super(\"Statement not executed yet - call the execute() method\");\n }\n}\n","import type { LogLevel } from \"snowflake-sdk\";\n\nexport interface LoggingOptions {\n /** optional function to log SQL statements (e.g. console.log) */\n logSql?: (sqlText: string) => void;\n /** turn on SDK-level logging */\n logLevel?: \"error\" | \"warn\" | \"debug\" | \"info\" | \"trace\" | \"off\";\n}\n\nexport function toSdkLogLevel(logLevel: string): LogLevel {\n return logLevel.toUpperCase() as LogLevel;\n}\n","import { SnowflakeError } from \"./SnowflakeError.ts\";\n\nexport class StatementAlreadyExecutedError extends SnowflakeError {\n constructor() {\n super(\"Statement already executed - it cannot be executed again\");\n }\n}\n"],"mappings":"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","names":["assert","SDK"]}