Skip to content
Snippets Groups Projects
Commit 1311d3b1 authored by Kenneth Bier's avatar Kenneth Bier
Browse files

adding snowflake test driver information

parent 8782d315
No related branches found
No related tags found
No related merge requests found
......@@ -86,7 +86,7 @@
:exclusions [org.clojure/clojurescript]]
[net.sf.cssbox/cssbox "4.12" ; HTML / CSS rendering
:exclusions [org.slf4j/slf4j-api]]
[net.snowflake/snowflake-jdbc "3.4.2"] ; Snowflake JDBC Client Library
[net.snowflake/snowflake-jdbc "3.5.5"] ; Snowflake JDBC Client Library
[com.clearspring.analytics/stream "2.9.5" ; Various sketching algorithms
:exclusions [org.slf4j/slf4j-api
it.unimi.dsi/fastutil]]
......
......@@ -2,31 +2,36 @@
"Snowflake Driver."
(:require [clojure.java.jdbc :as jdbc]
[clojure.string :as str]
[honeysql.core :as hsql]
[honeysql
[core :as hsql]
[helpers :as h]]
[metabase
[config :as config]
[driver :as driver]
[util :as u]]
[metabase.driver
[generic-sql :as sql]
[postgres :as postgres]]
[generic-sql :as sql]]
;; TODO delete
[metabase.models
[field :as field]
[table :as table]]
[metabase.util
[honeysql-extensions :as hx]
[ssh :as ssh]]))
(defn connection-details->spec
"Create a database specification for a snowflake database."
[{:keys [account regionid] :as opts}]
[{:keys [account regionid dbname] :as opts}]
(let [host (if regionid
(str account "." regionid)
account)]
(merge {:subprotocol "snowflake"
:classname "net.snowflake.client.jdbc.SnowflakeDriver"
:subname (str "//" host ".snowflakecomputing.com/")
;; Don't fetch schemas for databases if the user supplies a single database.
:db dbname
:client_metadata_request_use_connection_ctx true
:ssl true}
(dissoc opts :host :port))))
(dissoc opts :host :port :dbname))))
(defrecord SnowflakeDriver []
clojure.lang.Named
......@@ -35,7 +40,7 @@
(def ^:private snowflake-date-formatter
"The default timestamp format for Snowflake.
See https://docs.snowflake.net/manuals/sql-reference/data-types-datetime.html#timestamp."
(driver/create-db-time-formatter "EEE, dd MMM yyyy HH:mm:ss Z"))
(driver/create-db-time-formatters "EEE, dd MMM yyyy HH:mm:ss Z"))
(def ^:private snowflake-db-time-query
"Snowflake current database time, with hour and minute timezone offset."
......@@ -133,8 +138,9 @@
{:name "warehouse"
:display-name "Warehouse"
:placeholder "my_warehouse"}
{:name "db"
{:name "dbname"
:display-name "Database name"
:required true
:placeholder "cockerel"}
{:name "regionid"
:display-name "Region Id"
......@@ -154,26 +160,16 @@
(merge (sql/ISQLDriverDefaultsMixin)
{:connection-details->spec (u/drop-first-arg connection-details->spec)
:string-length-fn (u/drop-first-arg string-length-fn)
:excluded-schemas (constantly #{"information_schema"})
:date (u/drop-first-arg date)
:current-datetime-fn (constantly :%current_timestamp)
:set-timezone-sql (constantly "alter session set time_zone = %s")
:unix-timestamp->timestamp (u/drop-first-arg unix-timestamp->timestamp)
:column->base-type (u/drop-first-arg column->base-type)}
;; HACK ! When we test against Snowflake we use a session-unique schema so we can run simultaneous tests
;; against a single remote host; when running tests tell the sync process to ignore all the other schemas
#_(when config/is-test?
{:excluded-schemas (memoize
(fn [_]
(require 'metabase.test.data.snowflake)
(let [session-schema-number @(resolve 'metabase.test.data.snowflake/session-schema-number)]
(set (conj (for [i (range 240)
:when (not= i session-schema-number)]
(str "schema_" i))
"public")))))})))
:column->base-type (u/drop-first-arg column->base-type)}))
(defn -init-driver
"Register the Snowflake driver"
[]
(driver/register-driver! :Snowflake (SnowflakeDriver.)))
(driver/register-driver! :snowflake (SnowflakeDriver.)))
(ns metabase.driver.snowflake-test
(:require [metabase.test.data.datasets :refer [expect-with-engine]]
[metabase.test.util :as tu]))
(expect-with-engine :snowflake
"UTC"
(tu/db-timezone-id))
(ns metabase.test.data.snowflake
(:require [clojure.string :as s]
[metabase.driver.generic-sql :as sql]
[metabase.util
[honeysql-extensions :as hx]]
[metabase.test.data
[generic-sql :as generic]
[interface :as i]]
[metabase.util :as u])
(:import metabase.driver.snowflake.SnowflakeDriver))
(def ^:private ^:const field-base-type->sql-type
{:type/BigInteger "BIGINT"
:type/Boolean "BOOLEAN"
:type/Date "DATE"
:type/DateTime "TIMESTAMP"
:type/Decimal "DECIMAL"
:type/Float "FLOAT"
:type/Integer "INTEGER"
:type/Text "TEXT"
:type/Time "TIME"})
(defn- database->connection-details [context {:keys [database-name]}]
(merge {:account (i/db-test-env-var-or-throw :snowflake :account)
:user (i/db-test-env-var-or-throw :snowflake :user)
:password (i/db-test-env-var-or-throw :snowflake :password)
:warehouse (i/db-test-env-var-or-throw :snowflake :warehouse)}
(when (= context :db)
{:db database-name})))
(def schema-name "foo")
;; Snowflake requires you identify an object with db-name.schema-name.table-name
(defn qualified-name-components
([_ db-or-schema-name] [db-or-schema-name])
([_ db-name table-name] [db-name schema-name table-name])
([_ db-name table-name field-name] [db-name schema-name table-name field-name]))
;; Snowflake is very strict about quoting. If you create a resource with quotes
;; you must always reference it with quotes. Plus its default schema (public)
;; must be referenced without quotes. Therefore we create a new schema with
;; quotes so the quoting can be consistent across identifiers.
(defn- create-db-sql [driver {:keys [database-name]}]
(let [db (generic/qualify+quote-name driver database-name)
schema-name (generic/qualify+quote-name driver schema-name)]
(format "CREATE DATABASE %s; CREATE SCHEMA %s.%s; USE DATABASE %s;"
db db schema-name db)))
(u/strict-extend SnowflakeDriver
generic/IGenericSQLTestExtensions
(merge generic/DefaultsMixin
{:field-base-type->sql-type (u/drop-first-arg field-base-type->sql-type)
:create-db-sql create-db-sql
:execute-sql! generic/sequentially-execute-sql!
:pk-sql-type (constantly "INTEGER")
:qualified-name-components qualified-name-components})
i/IDriverTestExtensions
(merge generic/IDriverTestExtensionsMixin
{:database->connection-details (u/drop-first-arg database->connection-details)
:default-schema (constantly "foo")
:engine (constantly :snowflake)}))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment