Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion lib/gooddata/cloud_resources/redshift/redshift_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,10 @@ def realize_query(query, _params)
result = statement.get_result_set
metadata = result.get_meta_data
col_count = metadata.column_count
boolean_columns = boolean_column_indexes(metadata)
CSV.open(filename, 'wb') do |csv|
csv << Array(1..col_count).map { |i| metadata.get_column_name(i) } # build the header
csv << Array(1..col_count).map { |i| result.get_string(i)&.to_s } while result.next
csv << Array(1..col_count).map { |i| column_value(result, i, boolean_columns) } while result.next
end
end
end
Expand Down Expand Up @@ -98,6 +99,20 @@ def connect

private

# Driver 2.x getString() returns BOOLEAN as "t"/"f"; keep "true"/"false"
def boolean_column_indexes(metadata)
Array(1..metadata.column_count).select do |i|
[java.sql.Types::BIT, java.sql.Types::BOOLEAN].include?(metadata.get_column_type(i))
end
end

def column_value(result, index, boolean_columns)
return result.get_string(index)&.to_s unless boolean_columns.include?(index)

value = result.get_boolean(index)
result.was_null ? nil : value.to_s
end

def build_url(url, database)
url_parts = url.split('?')
url_path = url_parts[0].chomp('/')
Expand Down
44 changes: 43 additions & 1 deletion spec/unit/cloud_resources/redshift/redshift_client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
if RUBY_PLATFORM =~ /java/
require 'gooddata/cloud_resources/redshift/redshift_client'

describe GoodData::CloudResources::RedshiftClient do
shared_context 'redshift client with stubbed driver' do
let(:driver) { double('driver') }
let(:driver_class) { double('driver_class', new: driver) }
let(:options) do
Expand All @@ -32,6 +32,10 @@
allow(client).to receive_message_chain('com.amazon.redshift.jdbc42.Driver').and_return(driver_class)
client
end
end

describe GoodData::CloudResources::RedshiftClient do
include_context 'redshift client with stubbed driver'

def connect_properties
received = nil
Expand Down Expand Up @@ -67,4 +71,42 @@ def connect_properties
end
end
end

describe GoodData::CloudResources::RedshiftClient, '#realize_query' do
include_context 'redshift client with stubbed driver'

let(:authentication) { { 'basic' => { 'userName' => 'basic_user', 'password' => 'secret' } } }
let(:metadata) { double('metadata', column_count: 3) }
let(:result) { double('result') }
let(:statement) { double('statement', execute: true, get_result_set: result) }
let(:connection) { double('connection', create_statement: statement, close: nil) }

before do
# Other specs leave doubles in the global loggers
allow(GoodData).to receive(:gd_logger).and_return(double('gd_logger', info: nil))
allow(GoodData).to receive(:logger).and_return(double('logger', info: nil))
allow(driver).to receive(:connect).and_return(connection)
allow(result).to receive(:get_meta_data).and_return(metadata)
allow(metadata).to receive(:get_column_name) { |i| %w[name active deleted][i - 1] }
allow(metadata).to receive(:get_column_type) do |i|
[java.sql.Types::VARCHAR, java.sql.Types::BIT, java.sql.Types::BOOLEAN][i - 1]
end
allow(result).to receive(:next).and_return(true, true, false)
allow(result).to receive(:get_string).with(1).and_return('Alice', 'Bob')
# Driver 2.x getString() returns BOOLEAN as "t"/"f"
allow(result).to receive(:get_string).with(2).and_return('t', 'f')
allow(result).to receive(:get_boolean).with(2).and_return(true, false)
allow(result).to receive(:get_boolean).with(3).and_return(false, false)
allow(result).to receive(:was_null).and_return(false, false, false, true)
end

it 'writes BOOLEAN columns as true/false and NULL as empty' do
Dir.mktmpdir do |dir|
Dir.chdir(dir) do
rows = CSV.read(subject.realize_query('SELECT 1', nil))
expect(rows).to eq [%w[name active deleted], %w[Alice true false], ['Bob', 'false', nil]]
end
end
end
end
end
Loading