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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c92cf2b0a1bf2f44a8d3b2e7934a5b9f3399293409333cbd19e5749158272176
4
- data.tar.gz: 44e709abf74aa54c03345afd11ddfb15be5aec1fff1f76722fad1d05a7c9499d
3
+ metadata.gz: 79141f78a6f427133d3eade8a3e78d697d7526eab2d767fbafa7d29d3d2954fb
4
+ data.tar.gz: 1fae0c3ce116fe23afbb8611ee272999273cd7fa5f4687cc9a4fdd32a14605f4
5
5
  SHA512:
6
- metadata.gz: 3a01c990cd7454973a878bf9a7835e9bf19b1795ba44209aa9d844e88188af31b36712b4fbcfa4ce7de503401bc5faaa3d266324da944f17d1f52b05de217d55
7
- data.tar.gz: 75b2e70e21eec5de857922989fbbb3aee671905298dd1645e8da56d26791eb41ee29112769f03aafc08d6903d0b1f578eb7561e37bf6d3dc9095de36cf2b20a1
6
+ metadata.gz: e2d5f5564023af9db4070e39af8b23f113ac8cf5b4dda09e4443e4a5cd343cefb3c26e30d5754e5576ccf72dace589a4bd412992e0b2499922f46b443ae54fd8
7
+ data.tar.gz: '0877c8558d85087f5678b1df8c48646b7f68684f331e649c8bd4b7d6c8b5a72657656d9e57d6eeef41c98b4e2d4d937c38953ed29f999ef2e9bf393e57f82d87'
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "0.8.1"
2
+ ".": "0.9.0"
3
3
  }
data/.rubocop.yml CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  AllCops:
3
3
  NewCops: enable
4
- TargetRubyVersion: 3.0
4
+ TargetRubyVersion: 3.2
5
5
  Exclude:
6
6
  - 'vendor/**/*'
7
7
  - 'spec/**/*'
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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- altertable-lakehouse (0.8.1)
4
+ altertable-lakehouse (0.9.0)
5
5
  base64
6
6
 
7
7
  GEM
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 columns
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.0.0"
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: {}, &block) # rubocop:disable Lint/UnusedMethodArgument
150
- request(Net::HTTP::Get, path, params: params, headers: headers, &block)
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: {}, &block)
154
- request(Net::HTTP::Post, path, body: body, params: params, headers: headers, &block)
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: {}, &block) # rubocop:disable Lint/UnusedMethodArgument
158
- request(Net::HTTP::Delete, path, params: params, headers: headers, &block)
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: {}, **options)
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), **options)
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: {}, **options)
63
- req_body = Models::QueryRequest.new(statement: statement, **options).to_h.to_json
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: {}, **options)
81
- result = query(statement: statement, headers: headers, **options)
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 of column names or typed column descriptors (second NDJSON line)
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 = normalize_columns(item)
320
+ @columns = column_descriptors(item)
321
+ @column_names = @columns.map(&:name)
318
322
  else
319
- if @columns.is_a?(Array) && item.is_a?(Array)
320
- block.call(@columns.zip(item).to_h)
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
- # The query service emits typed column descriptors, such as
341
- # { "name" => "id", "type" => "INTEGER" }. Keep the public result
342
- # shape stable by exposing names and using them as row keys.
343
- def normalize_columns(columns)
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
- column.is_a?(Hash) && column.key?("name") ? column["name"] : column
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
@@ -1,5 +1,5 @@
1
1
  module Altertable
2
2
  module Lakehouse
3
- VERSION = "0.8.1"
3
+ VERSION = "0.9.0"
4
4
  end
5
5
  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]).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.untyped) }
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: untyped
120
+ @columns: Array[ColumnDescriptor]?
121
+ @column_names: Array[String]?
112
122
 
113
123
  attr_reader metadata: untyped
114
- attr_reader columns: untyped
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.8.1
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.0.0
252
+ version: 3.2.0
253
253
  required_rubygems_version: !ruby/object:Gem::Requirement
254
254
  requirements:
255
255
  - - ">="