sequel-snowflake 2.1.0 → 2.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eba6e3849823d647dca41ee39a327c8c2e832bfc4f45ceb33d184ae06ed834c4
4
- data.tar.gz: b04b7c352deb704dc3b08dda547fd6b52e0cecdb6fe52cc1f2abce3f4c4b8c3a
3
+ metadata.gz: d6b1159aee571c7ffc1ebf32e71fbdc7e572cbd98eafae9c88443b2363dd5754
4
+ data.tar.gz: 8f17176c4dc7405215dac368192083f9ccb6ea8fe15c42128ff696521e8f928e
5
5
  SHA512:
6
- metadata.gz: f682678759afd025e0ca7a7fc87c1dcdf5aaeb4c39b31519453d4064e2a168e43488a8dad341020b189a5dd65b191e22a9df51654f7b3d0b5a869a8b08abf94f
7
- data.tar.gz: 2b83a1c9bbea68cb0ae13497f1bb8b15d7ad767ab8b0a83f26c12b3ec753b70081a1d7c56bc89b78e9da8cbc5812bbb51df5ee09321071ff6698aa2f4b9adeb0
6
+ metadata.gz: 5721cfb399697e66a49c15f1e508a7ef2387822f6101150285e0c0cb8642321a0f74caaaaf9ceb22f7bcc7ecac24d214d9201997524bdbcfd72532defffe6d68
7
+ data.tar.gz: d16d45d262ceedf60d3b95909322c9020bcacebfbc4de0f4a8fbe6bae33233179844f6738c7ac493218379cc8305d68319e608f280bbe93543e90d98974df51f
@@ -14,10 +14,10 @@ jobs:
14
14
 
15
15
  steps:
16
16
  - uses: actions/checkout@v2
17
- - name: Set up Ruby 3.1
17
+ - name: Set up Ruby 3.4
18
18
  uses: ruby/setup-ruby@v1
19
19
  with:
20
- ruby-version: 3.1
20
+ ruby-version: 3.4
21
21
 
22
22
  - name: Publish to RubyGems
23
23
  run: |
@@ -19,16 +19,18 @@ jobs:
19
19
  runs-on: ubuntu-latest
20
20
  strategy:
21
21
  matrix:
22
- ruby-version: ['2.7', '3.0', '3.1']
22
+ ruby-version: ['3.3', '3.4']
23
23
 
24
24
  steps:
25
25
  - uses: actions/checkout@v2
26
- - name: Install unix-odbc
27
- run: sudo apt-get install unixodbc
26
+ - name: Update package lists
27
+ run: sudo apt-get update
28
+ - name: Install unixodbc-dev, odbcinst, and unixodbc
29
+ run: sudo apt-get -y install unixodbc-dev odbcinst unixodbc
28
30
  - name: Install Snowflake ODBC driver
29
31
  run: curl ${SNOWFLAKE_DRIVER_URL} -o snowflake_driver.deb && sudo dpkg -i snowflake_driver.deb
30
32
  env:
31
- SNOWFLAKE_DRIVER_URL: https://sfc-repo.snowflakecomputing.com/odbc/linux/2.25.2/snowflake-odbc-2.25.2.x86_64.deb
33
+ SNOWFLAKE_DRIVER_URL: https://sfc-repo.snowflakecomputing.com/odbc/linux/3.12.0/snowflake-odbc-3.12.0.x86_64.deb
32
34
  - name: Set up Ruby
33
35
  uses: ruby/setup-ruby@v1
34
36
  with:
data/CHANGELOG.md CHANGED
@@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/).
6
6
 
7
+ ## 2.3.0 / 2025-11-17
8
+ * Add support for `GROUP CUBE`
9
+ * Add support for `GROUP ROLLUP`
10
+ * Add support for `GROUPING SETS`
11
+
12
+ ## 2.2.0 / 2023-10-17
13
+ * Add support for `MERGE` (credit: @benalavi)
14
+ * Add requirement for `sequel` v5.58.0 or newer (to support the new MERGE methods).
15
+
7
16
  ## 2.1.0 / 2022-06-17
8
17
  * Add support for `EXPLAIN`.
