altertable-lakehouse 0.8.1 → 0.9.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/.release-please-manifest.json +1 -1
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +24 -0
- data/Gemfile.lock +1 -1
- data/README.md +2 -1
- data/altertable-lakehouse.gemspec +1 -1
- data/lib/altertable/lakehouse/adapters.rb +6 -6
- data/lib/altertable/lakehouse/client.rb +34 -16
- data/lib/altertable/lakehouse/version.rb +1 -1
- data/rbi/altertable/lakehouse.rbi +10 -2
- data/sig/altertable/lakehouse/client.rbs +18 -2
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 79141f78a6f427133d3eade8a3e78d697d7526eab2d767fbafa7d29d3d2954fb
|
|
4
|
+
data.tar.gz: 1fae0c3ce116fe23afbb8611ee272999273cd7fa5f4687cc9a4fdd32a14605f4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e2d5f5564023af9db4070e39af8b23f113ac8cf5b4dda09e4443e4a5cd343cefb3c26e30d5754e5576ccf72dace589a4bd412992e0b2499922f46b443ae54fd8
|
|
7
|
+
data.tar.gz: '0877c8558d85087f5678b1df8c48646b7f68684f331e649c8bd4b7d6c8b5a72657656d9e57d6eeef41c98b4e2d4d937c38953ed29f999ef2e9bf393e57f82d87'
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,30 @@ All notable changes to this project will be documented in this file.
|
|
|
7
7
|
### Added
|
|
8
8
|
|
|
9
9
|
* Support named and positional bind values through `QueryRequest#params`.
|
|
10
|
+
* `ColumnDescriptor` value objects (`Data`) for query columns, with `name` and `type` readers.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
* Require Ruby 3.2 or newer (`ColumnDescriptor` is a `Data` class). CI already only tested 3.2+.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
* `QueryResult#columns` and `query_all[:columns]` return typed column descriptors again instead of bare names; rows stay keyed by column name.
|
|
19
|
+
* A malformed `/query` column line (anything other than an array of `{ "name", "type" }` string objects) now raises `ParseError` instead of passing through untyped.
|
|
20
|
+
|
|
21
|
+
## [0.9.0](https://github.com/altertable-ai/altertable-lakehouse-ruby/compare/altertable-lakehouse/v0.8.2...altertable-lakehouse/v0.9.0) (2026-10-12)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### Miscellaneous Chores
|
|
25
|
+
|
|
26
|
+
* release 0.9.0 ([#58](https://github.com/altertable-ai/altertable-lakehouse-ruby/issues/58)) ([55fff71](https://github.com/altertable-ai/altertable-lakehouse-ruby/commit/55fff719c9e988d07cedd1a820752001aa4b53ea))
|
|
27
|
+
|
|
28
|
+
## [0.8.2](https://github.com/altertable-ai/altertable-lakehouse-ruby/compare/altertable-lakehouse/v0.8.1...altertable-lakehouse/v0.8.2) (2026-10-12)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
### Bug Fixes
|
|
32
|
+
|
|
33
|
+
* **query:** restore typed column descriptors ([a16ea67](https://github.com/altertable-ai/altertable-lakehouse-ruby/commit/a16ea679f581bcedf665f1f7b487601b34f66432))
|
|
10
34
|
|
|
11
35
|
## [0.8.1](https://github.com/altertable-ai/altertable-lakehouse-ruby/compare/altertable-lakehouse/v0.8.0...altertable-lakehouse/v0.8.1) (2026-10-07)
|
|
12
36
|
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -124,7 +124,8 @@ result = client.query_all(
|
|
|
124
124
|
)
|
|
125
125
|
|
|
126
126
|
puts result[:metadata] # Hash
|
|
127
|
-
puts result[:columns] # Array of
|
|
127
|
+
puts result[:columns] # Array of ColumnDescriptor (#name, #type)
|
|
128
|
+
puts result[:columns].first.type # e.g. "INTEGER"
|
|
128
129
|
result[:rows].each do |row|
|
|
129
130
|
puts row
|
|
130
131
|
end
|
|
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
|
|
|
12
12
|
spec.description = "Official Ruby client for Altertable Lakehouse API."
|
|
13
13
|
spec.homepage = "https://github.com/altertable-ai/altertable-lakehouse-ruby"
|
|
14
14
|
spec.license = "MIT"
|
|
15
|
-
spec.required_ruby_version = ">= 3.
|
|
15
|
+
spec.required_ruby_version = ">= 3.2.0"
|
|
16
16
|
|
|
17
17
|
spec.metadata["homepage_uri"] = spec.homepage
|
|
18
18
|
spec.metadata["source_code_uri"] = "https://github.com/altertable-ai/altertable-lakehouse-ruby"
|
|
@@ -146,16 +146,16 @@ module Altertable
|
|
|
146
146
|
@uri = URI.parse(@base_url)
|
|
147
147
|
end
|
|
148
148
|
|
|
149
|
-
def get(path, body: nil, params: {}, headers: {}, &
|
|
150
|
-
request(Net::HTTP::Get, path, params: params, headers: headers, &
|
|
149
|
+
def get(path, body: nil, params: {}, headers: {}, &) # rubocop:disable Lint/UnusedMethodArgument
|
|
150
|
+
request(Net::HTTP::Get, path, params: params, headers: headers, &)
|
|
151
151
|
end
|
|
152
152
|
|
|
153
|
-
def post(path, body: nil, params: {}, headers: {}, &
|
|
154
|
-
request(Net::HTTP::Post, path, body: body, params: params, headers: headers, &
|
|
153
|
+
def post(path, body: nil, params: {}, headers: {}, &)
|
|
154
|
+
request(Net::HTTP::Post, path, body: body, params: params, headers: headers, &)
|
|
155
155
|
end
|
|
156
156
|
|
|
157
|
-
def delete(path, body: nil, params: {}, headers: {}, &
|
|
158
|
-
request(Net::HTTP::Delete, path, params: params, headers: headers, &
|
|
157
|
+
def delete(path, body: nil, params: {}, headers: {}, &) # rubocop:disable Lint/UnusedMethodArgument
|
|
158
|
+
request(Net::HTTP::Delete, path, params: params, headers: headers, &)
|
|
159
159
|
end
|
|
160
160
|
|
|
161
161
|
private
|
|
@@ -12,7 +12,7 @@ module Altertable
|
|
|
12
12
|
DEFAULT_TIMEOUT = 10
|
|
13
13
|
DEFAULT_OPEN_TIMEOUT = 5
|
|
14
14
|
|
|
15
|
-
def initialize(username: nil, password: nil, basic_auth_token: nil, base_url: nil, timeout: nil, open_timeout: nil, user_agent: nil, adapter: nil, headers: {}, **
|
|
15
|
+
def initialize(username: nil, password: nil, basic_auth_token: nil, base_url: nil, timeout: nil, open_timeout: nil, user_agent: nil, adapter: nil, headers: {}, **)
|
|
16
16
|
# 1. Try passed basic_auth_token
|
|
17
17
|
# 2. Try passed username/password
|
|
18
18
|
# 3. Try ENV["ALTERTABLE_BASIC_AUTH_TOKEN"]
|
|
@@ -40,7 +40,7 @@ module Altertable
|
|
|
40
40
|
"User-Agent" => @user_agent
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
@adapter = select_adapter(adapter, base_url: @base_url, timeout: @timeout, open_timeout: @open_timeout, headers: default_headers.merge(headers), **
|
|
43
|
+
@adapter = select_adapter(adapter, base_url: @base_url, timeout: @timeout, open_timeout: @open_timeout, headers: default_headers.merge(headers), **)
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
# POST /append
|
|
@@ -59,8 +59,8 @@ module Altertable
|
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
# POST /query (streamed)
|
|
62
|
-
def query(statement:, headers: {}, **
|
|
63
|
-
req_body = Models::QueryRequest.new(statement: statement, **
|
|
62
|
+
def query(statement:, headers: {}, **)
|
|
63
|
+
req_body = Models::QueryRequest.new(statement: statement, **).to_h.to_json
|
|
64
64
|
|
|
65
65
|
enum = Enumerator.new do |yielder|
|
|
66
66
|
buffer = ""
|
|
@@ -77,8 +77,8 @@ module Altertable
|
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
# POST /query (accumulated)
|
|
80
|
-
def query_all(statement:, headers: {}, **
|
|
81
|
-
result = query(statement: statement, headers: headers, **
|
|
80
|
+
def query_all(statement:, headers: {}, **)
|
|
81
|
+
result = query(statement: statement, headers: headers, **)
|
|
82
82
|
rows = result.to_a # Accumulate
|
|
83
83
|
{
|
|
84
84
|
metadata: result.metadata,
|
|
@@ -278,17 +278,20 @@ module Altertable
|
|
|
278
278
|
end
|
|
279
279
|
end
|
|
280
280
|
|
|
281
|
+
ColumnDescriptor = Data.define(:name, :type)
|
|
282
|
+
|
|
281
283
|
class QueryResult
|
|
282
284
|
include Enumerable
|
|
283
285
|
|
|
284
286
|
# metadata: the stream header object (first NDJSON line)
|
|
285
|
-
# columns: array
|
|
287
|
+
# columns: ColumnDescriptor array (second NDJSON line)
|
|
286
288
|
attr_reader :metadata, :columns
|
|
287
289
|
|
|
288
290
|
def initialize(enum)
|
|
289
291
|
@enum = enum
|
|
290
292
|
@metadata = nil
|
|
291
293
|
@columns = nil
|
|
294
|
+
@column_names = nil
|
|
292
295
|
end
|
|
293
296
|
|
|
294
297
|
def each(&block)
|
|
@@ -314,10 +317,11 @@ module Altertable
|
|
|
314
317
|
when 0
|
|
315
318
|
@metadata = item
|
|
316
319
|
when 1
|
|
317
|
-
@columns =
|
|
320
|
+
@columns = column_descriptors(item)
|
|
321
|
+
@column_names = @columns.map(&:name)
|
|
318
322
|
else
|
|
319
|
-
if
|
|
320
|
-
block.call(@
|
|
323
|
+
if item.is_a?(Array)
|
|
324
|
+
block.call(@column_names.zip(item).to_h)
|
|
321
325
|
else
|
|
322
326
|
block.call(item)
|
|
323
327
|
end
|
|
@@ -337,16 +341,30 @@ module Altertable
|
|
|
337
341
|
message if message.is_a?(String)
|
|
338
342
|
end
|
|
339
343
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
return columns unless columns.is_a?(Array)
|
|
344
|
+
def column_descriptors(columns)
|
|
345
|
+
unless columns.is_a?(Array)
|
|
346
|
+
raise column_parse_error("expected an array of column objects, got #{columns.inspect}")
|
|
347
|
+
end
|
|
345
348
|
|
|
346
349
|
columns.map do |column|
|
|
347
|
-
|
|
350
|
+
name = column["name"] if column.is_a?(Hash)
|
|
351
|
+
type = column["type"] if column.is_a?(Hash)
|
|
352
|
+
unless name.is_a?(String) && type.is_a?(String)
|
|
353
|
+
raise column_parse_error("expected a { \"name\", \"type\" } column object, got #{column.inspect}")
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
ColumnDescriptor.new(name: name, type: type)
|
|
348
357
|
end
|
|
349
358
|
end
|
|
359
|
+
|
|
360
|
+
def column_parse_error(message)
|
|
361
|
+
ParseError.new(
|
|
362
|
+
"Malformed /query column line: #{message}",
|
|
363
|
+
operation: "query",
|
|
364
|
+
http_method: "POST",
|
|
365
|
+
http_path: "/query"
|
|
366
|
+
)
|
|
367
|
+
end
|
|
350
368
|
end
|
|
351
369
|
|
|
352
370
|
end
|
|
@@ -110,7 +110,7 @@ module Altertable
|
|
|
110
110
|
sig { params(statement: String, headers: T::Hash[String, String], options: T.untyped).returns(::Altertable::Lakehouse::QueryResult) }
|
|
111
111
|
def query(statement:, headers: {}, **options); end
|
|
112
112
|
|
|
113
|
-
sig { params(statement: String, headers: T::Hash[String, String], options: T.untyped).returns(T::Hash[Symbol, T.untyped])
|
|
113
|
+
sig { params(statement: String, headers: T::Hash[String, String], options: T.untyped).returns(T::Hash[Symbol, T.untyped]) }
|
|
114
114
|
def query_all(statement:, headers: {}, **options); end
|
|
115
115
|
|
|
116
116
|
sig do
|
|
@@ -204,13 +204,21 @@ module Altertable
|
|
|
204
204
|
def handle_response(resp); end
|
|
205
205
|
end
|
|
206
206
|
|
|
207
|
+
class ColumnDescriptor < Data
|
|
208
|
+
sig { returns(String) }
|
|
209
|
+
def name; end
|
|
210
|
+
|
|
211
|
+
sig { returns(String) }
|
|
212
|
+
def type; end
|
|
213
|
+
end
|
|
214
|
+
|
|
207
215
|
class QueryResult
|
|
208
216
|
include Enumerable
|
|
209
217
|
|
|
210
218
|
sig { returns(T.untyped) }
|
|
211
219
|
def metadata; end
|
|
212
220
|
|
|
213
|
-
sig { returns(T.
|
|
221
|
+
sig { returns(T.nilable(T::Array[::Altertable::Lakehouse::ColumnDescriptor])) }
|
|
214
222
|
def columns; end
|
|
215
223
|
|
|
216
224
|
sig { params(enum: T.untyped).void }
|
|
@@ -103,18 +103,34 @@ module Altertable
|
|
|
103
103
|
def handle_response: (Adapters::Response resp) -> untyped
|
|
104
104
|
end
|
|
105
105
|
|
|
106
|
+
class ColumnDescriptor < ::Data
|
|
107
|
+
attr_reader name: String
|
|
108
|
+
attr_reader type: String
|
|
109
|
+
|
|
110
|
+
def self.new: (name: String, type: String) -> instance
|
|
111
|
+
| (String name, String type) -> instance
|
|
112
|
+
def to_h: () -> { name: String, type: String }
|
|
113
|
+
end
|
|
114
|
+
|
|
106
115
|
class QueryResult
|
|
107
116
|
include Enumerable
|
|
108
117
|
|
|
109
118
|
@enum: Enumerator[untyped, untyped]
|
|
110
119
|
@metadata: untyped
|
|
111
|
-
@columns:
|
|
120
|
+
@columns: Array[ColumnDescriptor]?
|
|
121
|
+
@column_names: Array[String]?
|
|
112
122
|
|
|
113
123
|
attr_reader metadata: untyped
|
|
114
|
-
attr_reader columns:
|
|
124
|
+
attr_reader columns: Array[ColumnDescriptor]?
|
|
115
125
|
|
|
116
126
|
def initialize: (Enumerator[untyped, untyped] enum) -> void
|
|
117
127
|
def each: () { (untyped) -> void } -> void
|
|
128
|
+
|
|
129
|
+
private
|
|
130
|
+
|
|
131
|
+
def stream_error_message: (untyped item) -> String?
|
|
132
|
+
def column_descriptors: (untyped columns) -> Array[ColumnDescriptor]
|
|
133
|
+
def column_parse_error: (String message) -> ParseError
|
|
118
134
|
end
|
|
119
135
|
end
|
|
120
136
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: altertable-lakehouse
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Altertable AI
|
|
@@ -249,7 +249,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
249
249
|
requirements:
|
|
250
250
|
- - ">="
|
|
251
251
|
- !ruby/object:Gem::Version
|
|
252
|
-
version: 3.
|
|
252
|
+
version: 3.2.0
|
|
253
253
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
254
254
|
requirements:
|
|
255
255
|
- - ">="
|