trino-client 2.0.1 → 2.1.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: 50686d406d4aedd29016b8b5cfee3024869e797791cc53e099dbf813f6a7d135
4
- data.tar.gz: d4d2e2762b8eba6ecaf6c2dd07c19f1db37eee5c8d1ebf4c995d88ec768fe62c
3
+ metadata.gz: 887c8e77f79998cb038d93f27879b2ca268d455343cb4628b865306ba894ab1d
4
+ data.tar.gz: 2f28c84bc26e36da9de4f5b3d275d099ecd304341f6640bd75c973fd8d14eded
5
5
  SHA512:
6
- metadata.gz: 203db357ca5034c2000d836667ac1bb92d976300d7299663105af90f284657854eb061625b48756a4cba0d21a4d8342d5006c95a7b6eab7e37ca1abbe832c21d
7
- data.tar.gz: 5566882e00f6edac34ac3d863d78aea8f3358e829b86d7ffff9f51582b42315b7a2b87e0d71a7b22cfd98eea5ac0fb20ab28f1e219991f1ac62e28256cf914ec
6
+ metadata.gz: 34c0baa8b9f349abc713cb1ddfcd639d04a755308c8836a504fe6e58b62992f5cea14c34e8df3d29ae0351770550519aaf3d70f12ba8a63b5a8d28ffec463dc4
7
+ data.tar.gz: fd12c7387e02b80911b2a1f6f95e68fa2e4ce798b3dea762c9097d9809847993840d424a4b47a95e62bf1ff6649294649ec184065beb83b86f12b5ba2a655900
data/ChangeLog.md CHANGED
@@ -1,5 +1,9 @@
1
1
  trino-client-ruby
2
2
  ====
