Class: GoodData::CloudResources::SnowflakeClient

Inherits:
CloudResourceClient show all
Defined in:
lib/gooddata/cloud_resources/snowflake/snowflake_client.rb

Constant Summary collapse

SNOWFLAKE_GDC_APPLICATION_PARAMETER =
'application=gooddata_platform'
SNOWFLAKE_SEPARATOR_PARAM =
'?'

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from CloudResourceClient

descendants

Constructor Details

#initialize(options = {}) ⇒ SnowflakeClient

Returns a new instance of SnowflakeClient.



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/gooddata/cloud_resources/snowflake/snowflake_client.rb', line 38

def initialize(options = {})
  raise("Data Source needs a client to Snowflake to be able to query the storage but 'snowflake_client' is empty.") unless options['snowflake_client']

  if options['snowflake_client']['connection'].is_a?(Hash)
    @database = options['snowflake_client']['connection']['database']
    @schema = options['snowflake_client']['connection']['schema'] || 'public'
    @warehouse = options['snowflake_client']['connection']['warehouse']
    @url = build_url(options['snowflake_client']['connection']['url'])
    @authentication = options['snowflake_client']['connection']['authentication']
  else
    raise('Missing connection info for Snowflake client')

  end

  # When update driver class then also updating driver class using in connection(..) method below
  Java.net.snowflake.client.jdbc.SnowflakeDriver
end

Class Method Details

.accept?(type) ⇒ Boolean

Returns:

  • (Boolean)


33
34
35
# File 'lib/gooddata/cloud_resources/snowflake/snowflake_client.rb', line 33

def accept?(type)
  type == 'snowflake'
end

Instance Method Details

#build_url(url) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/gooddata/cloud_resources/snowflake/snowflake_client.rb', line 105

def build_url(url)
  is_contain = url.include?(SNOWFLAKE_GDC_APPLICATION_PARAMETER)
  unless is_contain
    if url.include?(SNOWFLAKE_SEPARATOR_PARAM)
      url.concat("&")
    else
      url.concat(SNOWFLAKE_SEPARATOR_PARAM)
    end
    url.concat(SNOWFLAKE_GDC_APPLICATION_PARAMETER)
  end

  url
end

#connectObject



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/gooddata/cloud_resources/snowflake/snowflake_client.rb', line 82

def connect
  GoodData.logger.info "Setting up connection to Snowflake #{@url}"

  prop = java.util.Properties.new
  prop.setProperty('schema', @schema)
  prop.setProperty('warehouse', @warehouse)
  prop.setProperty('db', @database)

  if @authentication['keyPair']
    prop.setProperty('user', @authentication['keyPair']['userName'])
    private_key_str = build_private_key(@authentication['keyPair']['privateKey'], @authentication['keyPair']['passPhrase'])
    prop.setProperty('private_key_base64', private_key_str)
  else
    prop.setProperty('user', @authentication['basic']['userName'])
    prop.setProperty('password', @authentication['basic']['password'])
  end

  # Add JDBC_QUERY_RESULT_FORMAT parameter to fix unsafe memory issue of Snowflake JDBC driver
  prop.setProperty('JDBC_QUERY_RESULT_FORMAT', 'JSON')

  @connection = com.snowflake.client.jdbc.SnowflakeDriver.new.connect(@url, prop)
end

#realize_query(query, _params) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/gooddata/cloud_resources/snowflake/snowflake_client.rb', line 56

def realize_query(query, _params)
  GoodData.gd_logger.info("Realize SQL query: type=snowflake status=started")

  connect
  filename = "#{SecureRandom.urlsafe_base64(6)}_#{Time.now.to_i}.csv"
  measure = Benchmark.measure do
    statement = @connection.create_statement

    has_result = statement.execute(query)
    if has_result
      result = statement.get_result_set
       = result.
      col_count = .column_count
      CSV.open(filename, 'wb') do |csv|
        csv << Array(1..col_count).map { |i| .get_column_name(i) } # build the header
        csv << Array(1..col_count).map { |i| result.get_string(i)&.to_s } while result.next
      end
    end
  end
  GoodData.gd_logger.info("Realize SQL query: type=snowflake status=finished duration=#{measure.real}")
  filename
ensure
  @connection&.close
  @connection = nil
end