or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

bigquery-client.mdclickhouse-client.mdcore-types.mdcredentials.mddatabricks-client.mdfactory-functions.mdindex.mdpostgres-client.mdredshift-client.mdsnowflake-client.mdsql-builders.mdssh-tunnel.mdtrino-client.md
tile.json

snowflake-client.mddocs/

Snowflake Client

Snowflake client with multiple authentication methods and native async queries.

Quick Start

import { SnowflakeWarehouseClient } from '@lightdash/warehouses';

const client = new SnowflakeWarehouseClient({
  type: 'snowflake',
  account: 'my-account',
  user: 'myuser',
  password: 'mypassword',
  database: 'ANALYTICS',
  warehouse: 'COMPUTE_WH',
  schema: 'PUBLIC',
});

await client.test();

Key Features

  • Multiple Auth: Password, key pair, OAuth, external browser
  • Native Async Queries: With pagination support
  • Session Config: Timezone and week start per query
  • Quoted Identifiers: Control case sensitivity
  • Semi-structured Data: VARIANT, OBJECT, ARRAY support

Authentication Methods

Password

{ type: 'snowflake', user: 'myuser', password: 'mypassword', ... }

Key Pair

{
  type: 'snowflake',
  user: 'myuser',
  privateKey: '-----BEGIN PRIVATE KEY-----\n...',
  privateKeyPass: 'passphrase', // Optional
  authenticationType: 'private_key',
  ...
}

OAuth SSO

{
  type: 'snowflake',
  user: 'myuser',
  token: 'short-lived-access-token',
  refreshToken: 'refresh-token',
  authenticationType: 'sso',
  ...
}

External Browser

{
  type: 'snowflake',
  user: 'myuser',
  authenticationType: 'external_browser',
  ...
}

Common Patterns

Query with Session Config

await client.streamQuery(
  'SELECT DATE_TRUNC(\'week\', order_date) as week, SUM(amount) FROM orders GROUP BY week',
  (data) => { /* process rows */ },
  { timezone: 'America/Los_Angeles', tags: {} }
);
// Sets TIMEZONE and WEEK_START session parameters

Async Query with Pagination

// Snowflake has native pagination support (unlike other warehouses)
// Returns: Promise<WarehouseExecuteAsyncQuery>
const result = await client.executeAsyncQuery(
  {
    sql: 'SELECT * FROM large_table',
    tags: {},
  },
  (rows, fields) => {
    // Optional callback: results stream immediately if provided
    console.log(`Received ${rows.length} rows`);
  }
);

// Retrieve paginated results (Snowflake-only feature)
// Returns: Promise<WarehouseGetAsyncQueryResults>
const page1 = await client.getAsyncQueryResults({
  sql: 'SELECT * FROM large_table',
  queryId: result.queryId,              // Required: from executeAsyncQuery
  queryMetadata: result.queryMetadata,  // Required: from executeAsyncQuery
  page: 1,                              // 1-indexed page number
  pageSize: 1000,                       // Rows per page
});

console.log(`Page 1: ${page1.rows.length} of ${page1.totalRows} rows`);
console.log(`Total pages: ${page1.pageCount}`);

Edge Cases:

  • getAsyncQueryResults only works with Snowflake (other warehouses throw NotImplementedError)
  • Must save queryId and queryMetadata from executeAsyncQuery to retrieve pages
  • Pages are 1-indexed (not 0-indexed)

SQL Builder

import { SnowflakeSqlBuilder } from '@lightdash/warehouses';

const builder = new SnowflakeSqlBuilder();
builder.getFieldQuoteChar(); // '"'
builder.escapeString("Winter's Sale"); // "Winter''s Sale"

Percentile SQL: Uses PERCENTILE_CONT (exact, slower than BigQuery's approx)

import { MetricType } from '@lightdash/common';

// Median (50th percentile)
const medianSql = builder.getMetricSql('revenue', {
  type: MetricType.MEDIAN,
  sql: 'revenue'
});
// Returns: "PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY revenue)"

// 99th percentile
const p99Sql = builder.getMetricSql('latency', {
  type: MetricType.PERCENTILE,
  sql: 'latency',
  percentile: 99
});
// Returns: "PERCENTILE_CONT(0.99) WITHIN GROUP (ORDER BY latency)"

Note: PERCENTILE_CONT provides exact results (unlike BigQuery's approximate). For large datasets, consider APPROX_PERCENTILE in custom SQL.

Field Type Enum

import { SnowflakeTypes } from '@lightdash/warehouses';

enum SnowflakeTypes {
  NUMBER, DECIMAL, NUMERIC, INTEGER, INT, BIGINT, SMALLINT,
  FLOAT, DOUBLE, REAL, STRING, TEXT, BOOLEAN,
  DATE, DATETIME, TIME, TIMESTAMP, TIMESTAMP_LTZ, TIMESTAMP_NTZ, TIMESTAMP_TZ,
  VARIANT, OBJECT, ARRAY, GEOGRAPHY,
}

Type Mapping Utility

import { mapFieldType } from '@lightdash/warehouses';

mapFieldType('NUMBER'); // DimensionType.NUMBER
mapFieldType('TIMESTAMP_TZ'); // DimensionType.TIMESTAMP
mapFieldType('VARCHAR'); // DimensionType.STRING

Error Handling

Common error codes:

  • 002003: Authentication failed
  • 390318: OAuth token expired
  • 390144: External browser auth failed

Custom error messages via environment variable:

export SNOWFLAKE_UNAUTHORIZED_ERROR_MESSAGE="Access denied to {snowflakeSchema}.{snowflakeTable}"

Session Configuration

Forced Settings (always applied):

  • QUOTED_IDENTIFIERS_IGNORE_CASE = FALSE

Optional Settings:

  • TIMEZONE: Set via query options
  • WEEK_START: From credentials startOfWeek

Options

{
  role: 'ANALYST', // Session role
  clientSessionKeepAlive: true, // Maintain session between queries
  queryTag: 'lightdash', // Query tracking tag
  quotedIdentifiersIgnoreCase: false, // Case sensitivity
  disableTimestampConversion: false, // Disable UTC conversion
}

Notes

  • Account format: my-account or my-account.us-east-1
  • Connection caching for external browser auth
  • Virtual warehouse controls compute resources
  • Native pagination for large result sets