sequel-snowflake 2.2.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: 772b801f7ed529ccadccd14d02fad21713a6e62d1d23a6b531647a4a876d5238
4
- data.tar.gz: 9b92e7bceb1899f346d117299e733b4773bf65b3b17140968b286ac262026a1e
3
+ metadata.gz: d6b1159aee571c7ffc1ebf32e71fbdc7e572cbd98eafae9c88443b2363dd5754
4
+ data.tar.gz: 8f17176c4dc7405215dac368192083f9ccb6ea8fe15c42128ff696521e8f928e
5
5
  SHA512:
6
- metadata.gz: bd4c7cdf415e197569747c1181056312b3f4389049b3de254ebd407c1e8d882e3cac9f6fe7a5351e6e1330d57abb89e2805fac4a51112049863af189660e7025
7
- data.tar.gz: 9d21e394346317988787eadf729d14a0a7caab19fddf639b9b1c9e9227766025c246e15f55b5e44ea9f4b34cc49eac387696ca3835d327a7e69ba34f34e539fa
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,7 +19,7 @@ jobs:
19
19
  runs-on: ubuntu-latest
20
20
  strategy:
21
21
  matrix:
22
- ruby-version: ['3.0', '3.1']
22
+ ruby-version: ['3.3', '3.4']
23
23
 
24
24
  steps:
25
25
  - uses: actions/checkout@v2
@@ -30,7 +30,7 @@ jobs:
30
30
  - name: Install Snowflake ODBC driver
31
31
  run: curl ${SNOWFLAKE_DRIVER_URL} -o snowflake_driver.deb && sudo dpkg -i snowflake_driver.deb
32
32
  env:
33
- SNOWFLAKE_DRIVER_URL: https://sfc-repo.snowflakecomputing.com/odbc/linux/3.1.1/snowflake-odbc-3.1.1.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
34
34
  - name: Set up Ruby
35
35
  uses: ruby/setup-ruby@v1
36
36
  with:
data/CHANGELOG.md CHANGED
@@ -4,6 +4,11 @@ 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
+
7
12
  ## 2.2.0 / 2023-10-17
8
13
  * Add support for `MERGE` (credit: @benalavi)
9
14
  * Add requirement for `sequel` v5.58.0 or newer (to support the new MERGE methods).
data/README.md CHANGED
@@ -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 3.0 and 3.1. 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.
@@ -38,9 +38,22 @@ module Sequel
38
38
  self
39
39
  end
40
40
 
41
- # Whether the MERGE statement is supported:
42
- # https://github.com/jeremyevans/sequel/blob/master/lib/sequel/dataset/features.rb#L129
43
- # Snowflake reference: https://docs.snowflake.com/en/sql-reference/sql/merge
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
44
57
  def supports_merge?
45
58
  true
46
59
  end
@@ -1,6 +1,6 @@
1
1
  module Sequel
2
2
  module Snowflake
3
3
  # sequel-snowflake version
4
- VERSION = "2.2.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"
@@ -1,7 +1,15 @@
1
1
  require 'securerandom'
2
2
 
3
3
  describe Sequel::Snowflake::Dataset do
4
- let(:db) { Sequel.connect(adapter: :snowflake, drvconnect: ENV['SNOWFLAKE_CONN_STR']) }
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
5
13
 
6
14
  describe 'Converting Snowflake data types' do
7
15
  # Create a test table with a reasonably-random suffix
@@ -70,33 +78,157 @@ describe Sequel::Snowflake::Dataset do
70
78
  end
71
79
  end
72
80
 
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
+
73
197
  describe 'MERGE feature' do
74
- let(:target_table) { "SEQUEL_SNOWFLAKE_SPECS_#{SecureRandom.hex(10)}".to_sym }
75
- let(:source_table) { "SEQUEL_SNOWFLAKE_SPECS_#{SecureRandom.hex(10)}".to_sym }
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
76
201
 
77
- before(:each) do
78
- db.create_table(target_table, :temp => true) do
202
+ @db.create_table(@target_table, :temp => true) do
79
203
  String :str
80
204
  String :str2
81
205
  String :str3
82
206
  end
83
207
 
84
- db.create_table(source_table, :temp => true) do
208
+ @db.create_table(@source_table, :temp => true) do
85
209
  String :from
86
210
  String :to
87
211
  String :whomst
88
212
  end
213
+ end
89
214
 
90
- db[target_table].insert({ str: 'foo', str2: 'foo', str3: 'phoo' })
91
- db[target_table].insert({ str: 'baz', str2: 'foo', str3: 'buzz' })
92
- db[source_table].insert({ from: 'foo', to: 'bar', whomst: 'me' })
215
+ after(:all) do
216
+ @db.drop_table(@target_table) if @target_table
217
+ @db.drop_table(@source_table) if @source_table
93
218
  end
94
219
 
95
- after(:each) do
96
- db.drop_table(target_table)
97
- db.drop_table(source_table)
220
+ before(:each) 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' })
98
227
  end
99
228
 
229
+ let(:target_table) { @target_table }
230
+ let(:source_table) { @source_table }
231
+
100
232
  it 'can use MERGE' do
101
233
  db[target_table].merge_using(source_table, str: :from).merge_update(str2: :to).merge
102
234
 
@@ -108,26 +240,27 @@ describe Sequel::Snowflake::Dataset do
108
240
  end
109
241
 
110
242
  describe '#explain' do
111
- # Create a test table with a reasonably-random suffix
112
- let(:test_table) { "SEQUEL_SNOWFLAKE_SPECS_#{SecureRandom.hex(10)}".to_sym }
243
+ before(:all) do
244
+ @test_table = "SEQUEL_SNOWFLAKE_SPECS_#{SecureRandom.hex(10)}".to_sym
113
245
 
114
- before(:each) do
115
- db.create_table(test_table, :temp => true) do
246
+ @db.create_table(@test_table, :temp => true) do
116
247
  Numeric :id
117
248
  String :name
118
249
  String :email
119
250
  String :title
120
251
  end
121
252
 
122
- db[test_table].insert(
253
+ @db[@test_table].insert(
123
254
  { id: 1, name: 'John Null', email: 'j.null@example.com', title: 'Software Tester' }
124
255
  )
125
256
  end
126
257
 
127
- after(:each) do
128
- db.drop_table(test_table)
258
+ after(:all) do
259
+ @db.drop_table(@test_table) if @test_table
129
260
  end
130
261
 
262
+ let(:test_table) { @test_table }
263
+
131
264
  it "should have explain output" do
132
265
  query = db.fetch("SELECT * FROM #{test_table} WHERE ID=1;")
133
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.2.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: 2023-10-19 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
@@ -100,6 +99,7 @@ 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
@@ -108,7 +108,6 @@ 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.26
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: