sequel-hexspace 1.0.0 → 2.0.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/CHANGELOG.md +37 -0
- data/LICENSE +1 -0
- data/lib/sequel/adapters/hexspace.rb +81 -3
- data/lib/sequel/adapters/shared/hexspace.rb +25 -0
- data/lib/sequel/adapters/shared/spark.rb +62 -4
- metadata +45 -11
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b4421ed6430cdfa0ede39d8b4956c01de6e65317af4c9ab72238e06aa98d0e18
|
|
4
|
+
data.tar.gz: b01b91610baad3b154d7a44c193ad29e88fc940de34473158e60521af958161e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bfb4bbe3fddb1be528f0cdd382e78dfcf651edd36de086248742cc4d31d23dfa293b4619ba70acf6066681fe58cb6b0661373badd187c80fd8df54935513e3cd
|
|
7
|
+
data.tar.gz: 5a979505d337170a4d41bf96e135118284b34461a21611167856d0e95b79b63bf11eb71f4adae733c7ea579347d40091fba7ab038bc1efa5d10ccdf701801f5e
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 2.0.0 (unreleased)
|
|
4
|
+
|
|
5
|
+
### Breaking
|
|
6
|
+
|
|
7
|
+
- Declare `required_ruby_version >= 3.3`. Ruby 3.2 reached end of life in March
|
|
8
|
+
2026 and is no longer tested. Installing on an older Ruby now fails with a
|
|
9
|
+
clear message rather than breaking at runtime. This is the only breaking
|
|
10
|
+
change, and it is what makes this release a major one.
|
|
11
|
+
|
|
12
|
+
### Note on the gap since 1.0.0
|
|
13
|
+
|
|
14
|
+
1.0.0 (April 2024) is the only version ever published; 1.0.1 was tagged in the
|
|
15
|
+
repository but never released. Everything below has therefore been unavailable
|
|
16
|
+
to users until now, and this is the first release to carry any of it. The list is
|
|
17
|
+
reconstructed from git history.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- Shared Hexspace mock adapter support, so dependent projects can test without a
|
|
22
|
+
live Spark server.
|
|
23
|
+
- `EXTERNAL`, `LOCATION` and `LIKE` support in `CREATE TABLE`.
|
|
24
|
+
- Always-on SimpleCov coverage and RuboCop enforcement in the development setup.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- Support thrift 0.24 by restoring `Thrift::Client#handle_exception` and
|
|
29
|
+
`#reply_seqid`, which 0.24.0 removed while hexspace's generated client still
|
|
30
|
+
calls them. Without this every Spark connection failed with a
|
|
31
|
+
`Sequel::DatabaseConnectionError`. thrift is constrained to `>= 0.18, < 0.25`.
|
|
32
|
+
- Silence a frozen-string-literal warning from thrift 0.22.0 on Ruby 3.4+.
|
|
33
|
+
- `Database#database_type` returns `:spark` rather than `:hexspace`.
|
|
34
|
+
- Ignore `CASCADE` in `drop_table_sql`, which Spark SQL does not accept.
|
|
35
|
+
- Route prepared `DELETE` statements through the emulated delete path.
|
|
36
|
+
- Date and timestamp casting and literalisation, including Ruby 4.0
|
|
37
|
+
compatibility.
|
data/LICENSE
CHANGED
|
@@ -1,10 +1,77 @@
|
|
|
1
|
+
require_relative 'shared/hexspace'
|
|
1
2
|
require 'hexspace'
|
|
2
|
-
|
|
3
|
+
|
|
4
|
+
# Backport upstream fix (THRIFT-5909, PR #3270) for thrift 0.22.0 on Ruby 3.4+.
|
|
5
|
+
# Thrift::Bytes.empty_byte_buffer calls force_encoding on string literals,
|
|
6
|
+
# which triggers "literal string will be frozen in the future" warnings.
|
|
7
|
+
# Remove this once thrift > 0.22.0 is released with the fix.
|
|
8
|
+
if defined?(Thrift::Bytes) && (spec = Gem.loaded_specs['thrift']) && spec.version < Gem::Version.new('0.23')
|
|
9
|
+
module Thrift
|
|
10
|
+
module Bytes
|
|
11
|
+
def self.empty_byte_buffer(size=nil)
|
|
12
|
+
if size&.positive?
|
|
13
|
+
"\0".b * size
|
|
14
|
+
else
|
|
15
|
+
''.b
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Restore Thrift::Client#handle_exception and #reply_seqid for thrift >= 0.24.
|
|
23
|
+
#
|
|
24
|
+
# hexspace's generated Thrift client (lib/hexspace/tcli_service.rb) calls both,
|
|
25
|
+
# 21 times each. thrift 0.24.0 removed them, folding their work into the new
|
|
26
|
+
# #validate_message_begin -- so on thrift 0.24 every Spark connection dies in
|
|
27
|
+
# recv_OpenSession with NoMethodError, surfacing as
|
|
28
|
+
# Sequel::DatabaseConnectionError.
|
|
29
|
+
#
|
|
30
|
+
# Upstream will not fix this for us: hexspace's generated client is untouched
|
|
31
|
+
# since 2023-05-08, the latest release (0.3.0, Apr 2025) predates thrift 0.24,
|
|
32
|
+
# and no issue or PR there mentions thrift. Regenerating that client against
|
|
33
|
+
# 0.24 would drop support for thrift < 0.24, which is a maintainer's decision
|
|
34
|
+
# rather than ours to force.
|
|
35
|
+
#
|
|
36
|
+
# Both methods are restored verbatim from thrift 0.23.0 and are implemented
|
|
37
|
+
# purely in terms of primitives thrift 0.24 still provides and still uses in
|
|
38
|
+
# validate_message_begin. The dequeue accounting is unchanged: exactly one
|
|
39
|
+
# dequeue_pending_seqid per call on both the reply and the exception path.
|
|
40
|
+
#
|
|
41
|
+
# Note this keeps 0.23 semantics -- it does NOT add 0.24's stricter checks for
|
|
42
|
+
# invalid message type and wrong method name. Remove once hexspace regenerates
|
|
43
|
+
# its client against thrift >= 0.24.
|
|
44
|
+
# rubocop:disable-next Style/GuardClause, Naming/PredicateMethod
|
|
45
|
+
if defined?(Thrift::Client)
|
|
46
|
+
# Both methods below are copied verbatim from thrift 0.23.0 and deliberately
|
|
47
|
+
# not restyled: keeping them byte-comparable with upstream is what makes them
|
|
48
|
+
# auditable. reply_seqid also cannot be renamed to a predicate -- hexspace's
|
|
49
|
+
# generated client calls it by that exact name.
|
|
50
|
+
module Thrift
|
|
51
|
+
module Client
|
|
52
|
+
unless method_defined?(:handle_exception) || private_method_defined?(:handle_exception)
|
|
53
|
+
def handle_exception(mtype)
|
|
54
|
+
if mtype == MessageTypes::EXCEPTION
|
|
55
|
+
dequeue_pending_seqid
|
|
56
|
+
raise_application_exception
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
unless method_defined?(:reply_seqid) || private_method_defined?(:reply_seqid)
|
|
62
|
+
def reply_seqid(rseqid)
|
|
63
|
+
expected_seqid = dequeue_pending_seqid
|
|
64
|
+
!expected_seqid.nil? && rseqid == expected_seqid
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
3
70
|
|
|
4
71
|
module Sequel
|
|
5
72
|
module Hexspace
|
|
6
73
|
class Database < Sequel::Database
|
|
7
|
-
include
|
|
74
|
+
include DatabaseMethods
|
|
8
75
|
|
|
9
76
|
set_adapter_scheme :hexspace
|
|
10
77
|
|
|
@@ -27,6 +94,17 @@ module Sequel
|
|
|
27
94
|
conn.instance_variable_set(:@sequel_invalid, true)
|
|
28
95
|
end
|
|
29
96
|
|
|
97
|
+
# Hexspace returns timestamp strings in UTC without an explicit offset.
|
|
98
|
+
# When no database timezone is configured, Sequel treats naive strings as
|
|
99
|
+
# local time, which shifts CURRENT_TIMESTAMP by the local UTC offset.
|
|
100
|
+
def to_application_timestamp(value)
|
|
101
|
+
if value.is_a?(String) && timezone.nil? && value !~ /(?:Z|[+-]\d{2}(?::?\d{2})?)\z/
|
|
102
|
+
Sequel.convert_timestamp(value, :utc)
|
|
103
|
+
else
|
|
104
|
+
super
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
30
108
|
def execute(sql, opts=OPTS)
|
|
31
109
|
synchronize(opts[:server]) do |conn|
|
|
32
110
|
res = log_connection_yield(sql, conn){conn.execute(sql, result_object: true)}
|
|
@@ -51,7 +129,7 @@ module Sequel
|
|
|
51
129
|
end
|
|
52
130
|
|
|
53
131
|
class Dataset < Sequel::Dataset
|
|
54
|
-
include
|
|
132
|
+
include DatasetMethods
|
|
55
133
|
|
|
56
134
|
def fetch_rows(sql)
|
|
57
135
|
execute(sql) do |result|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'spark'
|
|
4
|
+
|
|
5
|
+
module Sequel
|
|
6
|
+
|
|
7
|
+
module Hexspace
|
|
8
|
+
|
|
9
|
+
module DatabaseMethods
|
|
10
|
+
|
|
11
|
+
include Sequel::Spark::DatabaseMethods
|
|
12
|
+
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module DatasetMethods
|
|
16
|
+
|
|
17
|
+
include Sequel::Spark::DatasetMethods
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
Sequel::Database.set_shared_adapter_scheme(:hexspace, Sequel::Hexspace)
|
|
24
|
+
|
|
25
|
+
end
|
|
@@ -28,7 +28,7 @@ module Sequel
|
|
|
28
28
|
# ignoring the primary key setting.
|
|
29
29
|
{:type=>Integer}
|
|
30
30
|
end
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
def supports_create_table_if_not_exists?
|
|
33
33
|
true
|
|
34
34
|
end
|
|
@@ -116,8 +116,23 @@ module Sequel
|
|
|
116
116
|
sql
|
|
117
117
|
end
|
|
118
118
|
|
|
119
|
+
def create_table_prefix_sql(name, options)
|
|
120
|
+
sql = String.new
|
|
121
|
+
sql << 'CREATE '
|
|
122
|
+
sql << 'EXTERNAL ' if options[:external]
|
|
123
|
+
sql << 'TEMPORARY ' if options[:temp]
|
|
124
|
+
sql << 'TABLE '
|
|
125
|
+
sql << 'IF NOT EXISTS ' if options[:if_not_exists]
|
|
126
|
+
sql << quote_schema_table(name)
|
|
127
|
+
sql
|
|
128
|
+
end
|
|
129
|
+
|
|
119
130
|
def create_table_sql(name, generator, options)
|
|
120
|
-
|
|
131
|
+
if options[:like] || (options[:using] && generator.columns.empty?)
|
|
132
|
+
_append_table_view_options_sql(create_table_prefix_sql(name, options), options)
|
|
133
|
+
else
|
|
134
|
+
_append_table_view_options_sql(super, options)
|
|
135
|
+
end
|
|
121
136
|
end
|
|
122
137
|
|
|
123
138
|
def create_table_as_sql(name, sql, options)
|
|
@@ -142,10 +157,18 @@ module Sequel
|
|
|
142
157
|
end
|
|
143
158
|
|
|
144
159
|
def _append_table_view_options_sql(sql, options)
|
|
160
|
+
if like = options[:like]
|
|
161
|
+
sql << " LIKE " << literal(like)
|
|
162
|
+
end
|
|
163
|
+
|
|
145
164
|
if options[:using]
|
|
146
165
|
sql << " USING " << options[:using].to_s
|
|
147
166
|
end
|
|
148
167
|
|
|
168
|
+
if location = options[:location]
|
|
169
|
+
sql << " LOCATION " << literal(location)
|
|
170
|
+
end
|
|
171
|
+
|
|
149
172
|
if options[:partitioned_by]
|
|
150
173
|
sql << " PARTITIONED BY "
|
|
151
174
|
_append_column_list_sql(sql, options[:partitioned_by])
|
|
@@ -175,7 +198,7 @@ module Sequel
|
|
|
175
198
|
end
|
|
176
199
|
|
|
177
200
|
def _append_column_list_sql(sql, columns)
|
|
178
|
-
sql << '('
|
|
201
|
+
sql << '('
|
|
179
202
|
schema_utility_dataset.send(:identifier_list_append, sql, Array(columns))
|
|
180
203
|
sql << ')'
|
|
181
204
|
end
|
|
@@ -189,6 +212,12 @@ module Sequel
|
|
|
189
212
|
sql
|
|
190
213
|
end
|
|
191
214
|
|
|
215
|
+
# Spark SQL does not support CASCADE on DROP TABLE.
|
|
216
|
+
# Support :purge option, ignore :cascade.
|
|
217
|
+
def drop_table_sql(name, options)
|
|
218
|
+
"DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_schema_table(name)}#{' PURGE' if options[:purge]}"
|
|
219
|
+
end
|
|
220
|
+
|
|
192
221
|
def schema_parse_table(table, opts)
|
|
193
222
|
m = output_identifier_meth(opts[:dataset])
|
|
194
223
|
im = input_identifier_meth(opts[:dataset])
|
|
@@ -243,6 +272,17 @@ module Sequel
|
|
|
243
272
|
literal_append(sql, expr)
|
|
244
273
|
end
|
|
245
274
|
|
|
275
|
+
# Route prepared statement / bound variable deletes through the
|
|
276
|
+
# emulated delete path, since Spark does not support native DELETE.
|
|
277
|
+
def call(type, bind_variables=OPTS, *values, &)
|
|
278
|
+
if type == :delete
|
|
279
|
+
ps = to_prepared_statement(type, values, :extend=>send(:bound_variable_modules))
|
|
280
|
+
ps.bind(bind_variables).delete
|
|
281
|
+
else
|
|
282
|
+
super
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
246
286
|
# Emulate delete by selecting all rows except the ones being deleted
|
|
247
287
|
# into a new table, drop the current table, and rename the new
|
|
248
288
|
# table to the current table name.
|
|
@@ -310,7 +350,7 @@ module Sequel
|
|
|
310
350
|
true
|
|
311
351
|
end
|
|
312
352
|
|
|
313
|
-
def insert_supports_empty_values?
|
|
353
|
+
def insert_supports_empty_values?
|
|
314
354
|
false
|
|
315
355
|
end
|
|
316
356
|
|
|
@@ -318,6 +358,24 @@ module Sequel
|
|
|
318
358
|
sql << "to_binary('" << [v].pack("m*").gsub("\n", "") << "', 'base64')"
|
|
319
359
|
end
|
|
320
360
|
|
|
361
|
+
# Spark requires DATE 'YYYY-MM-DD' syntax instead of plain quoted strings
|
|
362
|
+
def literal_date_append(sql, v)
|
|
363
|
+
sql << "DATE "
|
|
364
|
+
super
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
# Spark requires TIMESTAMP 'YYYY-MM-DD HH:MM:SS' syntax instead of plain quoted strings
|
|
368
|
+
def literal_time_append(sql, v)
|
|
369
|
+
sql << "TIMESTAMP "
|
|
370
|
+
super
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
# Spark requires TIMESTAMP 'YYYY-MM-DD HH:MM:SS' syntax instead of plain quoted strings
|
|
374
|
+
def literal_datetime_append(sql, v)
|
|
375
|
+
sql << "TIMESTAMP "
|
|
376
|
+
super
|
|
377
|
+
end
|
|
378
|
+
|
|
321
379
|
def literal_false
|
|
322
380
|
"false"
|
|
323
381
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sequel-hexspace
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jeremy Evans
|
|
8
|
-
|
|
8
|
+
- Ryan Duryea
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: sequel
|
|
@@ -38,6 +38,26 @@ dependencies:
|
|
|
38
38
|
- - ">="
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: 0.2.1
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: thrift
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0.18'
|
|
48
|
+
- - "<"
|
|
49
|
+
- !ruby/object:Gem::Version
|
|
50
|
+
version: '0.25'
|
|
51
|
+
type: :runtime
|
|
52
|
+
prerelease: false
|
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
54
|
+
requirements:
|
|
55
|
+
- - ">="
|
|
56
|
+
- !ruby/object:Gem::Version
|
|
57
|
+
version: '0.18'
|
|
58
|
+
- - "<"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0.25'
|
|
41
61
|
- !ruby/object:Gem::Dependency
|
|
42
62
|
name: rake
|
|
43
63
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -58,14 +78,14 @@ dependencies:
|
|
|
58
78
|
requirements:
|
|
59
79
|
- - "~>"
|
|
60
80
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '
|
|
81
|
+
version: '6.0'
|
|
62
82
|
type: :development
|
|
63
83
|
prerelease: false
|
|
64
84
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
85
|
requirements:
|
|
66
86
|
- - "~>"
|
|
67
87
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '
|
|
88
|
+
version: '6.0'
|
|
69
89
|
- !ruby/object:Gem::Dependency
|
|
70
90
|
name: minitest-hooks
|
|
71
91
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -94,25 +114,40 @@ dependencies:
|
|
|
94
114
|
- - ">="
|
|
95
115
|
- !ruby/object:Gem::Version
|
|
96
116
|
version: '0'
|
|
117
|
+
- !ruby/object:Gem::Dependency
|
|
118
|
+
name: simplecov
|
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - "~>"
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: '1.0'
|
|
124
|
+
type: :development
|
|
125
|
+
prerelease: false
|
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
127
|
+
requirements:
|
|
128
|
+
- - "~>"
|
|
129
|
+
- !ruby/object:Gem::Version
|
|
130
|
+
version: '1.0'
|
|
97
131
|
description: |
|
|
98
132
|
This is a hexspace adapter for Sequel, designed to be used with Spark (not
|
|
99
133
|
Hive). You can use the hexspace:// protocol in the Sequel connection URL
|
|
100
134
|
to use this adapter.
|
|
101
|
-
email:
|
|
135
|
+
email: aguynamedryan@gmail.com
|
|
102
136
|
executables: []
|
|
103
137
|
extensions: []
|
|
104
138
|
extra_rdoc_files:
|
|
105
139
|
- LICENSE
|
|
106
140
|
files:
|
|
141
|
+
- CHANGELOG.md
|
|
107
142
|
- LICENSE
|
|
108
143
|
- README
|
|
109
144
|
- lib/sequel/adapters/hexspace.rb
|
|
145
|
+
- lib/sequel/adapters/shared/hexspace.rb
|
|
110
146
|
- lib/sequel/adapters/shared/spark.rb
|
|
111
|
-
homepage: https://github.com/
|
|
147
|
+
homepage: https://github.com/outcomesinsights/sequel-hexspace
|
|
112
148
|
licenses:
|
|
113
149
|
- MIT
|
|
114
150
|
metadata: {}
|
|
115
|
-
post_install_message:
|
|
116
151
|
rdoc_options:
|
|
117
152
|
- "--quiet"
|
|
118
153
|
- "--line-numbers"
|
|
@@ -127,15 +162,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
127
162
|
requirements:
|
|
128
163
|
- - ">="
|
|
129
164
|
- !ruby/object:Gem::Version
|
|
130
|
-
version: '
|
|
165
|
+
version: '3.3'
|
|
131
166
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
132
167
|
requirements:
|
|
133
168
|
- - ">="
|
|
134
169
|
- !ruby/object:Gem::Version
|
|
135
170
|
version: '0'
|
|
136
171
|
requirements: []
|
|
137
|
-
rubygems_version:
|
|
138
|
-
signing_key:
|
|
172
|
+
rubygems_version: 4.0.20
|
|
139
173
|
specification_version: 4
|
|
140
174
|
summary: Sequel adapter for hexspace driver and Apache Spark database
|
|
141
175
|
test_files: []
|