9
18
 
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  An adapter to connect to Snowflake databases using [Sequel](http://sequel.jeremyevans.net/).
4
4
  This provides proper types for returned values, as opposed to the ODBC adapter.
5
5
 
6
- [![Ruby](https://github.com/Yesware/sequel-snowflake/actions/workflows/ruby.yml/badge.svg)](https://github.com/Yesware/sequel-snowflake/actions/workflows/ruby.yml)
6
+ [![Ruby](https://github.com/vendasta/sequel-snowflake/actions/workflows/ruby.yml/badge.svg)](https://github.com/vendasta/sequel-snowflake/actions/workflows/ruby.yml)
7
7
 
8
8
  ## Installation
9
9
 
@@ -24,6 +24,11 @@ You'll also need [unixODBC](http://www.unixodbc.org/) (if on Linux/macOS) and th
24
24
  this adapter. Follow the Snowflake documentation on their ODBC Driver
25
25
  [here](https://docs.snowflake.com/en/user-guide/odbc.html) before proceeding.
26
26
 
27
+ After installing, you may need to configure `simba.snowflake.ini` and set
28
+ `DriverManagerEncoding` to "UTF-16", the default encoding for unixODBC. If
29
+ unixODBC was built specifically with the `DSQL_WCHART_CONVERT` flag, then
30
+ Snowflake's default of "UTF-32" is fine as-is.
31
+
27
32
  ## Usage
28
33
 
29
34
  When establishing the connection, specify `:snowflake` as the adapter to use.
@@ -57,7 +62,7 @@ be taken down either via the `after(:each)` blocks or when the connection is clo
57
62
 
58
63
  We have two workflows included in this project:
59
64
 
60
- * Ruby (`ruby.yml`): This runs the specs for this gem against Ruby 2.6, 2.7, and 3.0. Note
65
+ * Ruby (`ruby.yml`): This runs the specs for this gem against Ruby 3.3 and 3.4. Note
61
66
  that this requires the secret `SNOWFLAKE_CONN_STR` to be set (see above for example connection string),
62
67
  as we need to connect to Snowflake to run tests. These specs will be run for every pull request,
63
68
  and is run after every commit to those branches.
@@ -68,7 +73,7 @@ to authenticate with RubyGems.
68
73
 
69
74
  ## Contributing
70
75
 
71
- 1. Fork it ( https://github.com/Yesware/sequel-snowflake/fork )
76
+ 1. Fork it ( https://github.com/vendasta/sequel-snowflake/fork )
72
77
  2. Create your feature branch (`git checkout -b my-new-feature`)
73
78
  3. Commit your changes (`git commit -am 'Add some feature'`)
74
79
  4. Push to the branch (`git push origin my-new-feature`)
@@ -38,6 +38,26 @@ module Sequel
38
38
  self
39
39
  end
40
40
 
41
+ # https://docs.snowflake.com/en/sql-reference/constructs/group-by-cube
42
+ def supports_group_cube?
43
+ true
44
+ end
45
+
46
+ # https://docs.snowflake.com/en/sql-reference/constructs/group-by-rollup
47
+ def supports_group_rollup?
48
+ true
49
+ end
50
+
51
+ # https://docs.snowflake.com/en/sql-reference/constructs/group-by-grouping-sets
52
+ def supports_grouping_sets?
53
+ true
54
+ end
55
+
56
+ # https://docs.snowflake.com/en/sql-reference/sql/merge
57
+ def supports_merge?
58
+ true
59
+ end
60
+
41
61
  # This is similar to the ODBC adapter's Dataset#convert_odbc_value, except for some special casing
42
62
  # around Snowflake numerics, which come in through ODBC as Strings instead of Numbers.
43
63
  # In those cases, we need to examine the column type as well as the scale,
@@ -1,6 +1,6 @@
1
1
  module Sequel
2
2
  module Snowflake
3
3
  # sequel-snowflake version
4
- VERSION = "2.1.0"
4
+ VERSION = "2.3.0"
5
5
  end
6
6
  end
data/mise.toml ADDED
@@ -0,0 +1,2 @@
1
+ [tools]
2
+ ruby = "latest"
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
11
11
  spec.license = "MIT"
12
12
  spec.summary = %q{Sequel adapter for Snowflake}
13
13
  spec.description = spec.summary
14
- spec.homepage = "https://github.com/Yesware/sequel-snowflake"
14
+ spec.homepage = "https://github.com/vendasta/sequel-snowflake"
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0")
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
 
22
- spec.add_runtime_dependency 'sequel'
22
+ spec.add_runtime_dependency 'sequel', '>= 5.58.0'
23
23
  spec.add_runtime_dependency 'ruby-odbc'
24
24
 
25
25
  spec.add_development_dependency 'rake'
@@ -1,10 +1,19 @@
1
1
  require 'securerandom'
2
2
 
3
3
  describe Sequel::Snowflake::Dataset do
4
+ let(:db) { @db ||= Sequel.connect(adapter: :snowflake, drvconnect: ENV['SNOWFLAKE_CONN_STR']) }
5
+
6
+ before(:all) do
7
+ @db = Sequel.connect(adapter: :snowflake, drvconnect: ENV['SNOWFLAKE_CONN_STR'])
8
+ end
9
+
10
+ after(:all) do
11
+ @db.disconnect if @db
12
+ end
13
+
4
14
  describe 'Converting Snowflake data types' do
5
15
  # Create a test table with a reasonably-random suffix
6
- let!(:test_table) { "SEQUEL_SNOWFLAKE_SPECS_#{SecureRandom.hex(10)}".to_sym }
7
- let!(:db) { Sequel.connect(adapter: :snowflake, drvconnect: ENV['SNOWFLAKE_CONN_STR']) }
16
+ let(:test_table) { "SEQUEL_SNOWFLAKE_SPECS_#{SecureRandom.hex(10)}".to_sym }
8
17
 
9
18
  before(:each) do
10
19
  # Set timezone for parsing timestamps. This gives us a consistent timezone to test against below.
@@ -69,28 +78,189 @@ describe Sequel::Snowflake::Dataset do
69
78
  end
70
79
  end
71
80
 
72
- describe '#explain' do
73
- # Create a test table with a reasonably-random suffix
74
- let!(:test_table) { "SEQUEL_SNOWFLAKE_SPECS_#{SecureRandom.hex(10)}".to_sym }
75
- let!(:db) { Sequel.connect(adapter: :snowflake, drvconnect: ENV['SNOWFLAKE_CONN_STR']) }
81
+ describe 'GROUP BY features' do
82
+ before(:all) do
83
+ @products = "SEQUEL_SNOWFLAKE_SPECS_#{SecureRandom.hex(10)}".to_sym
84
+ @sales = "SEQUEL_SNOWFLAKE_SPECS_#{SecureRandom.hex(10)}".to_sym
85
+
86
+ @db.create_table(@products, :temp => true) do
87
+ Integer :product_id
88
+ Float :wholesale_price
89
+ end
90
+
91
+ @db.create_table(@sales, :temp => true) do
92
+ Integer :product_id
93
+ Float :retail_price
94
+ Integer :quantity
95
+ String :city
96
+ String :state
97
+ end
98
+
99
+ @db[@products].insert({ product_id: 1, wholesale_price: 1.00 })
100
+ @db[@products].insert({ product_id: 2, wholesale_price: 2.00 })
101
+ @db[@sales].insert({ product_id: 1, retail_price: 2.00, quantity: 1, city: 'SF', state: 'CA' })
102
+ @db[@sales].insert({ product_id: 1, retail_price: 2.00, quantity: 2, city: 'SJ', state: 'CA' })
103
+ @db[@sales].insert({ product_id: 2, retail_price: 5.00, quantity: 4, city: 'SF', state: 'CA' })
104
+ @db[@sales].insert({ product_id: 2, retail_price: 5.00, quantity: 8, city: 'SJ', state: 'CA' })
105
+ @db[@sales].insert({ product_id: 2, retail_price: 5.00, quantity: 16, city: 'Miami', state: 'FL' })
106
+ @db[@sales].insert({ product_id: 2, retail_price: 5.00, quantity: 32, city: 'Orlando', state: 'FL' })
107
+ @db[@sales].insert({ product_id: 2, retail_price: 5.00, quantity: 64, city: 'SJ', state: 'CA' })
108
+ end
109
+
110
+ after(:all) do
111
+ @db.drop_table(@products) if @products
112
+ @db.drop_table(@sales) if @sales
113
+ end
114
+
115
+ let(:products) { @products }
116
+ let(:sales) { @sales }
117
+
118
+ it 'can use GROUP CUBE' do
119
+ res = db.from(Sequel[products].as(:p)).
120
+ join(Sequel[sales].as(:s), Sequel[:p][:product_id] => Sequel[:s][:product_id]).
121
+ select(
122
+ Sequel[:s][:state],
123
+ Sequel[:s][:city],
124
+ Sequel.function(:sum, Sequel.*(Sequel.-(Sequel[:s][:retail_price], Sequel[:p][:wholesale_price]), Sequel[:s][:quantity])).as(:profit)
125
+ ).
126
+ group(Sequel[:s][:state], Sequel[:s][:city]).
127
+ group_cube.
128
+ order(Sequel.asc(Sequel[:s][:state], nulls: :last)).
129
+ order_append(Sequel[:s][:city]).
130
+ all
131
+
132
+ expect(res).to match_array([
133
+ { state: 'CA', city: 'SF', profit: 13 },
134
+ { state: 'CA', city: 'SJ', profit: 218 },
135
+ { state: 'CA', city: nil, profit: 231 },
136
+ { state: 'FL', city: 'Miami', profit: 48 },
137
+ { state: 'FL', city: 'Orlando', profit: 96 },
138
+ { state: 'FL', city: nil, profit: 144 },
139
+ { state: nil, city: 'Miami', profit: 48 },
140
+ { state: nil, city: 'Orlando', profit: 96 },
141
+ { state: nil, city: 'SF', profit: 13 },
142
+ { state: nil, city: 'SJ', profit: 218 },
143
+ { state: nil, city: nil, profit: 375 },
144
+ ])
145
+ end
146
+
147
+ it 'can use GROUP ROLLUP' do
148
+ res = db.from(Sequel[products].as(:p)).
149
+ join(Sequel[sales].as(:s), Sequel[:p][:product_id] => Sequel[:s][:product_id]).
150
+ select(
151
+ Sequel[:s][:state],
152
+ Sequel[:s][:city],
153
+ Sequel.function(:sum, Sequel.*(Sequel.-(Sequel[:s][:retail_price], Sequel[:p][:wholesale_price]), Sequel[:s][:quantity])).as(:profit)
154
+ ).
155
+ group(Sequel[:s][:state], Sequel[:s][:city]).
156
+ group_rollup.
157
+ order(Sequel.asc(Sequel[:s][:state], nulls: :last)).
158
+ order_append(Sequel[:s][:city]).
159
+ all
160
+
161
+ expect(res).to match_array([
162
+ { state: 'CA', city: 'SF', profit: 13 },
163
+ { state: 'CA', city: 'SJ', profit: 218 },
164
+ { state: 'CA', city: nil, profit: 231 },
165
+ { state: 'FL', city: 'Miami', profit: 48 },
166
+ { state: 'FL', city: 'Orlando', profit: 96 },
167
+ { state: 'FL', city: nil, profit: 144 },
168
+ { state: nil, city: nil, profit: 375 },
169
+ ])
170
+ end
171
+
172
+ it 'can use GROUPING SETS' do
173
+ res = db.from(Sequel[products].as(:p)).
174
+ join(Sequel[sales].as(:s), Sequel[:p][:product_id] => Sequel[:s][:product_id]).
175
+ select(
176
+ Sequel[:s][:state],
177
+ Sequel[:s][:city],
178
+ Sequel.function(:sum, Sequel.*(Sequel.-(Sequel[:s][:retail_price], Sequel[:p][:wholesale_price]), Sequel[:s][:quantity])).as(:profit)
179
+ ).
180
+ group([Sequel[:s][:state]], [Sequel[:s][:city]]).
181
+ grouping_sets.
182
+ order(Sequel.asc(Sequel[:s][:state], nulls: :last)).
183
+ order_append(Sequel[:s][:city]).
184
+ all
185
+
186
+ expect(res).to match_array([
187
+ { state: 'CA', city: nil, profit: 231 },
188
+ { state: 'FL', city: nil, profit: 144 },
189
+ { state: nil, city: 'Miami', profit: 48 },
190
+ { state: nil, city: 'Orlando', profit: 96 },
191
+ { state: nil, city: 'SF', profit: 13 },
192
+ { state: nil, city: 'SJ', profit: 218 },
193
+ ])
194
+ end
195
+ end
196
+
197
+ describe 'MERGE feature' do
198
+ before(:all) do
199
+ @target_table = "SEQUEL_SNOWFLAKE_SPECS_#{SecureRandom.hex(10)}".to_sym
200
+ @source_table = "SEQUEL_SNOWFLAKE_SPECS_#{SecureRandom.hex(10)}".to_sym
201
+
202
+ @db.create_table(@target_table, :temp => true) do
203
+ String :str
204
+ String :str2
205
+ String :str3
206
+ end
207
+
208
+ @db.create_table(@source_table, :temp => true) do
209
+ String :from
210
+ String :to
211
+ String :whomst
212
+ end
213
+ end
214
+
215
+ after(:all) do
216
+ @db.drop_table(@target_table) if @target_table
217
+ @db.drop_table(@source_table) if @source_table
218
+ end
76
219
 
77
220
  before(:each) do
78
- db.create_table(test_table, :temp => true) do
221
+ # Clear and repopulate data for each test since MERGE modifies data
222
+ db[@target_table].delete
223
+ db[@source_table].delete
224
+ db[@target_table].insert({ str: 'foo', str2: 'foo', str3: 'phoo' })
225
+ db[@target_table].insert({ str: 'baz', str2: 'foo', str3: 'buzz' })
226
+ db[@source_table].insert({ from: 'foo', to: 'bar', whomst: 'me' })
227
+ end
228
+
229
+ let(:target_table) { @target_table }
230
+ let(:source_table) { @source_table }
231
+
232
+ it 'can use MERGE' do
233
+ db[target_table].merge_using(source_table, str: :from).merge_update(str2: :to).merge
234
+
235
+ expect(db[target_table].select_all.all).to match_array([
236
+ { str: 'foo', str2: 'bar', str3: 'phoo' },
237
+ { str: 'baz', str2: 'foo', str3: 'buzz' }
238
+ ])
239
+ end
240
+ end
241
+
242
+ describe '#explain' do
243
+ before(:all) do
244
+ @test_table = "SEQUEL_SNOWFLAKE_SPECS_#{SecureRandom.hex(10)}".to_sym
245
+
246
+ @db.create_table(@test_table, :temp => true) do
79
247
  Numeric :id
80
248
  String :name
81
249
  String :email
82
250
  String :title
83
251
  end
84
252
 
85
- db[test_table].insert(
253
+ @db[@test_table].insert(
86
254
  { id: 1, name: 'John Null', email: 'j.null@example.com', title: 'Software Tester' }
87
255
  )
88
256
  end
89
257
 
90
- after(:each) do
91
- db.drop_table(test_table)
258
+ after(:all) do
259
+ @db.drop_table(@test_table) if @test_table
92
260
  end
93
261
 
262
+ let(:test_table) { @test_table }
263
+
94
264
  it "should have explain output" do
95
265
  query = db.fetch("SELECT * FROM #{test_table} WHERE ID=1;")
96
266
 
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel-snowflake
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yesware, Inc
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2022-06-17 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: sequel
@@ -16,14 +15,14 @@ dependencies:
16
15
  requirements:
17
16
  - - ">="
18
17
  - !ruby/object:Gem::Version
19
- version: '0'
18
+ version: 5.58.0
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - ">="
25
24
  - !ruby/object:Gem::Version
26
- version: '0'
25
+ version: 5.58.0
27
26
  - !ruby/object:Gem::Dependency
28
27
  name: ruby-odbc
29
28
  requirement: !ruby/object:Gem::Requirement
@@ -100,15 +99,15 @@ files:
100
99
  - lib/sequel-snowflake/version.rb
101
100
  - lib/sequel/adapters/shared/snowflake.rb
102
101
  - lib/sequel/adapters/snowflake.rb
102
+ - mise.toml
103
103
  - sequel-snowflake.gemspec
104
104
  - spec/sequel/adapters/snowflake_spec.rb
105
105
  - spec/snowflake_spec.rb
106
106
  - spec/spec_helper.rb
107
- homepage: https://github.com/Yesware/sequel-snowflake
107
+ homepage: https://github.com/vendasta/sequel-snowflake
108
108
  licenses:
109
109
  - MIT
110
110
  metadata: {}
111
- post_install_message:
112
111
  rdoc_options: []
113
112
  require_paths:
114
113
  - lib
@@ -123,8 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
122
  - !ruby/object:Gem::Version
124
123
  version: '0'
125
124
  requirements: []
126
- rubygems_version: 3.3.7
127
- signing_key:
125
+ rubygems_version: 3.6.9
128
126
  specification_version: 4
129
127
  summary: Sequel adapter for Snowflake
130
128
  test_files: