rb_snowflake_client 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +2 -2
- data/.github/workflows/release-gh-packages.yml +3 -2
- data/.github/workflows/release-rubygems.yml +3 -2
- data/CHANGELOG.md +128 -0
- data/Gemfile.lock +8 -8
- data/README.md +33 -6
- data/lib/ruby_snowflake/client/key_pair_jwt_auth_manager.rb +10 -2
- data/lib/ruby_snowflake/client.rb +16 -18
- data/lib/ruby_snowflake/row.rb +25 -5
- data/lib/ruby_snowflake/version.rb +1 -1
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9c1581fededb6e083bc1f55249d806fca4a63462fafee98f9277986729dd1107
|
4
|
+
data.tar.gz: e810744812f56a65d519d8a30ce96e97d2f1341479ee7aeb2a50766c0f541e90
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7cc78b78f3a5a3d056c826107aab889d23705ea76249800a7c098e43e8515db4fc9f85e11a2fae86cced570b1c5aaa869dded60495467bbb2b52241edd466c2e
|
7
|
+
data.tar.gz: 6b57c2a14a03fe96711d86554eb13b86bd5865a1aafa629a30ea02b2c27fc72f743f8942fc0d4d35b590d824cbd110c2ad3efbe6ffc235037c7039213644e97c
|
data/.github/workflows/ci.yml
CHANGED
@@ -12,9 +12,9 @@ jobs:
|
|
12
12
|
steps:
|
13
13
|
- uses: actions/checkout@v3
|
14
14
|
- name: Set up Ruby
|
15
|
-
uses: ruby/setup-ruby@
|
15
|
+
uses: ruby/setup-ruby@v1
|
16
16
|
with:
|
17
|
-
ruby-version: '3.
|
17
|
+
ruby-version: '3.3'
|
18
18
|
- name: Install dependencies
|
19
19
|
run: bundle install
|
20
20
|
- name: Build gem
|
@@ -1,5 +1,6 @@
|
|
1
1
|
name: Release to Github Packages
|
2
2
|
on:
|
3
|
+
workflow_dispatch:
|
3
4
|
push:
|
4
5
|
branches:
|
5
6
|
- "master"
|
@@ -14,9 +15,9 @@ jobs:
|
|
14
15
|
steps:
|
15
16
|
- uses: actions/checkout@v3
|
16
17
|
- name: Set up Ruby
|
17
|
-
uses: ruby/setup-ruby@
|
18
|
+
uses: ruby/setup-ruby@v1
|
18
19
|
with:
|
19
|
-
ruby-version: '3.
|
20
|
+
ruby-version: '3.3'
|
20
21
|
- name: Install dependencies
|
21
22
|
run: bundle install
|
22
23
|
- name: Build gem
|
@@ -1,5 +1,6 @@
|
|
1
1
|
name: Release to Rubygems
|
2
2
|
on:
|
3
|
+
workflow_dispatch:
|
3
4
|
push:
|
4
5
|
branches:
|
5
6
|
- "master"
|
@@ -11,9 +12,9 @@ jobs:
|
|
11
12
|
steps:
|
12
13
|
- uses: actions/checkout@v3
|
13
14
|
- name: Set up Ruby
|
14
|
-
uses: ruby/setup-ruby@
|
15
|
+
uses: ruby/setup-ruby@v1
|
15
16
|
with:
|
16
|
-
ruby-version: '3.
|
17
|
+
ruby-version: '3.3'
|
17
18
|
- name: Install dependencies
|
18
19
|
run: bundle install
|
19
20
|
- name: Publish to RubyGems
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
|
+
|
8
|
+
## [1.4.0] - 2025-05-01
|
9
|
+
### Added
|
10
|
+
- Enhanced Row API to implement Enumerable interface
|
11
|
+
- Added case-insensitive access to Row columns via both symbol and string keys
|
12
|
+
- Added numeric column access to Row (e.g., `row[0]`)
|
13
|
+
- Support setting organization or ENV["SNOWFLAKE_ORGANIZATION"] to nil or "" in JWT authentication
|
14
|
+
- Added default_role parameter and SNOWFLAKE_DEFAULT_ROLE env variable
|
15
|
+
|
16
|
+
## [1.3.0] - 2025-01-03
|
17
|
+
### Changed
|
18
|
+
- Bumped gem dependencies to newer versions
|
19
|
+
- Added support for role parameter in Client and query method
|
20
|
+
|
21
|
+
## [1.2.0] - 2025-01-03
|
22
|
+
### Changed
|
23
|
+
- Switched from Oj to JSON gem for parsing
|
24
|
+
- Improved performance by utilizing the optimized JSON gem
|
25
|
+
|
26
|
+
## [1.1.5] - 2024-12-19
|
27
|
+
### Fixed
|
28
|
+
- Parse exception detail OR message for better error handling
|
29
|
+
|
30
|
+
## [1.1.4] - 2024-11-05
|
31
|
+
### Fixed
|
32
|
+
- Fixed ENV variable issue
|
33
|
+
|
34
|
+
## [1.1.3] - 2024-08-09
|
35
|
+
### Added
|
36
|
+
- Retry HTTP codes in the 3xx range
|
37
|
+
|
38
|
+
## [1.1.2] - 2024-08-06
|
39
|
+
### Fixed
|
40
|
+
- CI error fixes
|
41
|
+
|
42
|
+
## [1.1.1] - 2024-07-12
|
43
|
+
### Fixed
|
44
|
+
- Added 502 to specific list of retryable HTTP error codes
|
45
|
+
- Fixed issue with checking string code presence in an array of integer values
|
46
|
+
|
47
|
+
## [1.1.0] - 2024-06-05
|
48
|
+
### Added
|
49
|
+
- Support for specifying a schema in query method
|
50
|
+
- Merged multiple community contributions
|
51
|
+
|
52
|
+
## [1.0.6] - 2024-06-05
|
53
|
+
### Added
|
54
|
+
- Allow specifying schema in query method
|
55
|
+
|
56
|
+
## [1.0.5] - 2024-03-20
|
57
|
+
### Added
|
58
|
+
- Added exponential backoff to retryable calls
|
59
|
+
- Improved handling of rate limiting (429 responses)
|
60
|
+
|
61
|
+
## [1.0.4] - 2024-01-30
|
62
|
+
### Fixed
|
63
|
+
- Fixed raise arguments
|
64
|
+
- Now properly raising OpenSSL errors to retry them
|
65
|
+
|
66
|
+
## [1.0.3] - 2024-01-17
|
67
|
+
### Fixed
|
68
|
+
- Now upcasing database and warehouse fields in requests
|
69
|
+
- Fixed error where lowercase field names would result in "Unable to run command without specifying database/warehouse"
|
70
|
+
|
71
|
+
## [1.0.2] - 2024-01-16
|
72
|
+
### Fixed
|
73
|
+
- Fixed typo in key pair memoization
|
74
|
+
|
75
|
+
## [1.0.1] - 2024-01-09
|
76
|
+
### Added
|
77
|
+
- Added `create_jwt_token` helper method for testing
|
78
|
+
- Support for time travel in tests
|
79
|
+
|
80
|
+
## [1.0.0] - 2023-12-11
|
81
|
+
### Changed
|
82
|
+
- First stable release
|
83
|
+
- Fixed markdown links in documentation
|
84
|
+
|
85
|
+
## [0.3.0] - 2023-12-08
|
86
|
+
### Added
|
87
|
+
- Support for Snowflake polling responses
|
88
|
+
- Handle async query execution
|
89
|
+
|
90
|
+
## [0.2.0] - 2023-12-07
|
91
|
+
### Added
|
92
|
+
- Extracted authentication logic into its own class
|
93
|
+
- Improved time handling for various Snowflake date/time types
|
94
|
+
- Support for TIME, DATETIME, TIMESTAMP, TIMESTAMP_LTZ, TIMESTAMP_NTZ, TIMESTAMP_TZ
|
95
|
+
|
96
|
+
## [0.1.2] - 2023-12-04
|
97
|
+
### Added
|
98
|
+
- Support for database parameter in requests
|
99
|
+
- Added missing dependencies to gemspec
|
100
|
+
|
101
|
+
## [0.1.1] - 2023-12-01
|
102
|
+
### Added
|
103
|
+
- Added `fetch` as an alias for `query` for compatibility with other clients
|
104
|
+
|
105
|
+
## [0.1.0] - 2023-11-28
|
106
|
+
### Added
|
107
|
+
- First minor version release with basic functionality
|
108
|
+
- Support for querying Snowflake with the HTTP API
|
109
|
+
- Support for streaming results
|
110
|
+
|
111
|
+
## [0.0.6] - 2023-11-27
|
112
|
+
### Changed
|
113
|
+
- Cleaned up key pair authentication
|
114
|
+
- Improved documentation with better setup instructions
|
115
|
+
|
116
|
+
## [0.0.5] - 2023-11-27
|
117
|
+
### Fixed
|
118
|
+
- Various bug fixes and improvements
|
119
|
+
|
120
|
+
## [0.0.4] - 2023-11-22
|
121
|
+
### Changed
|
122
|
+
- Fixed type handling for query results
|
123
|
+
- All specs now pass
|
124
|
+
|
125
|
+
## [0.0.3] - 2023-11-21
|
126
|
+
### Changed
|
127
|
+
- Renamed to RubySnowflake namespace
|
128
|
+
- Initial gem structure
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rb_snowflake_client (1.
|
4
|
+
rb_snowflake_client (1.4.0)
|
5
5
|
bigdecimal (>= 3.0)
|
6
6
|
concurrent-ruby (>= 1.2)
|
7
7
|
connection_pool (>= 2.4)
|
@@ -16,15 +16,15 @@ GEM
|
|
16
16
|
base64 (0.2.0)
|
17
17
|
bigdecimal (3.1.9)
|
18
18
|
coderay (1.1.3)
|
19
|
-
concurrent-ruby (1.3.
|
20
|
-
connection_pool (2.
|
21
|
-
diff-lcs (1.
|
22
|
-
dotenv (3.1.
|
23
|
-
json (2.
|
19
|
+
concurrent-ruby (1.3.5)
|
20
|
+
connection_pool (2.5.3)
|
21
|
+
diff-lcs (1.6.1)
|
22
|
+
dotenv (3.1.8)
|
23
|
+
json (2.11.3)
|
24
24
|
jwt (2.10.1)
|
25
25
|
base64
|
26
26
|
method_source (1.1.0)
|
27
|
-
parallel (1.
|
27
|
+
parallel (1.27.0)
|
28
28
|
pry (0.15.2)
|
29
29
|
coderay (~> 1.1)
|
30
30
|
method_source (~> 1.0)
|
@@ -34,7 +34,7 @@ GEM
|
|
34
34
|
rspec-core (~> 3.13.0)
|
35
35
|
rspec-expectations (~> 3.13.0)
|
36
36
|
rspec-mocks (~> 3.13.0)
|
37
|
-
rspec-core (3.13.
|
37
|
+
rspec-core (3.13.3)
|
38
38
|
rspec-support (~> 3.13.0)
|
39
39
|
rspec-expectations (3.13.3)
|
40
40
|
diff-lcs (>= 1.2.0, < 2.0)
|
data/README.md
CHANGED
@@ -30,11 +30,12 @@ require "rb_snowflake_client"
|
|
30
30
|
client = RubySnowflake::Client.new(
|
31
31
|
"https://yourinstance.region.snowflakecomputing.com", # insert your URL here
|
32
32
|
File.read("secrets/my_key.pem"), # your private key in PEM format (scroll down for instructions)
|
33
|
-
"snowflake-organization", # your account name (doesn't match your URL)
|
33
|
+
"snowflake-organization", # your account name (doesn't match your URL), using nil may be required depending on your snowflake account
|
34
34
|
"snowflake-account", # typically your subdomain
|
35
35
|
"snowflake-user", # Your snowflake user
|
36
36
|
"some_warehouse", # The name of your warehouse to use by default
|
37
37
|
"some_database", # The name of the database in the context of which the queries will run
|
38
|
+
default_role: "some_role", # The name of the role with which the queries will run. A `nil` value uses the primary role of the user.
|
38
39
|
max_connections: 12, # Config options can be passed in
|
39
40
|
connection_timeout: 45, # See below for the full set of options
|
40
41
|
query_timeout: 1200, # how long to wait for queries, in seconds
|
@@ -48,10 +49,12 @@ Available ENV variables (see below in the config section for details)
|
|
48
49
|
- `SNOWFLAKE_PRIVATE_KEY_PATH` or `SNOWFLAKE_PRIVATE_KEY`
|
49
50
|
- Use either the key or the path. Key takes precedence if both are provided.
|
50
51
|
- `SNOWFLAKE_ORGANIZATION`
|
52
|
+
- Optional, if you leave it off, the library will authenticate with an account name of only SNOWFLAKE_ACCOUNT
|
51
53
|
- `SNOWFLAKE_ACCOUNT`
|
52
54
|
- `SNOWFLAKE_USER`
|
53
55
|
- `SNOWFLAKE_DEFAULT_WAREHOUSE`
|
54
56
|
- `SNOWFLAKE_DEFAULT_DATABASE`
|
57
|
+
- `SNOWFLAKE_DEFAULT_ROLE`
|
55
58
|
- `SNOWFLAKE_JWT_TOKEN_TTL`
|
56
59
|
- `SNOWFLAKE_CONNECTION_TIMEOUT`
|
57
60
|
- `SNOWFLAKE_MAX_CONNECTIONS`
|
@@ -69,9 +72,19 @@ result = client.query("SELECT ID, NAME FROM SOMETABLE")
|
|
69
72
|
|
70
73
|
# result is Enumerable
|
71
74
|
result.each do |row|
|
72
|
-
|
73
|
-
puts row[
|
74
|
-
puts row
|
75
|
+
# Row implements Enumerable and provides flexible column access:
|
76
|
+
puts row[:id] # access with symbols (case-insensitive)
|
77
|
+
puts row["name"] # access with strings (case-insensitive)
|
78
|
+
puts row[0] # access with numeric indices
|
79
|
+
|
80
|
+
# Row has Enumerable methods
|
81
|
+
puts row.keys # get all column names
|
82
|
+
puts row.values # get all values
|
83
|
+
puts row.to_h # convert to Hash with column names as keys
|
84
|
+
|
85
|
+
# Use all Enumerable methods
|
86
|
+
row.each { |column_name, value| puts "#{column_name}: #{value}" }
|
87
|
+
filtered = row.select { |column, value| column.start_with?("i") }
|
75
88
|
end
|
76
89
|
```
|
77
90
|
|
@@ -111,6 +124,14 @@ client.query("SELECT * FROM BIGTABLE", warehouse: "FAST_WH")
|
|
111
124
|
client.query("SELECT * FROM BIGTABLE", schema: "MY_SCHEMA")
|
112
125
|
```
|
113
126
|
|
127
|
+
## Specifying role
|
128
|
+
|
129
|
+
Queries by default use the primary role assigned to the account. If there are multiple roles you can switch between them on a per query basis.
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
client.query("SELECT * FROM BIGTABLE", role: "MY_ROLE")
|
133
|
+
```
|
134
|
+
|
114
135
|
## Binding parameters
|
115
136
|
|
116
137
|
Say we have `BIGTABLE` with a `data` column of a type `VARIANT`.
|
@@ -157,7 +178,9 @@ end
|
|
157
178
|
|
158
179
|
1. Does not yet support multiple statements (work around is to wrap in `BEGIN ... END`)
|
159
180
|
2. Only supports key pair authentication
|
160
|
-
3.
|
181
|
+
3. It's faster to work directly with the row value and not call to_h if you don't need to
|
182
|
+
4. Rows are Enumerable, providing access to methods like `each`, `map`, `select`, `keys`, and `values`
|
183
|
+
5. Row column access is case-insensitive and supports string keys, symbol keys, and numeric indices
|
161
184
|
|
162
185
|
# Setting up a user for key pair authentication
|
163
186
|
|
@@ -205,7 +228,7 @@ or alternatively, use the client to verify:
|
|
205
228
|
client = RubySnowflake::Client.new(
|
206
229
|
"https://yourinstance.region.snowflakecomputing.com", # insert your URL here
|
207
230
|
File.read("secrets/my_key.pem"), # path to your private key
|
208
|
-
"snowflake-organization", # your account name (doesn't match your URL)
|
231
|
+
"snowflake-organization", # your account name (doesn't match your URL), using nil may be required depending on your snowflake account
|
209
232
|
"snowflake-account", # typically your subdomain
|
210
233
|
"snowflake-user", # Your snowflake user
|
211
234
|
"some_warehouse", # The name of your warehouse to use by default
|
@@ -213,6 +236,10 @@ client = RubySnowflake::Client.new(
|
|
213
236
|
)
|
214
237
|
```
|
215
238
|
|
239
|
+
# Change Log
|
240
|
+
|
241
|
+
See [Change Log](CHANGELOG.md)
|
242
|
+
|
216
243
|
# Code of conduct
|
217
244
|
|
218
245
|
See [Code of Coduct](CODE_OF_CONDUCT.md)
|
@@ -30,8 +30,8 @@ module RubySnowflake
|
|
30
30
|
private_key = OpenSSL::PKey.read(@private_key_pem)
|
31
31
|
|
32
32
|
payload = {
|
33
|
-
:iss => "#{
|
34
|
-
:sub => "#{
|
33
|
+
:iss => "#{account_name}.#{@user.upcase}.#{public_key_fingerprint}",
|
34
|
+
:sub => "#{account_name}.#{@user.upcase}",
|
35
35
|
:iat => now,
|
36
36
|
:exp => @token_expires_at
|
37
37
|
}
|
@@ -45,6 +45,14 @@ module RubySnowflake
|
|
45
45
|
Time.now.to_i > @token_expires_at
|
46
46
|
end
|
47
47
|
|
48
|
+
def account_name
|
49
|
+
if @organization == nil || @organization == ""
|
50
|
+
@account.upcase
|
51
|
+
else
|
52
|
+
"#{@organization.upcase}-#{@account.upcase}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
48
56
|
def public_key_fingerprint
|
49
57
|
return @public_key_fingerprint unless @public_key_fingerprint.nil?
|
50
58
|
|
@@ -22,22 +22,12 @@ require_relative "streaming_result"
|
|
22
22
|
|
23
23
|
module RubySnowflake
|
24
24
|
class Error < StandardError
|
25
|
-
# This will get pulled through to Sentry, see:
|
26
|
-
# https://github.com/getsentry/sentry-ruby/blob/11ecd254c0d2cae2b327f0348074e849095aa32d/sentry-ruby/lib/sentry/error_event.rb#L31-L33
|
27
|
-
attr_reader :sentry_context
|
28
|
-
|
29
25
|
def initialize(details)
|
30
|
-
@sentry_context = details
|
31
26
|
@details = details
|
32
27
|
end
|
33
28
|
|
34
29
|
def message
|
35
|
-
|
36
|
-
super
|
37
|
-
else
|
38
|
-
@details.to_s
|
39
|
-
end
|
40
|
-
|
30
|
+
@details.to_s
|
41
31
|
end
|
42
32
|
end
|
43
33
|
|
@@ -67,6 +57,8 @@ module RubySnowflake
|
|
67
57
|
DEFAULT_HTTP_RETRIES = 2
|
68
58
|
# how long to wait to allow a query to complete, in seconds
|
69
59
|
DEFAULT_QUERY_TIMEOUT = 600 # 10 minutes
|
60
|
+
# default role to use
|
61
|
+
DEFAULT_ROLE = nil
|
70
62
|
|
71
63
|
JSON_PARSE_OPTIONS = { decimal_class: BigDecimal }.freeze
|
72
64
|
VALID_RESPONSE_CODES = %w(200 202).freeze
|
@@ -74,7 +66,7 @@ module RubySnowflake
|
|
74
66
|
POLLING_INTERVAL = 2 # seconds
|
75
67
|
|
76
68
|
# can't be set after initialization
|
77
|
-
attr_reader :connection_timeout, :max_connections, :logger, :max_threads_per_query, :thread_scale_factor, :http_retries, :query_timeout
|
69
|
+
attr_reader :connection_timeout, :max_connections, :logger, :max_threads_per_query, :thread_scale_factor, :http_retries, :query_timeout, :default_role
|
78
70
|
|
79
71
|
def self.from_env(logger: DEFAULT_LOGGER,
|
80
72
|
log_level: DEFAULT_LOG_LEVEL,
|
@@ -84,14 +76,15 @@ module RubySnowflake
|
|
84
76
|
max_threads_per_query: env_option("SNOWFLAKE_MAX_THREADS_PER_QUERY", DEFAULT_MAX_THREADS_PER_QUERY),
|
85
77
|
thread_scale_factor: env_option("SNOWFLAKE_THREAD_SCALE_FACTOR", DEFAULT_THREAD_SCALE_FACTOR),
|
86
78
|
http_retries: env_option("SNOWFLAKE_HTTP_RETRIES", DEFAULT_HTTP_RETRIES),
|
87
|
-
query_timeout: env_option("SNOWFLAKE_QUERY_TIMEOUT", DEFAULT_QUERY_TIMEOUT)
|
79
|
+
query_timeout: env_option("SNOWFLAKE_QUERY_TIMEOUT", DEFAULT_QUERY_TIMEOUT),
|
80
|
+
default_role: env_option("SNOWFLAKE_DEFAULT_ROLE", DEFAULT_ROLE))
|
88
81
|
private_key =
|
89
82
|
if key = ENV["SNOWFLAKE_PRIVATE_KEY"]
|
90
83
|
key
|
91
84
|
elsif path = ENV["SNOWFLAKE_PRIVATE_KEY_PATH"]
|
92
85
|
File.read(path)
|
93
86
|
else
|
94
|
-
raise MissingConfig
|
87
|
+
raise MissingConfig, "Either ENV['SNOWFLAKE_PRIVATE_KEY'] or ENV['SNOWFLAKE_PRIVATE_KEY_PATH'] must be set"
|
95
88
|
end
|
96
89
|
|
97
90
|
new(
|
@@ -102,6 +95,7 @@ module RubySnowflake
|
|
102
95
|
ENV.fetch("SNOWFLAKE_USER"),
|
103
96
|
ENV["SNOWFLAKE_DEFAULT_WAREHOUSE"],
|
104
97
|
ENV["SNOWFLAKE_DEFAULT_DATABASE"],
|
98
|
+
default_role: ENV.fetch("SNOWFLAKE_DEFAULT_ROLE", nil),
|
105
99
|
logger: logger,
|
106
100
|
log_level: log_level,
|
107
101
|
jwt_token_ttl: jwt_token_ttl,
|
@@ -116,6 +110,7 @@ module RubySnowflake
|
|
116
110
|
|
117
111
|
def initialize(
|
118
112
|
uri, private_key, organization, account, user, default_warehouse, default_database,
|
113
|
+
default_role: nil,
|
119
114
|
logger: DEFAULT_LOGGER,
|
120
115
|
log_level: DEFAULT_LOG_LEVEL,
|
121
116
|
jwt_token_ttl: DEFAULT_JWT_TOKEN_TTL,
|
@@ -131,6 +126,7 @@ module RubySnowflake
|
|
131
126
|
KeyPairJwtAuthManager.new(organization, account, user, private_key, jwt_token_ttl)
|
132
127
|
@default_warehouse = default_warehouse
|
133
128
|
@default_database = default_database
|
129
|
+
@default_role = default_role
|
134
130
|
|
135
131
|
# set defaults for config settings
|
136
132
|
@logger = logger
|
@@ -147,9 +143,10 @@ module RubySnowflake
|
|
147
143
|
@_enable_polling_queries = false
|
148
144
|
end
|
149
145
|
|
150
|
-
def query(query, warehouse: nil, streaming: false, database: nil, schema: nil, bindings: nil)
|
146
|
+
def query(query, warehouse: nil, streaming: false, database: nil, schema: nil, bindings: nil, role: nil)
|
151
147
|
warehouse ||= @default_warehouse
|
152
148
|
database ||= @default_database
|
149
|
+
role ||= @default_role
|
153
150
|
|
154
151
|
query_start_time = Time.now.to_i
|
155
152
|
response = nil
|
@@ -159,7 +156,8 @@ module RubySnowflake
|
|
159
156
|
"schema" => schema&.upcase,
|
160
157
|
"database" => database&.upcase,
|
161
158
|
"statement" => query,
|
162
|
-
"bindings" => bindings
|
159
|
+
"bindings" => bindings,
|
160
|
+
"role" => role
|
163
161
|
}
|
164
162
|
|
165
163
|
response = request_with_auth_and_headers(
|
@@ -228,11 +226,11 @@ module RubySnowflake
|
|
228
226
|
|
229
227
|
# there are a class of errors we want to retry rather than just giving up
|
230
228
|
if retryable_http_response_code?(response.code)
|
231
|
-
raise RetryableBadResponseError
|
229
|
+
raise RetryableBadResponseError,
|
232
230
|
"Retryable bad response! Got code: #{response.code}, w/ message #{response.body}"
|
233
231
|
|
234
232
|
else # not one we should retry
|
235
|
-
raise BadResponseError
|
233
|
+
raise BadResponseError,
|
236
234
|
"Bad response! Got code: #{response.code}, w/ message #{response.body}"
|
237
235
|
end
|
238
236
|
end
|
data/lib/ruby_snowflake/row.rb
CHANGED
@@ -5,6 +5,8 @@ require "time"
|
|
5
5
|
|
6
6
|
module RubySnowflake
|
7
7
|
class Row
|
8
|
+
include Enumerable
|
9
|
+
|
8
10
|
EPOCH_JULIAN_DAY_NUMBER = Date.new(1970,1,1).jd
|
9
11
|
TIME_FORMAT = "%s.%N".freeze
|
10
12
|
|
@@ -16,7 +18,13 @@ module RubySnowflake
|
|
16
18
|
|
17
19
|
# see: https://docs.snowflake.com/en/developer-guide/sql-api/handling-responses#getting-the-data-from-the-results
|
18
20
|
def [](column)
|
19
|
-
index = column.is_a?(Numeric)
|
21
|
+
index = if column.is_a?(Numeric)
|
22
|
+
Integer(column)
|
23
|
+
else
|
24
|
+
# Handle column names case-insensitively regardless of string or symbol
|
25
|
+
@column_to_index[column.to_s.downcase]
|
26
|
+
end
|
27
|
+
|
20
28
|
return nil if index.nil?
|
21
29
|
return nil if @data[index].nil?
|
22
30
|
|
@@ -49,12 +57,24 @@ module RubySnowflake
|
|
49
57
|
end
|
50
58
|
end
|
51
59
|
|
52
|
-
def
|
53
|
-
|
60
|
+
def each
|
61
|
+
return to_enum __method__ unless block_given?
|
62
|
+
|
54
63
|
@column_to_index.each_pair do |name, index|
|
55
|
-
|
64
|
+
yield(name, self[index])
|
56
65
|
end
|
57
|
-
|
66
|
+
|
67
|
+
self
|
68
|
+
end
|
69
|
+
|
70
|
+
def keys
|
71
|
+
map { |k, _| k }
|
72
|
+
end
|
73
|
+
|
74
|
+
alias columns keys
|
75
|
+
|
76
|
+
def values
|
77
|
+
map { |_, v| v }
|
58
78
|
end
|
59
79
|
|
60
80
|
def to_s
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rb_snowflake_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rinsed
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-01
|
11
|
+
date: 2025-05-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bigdecimal
|
@@ -124,6 +124,7 @@ files:
|
|
124
124
|
- ".github/workflows/release-gh-packages.yml"
|
125
125
|
- ".github/workflows/release-rubygems.yml"
|
126
126
|
- ".gitignore"
|
127
|
+
- CHANGELOG.md
|
127
128
|
- CODE_OF_CONDUCT.md
|
128
129
|
- Gemfile
|
129
130
|
- Gemfile.lock
|
@@ -146,7 +147,7 @@ homepage: https://github.com/rinsed-org/rb-snowflake-client
|
|
146
147
|
licenses:
|
147
148
|
- MIT
|
148
149
|
metadata: {}
|
149
|
-
post_install_message:
|
150
|
+
post_install_message:
|
150
151
|
rdoc_options: []
|
151
152
|
require_paths:
|
152
153
|
- lib
|
@@ -161,8 +162,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
161
162
|
- !ruby/object:Gem::Version
|
162
163
|
version: '0'
|
163
164
|
requirements: []
|
164
|
-
rubygems_version: 3.
|
165
|
-
signing_key:
|
165
|
+
rubygems_version: 3.5.22
|
166
|
+
signing_key:
|
166
167
|
specification_version: 4
|
167
168
|
summary: Snowflake connector for Ruby
|
168
169
|
test_files: []
|