3
+ ## 2.1.0
4
+ - Add utility for transforming Trino ROW type columns into Ruby hashes ([#117](https://github.com/treasure-data/trino-client-ruby/issues/117)) [[e14251c](https://github.com/treasure-data/trino-client-ruby/commit/e14251c)]
5
+ - Bump actions/checkout from 3 to 4 ([#116](https://github.com/treasure-data/trino-client-ruby/issues/116)) [[ebd9d9e](https://github.com/treasure-data/trino-client-ruby/commit/ebd9d9e)]
6
+
3
7
  ## 2.0.1
4
8
  - Reduce published gem size ([#113](https://github.com/treasure-data/trino-client-ruby/issues/113)) [[4e03819](https://github.com/treasure-data/trino-client-ruby/commit/4e03819)]
5
9
  - Update standard requirement from ~> 1.24.3 to ~> 1.30.1 ([#112](https://github.com/treasure-data/trino-client-ruby/issues/112)) [[b9f9c0c](https://github.com/treasure-data/trino-client-ruby/commit/b9f9c0c)]
@@ -0,0 +1,115 @@
1
+ module Trino::Client
2
+ class ColumnValueParser
3
+ INSIDE_MATCHING_PARENS_REGEX = /\((?>[^)(]+|\g<0>)*\)/
4
+
5
+ attr_reader :name, :type, :scalar_parser
6
+
7
+ def initialize(column, scalar_parser = nil)
8
+ @name = column.name
9
+ @type = prepare_type_for_parsing(column.type)
10
+ @scalar_parser = scalar_parser
11
+ end
12
+
13
+ # Public: Parse the value of a row's field by using its column's Trino type.
14
+ # Trino types can be scalars like VARCHAR and TIMESTAMP or complex types
15
+ # like ARRAY and ROW. ROW types are treated as objects.
16
+ # An ARRAY column's type is an array of types as you'd expect. A ROW
17
+ # column's type is a comma-separated list of space-separated (name, type) tuples.
18
+ #
19
+ # data - The value of a row's field. Can be a string, number, an array of those,
20
+ # or an arrays of arrays, etc.
21
+ # dtype - The Trino type string of the column. See above explanation.
22
+ #
23
+ # Returns:
24
+ # - The given value for strings and numbers
25
+ # - A Time for timestamps
26
+ # - A Hash of { field1 => value1, field2 => value2, ...etc } for row types
27
+ # - An array of the above for array types
28
+ def value(data, dtype = type)
29
+ # Convert Trino ARRAY elements into Ruby Arrays
30
+ if starts_with?(dtype, 'array(')
31
+ return parse_array_element(data, dtype)
32
+
33
+ # Convert Trino ROW elements into Ruby Hashes
34
+ elsif starts_with?(dtype, 'row(')
35
+ return parse_row_element(data, dtype)
36
+
37
+ # If defined, use scalar_parser to convert scalar types
38
+ elsif !scalar_parser.nil?
39
+ return scalar_parser.call(data, dtype)
40
+ end
41
+
42
+ # Otherwise, values are returned unaltered
43
+ data
44
+ end
45
+
46
+ private
47
+
48
+ # Private: Remove quotation marks and handle recent versions of
49
+ # Trino having a 'with time zone' suffix on some fields that breaks
50
+ # out assumption that types don't have spaces in them.
51
+ #
52
+ # Returns a string.
53
+ def prepare_type_for_parsing(type)
54
+ type.gsub('"', '').gsub(' with time zone', '_with_time_zone')
55
+ end
56
+
57
+ def parse_array_element(data, dtype)
58
+ # If the element is empty, return an empty array
59
+ return [] if blank?(data)
60
+
61
+ # Inner data type will be the current dtype with `array(` and `)` chopped off
62
+ inner_dtype = dtype.match(INSIDE_MATCHING_PARENS_REGEX)[0][1..-2]
63
+
64
+ data.map { |inner_data| value(inner_data, inner_dtype) }
65
+ end
66
+
67
+ def parse_row_element(data, dtype)
68
+ # If the element is empty, return an empty object
69
+ return {} if blank?(data)
70
+
71
+ parsed_row_element = {}
72
+
73
+ inner_dtype = dtype.match(INSIDE_MATCHING_PARENS_REGEX)[0][1..-2]
74
+ elems = inner_dtype.split(' ')
75
+ num_elems_to_skip = 0
76
+ field_position = 0
77
+
78
+ # Iterate over each datatype of the row and mutate parsed_row_element
79
+ # to have a key of the field name and value for that field's value.
80
+ elems.each_with_index do |field, i|
81
+ # We detected an array or row and are skipping all of the elements within it
82
+ # since its conversion was handled by calling `value` recursively.
83
+ if num_elems_to_skip.positive?
84
+ num_elems_to_skip -= 1
85
+ next
86
+ end
87
+
88
+ # Field names never have these characters and are never the last element.
89
+ next if field.include?(',') || field.include?('(') || field.include?(')') || i == elems.length - 1
90
+
91
+ type = elems[(i + 1)..].join(' ')
92
+
93
+ # If this row has a nested array or row, the type of this field is that array or row's type.
94
+ if starts_with?(type, 'array(') || starts_with?(type, 'row(')
95
+ datatype = type.sub(/\(.*/, '')
96
+ type = "#{datatype}#{type.match(INSIDE_MATCHING_PARENS_REGEX)[0]}"
97
+ num_elems_to_skip = type.split(' ').length # see above comment about num_elems_to_skip
98
+ end
99
+
100
+ parsed_row_element[field] = value(data[field_position], type)
101
+ field_position += 1
102
+ end
103
+
104
+ parsed_row_element
105
+ end
106
+
107
+ def blank?(obj)
108
+ obj.respond_to?(:empty?) ? !!obj.empty? : !obj
109
+ end
110
+
111
+ def starts_with?(str, prefix)
112
+ prefix.respond_to?(:to_str) && str[0, prefix.length] == prefix
113
+ end
114
+ end
115
+ end
@@ -18,6 +18,7 @@ module Trino::Client
18
18
  require 'faraday'
19
19
  require 'faraday/gzip'
20
20
  require 'faraday/follow_redirects'
21
+ require 'trino/client/column_value_parser'
21
22
  require 'trino/client/models'
22
23
  require 'trino/client/errors'
23
24
  require 'trino/client/faraday_client'
@@ -44,6 +45,19 @@ module Trino::Client
44
45
  Trino::Client.faraday_client(options)
45
46
  end
46
47
 
48
+ def self.transform_row(column_value_parsers, row)
49
+ row_object = {}
50
+
51
+ row.each_with_index do |element, i|
52
+ column = column_value_parsers[i]
53
+ value = column.value(element)
54
+
55
+ row_object[column.name] = value
56
+ end
57
+
58
+ row_object
59
+ end
60
+
47
61
  def initialize(api)
48
62
  @api = api
49
63
  end
@@ -86,6 +100,20 @@ module Trino::Client
86
100
  return @api.current_results.columns
87
101
  end
88
102
 
103
+ def column_value_parsers
104
+ @column_value_parsers ||= columns.map {|column|
105
+ ColumnValueParser.new(column)
106
+ }
107
+ end
108
+
109
+ def transform_rows
110
+ rows.map(&:transform_row)
111
+ end
112
+
113
+ def transform_row(row)
114
+ self.class.transform_row(column_value_parsers, row)
115
+ end
116
+
89
117
  def rows
90
118
  rows = []
91
119
  each_row_chunk {|chunk|
@@ -15,6 +15,6 @@
15
15
  #
16
16
  module Trino
17
17
  module Client
18
- VERSION = "2.0.1"
18
+ VERSION = "2.1.0"
19
19
  end
20
20
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trino-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sadayuki Furuhashi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-17 00:00:00.000000000 Z
11
+ date: 2023-09-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -190,6 +190,7 @@ files:
190
190
  - lib/trino-client.rb
191
191
  - lib/trino/client.rb
192
192
  - lib/trino/client/client.rb
193
+ - lib/trino/client/column_value_parser.rb
193
194
  - lib/trino/client/errors.rb
194
195
  - lib/trino/client/faraday_client.rb
195
196
  - lib/trino/client/model_versions/0.149.rb